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
@@ -1,7 +1,7 @@
|
|
1
1
|
module Furnace
|
2
2
|
class SSA::PhiInsn < SSA::GenericInstruction
|
3
|
-
def initialize(
|
4
|
-
super(
|
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
|
33
|
-
@operands
|
34
|
-
p.name
|
35
|
-
|
36
|
-
value.
|
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
|
@@ -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
|
data/lib/furnace/ssa/module.rb
CHANGED
@@ -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
|
-
|
4
|
-
attr_reader
|
3
|
+
attr_reader :function
|
4
|
+
attr_reader :name
|
5
5
|
|
6
|
-
def initialize(
|
6
|
+
def initialize(name=nil)
|
7
7
|
super()
|
8
8
|
|
9
|
-
@function =
|
10
|
-
|
9
|
+
@function = nil
|
10
|
+
@name = name
|
11
11
|
end
|
12
12
|
|
13
13
|
def name=(name)
|
14
|
-
|
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
|
18
|
-
p.name
|
38
|
+
def awesome_print_as_value(p=AwesomePrinter.new)
|
39
|
+
p.name(@name)
|
19
40
|
end
|
20
41
|
|
21
42
|
def inspect
|
22
|
-
|
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
|
3
|
+
def terminator?
|
4
4
|
true
|
5
5
|
end
|
6
6
|
|
7
|
-
def
|
8
|
-
|
7
|
+
def has_side_effects?
|
8
|
+
exits?
|
9
9
|
end
|
10
10
|
|
11
11
|
def exits?
|
12
|
-
raise NotImplementedError, "reimplement
|
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.
|
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
|
data/lib/furnace/ssa/user.rb
CHANGED
@@ -2,12 +2,18 @@ module Furnace
|
|
2
2
|
class SSA::User < SSA::NamedValue
|
3
3
|
attr_reader :operands
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
super(
|
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
|
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
|
data/lib/furnace/ssa/value.rb
CHANGED
@@ -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
|
-
|
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
|
55
|
-
|
58
|
+
def awesome_print(p=AwesomePrinter.new)
|
59
|
+
awesome_print_as_value(p)
|
56
60
|
end
|
57
61
|
|
58
|
-
def
|
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
|
-
|
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 =
|
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 =
|
26
|
+
self_changed = true
|
27
|
+
changed.add stage
|
19
28
|
end
|
20
29
|
end
|
21
30
|
|
22
|
-
return self_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
|
data/lib/furnace/type.rb
ADDED
@@ -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
|