furnace 0.4.0.beta.1 → 0.4.0.beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +6 -0
  3. data/INSTRUMENT.md +250 -0
  4. data/Rakefile +1 -1
  5. data/lib/furnace.rb +10 -6
  6. data/lib/furnace/ast/node.rb +15 -1
  7. data/lib/furnace/awesome_printer.rb +121 -0
  8. data/lib/furnace/context.rb +0 -0
  9. data/lib/furnace/ssa.rb +7 -25
  10. data/lib/furnace/ssa/argument.rb +14 -10
  11. data/lib/furnace/ssa/basic_block.rb +70 -25
  12. data/lib/furnace/ssa/builder.rb +11 -7
  13. data/lib/furnace/ssa/constant.rb +19 -11
  14. data/lib/furnace/ssa/event_stream.rb +145 -0
  15. data/lib/furnace/ssa/function.rb +78 -57
  16. data/lib/furnace/ssa/generic_instruction.rb +12 -5
  17. data/lib/furnace/ssa/instruction.rb +50 -35
  18. data/lib/furnace/ssa/instruction_syntax.rb +9 -25
  19. data/lib/furnace/ssa/instructions/branch.rb +2 -2
  20. data/lib/furnace/ssa/instructions/phi.rb +12 -10
  21. data/lib/furnace/ssa/instructions/return.rb +3 -3
  22. data/lib/furnace/ssa/instructions/return_value.rb +11 -0
  23. data/lib/furnace/ssa/instrumentation.rb +33 -0
  24. data/lib/furnace/ssa/module.rb +5 -1
  25. data/lib/furnace/ssa/named_value.rb +31 -10
  26. data/lib/furnace/ssa/terminator_instruction.rb +6 -6
  27. data/lib/furnace/ssa/types/basic_block.rb +4 -8
  28. data/lib/furnace/ssa/types/function.rb +4 -8
  29. data/lib/furnace/ssa/user.rb +14 -15
  30. data/lib/furnace/ssa/value.rb +9 -5
  31. data/lib/furnace/transform/iterative.rb +20 -4
  32. data/lib/furnace/type.rb +9 -0
  33. data/lib/furnace/type/bottom.rb +11 -0
  34. data/lib/furnace/type/top.rb +72 -0
  35. data/lib/furnace/type/value.rb +13 -0
  36. data/lib/furnace/type/variable.rb +61 -0
  37. data/lib/furnace/version.rb +1 -1
  38. data/test/{test_helper.rb → helper.rb} +28 -3
  39. data/test/{ast_test.rb → test_ast.rb} +13 -1
  40. data/test/test_awesome_printer.rb +148 -0
  41. data/test/{ssa_test.rb → test_ssa.rb} +276 -315
  42. data/test/{transform_test.rb → test_transform.rb} +2 -2
  43. data/test/test_type.rb +138 -0
  44. metadata +83 -105
  45. data/lib/furnace/graphviz.rb +0 -49
  46. data/lib/furnace/ssa/generic_type.rb +0 -16
  47. data/lib/furnace/ssa/pretty_printer.rb +0 -113
  48. data/lib/furnace/ssa/type.rb +0 -27
  49. data/lib/furnace/ssa/types/void.rb +0 -15
@@ -1,11 +1,11 @@
1
1
  module Furnace
2
2
  class SSA::BranchInsn < SSA::TerminatorInstruction
3
3
  syntax do |s|
4
- s.operand :target, SSA::BasicBlock
4
+ s.operand :target
5
5
  end
6
6
 
7
7
  def exits?
8
8
  false
9
9
  end
10
10
  end
11
- end
11
+ end
@@ -1,7 +1,7 @@
1
1
  module Furnace
2
2
  class SSA::PhiInsn < SSA::GenericInstruction
3
- def initialize(basic_block, type, operands={}, name=nil)
4
- super(basic_block, type, operands, name)
3
+ def initialize(type, operands={}, name=nil)
4
+ super(type, operands, name)
5
5
  end
6
6
 
7
7
  def each_operand(&block)
@@ -29,13 +29,11 @@ module Furnace
29
29
 
30
30
  protected
31
31
 
