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.
- checksums.yaml +7 -0
- data/.travis.yml +6 -0
- data/INSTRUMENT.md +250 -0
- data/Rakefile +1 -1
- data/lib/furnace.rb +10 -6
- data/lib/furnace/ast/node.rb +15 -1
- data/lib/furnace/awesome_printer.rb +121 -0
- data/lib/furnace/context.rb +0 -0
- data/lib/furnace/ssa.rb +7 -25
- data/lib/furnace/ssa/argument.rb +14 -10
- data/lib/furnace/ssa/basic_block.rb +70 -25
- data/lib/furnace/ssa/builder.rb +11 -7
- data/lib/furnace/ssa/constant.rb +19 -11
- data/lib/furnace/ssa/event_stream.rb +145 -0
- data/lib/furnace/ssa/function.rb +78 -57
- data/lib/furnace/ssa/generic_instruction.rb +12 -5
- data/lib/furnace/ssa/instruction.rb +50 -35
- data/lib/furnace/ssa/instruction_syntax.rb +9 -25
- data/lib/furnace/ssa/instructions/branch.rb +2 -2
- data/lib/furnace/ssa/instructions/phi.rb +12 -10
- data/lib/furnace/ssa/instructions/return.rb +3 -3
- data/lib/furnace/ssa/instructions/return_value.rb +11 -0
- data/lib/furnace/ssa/instrumentation.rb +33 -0
- data/lib/furnace/ssa/module.rb +5 -1
- data/lib/furnace/ssa/named_value.rb +31 -10
- data/lib/furnace/ssa/terminator_instruction.rb +6 -6
- data/lib/furnace/ssa/types/basic_block.rb +4 -8
- data/lib/furnace/ssa/types/function.rb +4 -8
- data/lib/furnace/ssa/user.rb +14 -15
- data/lib/furnace/ssa/value.rb +9 -5
- data/lib/furnace/transform/iterative.rb +20 -4
- data/lib/furnace/type.rb +9 -0
- data/lib/furnace/type/bottom.rb +11 -0
- data/lib/furnace/type/top.rb +72 -0
- data/lib/furnace/type/value.rb +13 -0
- data/lib/furnace/type/variable.rb +61 -0
- data/lib/furnace/version.rb +1 -1
- data/test/{test_helper.rb → helper.rb} +28 -3
- data/test/{ast_test.rb → test_ast.rb} +13 -1
- data/test/test_awesome_printer.rb +148 -0
- data/test/{ssa_test.rb → test_ssa.rb} +276 -315
- data/test/{transform_test.rb → test_transform.rb} +2 -2
- data/test/test_type.rb +138 -0
- metadata +83 -105
- data/lib/furnace/graphviz.rb +0 -49
- data/lib/furnace/ssa/generic_type.rb +0 -16
- data/lib/furnace/ssa/pretty_printer.rb +0 -113
- data/lib/furnace/ssa/type.rb +0 -27
- data/lib/furnace/ssa/types/void.rb +0 -15
data/lib/furnace/ssa/function.rb
CHANGED
@@ -1,40 +1,42 @@
|
|
1
1
|
module Furnace
|
2
2
|
class SSA::Function
|
3
3
|
attr_reader :original_name
|
4
|
-
|
4
|
+
attr_reader :name
|
5
5
|
attr_reader :arguments
|
6
|
-
|
6
|
+
attr_reader :return_type
|
7
7
|
|
8
8
|
attr_accessor :entry
|
9
9
|
|
10
|
-
def initialize(name=nil, arguments=[], return_type=
|
11
|
-
@original_name
|
12
|
-
@name
|
13
|
-
|
14
|
-
@
|
10
|
+
def initialize(name=nil, arguments=[], return_type=Type::Bottom.new)
|
11
|
+
@original_name = name
|
12
|
+
@name = name
|
13
|
+
@return_type = return_type.to_type
|
14
|
+
@arguments = arguments
|
15
15
|
|
16
|
-
@basic_blocks
|
16
|
+
@basic_blocks = Set.new
|
17
17
|
|
18
|
-
@name_prefixes
|
19
|
-
@next_name
|
18
|
+
@name_prefixes = [""].to_set
|
19
|
+
@next_name = 0
|
20
|
+
|
21
|
+
SSA.instrument(self)
|
20
22
|
end
|
21
23
|
|
22
24
|
def initialize_copy(original)
|
23
|
-
@
|
25
|
+
@name_prefixes = [""].to_set
|
26
|
+
@name = @original_name
|
24
27
|
|
25
28
|
value_map = Hash.new do |value_map, value|
|
26
29
|
new_value = value.dup
|
27
30
|
value_map[value] = new_value
|
28
31
|
|
29
32
|
if new_value.is_a? SSA::User
|
30
|
-
new_value.function = self
|
31
33
|
new_value.operands = value.translate_operands(value_map)
|
32
34
|
end
|
33
35
|
|
34
36
|
new_value
|
35
37
|
end
|
36
38
|
|
37
|
-
|
39
|
+
self.arguments = @arguments.map do |arg|
|
38
40
|
new_arg = arg.dup
|
39
41
|
new_arg.function = self
|
40
42
|
value_map[arg] = new_arg
|
@@ -42,13 +44,16 @@ module Furnace
|
|
42
44
|
new_arg
|
43
45
|
end
|
44
46
|
|
45
|
-
|
47
|
+
old_basic_blocks = @basic_blocks
|
48
|
+
@basic_blocks = Set[]
|
49
|
+
|
50
|
+
old_basic_blocks.each do |bb|
|
46
51
|
new_bb = bb.dup
|
47
52
|
new_bb.function = self
|
48
53
|
|
49
54
|
value_map[bb] = new_bb
|
50
55
|
|
51
|
-
new_bb
|
56
|
+
add new_bb
|
52
57
|
end
|
53
58
|
|
54
59
|
@entry = value_map[@entry]
|
@@ -64,8 +69,26 @@ module Furnace
|
|
64
69
|
end
|
65
70
|
end
|
66
71
|
|
72
|
+
def name=(name)
|
73
|
+
@name = name
|
74
|
+
|
75
|
+
SSA.instrument(self)
|
76
|
+
end
|
77
|
+
|
67
78
|
def arguments=(arguments)
|
68
79
|
@arguments = sanitize_arguments(arguments)
|
80
|
+
|
81
|
+
@arguments.each do |arg|
|
82
|
+
arg.function = self
|
83
|
+
end
|
84
|
+
|
85
|
+
SSA.instrument(self)
|
86
|
+
end
|
87
|
+
|
88
|
+
def return_type=(return_type)
|
89
|
+
@return_type = return_type.to_type
|
90
|
+
|
91
|
+
SSA.instrument(self)
|
69
92
|
end
|
70
93
|
|
71
94
|
def make_name(prefix=nil)
|
@@ -89,6 +112,10 @@ module Furnace
|
|
89
112
|
|
90
113
|
alias each_basic_block each
|
91
114
|
|
115
|
+
def size
|
116
|
+
@basic_blocks.count
|
117
|
+
end
|
118
|
+
|
92
119
|
def include?(name)
|
93
120
|
@basic_blocks.any? { |n| n.name == name }
|
94
121
|
end
|
@@ -102,23 +129,43 @@ module Furnace
|
|
102
129
|
end
|
103
130
|
|
104
131
|
def add(block)
|
132
|
+
block.function = self
|
105
133
|
@basic_blocks.add block
|
134
|
+
|
135
|
+
SSA.instrument(self)
|
106
136
|
end
|
107
137
|
|
108
138
|
alias << add
|
109
139
|
|
110
140
|
def remove(block)
|
111
141
|
@basic_blocks.delete block
|
142
|
+
block.detach
|
143
|
+
|
144
|
+
SSA.instrument(self)
|
112
145
|
end
|
113
146
|
|
114
|
-
def each_instruction(
|
115
|
-
return to_enum(:each_instruction,
|
147
|
+
def each_instruction(*types, &proc)
|
148
|
+
return to_enum(:each_instruction, *types) if proc.nil?
|
116
149
|
|
117
150
|
each do |block|
|
118
|
-
block.each(
|
151
|
+
block.each(*types, &proc)
|
119
152
|
end
|
120
153
|
end
|
121
154
|
|
155
|
+
def replace_type_with(type, replacement)
|
156
|
+
@arguments.each do |arg|
|
157
|
+
arg.replace_type_with(type, replacement)
|
158
|
+
end
|
159
|
+
|
160
|
+
each_instruction do |insn|
|
161
|
+
insn.replace_type_with(type, replacement)
|
162
|
+
end
|
163
|
+
|
164
|
+
self.return_type = return_type.replace_type_with(type, replacement)
|
165
|
+
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
122
169
|
def predecessors_for(name)
|
123
170
|
predecessors = Set[]
|
124
171
|
|
@@ -132,51 +179,25 @@ module Furnace
|
|
132
179
|
end
|
133
180
|
|
134
181
|
def self.to_type
|
135
|
-
SSA::FunctionType.
|
182
|
+
SSA::FunctionType.new
|
136
183
|
end
|
137
184
|
|
138
185
|
def to_value
|
139
186
|
SSA::Constant.new(self.class.to_type, @name)
|
140
187
|
end
|
141
188
|
|
142
|
-
def
|
143
|
-
p.keyword
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
basic_block.pretty_print(p)
|
152
|
-
p.newline
|
153
|
-
end
|
154
|
-
|
155
|
-
p.text "}"
|
156
|
-
p.newline
|
189
|
+
def awesome_print(p=AwesomePrinter.new)
|
190
|
+
p.keyword('function').
|
191
|
+
nest(@return_type).
|
192
|
+
text(@name).
|
193
|
+
collection('(', ', ', ') {', @arguments).
|
194
|
+
newline.
|
195
|
+
collection(@basic_blocks).
|
196
|
+
append('}').
|
197
|
+
newline
|
157
198
|
end
|
158
199
|
|
159
|
-
alias inspect
|
160
|
-
|
161
|
-
def to_graphviz
|
162
|
-
Graphviz.new do |graph|
|
163
|
-
@basic_blocks.each do |block|
|
164
|
-
options = {}
|
165
|
-
|
166
|
-
if @entry == block
|
167
|
-
options.merge!({ color: 'green' })
|
168
|
-
elsif block.returns?
|
169
|
-
options.merge!({ color: 'red' })
|
170
|
-
end
|
171
|
-
|
172
|
-
graph.node block.name, block.inspect, options
|
173
|
-
|
174
|
-
block.successor_names.each do |name|
|
175
|
-
graph.edge block.name, name
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
200
|
+
alias inspect awesome_print
|
180
201
|
|
181
202
|
protected
|
182
203
|
|
@@ -185,7 +206,7 @@ module Furnace
|
|
185
206
|
if !argument.is_a?(SSA::Argument)
|
186
207
|
raise ArgumentError, "function #{@name} arguments: #{argument.inspect} (at #{index}) is not an Argument"
|
187
208
|
end
|
188
|
-
end
|
209
|
+
end.dup.freeze
|
189
210
|
end
|
190
211
|
end
|
191
|
-
end
|
212
|
+
end
|
@@ -2,13 +2,20 @@ module Furnace
|
|
2
2
|
class SSA::GenericInstruction < SSA::Instruction
|
3
3
|
attr_reader :type
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
|
7
|
-
|
5
|
+
def initialize(type, operands=[], name=nil)
|
6
|
+
@type = type.to_type
|
7
|
+
|
8
|
+
super(operands, name)
|
8
9
|
end
|
9
10
|
|
10
11
|
def type=(type)
|
11
|
-
@type
|
12
|
+
@type = type.to_type
|
13
|
+
|
14
|
+
SSA.instrument(self)
|
15
|
+
end
|
16
|
+
|
17
|
+
def replace_type_with(type, replacement)
|
18
|
+
self.type = self.type.replace_type_with(type, replacement)
|
12
19
|
end
|
13
20
|
end
|
14
|
-
end
|
21
|
+
end
|
@@ -8,26 +8,39 @@ module Furnace
|
|
8
8
|
SSA::InstructionSyntax.new(self).evaluate(&block)
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
attr_reader :basic_block
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
@basic_block = basic_block
|
13
|
+
def opcode
|
14
|
+
self.class.opcode
|
16
15
|
end
|
17
16
|
|
18
|
-
def
|
19
|
-
|
17
|
+
def basic_block=(basic_block)
|
18
|
+
if @basic_block && @basic_block != basic_block
|
19
|
+
@basic_block.remove self
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
+
if basic_block
|
23
|
+
self.function = basic_block.function
|
24
|
+
end
|
25
|
+
|
26
|
+
@basic_block = basic_block
|
27
|
+
|
28
|
+
SSA.instrument(self)
|
22
29
|
end
|
23
30
|
|
24
|
-
def
|
25
|
-
|
31
|
+
def detach
|
32
|
+
@basic_block = nil
|
33
|
+
|
34
|
+
super
|
26
35
|
end
|
27
36
|
|
28
37
|
def remove
|
29
|
-
@basic_block.remove self
|
30
|
-
|
38
|
+
@basic_block.remove self if @basic_block
|
39
|
+
end
|
40
|
+
|
41
|
+
def erase
|
42
|
+
remove
|
43
|
+
drop_references
|
31
44
|
end
|
32
45
|
|
33
46
|
def replace_with(value)
|
@@ -35,12 +48,15 @@ module Furnace
|
|
35
48
|
|
36
49
|
if value.is_a? SSA::Instruction
|
37
50
|
@basic_block.replace self, value
|
38
|
-
|
51
|
+
drop_references
|
39
52
|
else
|
40
|
-
|
53
|
+
erase
|
41
54
|
end
|
42
55
|
end
|
43
56
|
|
57
|
+
def replace_type_with(type, replacement)
|
58
|
+
end
|
59
|
+
|
44
60
|
def has_side_effects?
|
45
61
|
false
|
46
62
|
end
|
@@ -49,44 +65,43 @@ module Furnace
|
|
49
65
|
false
|
50
66
|
end
|
51
67
|
|
52
|
-
def
|
53
|
-
unless type ==
|
54
|
-
p.type
|
55
|
-
|
56
|
-
|
68
|
+
def awesome_print(p=AwesomePrinter.new)
|
69
|
+
unless type == Type::Bottom.new
|
70
|
+
p.nest(type).
|
71
|
+
name(name).
|
72
|
+
text('=')
|
57
73
|
end
|
58
74
|
|
59
|
-
|
60
|
-
p.keyword opcode
|
61
|
-
else
|
62
|
-
p.keyword_invalid opcode
|
63
|
-
end
|
75
|
+
p.keyword(opcode)
|
64
76
|
|
65
|
-
|
66
|
-
|
77
|
+
awesome_print_parameters(p)
|
78
|
+
awesome_print_operands(p)
|
67
79
|
|
68
80
|
p
|
69
81
|
end
|
70
82
|
|
71
|
-
def
|
72
|
-
if type ==
|
73
|
-
p.type
|
83
|
+
def awesome_print_as_value(p=AwesomePrinter.new)
|
84
|
+
if type == Type::Bottom.new
|
85
|
+
p.nest(type)
|
74
86
|
else
|
75
87
|
super
|
76
88
|
end
|
77
89
|
end
|
78
90
|
|
79
|
-
|
80
|
-
|
81
|
-
def pretty_parameters(p)
|
91
|
+
def awesome_print_parameters(p=AwesomePrinter.new)
|
92
|
+
p
|
82
93
|
end
|
83
94
|
|
84
|
-
def
|
95
|
+
def awesome_print_operands(p=AwesomePrinter.new)
|
85
96
|
if @operands
|
86
|
-
p.
|
97
|
+
p.collection('', ', ', '', @operands) do |operand|
|
98
|
+
operand.awesome_print_as_value(p)
|
99
|
+
end
|
87
100
|
else
|
88
|
-
p.text
|
101
|
+
p.text('<DETACHED>')
|
89
102
|
end
|
90
103
|
end
|
104
|
+
|
105
|
+
protected :function=
|
91
106
|
end
|
92
|
-
end
|
107
|
+
end
|
@@ -2,7 +2,7 @@ module Furnace
|
|
2
2
|
class SSA::InstructionSyntax
|
3
3
|
def initialize(klass)
|
4
4
|
@klass = klass
|
5
|
-
@operands =
|
5
|
+
@operands = []
|
6
6
|
@splat = nil
|
7
7
|
end
|
8
8
|
|
@@ -12,11 +12,10 @@ module Furnace
|
|
12
12
|
codegen
|
13
13
|
end
|
14
14
|
|
15
|
-
def operand(name
|
15
|
+
def operand(name)
|
16
16
|
check_for_splat
|
17
17
|
|
18
|
-
|
19
|
-
@operands[name.to_sym] = type
|
18
|
+
@operands << name.to_sym
|
20
19
|
end
|
21
20
|
|
22
21
|
def splat(name)
|
@@ -37,7 +36,7 @@ module Furnace
|
|
37
36
|
operands, splat = @operands, @splat
|
38
37
|
|
39
38
|
@klass.class_eval do
|
40
|
-
operands.each_with_index do |
|
39
|
+
operands.each_with_index do |operand, index|
|
41
40
|
define_method(operand) do
|
42
41
|
@operands[index]
|
43
42
|
end
|
@@ -45,10 +44,14 @@ module Furnace
|
|
45
44
|
define_method(:"#{operand}=") do |value|
|
46
45
|
value = value.to_value
|
47
46
|
|
47
|
+
return if @operands[index] == value
|
48
|
+
|
48
49
|
@operands[index].remove_use self if @operands[index]
|
49
50
|
@operands[index] = value
|
50
51
|
value.add_use self if value
|
51
52
|
|
53
|
+
SSA.instrument(self)
|
54
|
+
|
52
55
|
value
|
53
56
|
end
|
54
57
|
end
|
@@ -82,28 +85,9 @@ module Furnace
|
|
82
85
|
@operands = values
|
83
86
|
end
|
84
87
|
|
85
|
-
verify!
|
86
|
-
|
87
88
|
values
|
88
89
|
end
|
89
|
-
|
90
|
-
define_method(:verify!) do |ignore_nil_types=true|
|
91
|
-
return if @operands.nil?
|
92
|
-
|
93
|
-
operands.each_with_index do |(operand, type), index|
|
94
|
-
next if type.nil?
|
95
|
-
|
96
|
-
value = send operand
|
97
|
-
next if ignore_nil_types && value.type.nil?
|
98
|
-
|
99
|
-
if value.type.nil? || !value.type.subtype_of?(type)
|
100
|
-
raise TypeError, "Wrong type for operand ##{index + 1} `#{operand}': #{SSA.inspect_type type} is expected, #{SSA.inspect_type value.type} is present"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
nil
|
105
|
-
end
|
106
90
|
end
|
107
91
|
end
|
108
92
|
end
|
109
|
-
end
|
93
|
+
end
|