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
@@ -0,0 +1,13 @@
1
+ module Furnace
2
+ class Type::Value < Type::Top
3
+ attr_reader :value
4
+
5
+ def initialize(value)
6
+ @value = value
7
+ end
8
+
9
+ def to_s
10
+ %{'#{@value.inspect}}
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,61 @@
1
+ module Furnace
2
+ class Type::Variable
3
+ def initialize
4
+ freeze
5
+ end
6
+
7
+ def to_type
8
+ self
9
+ end
10
+
11
+ def subtype_of?(other)
12
+ other.instance_of?(Type::Top) ||
13
+ self == other
14
+ end
15
+
16
+ def supertype_of?(other)
17
+ other.subtype_of?(self)
18
+ end
19
+
20
+ def variable?
21
+ true
22
+ end
23
+
24
+ def replace_type_with(type, replacement)
25
+ if self == type
26
+ replacement.to_type
27
+ else
28
+ self
29
+ end
30
+ end
31
+
32
+ def specialize(other)
33
+ { self => other }
34
+ end
35
+
36
+ def awesome_print(p=AwesomePrinter.new)
37
+ p.type_variable self
38
+ end
39
+ end
40
+
41
+ class Type::Variable::Annotator
42
+ def initialize
43
+ @last_annotation = "a"
44
+
45
+ @annotations = Hash.new do |hash, var|
46
+ unless var.is_a? Type::Variable
47
+ raise ArgumentError, "#{self.class} cannot annotate #{var.class}"
48
+ end
49
+
50
+ annotation = @last_annotation
51
+ @last_annotation = @last_annotation.succ
52
+
53
+ hash[var] = annotation
54
+ end
55
+ end
56
+
57
+ def annotate(var)
58
+ @annotations[var]
59
+ end
60
+ end
61
+ end
@@ -1,3 +1,3 @@
1
1
  module Furnace
2
- VERSION = "0.4.0.beta.1"
2
+ VERSION = "0.4.0.beta.2"
3
3
  end
@@ -19,7 +19,32 @@ end
19
19
  require 'simplecov'
20
20
  SimpleCov.start
21
21
 
22
- $LOAD_PATH << File.expand_path('../../lib', __FILE__)
23
-
24
22
  require 'furnace'
25
- include Furnace
23
+ include Furnace
24
+
25
+ class RubyType < Type::Top
26
+ attr_reader :ruby_type
27
+
28
+ def initialize(ruby_type)
29
+ @ruby_type = ruby_type
30
+ end
31
+
32
+ def ==(other)
33
+ other.instance_of?(RubyType) &&
34
+ @ruby_type == other.ruby_type
35
+ end
36
+
37
+ def hash
38
+ [self.class, @ruby_type].hash
39
+ end
40
+
41
+ def to_s
42
+ "^#{@ruby_type}"
43
+ end
44
+ end
45
+
46
+ class Class
47
+ def to_type
48
+ RubyType.new(self)
49
+ end
50
+ end
@@ -1,4 +1,4 @@
1
- require_relative 'test_helper'
1
+ require_relative 'helper'
2
2
 
3
3
  describe AST::Node do
4
4
  extend Furnace::AST::Sexp
@@ -107,6 +107,18 @@ describe AST::Node do
107
107
  var_name.should.equal :$foo
108
108
  value.should.equal s(:integer, 1)
109
109
  end
110
+
111
+ it 'should concatenate with arrays' do
112
+ node = s(:gasgn, :$foo)
113
+ (node + [s(:integer, 1)]).
114
+ should.equal s(:gasgn, :$foo, s(:integer, 1))
115
+ end
116
+
117
+ it 'should append elements' do
118
+ node = s(:array)
119
+ (node << s(:integer, 1) << s(:string, "foo")).
120
+ should.equal s(:array, s(:integer, 1), s(:string, "foo"))
121
+ end
110
122
  end
111
123
 
112
124
  describe AST::Processor do
@@ -0,0 +1,148 @@
1
+ require_relative 'helper'
2
+
3
+ describe AwesomePrinter do
4
+ AwesomePrinter.colorize = false
5
+
6
+ it 'outputs chunks' do
7
+ AwesomePrinter.new do |p|
8
+ p.text 'foo'
9
+ end.should == 'foo'
10
+
11
+ AwesomePrinter.new do |p|
12
+ Integer.to_type.awesome_print(p)
13
+ end.should == '^Integer'
14
+
15
+ AwesomePrinter.new do |p|
16
+ p.keyword 'bar'
17
+ end.should == 'bar'
18
+ end
19
+
20
+ it 'supports matching by =~' do
21
+ AwesomePrinter.new do |p|
22
+ p.text 'foo'
23
+ end.should =~ /foo/
24
+ end
25
+
26
+ it 'ensures space between chunks' do
27
+ AwesomePrinter.new do |p|
28
+ p.text 'foo'
29
+ p.keyword 'doh'
30
+ p.text 'bar'
31
+ end.should == 'foo doh bar'
32
+ end
33
+
34
+ it 'adds no space before and after #append' do
35
+ AwesomePrinter.new do |p|
36
+ p.text 'foo'
37
+ p.append 'bar'
38
+ p.text 'baz'
39
+ end.should == 'foobarbaz'
40
+ end
41
+
42
+ it 'adds no space after #newline' do
43
+ AwesomePrinter.new do |p|
44
+ p.text 'foo'
45
+ p.newline
46
+ p.text 'bar'
47
+ end.should == "foo\nbar"
48
+ end
49
+
50
+ it 'converts objects to chunks with to_s' do
51
+ AwesomePrinter.new do |p|
52
+ p.text :foo
53
+ p.text 1
54
+ p.keyword :bar
55
+ end.should == 'foo 1 bar'
56
+ end
57
+
58
+ it 'when nesting, delegates to #awesome_print and then #to_s' do
59
+ with_awesome_print = Object.new.tap do |o|
60
+ def o.awesome_print(p)
61
+ p.text "awesome print"
62
+ end
63
+ end
64
+
65
+ with_inspect = Object.new.tap do |o|
66
+ def o.to_s
67
+ "awesome to_s"
68
+ end
69
+ end
70
+
71
+ AwesomePrinter.new do |p|
72
+ p.nest with_awesome_print
73
+ p.nest with_inspect
74
+ end.should == 'awesome print awesome to_s'
75
+ end
76
+
77
+ it 'prints %names' do
78
+ AwesomePrinter.new do |p|
79
+ p.name 'foo'
80
+ end.should == '%foo'
81
+ end
82
+
83
+ it 'prints type variables' do
84
+ a, b = 2.times.map { Type::Variable.new }
85
+
86
+ AwesomePrinter.new do |p|
87
+ p.type_variable a
88
+ p.type_variable b
89
+ p.type_variable a
90
+ end.should == '~a ~b ~a'
91
+ end
92
+
93
+ it 'prints type variables with passed Annotator' do
94
+ a, b = 2.times.map { Type::Variable.new }
95
+
96
+ ann = Type::Variable::Annotator.new
97
+ ann.annotate a
98
+
99
+ AwesomePrinter.new(false, ann) do |p|
100
+ p.type_variable b
101
+ end.should == '~b'
102
+ end
103
+
104
+ it 'prints collections' do
105
+ AwesomePrinter.new do |p|
106
+ p.collection(%w(a b c))
107
+ end.should == 'abc'
108
+
109
+ AwesomePrinter.new do |p|
110
+ p.collection('<', '; ', '>', %w(a b c))
111
+ end.should == '<a; b; c>'
112
+ end
113
+
114
+ it 'ensures space before collections' do
115
+ AwesomePrinter.new do |p|
116
+ p.text 'foo'
117
+ p.collection(%w(a b c))
118
+ end.should == 'foo abc'
119
+ end
120
+
121
+ it 'prints collections with custom iterator' do
122
+ AwesomePrinter.new do |p|
123
+ p.collection(%w(abc def)) do |e|
124
+ p.text e.reverse
125
+ end
126
+ end.should == 'cbafed'
127
+ end
128
+
129
+ it 'chains' do
130
+ AwesomePrinter.new do |p|
131
+ p.append("foo").should == p
132
+ p.text("foo").should == p
133
+ p.newline.should == p
134
+ p.nest("foo").should == p
135
+ p.name("foo").should == p
136
+ p.type("foo").should == p
137
+ p.type_variable(Type::Variable.new).should == p
138
+ p.keyword("foo").should == p
139
+ p.collection(%w(a b)).should == p
140
+ end
141
+ end
142
+
143
+ it 'adds colors if requested' do
144
+ AwesomePrinter.new(true) do |p|
145
+ p.keyword :bar
146
+ end.should == "\e[1;37mbar\e[0m"
147
+ end
148
+ end
@@ -1,27 +1,7 @@
1
- require_relative 'test_helper'
1
+ require_relative 'helper'
2
2
 
3
3
  describe SSA do
4
- SSA::PrettyPrinter.colorize = false
5
-
6
- class SSARubyType < SSA::GenericType
7
- def initialize(ruby_type)
8
- @ruby_type = ruby_type
9
- end
10
-
11
- def parameters
12
- [@ruby_type]
13
- end
14
-
15
- def inspect
16
- "^#{@ruby_type}"
17
- end
18
- end
19
-
20
- class Class
21
- def to_type
22
- SSARubyType.new(self)
23
- end
24
- end
4
+ AwesomePrinter.colorize = false
25
5
 
26
6
  class BindingInsn < SSA::Instruction
27
7
  def type
@@ -31,7 +11,11 @@ describe SSA do
31
11
 
32
12
  class DupInsn < SSA::Instruction
33
13
  def type
34
- operands.first.type
14
+ if operands
15
+ operands.first.type
16
+ else
17
+ Type::Top.new
18
+ end
35
19
  end
36
20
  end
37
21
 
@@ -47,8 +31,8 @@ describe SSA do
47
31
  class CondBranchInsn < SSA::TerminatorInstruction
48
32
  syntax do |s|
49
33
  s.operand :condition
50
- s.operand :if_true, SSA::BasicBlock
51
- s.operand :if_false, SSA::BasicBlock
34
+ s.operand :if_true
35
+ s.operand :if_false
52
36
  end
53
37
 
54
38
  def exits?
@@ -56,6 +40,9 @@ describe SSA do
56
40
  end
57
41
  end
58
42
 
43
+ class IsBInsn < SSA::Instruction
44
+ end
45
+
59
46
  module TestScope
60
47
  include SSA
61
48
 
@@ -74,129 +61,35 @@ describe SSA do
74
61
 
75
62
  before do
76
63
  @function = SSA::Function.new('foo')
77
- @basic_block = SSA::BasicBlock.new(@function)
64
+ @basic_block = SSA::BasicBlock.new
78
65
  @function.add @basic_block
79
66
  @function.entry = @basic_block
80
67
  end
81
68
 
82
- def insn_noary(basic_block)
83
- BindingInsn.new(basic_block)
69
+ def insn_noary
70
+ BindingInsn.new
84
71
  end
85
72
 
86
- def insn_unary(basic_block, what)
87
- DupInsn.new(basic_block, [what])
73
+ def insn_unary(what)
74
+ DupInsn.new([what])
88
75
  end
89
76
 
90
- def insn_binary(basic_block, left, right)
91
- TupleConcatInsn.new(basic_block, [left, right])
77
+ def insn_binary(left, right)
78
+ TupleConcatInsn.new([left, right])
92
79
  end
93
80
 
94
81
  it 'converts class names to opcodes' do
95
82
  SSA.class_name_to_opcode(DupInsn).should == 'dup'
96
83
  SSA.class_name_to_opcode(TupleConcatInsn).should == 'tuple_concat'
97
84
  SSA.class_name_to_opcode(TestScope::NestedInsn).should == 'nested'
85
+ SSA.class_name_to_opcode(IsBInsn).should == 'is_b'
98
86
  end
99
87
 
100
88
  it 'converts opcodes to class names' do
101
89
  SSA.opcode_to_class_name('foo').should == 'FooInsn'
102
90
  SSA.opcode_to_class_name('foo_bar').should == 'FooBarInsn'
103
91
  SSA.opcode_to_class_name(:foo_bar).should == 'FooBarInsn'
104
- end
105
-
106
- describe SSA::PrettyPrinter do
107
- it 'outputs chunks' do
108
- SSA::PrettyPrinter.new do |p|
109
- p.text 'foo'
110
- end.to_s.should == 'foo'
111
-
112
- SSA::PrettyPrinter.new do |p|
113
- p.type Integer.to_type
114
- end.to_s.should == '^Integer'
115
-
116
- SSA::PrettyPrinter.new do |p|
117
- p.keyword 'bar'
118
- end.to_s.should == 'bar'
119
- end
120
-
121
- it 'ensures space between chunks' do
122
- SSA::PrettyPrinter.new do |p|
123
- p.text 'foo'
124
- p.keyword 'doh'
125
- p.text 'bar'
126
- end.to_s.should == 'foo doh bar'
127
- end
128
-
129
- it 'adds no space inside #text chunk' do
130
- SSA::PrettyPrinter.new do |p|
131
- p.text 'foo', 'bar'
132
- p.keyword 'squick'
133
- end.to_s.should == 'foobar squick'
134
- end
135
-
136
- it 'adds no space after newline' do
137
- SSA::PrettyPrinter.new do |p|
138
- p.text 'foo'
139
- p.newline
140
- p.text 'bar'
141
- end.to_s.should == "foo\nbar"
142
- end
143
-
144
- it 'converts objects to chunks with to_s' do
145
- SSA::PrettyPrinter.new do |p|
146
- p.text :foo
147
- p.text 1
148
- p.keyword :bar
149
- end.to_s.should == 'foo 1 bar'
150
- end
151
-
152
- it 'adds colors if requested' do
153
- SSA::PrettyPrinter.new(true) do |p|
154
- p.keyword :bar
155
- end.to_s.should == "\e[1;37mbar\e[0m"
156
- end
157
- end
158
-
159
- describe SSA::Type do
160
- before do
161
- @type = SSA::Type.new
162
- end
163
-
164
- it 'converts to type' do
165
- @type.to_type.should.be.equal @type
166
- end
167
-
168
- it 'is a monotype' do
169
- @type.should.be.monotype
170
- end
171
-
172
- it 'should be ==, eql?, subtype_of? and have the same hash as another instance' do
173
- other = SSA::Type.new
174
- @type.should == other
175
- @type.should.be.eql other
176
- @type.should.be.subtype_of other
177
- @type.hash.should == other.hash
178
- end
179
-
180
- describe SSA::GenericType do
181
- before do
182
- @type = Integer.to_type
183
- end
184
-
185
- it 'should compare its parameters' do
186
- otheri = Integer.to_type
187
- otherf = Float.to_type
188
-
189
- @type.should == otheri
190
- @type.should.be.eql otheri
191
- @type.should.be.subtype_of otheri
192
- @type.hash.should == otheri.hash
193
-
194
- @type.should.not == otherf
195
- @type.should.not.be.eql otherf
196
- @type.should.not.be.subtype_of otherf
197
- @type.hash.should.not == otherf.hash
198
- end
199
- end
92
+ SSA.opcode_to_class_name(:is_b).should == 'IsBInsn'
200
93
  end
201
94
 
202
95
  describe SSA::Value do
@@ -204,8 +97,8 @@ describe SSA do
204
97
  @val = SSA::Value.new
205
98
  end
206
99
 
207
- it 'has void type' do
208
- @val.type.should == SSA.void
100
+ it 'has bottom type' do
101
+ @val.type.should == Type::Bottom.new
209
102
  end
210
103
 
211
104
  it 'is not constant' do
@@ -221,7 +114,7 @@ describe SSA do
221
114
  end
222
115
 
223
116
  it 'pretty prints' do
224
- @val.pretty_print.should =~ %r{#<Furnace::SSA::Value}
117
+ @val.awesome_print.should =~ %r{#<Furnace::SSA::Value}
225
118
  end
226
119
 
227
120
  it 'has an use list' do
@@ -244,7 +137,7 @@ describe SSA do
244
137
  it 'can have all of its uses replaced' do
245
138
  val1, val2 = 2.times.map { SSA::Value.new }
246
139
 
247
- user = SSA::User.new(@function, [val1])
140
+ user = SSA::User.new([val1], 'foo')
248
141
 
249
142
  val1.replace_all_uses_with(val2)
250
143
 
@@ -259,7 +152,7 @@ describe SSA do
259
152
  end
260
153
 
261
154
  it 'pretty prints' do
262
- @imm.pretty_print.should == '^Integer 1'
155
+ @imm.awesome_print.should == '^Integer 1'
263
156
  end
264
157
 
265
158
  it 'converts to value' do
@@ -279,49 +172,32 @@ describe SSA do
279
172
  end
280
173
  end
281
174
 
282
- describe SSA::VoidType do
283
- it 'allows to retrieve a constant' do
284
- const = SSA.void_value
285
- const.should.be.constant
286
- const.type.should.be.instance_of SSA::VoidType
287
- end
288
-
289
- it 'inspects as void' do
290
- SSA.void.inspect.should == 'void'
291
- end
292
-
293
- it 'inspects as void in constants' do
294
- SSA.void_value.inspect.should == 'void'
295
- end
296
- end
297
-
298
175
  describe SSA::NamedValue do
299
176
  it 'receives unique names' do
300
- values = 5.times.map { SSA::NamedValue.new(@function, nil) }
301
- values.map(&:name).uniq.count.should == values.size
177
+ values = 5.times.map do
178
+ v = SSA::NamedValue.new(nil)
179
+ v.function = @function
180
+ v
181
+ end
182
+
183
+ values.map(&:name).uniq.size.should == 5
302
184
  end
303
185
 
304
186
  it 'receives unique names even if explicitly specified name conflicts' do
305
- i1 = SSA::NamedValue.new(@function, "foo")
306
- i2 = SSA::NamedValue.new(@function, "foo")
307
- i2.name.should.not == i1.name
187
+ i1 = SSA::NamedValue.new("foo")
188
+ i1.function = @function
308
189
 
309
- i2.name = 'foo'
190
+ i2 = SSA::NamedValue.new("foo")
191
+ i2.name.should == i1.name
192
+
193
+ i2.function = @function
310
194
  i2.name.should.not == i1.name
311
195
  end
312
196
  end
313
197
 
314
198
  describe SSA::Argument do
315
199
  before do
316
- @val = SSA::Argument.new(@function, nil, 'foo')
317
- end
318
-
319
- it 'pretty prints' do
320
- SSA::Argument.new(@function, nil, 'baz').pretty_print.
321
- should == '<?> %baz'
322
-
323
- SSA::Argument.new(@function, Integer, 'bar').pretty_print.
324
- should == '^Integer %bar'
200
+ @val = SSA::Argument.new(Integer, 'foo')
325
201
  end
326
202
 
327
203
  it 'converts to value' do
@@ -334,15 +210,24 @@ describe SSA do
334
210
  end
335
211
 
336
212
  it 'compares by identity' do
337
- @val.should.not == SSA::Argument.new(@function, nil, 'foo')
213
+ @val.should.not == SSA::Argument.new(Integer, 'foo')
338
214
  end
339
215
 
340
216
  it 'is not constant' do
341
217
  @val.should.not.be.constant
342
218
  end
343
219
 
344
- it 'has side effects' do
345
- @val.has_side_effects?.should == true
220
+ it 'replaces its type' do
221
+ ty = Type::Variable.new
222
+
223
+ val = SSA::Argument.new(ty, 'foo')
224
+ val.replace_type_with(ty, Integer.to_type)
225
+ val.type.should == Integer.to_type
226
+ end
227
+
228
+ it 'pretty prints' do
229
+ @val.awesome_print.
230
+ should == '^Integer %foo'
346
231
  end
347
232
  end
348
233
 
@@ -350,14 +235,14 @@ describe SSA do
350
235
  it 'enumerates operands' do
351
236
  val1, val2 = 2.times.map { SSA::Value.new }
352
237
 
353
- user = SSA::User.new(@function, [val1, val2])
238
+ user = SSA::User.new([val1, val2])
354
239
  user.should.enumerate :each_operand, [val1, val2]
355
240
  end
356
241
 
357
242
  it 'populates use lists' do
358
243
  val = SSA::Value.new
359
244
 
360
- user = SSA::User.new(@function)
245
+ user = SSA::User.new
361
246
  val.should.enumerate :each_use, []
362
247
 
363
248
  user.operands = [val]
@@ -367,7 +252,7 @@ describe SSA do
367
252
  it 'updates use lists' do
368
253
  val1, val2 = 2.times.map { SSA::Value.new }
369
254
 
370
- user = SSA::User.new(@function)
255
+ user = SSA::User.new
371
256
  val1.should.enumerate :each_use, []
372
257
  val2.should.enumerate :each_use, []
373
258
 
@@ -382,17 +267,17 @@ describe SSA do
382
267
 
383
268
  it 'detaches from values' do
384
269
  val = SSA::Value.new
385
- user = SSA::User.new(@function, [val])
270
+ user = SSA::User.new([val])
386
271
 
387
272
  val.should.enumerate :each_use, [user]
388
- user.detach
273
+ user.drop_references
389
274
  val.should.enumerate :each_use, []
390
275
  end
391
276
 
392
277
  it 'can replace uses of values' do
393
278
  val1, val2 = 2.times.map { SSA::Value.new }
394
279
 
395
- user = SSA::User.new(@function, [val1])
280
+ user = SSA::User.new([val1])
396
281
  user.replace_uses_of(val1, val2)
397
282
 
398
283
  val1.should.enumerate :each_use, []
@@ -402,7 +287,7 @@ describe SSA do
402
287
  it 'barfs on #replace_uses_of if the value is not used' do
403
288
  val1, val2 = 2.times.map { SSA::Value.new }
404
289
 
405
- user = SSA::User.new(@function, [val1])
290
+ user = SSA::User.new([val1])
406
291
 
407
292
  -> { user.replace_uses_of(val2, val1) }.should.raise ArgumentError
408
293
  end
@@ -410,106 +295,132 @@ describe SSA do
410
295
 
411
296
  describe SSA::Instruction do
412
297
  it 'is not terminator' do
413
- i = insn_noary(@basic_block)
298
+ i = insn_noary
414
299
  i.should.not.be.terminator
415
300
  end
416
301
 
417
302
  it 'does not have side effects' do
418
- i = insn_noary(@basic_block)
303
+ i = insn_noary
419
304
  i.has_side_effects?.should == false
420
305
  end
421
306
 
422
307
  it 'removes itself from basic block' do
423
- i = insn_noary(@basic_block)
308
+ i = insn_noary
424
309
  @basic_block.append i
425
310
 
426
311
  i.remove
427
312
  @basic_block.to_a.should.be.empty
313
+ i.operands.should == []
314
+ end
315
+
316
+ it 'erases itself from basic block' do
317
+ i = insn_noary
318
+ @basic_block.append i
319
+
320
+ i.erase
321
+ @basic_block.to_a.should.be.empty
322
+ i.operands.should == nil
428
323
  end
429
324
 
430
325
  it 'replaces uses of itself with instructions' do
431
- i1 = insn_noary(@basic_block)
326
+ i1 = insn_noary
432
327
  @basic_block.append i1
433
328
 
434
- i2 = insn_unary(@basic_block, i1)
329
+ i2 = insn_unary(i1)
435
330
  @basic_block.append i2
436
331
 
437
- i1a = insn_noary(@basic_block)
332
+ i1a = insn_noary
438
333
  i1.replace_with i1a
334
+ i1.operands.should == nil
439
335
 
440
336
  @basic_block.to_a.should == [i1a, i2]
441
337
  i2.operands.should == [i1a]
442
338
  end
443
339
 
444
340
  it 'replaces uses of itself with constants' do
445
- i1 = insn_noary(@basic_block)
341
+ i1 = insn_noary
446
342
  @basic_block.append i1
447
343
 
448
- i2 = insn_unary(@basic_block, i1)
344
+ i2 = insn_unary(i1)
449
345
  @basic_block.append i2
450
346
 
451
347
  c1 = SSA::Constant.new(Integer, 1)
452
348
  i1.replace_with c1
349
+ i1.operands.should == nil
453
350
 
454
351
  @basic_block.to_a.should == [i2]
455
352
  i2.operands.should == [c1]
456
353
  end
457
354
 
458
355
  it 'pretty prints' do
459
- dup = DupInsn.new(@basic_block, [SSA::Constant.new(Integer, 1)])
460
- dup.pretty_print.should == '^Integer %2 = dup ^Integer 1'
461
- dup.inspect_as_value.should == '%2'
356
+ dup = DupInsn.new([SSA::Constant.new(Integer, 1)])
357
+ dup.basic_block = @basic_block
358
+ dup.awesome_print.should =~ /\^Integer %\d+ = dup \^Integer 1/
359
+ dup.awesome_print_as_value.should =~ /^%\d+/
462
360
 
463
- concat = TupleConcatInsn.new(@basic_block,
361
+ concat = TupleConcatInsn.new(
464
362
  [SSA::Constant.new(Array, [1]), SSA::Constant.new(Array, [2,3])])
465
- concat.pretty_print.should == '^Array %3 = tuple_concat ^Array [1], ^Array [2, 3]'
466
- concat.inspect_as_value.should == '%3'
363
+ concat.basic_block = @basic_block
364
+ concat.awesome_print.should =~ /\^Array %\d+ = tuple_concat \^Array \[1\], \^Array \[2, 3\]/
365
+ concat.awesome_print_as_value.should =~ /^%\d+/
467
366
 
468
- zero_arity = BindingInsn.new(@basic_block)
469
- zero_arity.pretty_print.should == '^Binding %4 = binding'
470
- zero_arity.inspect_as_value.should == '%4'
367
+ zero_arity = BindingInsn.new
368
+ zero_arity.basic_block = @basic_block
369
+ zero_arity.awesome_print.should =~ /\^Binding %\d+ = binding/
370
+ zero_arity.awesome_print_as_value.should =~ /^%\d+/
471
371
 
472
- zero_all = TestScope::NestedInsn.new(@basic_block)
473
- zero_all.pretty_print.should == 'nested'
474
- zero_all.inspect_as_value.should == 'void'
372
+ zero_all = TestScope::NestedInsn.new
373
+ zero_all.basic_block = @basic_block
374
+ zero_all.awesome_print.should == 'nested'
375
+ zero_all.awesome_print_as_value.should == 'bottom'
475
376
  end
476
377
 
477
378
  describe SSA::GenericInstruction do
478
379
  it 'has settable type' do
479
- i = GenericInsn.new(@basic_block, Integer, [])
480
- i.pretty_print.should =~ /\^Integer %\d+ = generic/
380
+ i = GenericInsn.new(Integer, [])
381
+ i.basic_block = @basic_block
382
+ i.awesome_print.should =~ /\^Integer %\d+ = generic/
481
383
  i.type = Binding
482
- i.pretty_print.should =~ /\^Binding %\d+ = generic/
384
+ i.awesome_print.should =~ /\^Binding %\d+ = generic/
385
+ end
386
+
387
+ it 'replaces its type' do
388
+ ty = Type::Variable.new
389
+
390
+ i = GenericInsn.new(ty, [])
391
+ i.replace_type_with(ty, Integer.to_type)
392
+ i.type.should == Integer.to_type
483
393
  end
484
394
 
485
395
  describe SSA::PhiInsn do
486
396
  it 'accepts operand hash' do
487
397
  -> {
488
- phi = SSA::PhiInsn.new(@basic_block, nil,
398
+ phi = SSA::PhiInsn.new(Integer,
489
399
  { @basic_block => SSA::Constant.new(Integer, 1) })
490
400
  }.should.not.raise
491
401
  end
492
402
 
493
403
  it 'enumerates operands' do
494
404
  val1, val2 = 2.times.map { SSA::Value.new }
495
- bb1, bb2 = 2.times.map { SSA::BasicBlock.new(@function) }
405
+ bb1, bb2 = 2.times.map { SSA::BasicBlock.new }
496
406
 
497
- phi = SSA::PhiInsn.new(@basic_block, nil,
407
+ phi = SSA::PhiInsn.new(Integer,
498
408
  { bb1 => val1, bb2 => val2 })
499
409
  phi.should.enumerate :each_operand, [val1, val2, bb1, bb2]
500
410
  end
501
411
 
502
412
  it 'pretty prints' do
503
- phi = SSA::PhiInsn.new(@basic_block, nil,
413
+ phi = SSA::PhiInsn.new(Integer,
504
414
  { @basic_block => SSA::Constant.new(Integer, 1) })
505
- phi.pretty_print.should =~
506
- /<?> %\d = phi %\d => \^Integer 1/
415
+ phi.basic_block = @basic_block
416
+ phi.awesome_print.should =~
417
+ /\^Integer %\d = phi %\d => \^Integer 1/
507
418
  end
508
419
 
509
420
  it 'maintains use chains' do
510
421
  val = SSA::Value.new
511
- phi = SSA::PhiInsn.new(@basic_block, nil,
512
- { @basic_block => val })
422
+ phi = SSA::PhiInsn.new(Integer,
423
+ { @basic_block => val })
513
424
  val.should.enumerate :each_use, [phi]
514
425
  @basic_block.should.enumerate :each_use, [phi]
515
426
  end
@@ -517,8 +428,8 @@ describe SSA do
517
428
  it 'can replace uses of values' do
518
429
  val1, val2 = 2.times.map { SSA::Value.new }
519
430
 
520
- phi = SSA::PhiInsn.new(@basic_block, nil,
521
- { @basic_block => val1 })
431
+ phi = SSA::PhiInsn.new(Integer,
432
+ { @basic_block => val1 })
522
433
  phi.replace_uses_of(val1, val2)
523
434
 
524
435
  val1.should.enumerate :each_use, []
@@ -527,9 +438,9 @@ describe SSA do
527
438
 
528
439
  it 'can replace uses of basic blocks' do
529
440
  val = SSA::Value.new
530
- bb2 = SSA::BasicBlock.new(@function)
441
+ bb2 = SSA::BasicBlock.new
531
442
 
532
- phi = SSA::PhiInsn.new(@basic_block, nil,
443
+ phi = SSA::PhiInsn.new(Integer,
533
444
  { @basic_block => val })
534
445
  phi.replace_uses_of(@basic_block, bb2)
535
446
 
@@ -541,7 +452,7 @@ describe SSA do
541
452
  it 'barfs on #replace_uses_of if the value is not used' do
542
453
  val1, val2 = 2.times.map { SSA::Value.new }
543
454
 
544
- phi = SSA::PhiInsn.new(@basic_block, nil,
455
+ phi = SSA::PhiInsn.new(Integer,
545
456
  { @basic_block => val1 })
546
457
 
547
458
  -> { phi.replace_uses_of(val2, val1) }.should.raise ArgumentError
@@ -551,31 +462,54 @@ describe SSA do
551
462
 
552
463
  describe SSA::TerminatorInstruction do
553
464
  it 'is a terminator' do
554
- i = SSA::TerminatorInstruction.new(@basic_block, [])
465
+ i = SSA::TerminatorInstruction.new([])
555
466
  i.should.be.terminator
556
467
  end
557
468
 
558
- it 'has side effects' do
559
- i = SSA::TerminatorInstruction.new(@basic_block, [])
469
+ it 'has side effects if exits?' do
470
+ i = SSA::TerminatorInstruction.new([])
471
+
472
+ def i.exits?; true; end
560
473
  i.has_side_effects?.should == true
561
474
  end
562
475
 
563
476
  it 'requires to implement #exits?' do
564
- i = SSA::TerminatorInstruction.new(@basic_block, [])
477
+ i = SSA::TerminatorInstruction.new([])
565
478
  -> { i.exits? }.should.raise NotImplementedError
566
479
  end
567
480
 
568
481
  describe SSA::BranchInsn do
569
482
  it 'does not exit the method' do
570
- i = SSA::BranchInsn.new(@basic_block, [@basic_block])
483
+ i = SSA::BranchInsn.new([@basic_block])
571
484
  i.exits?.should == false
572
485
  end
573
486
  end
574
487
 
575
488
  describe SSA::ReturnInsn do
489
+ before do
490
+ @i = SSA::ReturnInsn.new
491
+ end
492
+
493
+ it 'exits the method' do
494
+ @i.exits?.should == true
495
+ end
496
+
497
+ it 'returns bottom in #value_type' do
498
+ @i.value_type.should == Type::Bottom.new
499
+ end
500
+ end
501
+
502
+ describe SSA::ReturnValueInsn do
503
+ before do
504
+ @i = SSA::ReturnValueInsn.new([SSA::Constant.new(Integer, 1)])
505
+ end
506
+
576
507
  it 'exits the method' do
577
- i = SSA::ReturnInsn.new(@basic_block, [SSA.void_value])
578
- i.exits?.should == true
508
+ @i.exits?.should == true
509
+ end
510
+
511
+ it 'returns value type in #value_type' do
512
+ @i.value_type.should == Integer.to_type
579
513
  end
580
514
  end
581
515
  end
@@ -587,18 +521,18 @@ describe SSA do
587
521
  end
588
522
 
589
523
  it 'has the type of BasicBlock' do
590
- @basic_block.type.should == SSA::BasicBlock.to_type
524
+ @basic_block.type.should == SSA::BasicBlockType.new
591
525
  end
592
526
 
593
527
  it 'pretty prints' do
594
- @basic_block.append insn_noary(@basic_block)
595
- @basic_block.append insn_noary(@basic_block)
596
- @basic_block.pretty_print.should ==
597
- "1:\n ^Binding %2 = binding\n ^Binding %3 = binding\n"
528
+ @basic_block.append insn_noary
529
+ @basic_block.append insn_noary
530
+ @basic_block.awesome_print.should ==
531
+ "1:\n ^Binding %2 = binding\n ^Binding %3 = binding\n\n"
598
532
  end
599
533
 
600
534
  it 'inspects as value' do
601
- @basic_block.inspect_as_value.should == 'label %1'
535
+ @basic_block.awesome_print_as_value.should == 'label %1'
602
536
  end
603
537
 
604
538
  it 'is constant' do
@@ -606,14 +540,21 @@ describe SSA do
606
540
  end
607
541
 
608
542
  it 'can append instructions' do
609
- i1, i2 = 2.times.map { insn_noary(@basic_block) }
543
+ i1, i2 = 2.times.map { insn_noary }
610
544
  @basic_block.append i1
611
545
  @basic_block.append i2
612
546
  @basic_block.to_a.should == [i1, i2]
613
547
  end
614
548
 
549
+ it 'can prepend instructions' do
550
+ i1, i2 = 2.times.map { insn_noary }
551
+ @basic_block.prepend i1
552
+ @basic_block.prepend i2
553
+ @basic_block.to_a.should == [i2, i1]
554
+ end
555
+
615
556
  it 'can insert instructions' do
616
- i1, i2, i3 = 3.times.map { insn_noary(@basic_block) }
557
+ i1, i2, i3 = 3.times.map { insn_noary }
617
558
  @basic_block.append i1
618
559
  -> { @basic_block.insert i3, i2 }.should.raise ArgumentError, %r|is not found|
619
560
  @basic_block.append i3
@@ -621,38 +562,49 @@ describe SSA do
621
562
  @basic_block.to_a.should == [i1, i2, i3]
622
563
  end
623
564
 
565
+ it 'can splice instructions' do
566
+ i1, i2, i3 = 3.times.map { insn_noary }
567
+ @basic_block.append i1
568
+ @basic_block.append i2
569
+ @basic_block.append i3
570
+ @basic_block.splice(i2).should == [i3]
571
+ @basic_block.to_a.should == [i1, i2]
572
+
573
+ -> { @basic_block.splice(i3) }.should.raise(ArgumentError, %r|is not found|)
574
+ end
575
+
624
576
  it 'is not affected by changes to #to_a value' do
625
- i1 = insn_noary(@basic_block)
577
+ i1 = insn_noary
626
578
  @basic_block.append i1
627
579
  @basic_block.to_a.clear
628
580
  @basic_block.to_a.size.should == 1
629
581
  end
630
582
 
631
583
  it 'enumerates instructions' do
632
- i1 = insn_noary(@basic_block)
584
+ i1 = insn_noary
633
585
  @basic_block.append i1
634
586
  @basic_block.should.enumerate :each, [i1]
635
587
  end
636
588
 
637
589
  it 'enumerates instructions by type' do
638
- i1 = BindingInsn.new(@basic_block)
590
+ i1 = BindingInsn.new
639
591
  @basic_block.append i1
640
592
 
641
- i2 = GenericInsn.new(@basic_block)
593
+ i2 = GenericInsn.new(Integer)
642
594
  @basic_block.append i2
643
595
 
644
596
  @basic_block.each(BindingInsn).should.enumerate :each, [i1]
645
597
  end
646
598
 
647
599
  it 'can check for presence of instructions' do
648
- i1, i2 = 2.times.map { insn_noary(@basic_block) }
600
+ i1, i2 = 2.times.map { insn_noary }
649
601
  @basic_block.append i1
650
602
  @basic_block.should.include i1
651
603
  @basic_block.should.not.include i2
652
604
  end
653
605
 
654
606
  it 'can remove instructions' do
655
- i1, i2 = 2.times.map { insn_noary(@basic_block) }
607
+ i1, i2 = 2.times.map { insn_noary }
656
608
  @basic_block.append i1
657
609
  @basic_block.append i2
658
610
  @basic_block.remove i1
@@ -660,7 +612,7 @@ describe SSA do
660
612
  end
661
613
 
662
614
  it 'can replace instructions' do
663
- i1, i2, i3, i4 = 4.times.map { insn_noary(@basic_block) }
615
+ i1, i2, i3, i4 = 4.times.map { insn_noary }
664
616
  @basic_block.append i1
665
617
  @basic_block.append i2
666
618
  @basic_block.append i3
@@ -673,28 +625,26 @@ describe SSA do
673
625
  @branch_bb = @basic_block
674
626
  @branch_bb.name = 'branch'
675
627
 
676
- @body_bb = SSA::BasicBlock.new(@function, 'body')
628
+ @body_bb = SSA::BasicBlock.new([], 'body')
677
629
  @function.add @body_bb
678
630
 
679
- @ret_bb = SSA::BasicBlock.new(@function, 'ret')
631
+ @ret_bb = SSA::BasicBlock.new([], 'ret')
680
632
  @function.add @ret_bb
681
633
 
682
- @cond = DupInsn.new(@branch_bb,
683
- [ SSA::Constant.new(TrueClass, true) ])
634
+ @cond = DupInsn.new([ SSA::Constant.new(TrueClass, true) ])
684
635
  @branch_bb.append @cond
685
636
 
686
- @cond_br = CondBranchInsn.new(@branch_bb,
637
+ @cond_br = CondBranchInsn.new(
687
638
  [ @cond,
688
639
  @body_bb,
689
640
  @ret_bb ])
690
641
  @branch_bb.append @cond_br
691
642
 
692
- @uncond_br = SSA::BranchInsn.new(@body_bb,
643
+ @uncond_br = SSA::BranchInsn.new(
693
644
  [ @ret_bb ])
694
645
  @body_bb.append @uncond_br
695
646
 
696
- @ret = SSA::ReturnInsn.new(@ret_bb,
697
- [ SSA.void_value ])
647
+ @ret = SSA::ReturnInsn.new
698
648
  @ret_bb.append @ret
699
649
  end
700
650
 
@@ -734,12 +684,12 @@ describe SSA do
734
684
  SSA::Constant.new(SSA::Function, @function.name)
735
685
 
736
686
  @function.name = 'foo'
737
- @function.to_value.inspect_as_value.should ==
687
+ @function.to_value.awesome_print_as_value.should ==
738
688
  'function "foo"'
739
689
  end
740
690
 
741
691
  it 'converts to type' do
742
- SSA::Function.to_type.should == SSA::FunctionType.instance
692
+ SSA::Function.to_type.should == SSA::FunctionType.new
743
693
  end
744
694
 
745
695
  it 'generates numeric names in #make_name(nil)' do
@@ -762,39 +712,47 @@ describe SSA do
762
712
  @function.should.not.include 'foobar'
763
713
  end
764
714
 
715
+ it 'reports #size' do
716
+ @function.size.should == 1
717
+ end
718
+
765
719
  it 'removes blocks' do
766
720
  @function.remove @basic_block
767
721
  @function.should.not.include '1'
768
722
  end
769
723
 
770
724
  it 'iterates each instruction in each block' do
771
- bb2 = SSA::BasicBlock.new(@function)
725
+ bb2 = SSA::BasicBlock.new
772
726
  @function.add bb2
773
727
 
774
- i1 = insn_noary(@basic_block)
728
+ i1 = insn_noary
775
729
  @basic_block.append i1
776
730
 
777
- i2 = insn_unary(@basic_block, i1)
731
+ i2 = insn_unary(i1)
778
732
  bb2.append i2
779
733
 
780
734
  @function.should.enumerate :each_instruction, [i1, i2]
781
735
  end
782
736
 
737
+ it 'sanitizes arguments' do
738
+ -> { @function.arguments = [1] }.should.raise(ArgumentError)
739
+ end
740
+
783
741
  it 'pretty prints' do
784
742
  @function.name = 'foo'
785
743
  @function.arguments = [
786
- SSA::Argument.new(@function, Integer, 'count'),
787
- SSA::Argument.new(@function, Binding, 'outer')
744
+ SSA::Argument.new(Integer, 'count'),
745
+ SSA::Argument.new(Binding, 'outer')
788
746
  ]
789
747
 
790
- @basic_block.append insn_binary(@basic_block, *@function.arguments)
748
+ @basic_block.append insn_binary(*@function.arguments)
791
749
 
792
- bb2 = SSA::BasicBlock.new(@function, 'foo')
750
+ bb2 = SSA::BasicBlock.new([], 'foo')
793
751
  @function.add bb2
794
- bb2.append insn_unary(@basic_block, SSA::Constant.new(Integer, 1))
752
+ bb2.append insn_unary(SSA::Constant.new(Integer, 1))
795
753
 
796
- @function.pretty_print.should == <<-END
797
- function void foo( ^Integer %count, ^Binding %outer ) {
754
+ @function.awesome_print.should == <<-END
755
+ function bottom foo (^Integer %count, ^Binding %outer) {
798
756
  1:
799
757
  ^Array %2 = tuple_concat %count, %outer
800
758
 
@@ -808,7 +766,7 @@ foo:
808
766
  it 'duplicates all its content' do
809
767
  @function.name = 'foo;1'
810
768
  @function.arguments = [
811
- SSA::Argument.new(@function, Integer, 'count'),
769
+ SSA::Argument.new(Integer, 'count'),
812
770
  ]
813
771
 
814
772
  f1a1 = @function.arguments.first
@@ -816,20 +774,20 @@ foo:
816
774
  f1bb1 = @function.entry
817
775
  f1bb1.name = 'bb1'
818
776
 
819
- f1bb2 = SSA::BasicBlock.new(@function, 'bb2')
777
+ f1bb2 = SSA::BasicBlock.new([], 'bb2')
820
778
  @function.add f1bb2
821
779
 
822
- f1i1 = insn_unary(@basic_block, f1a1)
780
+ f1i1 = insn_unary(f1a1)
823
781
  @basic_block.append f1i1
824
782
 
825
783
  f1c1 = SSA::Constant.new(Array, [1])
826
- f1i2 = insn_binary(@basic_block, f1i1, f1c1)
784
+ f1i2 = insn_binary(f1i1, f1c1)
827
785
  f1bb2.append f1i2
828
786
 
829
- f1bb3 = SSA::BasicBlock.new(@function, 'bb3')
787
+ f1bb3 = SSA::BasicBlock.new([], 'bb3')
830
788
  @function.add f1bb3
831
789
 
832
- f1phi = SSA::PhiInsn.new(f1bb3, nil,
790
+ f1phi = SSA::PhiInsn.new(Integer,
833
791
  { f1bb1 => f1i1, f1bb2 => f1i2 })
834
792
  f1bb3.append f1phi
835
793
 
@@ -872,7 +830,7 @@ foo:
872
830
  end
873
831
 
874
832
  f2.name = f1.name
875
- f2.pretty_print.to_s.should == f1.pretty_print.to_s
833
+ f2.awesome_print.to_s.should == f1.awesome_print.to_s
876
834
  end
877
835
  end
878
836
 
@@ -896,7 +854,7 @@ foo:
896
854
  bar, = @f.arguments
897
855
  bar.type.should == Integer.to_type
898
856
  bar.name.should == 'bar'
899
- @f.return_type.should == Float
857
+ @f.return_type.should == Float.to_type
900
858
 
901
859
  bb = @f.find('1')
902
860
  @f.entry.should == bb
@@ -917,10 +875,19 @@ foo:
917
875
  end
918
876
 
919
877
  it 'builds ReturnInsn' do
920
- @b.return SSA.void_value
878
+ @b.return
921
879
  i, = @b.block.to_a
922
880
  i.should.be.instance_of SSA::ReturnInsn
923
- i.operands.should == [SSA.void_value]
881
+ i.operands.should == []
882
+ end
883
+
884
+ it 'builds ReturnValueInsn' do
885
+ v1 = SSA::Constant.new(Integer, 1)
886
+
887
+ @b.return_value v1
888
+ i, = @b.block.to_a
889
+ i.should.be.instance_of SSA::ReturnValueInsn
890
+ i.operands.should == [v1]
924
891
  end
925
892
  end
926
893
 
@@ -932,12 +899,6 @@ foo:
932
899
  end
933
900
  end
934
901
 
935
- class SyntaxTypedInsn < SSA::Instruction
936
- syntax do |s|
937
- s.operand :foo, Integer
938
- end
939
- end
940
-
941
902
  class SyntaxSplatInsn < SSA::Instruction
942
903
  syntax do |s|
943
904
  s.operand :foo
@@ -948,45 +909,36 @@ foo:
948
909
  before do
949
910
  @iconst = SSA::Constant.new(Integer, 1)
950
911
  @fconst = SSA::Constant.new(Float, 1.0)
951
- @iinsn = DupInsn.new(@basic_block, [ @iconst ])
912
+ @iinsn = DupInsn.new([ @iconst ])
952
913
  end
953
914
 
954
915
  it 'accepts operands and decomposes them' do
955
- i = SyntaxUntypedInsn.new(@basic_block, [ @iconst, @fconst ])
916
+ i = SyntaxUntypedInsn.new([ @iconst, @fconst ])
956
917
  i.foo.should == @iconst
957
918
  i.bar.should == @fconst
958
919
  end
959
920
 
960
921
  it 'allows to change operands through accessors' do
961
- i = SyntaxUntypedInsn.new(@basic_block, [ @iconst, @fconst ])
922
+ i = SyntaxUntypedInsn.new([ @iconst, @fconst ])
962
923
  i.foo = @iinsn
963
924
  i.operands.should == [@iinsn, @fconst]
964
925
  end
965
926
 
966
927
  it 'does not accept wrong amount of operands' do
967
- -> { SyntaxUntypedInsn.new(@basic_block, [ @iconst ]) }.
928
+ -> { SyntaxUntypedInsn.new([ @iconst ]) }.
968
929
  should.raise ArgumentError
969
- -> { SyntaxUntypedInsn.new(@basic_block, [ @iconst, @iconst, @iconst ]) }.
930
+ -> { SyntaxUntypedInsn.new([ @iconst, @iconst, @iconst ]) }.
970
931
  should.raise ArgumentError
971
932
  end
972
933
 
973
- it 'accepts only correct typed operands' do
974
- -> { SyntaxTypedInsn.new(@basic_block, [ @fconst ]) }.
975
- should.raise TypeError
976
- -> { SyntaxTypedInsn.new(@basic_block, [ @iconst ]) }.
977
- should.not.raise
978
- -> { SyntaxTypedInsn.new(@basic_block, [ @iinsn ]) }.
979
- should.not.raise
980
- end
981
-
982
934
  it 'accepts splat' do
983
- i = SyntaxSplatInsn.new(@basic_block, [ @iconst, @fconst, @iinsn ])
935
+ i = SyntaxSplatInsn.new([ @iconst, @fconst, @iinsn ])
984
936
  i.foo.should == @iconst
985
937
  i.bars.should == [@fconst, @iinsn]
986
938
  end
987
939
 
988
940
  it 'does not accept wrong amount of operands with splat' do
989
- -> { SyntaxSplatInsn.new(@basic_block, []) }.
941
+ -> { SyntaxSplatInsn.new([]) }.
990
942
  should.raise ArgumentError
991
943
  end
992
944
 
@@ -1011,41 +963,14 @@ foo:
1011
963
  end
1012
964
 
1013
965
  it 'allows to update splat' do
1014
- i = SyntaxSplatInsn.new(@basic_block, [ @iconst, @fconst, @iinsn ])
966
+ i = SyntaxSplatInsn.new([ @iconst, @fconst, @iinsn ])
1015
967
  i.bars = [@iinsn, @fconst]
1016
968
  i.bars.should == [@iinsn, @fconst]
1017
969
  i.operands.should == [@iconst, @iinsn, @fconst]
1018
970
  end
1019
971
 
1020
- it 'allows to inquire status' do
1021
- i = SyntaxTypedInsn.new(@basic_block, [ @iconst ])
1022
- i.should.be.valid
1023
- i.foo = @fconst
1024
- i.should.not.be.valid
1025
- end
1026
-
1027
- it 'highlights invalid insns when pretty printing' do
1028
- i = SyntaxTypedInsn.new(@basic_block, [ @iconst ])
1029
- i.foo = @fconst
1030
- i.pretty_print.should =~ /!syntax_typed/
1031
- end
1032
-
1033
- it 'allows to treat nil type as error' do
1034
- phi = SSA::PhiInsn.new(@basic_block, nil)
1035
-
1036
- i = SyntaxTypedInsn.new(@basic_block, [ @iconst ])
1037
- i.should.be.valid(true)
1038
- i.should.be.valid(false)
1039
- -> { i.verify!(false) }.should.not.raise
1040
-
1041
- i.foo = phi
1042
- i.should.be.valid(true)
1043
- i.should.not.be.valid(false)
1044
- -> { i.verify!(false) }.should.raise TypeError, %r|<?>|
1045
- end
1046
-
1047
972
  it 'does not interfere with def-use tracking' do
1048
- i = SyntaxUntypedInsn.new(@basic_block, [ @iconst, @fconst ])
973
+ i = SyntaxUntypedInsn.new([ @iconst, @fconst ])
1049
974
  @fconst.should.enumerate :each_use, [ i ]
1050
975
 
1051
976
  i.bar = @iinsn
@@ -1054,12 +979,48 @@ foo:
1054
979
  end
1055
980
 
1056
981
  it 'does not break on replace_uses_of' do
1057
- i = SyntaxUntypedInsn.new(@basic_block, [ @iconst, @fconst ])
982
+ i = SyntaxUntypedInsn.new([ @iconst, @fconst ])
1058
983
  i.replace_uses_of @iconst, @fconst
1059
984
  i.foo.should == @fconst
1060
985
  end
1061
986
  end
1062
987
 
988
+ describe SSA::EventStream do
989
+ before do
990
+ @b = TestBuilder.new('foo',
991
+ [ [Integer, 'bar'], [Binding, 'baz'] ],
992
+ Float)
993
+ @fun = @b.function
994
+
995
+ SSA.start_instrumentation
996
+
997
+ @mod = SSA::Module.new
998
+ @mod.add @fun
999
+ end
1000
+
1001
+ it 'instruments functions' do
1002
+ iconst = SSA::Constant.new(Integer, 1)
1003
+ iconst2 = @b.append :dup, [ iconst ]
1004
+
1005
+ iconst2.name = 'dupped'
1006
+
1007
+ @b.add_block do
1008
+ @b.return_value iconst2
1009
+ end
1010
+
1011
+ SSA.instrumentation.mark_transform(@fun, "footrans")
1012
+ @fun.remove @b.block
1013
+
1014
+ # It's not possible to verify the instrumentation data,
1015
+ # as it includes object_ids, so we just check that no exception
1016
+ # is raised and it's not nil.
1017
+ SSA.instrumentation.data.should.is_a? Array
1018
+
1019
+ # Disable instrumentation
1020
+ SSA.instrumentation = nil
1021
+ end
1022
+ end
1023
+
1063
1024
  describe SSA::Module do
1064
1025
  before do
1065
1026
  @module = SSA::Module.new
@@ -1126,4 +1087,4 @@ foo:
1126
1087
  @module.should.not.include 'foo'
1127
1088
  end
1128
1089
  end
1129
- end
1090
+ end