32
- def pretty_operands(p)
33
- @operands.each_with_index do |(basic_block, value), index|
34
- p.name basic_block.name
35
- p.text '=>'
36
- value.inspect_as_value p
37
-
38
- p << ',' if index < @operands.count - 1
32
+ def awesome_print_operands(p)
33
+ p.collection('', ', ', '', @operands) do |basic_block, value|
34
+ p.name(basic_block.name).
35
+ text('=>')
36
+ value.awesome_print_as_value p
39
37
  end
40
38
  end
41
39
 
@@ -45,6 +43,8 @@ module Furnace
45
43
  @operands.delete use
46
44
  @operands[new_use] = value
47
45
 
46
+ SSA.instrument(self)
47
+
48
48
  true
49
49
  else
50
50
  found = false
@@ -56,8 +56,10 @@ module Furnace
56
56
  end
57
57
  end
58
58
 
59
+ SSA.instrument(self)
60
+
59
61
  found
60
62
  end
61
63
  end
62
64
  end
63
- end
65
+ end
@@ -1,11 +1,11 @@
1
1
  module Furnace
2
2
  class SSA::ReturnInsn < SSA::TerminatorInstruction
3
- syntax do |s|
4
- s.operand :value
3
+ def value_type
4
+ Type::Bottom.new
5
5
  end
6
6
 
7
7
  def exits?
8
8
  true
9
9
  end
10
10
  end
11
- end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Furnace
2
+ class SSA::ReturnValueInsn < SSA::ReturnInsn
3
+ syntax do |s|
4
+ s.operand :value
5
+ end
6
+
7
+ def value_type
8
+ value.type
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ module Furnace
2
+ module SSA
3
+ @instrumentation = nil
4
+
5
+ def self.instrumentation
6
+ if block_given?
7
+ yield @instrumentation if @instrumentation
8
+ else
9
+ @instrumentation
10
+ end
11
+ end
12
+
13
+ def self.instrumentation=(instrumentation)
14
+ @instrumentation = instrumentation
15
+ end
16
+
17
+ def self.start_instrumentation
18
+ @instrumentation = SSA::EventStream.new
19
+ end
20
+
21
+ def self.dump_instrumentation(filename)
22
+ File.open(filename, 'w') do |io|
23
+ io.write JSON.dump(@instrumentation.data)
24
+ end
25
+ end
26
+
27
+ def self.instrument(what)
28
+ instrumentation do |i|
29
+ i.process(what)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -37,10 +37,14 @@ module Furnace
37
37
  end
38
38
 
39
39
  @functions[function.name] = function
40
+
41
+ SSA.instrument(self)
40
42
  end
41
43
 
42
44
  def remove(name)
43
45
  @functions.delete name
46
+
47
+ SSA.instrument(self)
44
48
  end
45
49
 
46
50
  protected
@@ -49,4 +53,4 @@ module Furnace
49
53
  @next_id += 1
50
54
  end
51
55
  end
52
- end
56
+ end
@@ -1,25 +1,46 @@
1
1
  module Furnace
2
2
  class SSA::NamedValue < SSA::Value
3
- attr_accessor :function
4
- attr_reader :name
3
+ attr_reader :function
4
+ attr_reader :name
5
5
 
6
- def initialize(function, name)
6
+ def initialize(name=nil)
7
7
  super()
8
8
 
9
- @function = function
10
- self.name = name
9
+ @function = nil
10
+ @name = name
11
11
  end
12
12
 
13
13
  def name=(name)
14
- @name = @function.make_name(name)
14
+ if @function
15
+ @name = @function.make_name(name)
16
+ else
17
+ @name = name
18
+ end
19
+
20
+ SSA.instrument(self)
21
+ end
22
+
23
+ def function=(function)
24
+ if @function != function
25
+ @name = function.make_name(@name)
26
+ @function = function
27
+ end
28
+
29
+ SSA.instrument(self)
30
+ end
31
+
32
+ def detach
33
+ @function = nil
34
+
35
+ SSA.instrument(self)
15
36
  end
16
37
 
