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

Sign up to get free protection for your applications and to get access to all the features.
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