furnace 0.4.0.beta.1 → 0.4.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.
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