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
File without changes
@@ -1,21 +1,9 @@
1
1
  module Furnace
2
2
  module SSA
3
- def self.void
4
- SSA::VoidType.instance
5
- end
6
-
7
- def self.void_value
8
- SSA::VoidType.value
9
- end
10
-
11
3
  def self.class_name_to_opcode(klass)
12
- klass.to_s.split('::').last.gsub(/([a-z]|^)([A-Z])/) do
13
- if $1.empty?
14
- $2.downcase
15
- else
16
- "#{$1}_#{$2.downcase}"
17
- end
18
- end.gsub(/_insn$/, '')
4
+ klass.to_s.split('::').last.
5
+ gsub(/([A-Z])/) { '_' + $1.downcase }.
6
+ gsub(/^_(.+)_insn$/, '\1')
19
7
  end
20
8
 
21
9
  def self.opcode_to_class_name(opcode)
@@ -27,18 +15,11 @@ module Furnace
27
15
  end
28
16
  end + 'Insn'
29
17
  end
30
-
31
- def self.inspect_type(type)
32
- type ? type.inspect : '<?>'
33
- end
34
18
  end
35
19
 
36
- require_relative 'ssa/pretty_printer'
37
-
38
- require_relative 'ssa/type'
39
- require_relative 'ssa/generic_type'
20
+ require_relative 'ssa/event_stream'
21
+ require_relative 'ssa/instrumentation'
40
22
 
41
- require_relative 'ssa/types/void'
42
23
  require_relative 'ssa/types/basic_block'
43
24
  require_relative 'ssa/types/function'
44
25
 
@@ -59,8 +40,9 @@ module Furnace
59
40
  require_relative 'ssa/instructions/phi'
60
41
  require_relative 'ssa/instructions/branch'
61
42
  require_relative 'ssa/instructions/return'
43
+ require_relative 'ssa/instructions/return_value'
62
44
 
63
45
  require_relative 'ssa/module'
64
46
 
65
47
  require_relative 'ssa/builder'
66
- end
48
+ end
@@ -2,22 +2,26 @@ module Furnace
2
2
  class SSA::Argument < SSA::NamedValue
3
3
  attr_reader :type
4
4
 
5
- def initialize(function, type, name)
6
- super(function, name)
7
- self.type = type
5
+ def initialize(type, name)
6
+ @type = type.to_type
7
+
8
+ super(name)
8
9
  end
9
10
 
10
11
  def type=(type)
11
- @type = type.to_type if type
12
+ @type = type.to_type
13
+
14
+ SSA.instrument(self)
12
15
  end
13
16
 
14
- def has_side_effects?
15
- true
17
+ def replace_type_with(type, replacement)
18
+ self.type = self.type.
19
+ replace_type_with(type, replacement)
16
20
  end
17
21
 
18
- def pretty_print(p=SSA::PrettyPrinter.new)
19
- p.type type
20
- p.name name
22
+ def awesome_print(p=AwesomePrinter.new)
23
+ p.nest(@type).
24
+ name(name)
21
25
  end
22
26
  end
23
- end
27
+ end
@@ -1,32 +1,41 @@
1
1
  module Furnace
2
2
  class SSA::BasicBlock < SSA::NamedValue
3
- def initialize(function, name=nil, insns=[])
4
- super(function, name)
3
+ def initialize(insns=[], name=nil)
5
4
  @instructions = insns.to_a
5
+
6
+ super(name)
6
7
  end
7
8
 
8
9
  def initialize_copy(original)
9
- super
10
-
11
10
  @instructions = []
11
+
12
+ super
12
13
  end
13
14
 
14
15
  def to_a
15
16
  @instructions.dup
16
17
  end
17
18
 
19
+ def function=(function)
20
+ if @function && @function != function
21
+ @function.remove self
22
+ end
23
+
24
+ super
25
+ end
26
+
18
27
  def include?(instruction)
19
28
  @instructions.include? instruction
20
29
  end
21
30
 
22
- def each(type=nil, &proc)
23
- if type.nil?
31
+ def each(*types, &proc)
32
+ if types.empty?
24
33
  @instructions.each(&proc)
25
34
  else
26
- return to_enum(:each, type) if proc.nil?
35
+ return to_enum(:each, *types) if proc.nil?
27
36
 
28
37
  @instructions.each do |insn|
29
- if insn.instance_of? type
38
+ if types.include?(insn.class)
30
39
  yield insn
31
40
  end
32
41
  end
@@ -35,18 +44,42 @@ module Furnace
35
44
 
36
45
  alias each_instruction each
37
46
 
47
+ def prepend(instruction)
48
+ instruction.basic_block = self
49
+ @instructions.unshift instruction
50
+
51
+ SSA.instrument(self)
52
+ end
53
+
38
54
  def append(instruction)