17
- def inspect_as_value(p=SSA::PrettyPrinter.new)
18
- p.name name
38
+ def awesome_print_as_value(p=AwesomePrinter.new)
39
+ p.name(@name)
19
40
  end
20
41
 
21
42
  def inspect
22
- pretty_print
43
+ awesome_print
23
44
  end
24
45
  end
25
- end
46
+ end
@@ -1,24 +1,24 @@
1
1
  module Furnace
2
2
  class SSA::TerminatorInstruction < SSA::Instruction
3
- def has_side_effects?
3
+ def terminator?
4
4
  true
5
5
  end
6
6
 
7
- def terminator?
8
- true
7
+ def has_side_effects?
8
+ exits?
9
9
  end
10
10
 
11
11
  def exits?
12
- raise NotImplementedError, "reimplement SSA::TerminatorInstruction#exits? in a subclass"
12
+ raise NotImplementedError, "reimplement #{self.class}#exits?"
13
13
  end
14
14
 
15
15
  def successors
16
16
  operands.
17
17
  select do |value|
18
- value.type == SSA::BasicBlockType.instance
18
+ value.type == SSA::BasicBlockType.new
19
19
  end.map do |value|
20
20
  value.name
21
21
  end
22
22
  end
23
23
  end
24
- end
24
+ end
@@ -1,11 +1,7 @@
1
1
  module Furnace
2
- class SSA::BasicBlockType < SSA::Type
3
- def self.instance
4
- @instance ||= new
5
- end
6
-
7
- def inspect
8
- "label"
2
+ class SSA::BasicBlockType < Type::Top
3
+ def to_s
4
+ 'label'
9
5
  end
10
6
  end
11
- end
7
+ end
@@ -1,11 +1,7 @@
1
1
  module Furnace
2
- class SSA::FunctionType < SSA::Type
3
- def self.instance
4
- @instance ||= new
5
- end
6
-
7
- def inspect
8
- "function"
2
+ class SSA::FunctionType < Type::Top
3
+ def to_s
4
+ 'function'
9
5
  end
10
6
  end
11
- end
7
+ end
@@ -2,12 +2,18 @@ module Furnace
2
2
  class SSA::User < SSA::NamedValue
3
3
  attr_reader :operands
4
4
 
5
- def initialize(function, operands=[], name=nil)
6
- super(function, name)
5
+ def initialize(operands=[], name=nil)
6
+ super(name)
7
7
 
8
8
  self.operands = operands
9
9
  end
10
10
 
11
+ def initialize_copy(original)
12
+ @operands = nil
13
+
14
+ super
15
+ end
16
+
11
17
  def each_operand(&block)
12
18
  @operands.each &block if @operands
13
19
  end
@@ -18,7 +24,7 @@ module Furnace
18
24
  end
19
25
  end
20
26
 
21
- def detach
27
+ def drop_references
22
28
  update_use_lists do
23
29
  @operands = nil
24
30
  end
@@ -41,17 +47,6 @@ module Furnace
41
47
  self
42
48
  end
43
49
 
44
- def valid?(*args)
45
- verify!(*args)
46
- true
47
- rescue TypeError
48
- false
49
- end
50
-
51
- def verify!
52
- # do nothing
53
- end
54
-
55
50
  protected
56
51
 
57
52
  def update_use_lists
@@ -65,6 +60,8 @@ module Furnace
65
60
  operand.add_use(self)
66
61
  end
67
62
 
63
+ SSA.instrument(self)
64
+
68
65
  value
69
66
  end
70
67
 
@@ -78,7 +75,9 @@ module Furnace
78
75
  end
79
76
  end
80
77
 
78
+ SSA.instrument(self)
79
+
81
80
  found
82
81
  end
83
82
  end
84
- end
83
+ end
@@ -2,14 +2,18 @@ module Furnace
2
2
  class SSA::Value
3
3
  def initialize
4
4
  @uses = Set.new
5
+
6
+ SSA.instrument(self)
5
7
  end
6
8
 
7
9
  def initialize_copy(original)
8
10
  @uses = Set.new
11
+
12
+ SSA.instrument(self)
9
13
  end
10
14
 
11
15
  def type
12
- SSA.void
16
+ Type::Bottom.new
13
17
  end
