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
File without changes
|
data/lib/furnace/ssa.rb
CHANGED
@@ -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.
|
13
|
-
|
14
|
-
|
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/
|
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
|
data/lib/furnace/ssa/argument.rb
CHANGED
@@ -2,22 +2,26 @@ module Furnace
|
|
2
2
|
class SSA::Argument < SSA::NamedValue
|
3
3
|
attr_reader :type
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
|
7
|
-
|
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
|
12
|
+
@type = type.to_type
|
13
|
+
|
14
|
+
SSA.instrument(self)
|
12
15
|
end
|
13
16
|
|
14
|
-
def
|
15
|
-
|
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
|
19
|
-
p.type
|
20
|
-
|
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(
|
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(
|
23
|
-
if
|
31
|
+
def each(*types, &proc)
|
32
|
+
if types.empty?
|
24
33
|
@instructions.each(&proc)
|
25
34
|
else
|
26
|
-
return to_enum(:each,
|
35
|
+
return to_enum(:each, *types) if proc.nil?
|
27
36
|
|
28
37
|
@instructions.each do |insn|
|
29
|
-
if insn.
|
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
|
68
|
+
unless (idx = index(before))
|
46
69
|
raise ArgumentError, "Instruction #{before} is not found"
|
47
70
|
end
|
48
71
|
|
49
|
-
|
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
|
58
|
-
|
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.
|
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
|
100
|
-
p.text
|
101
|
-
|
143
|
+
def awesome_print(p=AwesomePrinter.new)
|
144
|
+
p.text(@name).
|
145
|
+
append(":").
|
146
|
+
newline
|
102
147
|
|
103
|
-
|
104
|
-
p
|
105
|
-
|
106
|
-
|
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
|
113
|
-
p.keyword
|
114
|
-
|
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
|
data/lib/furnace/ssa/builder.rb
CHANGED
@@ -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(
|
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
|
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(
|
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=
|
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
|
87
|
-
append(:return
|
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
|
data/lib/furnace/ssa/constant.rb
CHANGED
@@ -1,17 +1,25 @@
|
|
1
1
|
module Furnace
|
2
2
|
class SSA::Constant < SSA::Value
|
3
|
-
attr_reader
|
4
|
-
|
3
|
+
attr_reader :type
|
4
|
+
attr_reader :value
|
5
5
|
|
6
6
|
def initialize(type, value)
|
7
|
-
|
7
|
+
@value = value
|
8
|
+
@type = type.to_type
|
8
9
|
|
9
|
-
|
10
|
-
@value = value
|
10
|
+
super()
|
11
11
|
end
|
12
12
|
|
13
13
|
def type=(type)
|
14
|
-
@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
|
34
|
-
p
|
35
|
-
p.text @value.inspect
|
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
|
-
|
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
|