55
+ instruction.basic_block = self
39
56
  @instructions.push instruction
57
+
58
+ SSA.instrument(self)
40
59
  end
41
60
 
42
61
  alias << append
43
62
 
63
+ def index(instruction)
64
+ @instructions.index(instruction)
65
+ end
66
+
44
67
  def insert(before, instruction)
45
- unless index = @instructions.index(before)
68
+ unless (idx = index(before))
46
69
  raise ArgumentError, "Instruction #{before} is not found"
47
70
  end
48
71
 
49
- @instructions.insert index, instruction
72
+ instruction.basic_block = self
73
+ @instructions.insert idx, instruction
74
+
75
+ SSA.instrument(self)
76
+ end
77
+
78
+ def remove(instruction)
79
+ @instructions.delete instruction
80
+ instruction.detach
81
+
82
+ SSA.instrument(self)
50
83
  end
51
84
 
52
85
  def replace(instruction, replace_with)
@@ -54,8 +87,19 @@ module Furnace
54
87
  remove instruction
55
88
  end
56
89
 
57
- def remove(instruction)
58
- @instructions.delete instruction
90
+ def splice(after)
91
+ unless (idx = index(after))
92
+ raise ArgumentError, "Instruction #{after} is not found"
93
+ end
94
+
95
+ result = []
96
+
97
+ @instructions[idx + 1..-1].each do |insn|
98
+ result << insn
99
+ remove insn
100
+ end
101
+
102
+ result
59
103
  end
60
104
 
61
105
  def terminator
@@ -85,7 +129,7 @@ module Furnace
85
129
  end
86
130
 
87
131
  def self.to_type
88
- SSA::BasicBlockType.instance
132
+ SSA::BasicBlockType.new
89
133
  end
90
134
 
91
135
  def type
@@ -96,22 +140,23 @@ module Furnace
96
140
  true
97
141
  end
98
142
 
99
- def pretty_print(p=SSA::PrettyPrinter.new)
100
- p.text @name, ":"
101
- p.newline
143
+ def awesome_print(p=AwesomePrinter.new)
144
+ p.text(@name).
145
+ append(":").
146
+ newline
102
147
 
103
- each do |insn|
104
- p << ' '
105
- insn.pretty_print(p)
106
- p.newline
148
+ p.collection(@instructions) do |insn|
149
+ p.append(' ').
150
+ nest(insn).
151
+ newline
107
152
  end
108
153
 
109
- p
154
+ p.newline
110
155
  end
111
156
 
112
- def inspect_as_value(p=SSA::PrettyPrinter.new)
113
- p.keyword 'label'
114
- p.name name
157
+ def awesome_print_as_value(p=AwesomePrinter.new)
158
+ p.keyword('label').
159
+ name(name)
115
160
  end
116
161
  end
117
- end
162
+ end
@@ -10,7 +10,7 @@ module Furnace
10
10
  def initialize(name, arguments=[], return_type=nil)
11
11
  @function = SSA::Function.new(name, [], return_type)
12
12
  @function.arguments = arguments.map do |(type, name)|
13
- SSA::Argument.new(@function, type, name)
13
+ SSA::Argument.new(type, name)
14
14
  end
15
15
 
16
16
  @block = @function.entry = add_block
@@ -21,7 +21,7 @@ module Furnace
21
21
  end
22
22
 
23
23
  def add_block
24
- block = SSA::BasicBlock.new(@function)
24
+ block = SSA::BasicBlock.new
25
25
  @function.add block
26
26
 
27
27
  if block_given?
@@ -35,7 +35,7 @@ module Furnace
35
35
  end
36
36
 
37
37
  def append(instruction, *args)
38
- insn = lookup_insn(instruction).new(@block, *args)
38
+ insn = lookup_insn(instruction).new(*args)
39
39
  @block.append insn
40
40
 
41
41
  insn
@@ -64,7 +64,7 @@ module Furnace
64
64
  @block = old_block
65
65
  end
66
66
 
67
- def control_flow_op(instruction, type=nil, uses)
67
+ def control_flow_op(instruction, type=Type::Variable.new, uses)
68
68
  cond_block = @block
69
69
  post_block = add_block
70
70
 
@@ -83,8 +83,12 @@ module Furnace
83
83
  end)
84
84
  end
85
85
 
86
- def return(value)
87
- append(:return, [ value ])
86
+ def return
87
+ append(:return)
88
+ end
89
+
90
+ def return_value(value)
91
+ append(:return_value, [ value ])
88
92
  end
89
93
 
90
94
  def method_missing(opcode, *args)
@@ -97,4 +101,4 @@ module Furnace
97
101
  end
98
102
  end
99
103
  end
100
- end
104
+ end
@@ -1,17 +1,25 @@
1
1
  module Furnace
2
2
  class SSA::Constant < SSA::Value