14
18
 
15
19
  def constant?
@@ -51,12 +55,12 @@ module Furnace
51
55
  equal?(other.to_value)
52
56
  end
53
57
 
54
- def pretty_print(p=SSA::PrettyPrinter.new)
55
- inspect_as_value(p)
58
+ def awesome_print(p=AwesomePrinter.new)
59
+ awesome_print_as_value(p)
56
60
  end
57
61
 
58
- def inspect_as_value(p=SSA::PrettyPrinter.new)
62
+ def awesome_print_as_value(p=AwesomePrinter.new)
59
63
  p.text inspect
60
64
  end
61
65
  end
62
- end
66
+ end
@@ -1,25 +1,41 @@
1
+ require 'set'
2
+
1
3
  module Furnace
2
4
  module Transform
3
5
  class Iterative
4
- def initialize(stages)
6
+ LOOP_THRESHOLD = 100
7
+
8
+ def initialize(stages, options={})
5
9
  @stages = stages
10
+
11
+ @debug = options[:debug]
12
+ @iterations = 0
6
13
  end
7
14
 
8
15
  def run(context)
9
16
  self_changed = false
10
17
 
11
18
  loop do
12
- changed = false
19
+ changed = Set[]
13
20
 
14
21
  @stages.each do |stage|
22
+ # FIXME?
15
23
  return self_changed if stage.nil?
16
24
 
17
25
  if stage.run(context)
18
- self_changed = changed = true
26
+ self_changed = true
27
+ changed.add stage
19
28
  end
20
29
  end
21
30
 
22
- return self_changed unless changed
31
+ return self_changed if changed.empty?
32
+
33
+ if @debug
34
+ @iterations += 1
35
+ if @iterations > LOOP_THRESHOLD
36
+ raise "Transform::Iterative has detected infinite loop in: #{changed.to_a}"
37
+ end
38
+ end
23
39
  end
24
40
  end
25
41
  end
@@ -0,0 +1,9 @@
1
+ module Furnace
2
+ module Type
3
+ end
4
+
5
+ require_relative 'type/top'
6
+ require_relative 'type/bottom'
7
+ require_relative 'type/value'
8
+ require_relative 'type/variable'
9
+ end
@@ -0,0 +1,11 @@
1
+ module Furnace
2
+ class Type::Bottom < Type::Top
3
+ def subtype_of?(other)
4
+ other.is_a?(Type::Top)
5
+ end
6
+
7
+ def to_s
8
+ 'bottom'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,72 @@
1
+ module Furnace
2
+ class Type::Top
3
+ class << self
4
+ def normalize(*params)
5
+ params
6
+ end
7
+
8
+ def new(*params)
9
+ @instances[normalize(*params)]
10
+ end
11
+
12
+ protected
13
+
14
+ def setup_singleton
15
+ @instances = Hash.new do |hash, params|
16
+ inst = allocate
17
+ inst.send :initialize, *params
18
+ inst.freeze
19
+
20
+ hash[params] = inst
21
+ end
22
+ end
23
+
24
+ def inherited(klass)
25
+ klass.setup_singleton
26
+ end
27
+ end
28
+
29
+ setup_singleton
30
+
31
+ def to_type
32
+ self
33
+ end
34
+
35
+ def subtype_of?(other)
36
+ other.instance_of?(Type::Top) ||
37
+ self == other
38
+ end
39
+
40
+ def supertype_of?(other)
41
+ other.subtype_of?(self)
42
+ end
43
+
44
+ def variable?
45
+ false
46
+ end
47
+
48
+ def replace_type_with(type, replacement)
49
+ if self == type
50
+ replacement.to_type
51
+ else
52
+ self
53
+ end
54
+ end
55
+
56
+ def specialize(other)
57
+ if self == other
58
+ {}
59
+ else
60
+ raise ArgumentError, "cannot specialize #{self.to_s} with #{other.to_s}"
61
+ end
62
+ end
63
+
64
+ def to_s
65
+ 'top'
66
+ end
67
+
68
+ def awesome_print(p=AwesomePrinter.new)
69
+ p.type(self)
70
+ end
71
+ end
72
+ end