3
- attr_reader :type
4
- attr_accessor :value
3
+ attr_reader :type
4
+ attr_reader :value
5
5
 
6
6
  def initialize(type, value)
7
- super()
7
+ @value = value
8
+ @type = type.to_type
8
9
 
9
- self.type = type
10
- @value = value
10
+ super()
11
11
  end
12
12
 
13
13
  def type=(type)
14
- @type = type.to_type
14
+ @type = type.to_type
15
+
16
+ SSA.instrument(self)
17
+ end
18
+
19
+ def value=(value)
20
+ @value = value
21
+
22
+ SSA.instrument(self)
15
23
  end
16
24
 
17
25
  def constant?
@@ -30,14 +38,14 @@ module Furnace
30
38
  end
31
39
  end
32
40
 
33
- def inspect_as_value(p=SSA::PrettyPrinter.new)
34
- p.type type
35
- p.text @value.inspect unless type == SSA.void
41
+ def awesome_print_as_value(p=AwesomePrinter.new)
42
+ type.awesome_print(p)
43
+ p.text @value.inspect
36
44
  p
37
45
  end
38
46
 
39
47
  def inspect
40
- pretty_print
48
+ awesome_print
41
49
  end
42
50
  end
43
- end
51
+ end
@@ -0,0 +1,145 @@
1
+ module Furnace
2
+ class SSA::EventStream
3
+ def initialize
4
+ @events = []
5
+ @types = Set[]
6
+ @annotator = Type::Variable::Annotator.new
7
+ end
8
+
9
+ def data
10
+ @events
11
+ end
12
+
13
+ def process(object)
14
+ case object
15
+ # Types
16
+ when Type::Bottom
17
+ event = {
18
+ kind: "type_bottom",
19
+ name: "bottom",
20
+ }
21
+
22
+ when Type::Top
23
+ event = {
24
+ kind: "type",
25
+ name: object.awesome_print(printer).to_s,
26
+ }
27
+
28
+ when Type::Variable
29
+ event = {
30
+ kind: "type_variable",
31
+ name: object.awesome_print(printer).to_s,
32
+ }
33
+
34
+ # Entities
35
+ when SSA::Constant
36
+ event = {
37
+ kind: "constant",
38
+ type: type(object.type),
39
+ value: object.value.inspect,
40
+ }
41
+
42
+ when SSA::Argument
43
+ event = {
44
+ kind: "argument",
45
+ name: object.name,
46
+ type: type(object.type),
47
+ }
48
+
49
+ when SSA::BasicBlock
50
+ event = {
51
+ kind: "basic_block",
52
+ name: object.name,
53
+ instruction_ids: ids(object.each),
54
+ }
55
+
56
+ when SSA::PhiInsn
57
+ if object.operands
58
+ operand_ids = object.operands.
59
+ map do |block, value|
60
+ [ id(block), id(value) ]
61
+ end
62
+ end
63
+
64
+ event = {
65
+ kind: "phi",
66
+ name: object.name,
67
+ type: type(object.type),
68
+ operand_ids: operand_ids,
69
+ }
70
+
71
+ when SSA::Instruction
72
+ event = {
73
+ kind: "instruction",
74
+ name: object.name,
75
+ opcode: object.opcode,
76
+ type: type(object.type),
77
+ operand_ids: ids(object.operands),
78
+ }
79
+
80
+ when SSA::Function
81
+ event = {
82
+ kind: "function",
83
+ name: object.name,
84
+ argument_ids: ids(object.arguments),
85
+ return_type: type(object.return_type),
86
+ entry_id: id(object.entry),
87
+ basic_block_ids: ids(object.each),
88
+ }
89
+
90
+ when SSA::Module
91
+ event = {
92
+ kind: "module",
93
+ function_ids: ids(object.each),
94
+ }
95
+
96
+ else
97
+ raise "Cannot instrument #{object.class}"
98
+ end
99
+
100
+ @events << { id: id(object) }.merge(event)
101
+
102
+ nil
103
+ end
104
+
105
+ def mark_transform(function, name)
106
+ @events << {
107
+ kind: "transform",
108
+ function_id: id(function),
109
+ name: name
110
+ }
111
+ end
112
+
113
+ protected
114
+
115
+ def id(object)
116
+ if object
117
+ object.object_id
118
+ end
119
+ end
120
+
121
+ def ids(objects)
122
+ if objects
123
+ objects.map do |object|
124
+ id(object)
125
+ end
126
+ end
127
+ end
128
+
129
+ def type(type)
130
+ if @types.include?(type)
131
+ type.object_id
132
+ else
133
+ @types.add type
134
+
135
+ process(type)
136
+
137
+ type.object_id
138
+ end
139
+ end
140
+
141
+ def printer
142
+ AwesomePrinter.new(false, @annotator)
143
+ end
144
+ end
145
+ end