rpiet 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +12 -0
- data/bin/color_wheel +84 -0
- data/bin/image_gen +39 -0
- data/bin/rpiet +68 -11
- data/images/counter.txt +7 -0
- data/lib/rpiet/asg/graph_interpreter.rb +39 -0
- data/lib/rpiet/asg/parser.rb +156 -0
- data/lib/rpiet/asg/visitor.rb +66 -0
- data/lib/rpiet/asg.rb +336 -0
- data/lib/rpiet/codel_chooser.rb +32 -4
- data/lib/rpiet/color.rb +70 -25
- data/lib/rpiet/cycle.rb +18 -7
- data/lib/rpiet/debugger/debugger.rb +298 -0
- data/lib/rpiet/debugger/stylesheet.css +88 -0
- data/lib/rpiet/direction_pointer.rb +49 -18
- data/lib/rpiet/event_handler.rb +62 -7
- data/lib/rpiet/group.rb +25 -8
- data/lib/rpiet/image/ascii_image.rb +8 -20
- data/lib/rpiet/image/image.rb +8 -3
- data/lib/rpiet/image/url_image.rb +28 -14
- data/lib/rpiet/interpreter.rb +72 -72
- data/lib/rpiet/ir/assembler.rb +87 -0
- data/lib/rpiet/ir/builder.rb +255 -0
- data/lib/rpiet/ir/cfg.rb +494 -0
- data/lib/rpiet/ir/instructions.rb +536 -0
- data/lib/rpiet/ir/ir_cfg_interpreter.rb +23 -0
- data/lib/rpiet/ir/ir_interpreter.rb +101 -0
- data/lib/rpiet/ir/ir_native_interpreter.rb +77 -0
- data/lib/rpiet/ir/jruby_backend.rb +279 -0
- data/lib/rpiet/ir/operands.rb +28 -0
- data/lib/rpiet/ir/passes/data_flow_problem.rb +32 -0
- data/lib/rpiet/ir/passes/flow_graph_node.rb +76 -0
- data/lib/rpiet/ir/passes/peephole.rb +214 -0
- data/lib/rpiet/ir/passes/push_pop_elimination_pass.rb +112 -0
- data/lib/rpiet/live_machine_state.rb +15 -0
- data/lib/rpiet/machine.rb +62 -32
- data/lib/rpiet/source.rb +83 -0
- data/lib/rpiet/version.rb +1 -1
- data/lib/rpiet.rb +2 -2
- data/rpiet.gemspec +19 -0
- data/spec/asg/visitor_spec.rb +41 -0
- data/spec/cycle_spec.rb +34 -34
- data/spec/direction_pointer_spec.rb +33 -6
- data/spec/group_spec.rb +73 -48
- data/spec/interpreter_spec.rb +161 -12
- data/spec/ir/assembler_spec.rb +122 -0
- data/spec/ir/builder_spec.rb +20 -0
- data/spec/ir/cfg_spec.rb +151 -0
- data/spec/ir/ir_interpreter_spec.rb +102 -0
- data/spec/ir/passes/push_pop_elimination_pass_spec.rb +34 -0
- data/spec/machine_spec.rb +5 -3
- data/spec/source_spec.rb +69 -0
- data/spec/spec_helper.rb +78 -0
- metadata +54 -16
- data/images/nfib.png +0 -0
data/spec/group_spec.rb
CHANGED
@@ -1,57 +1,82 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/rpiet/group'
|
3
|
+
require_relative '../lib/rpiet/color'
|
3
4
|
|
4
5
|
describe "Group" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
6
|
+
SQUARE = <<-EOS
|
7
|
+
.###.
|
8
|
+
.###.
|
9
|
+
.###.
|
10
|
+
EOS
|
11
|
+
|
12
|
+
WACKY = <<-EOS
|
13
|
+
.#.#.
|
14
|
+
#####
|
15
|
+
.#.#.
|
16
|
+
EOS
|
17
|
+
|
18
|
+
HOOKY = <<-EOS
|
19
|
+
.#.#.#
|
20
|
+
######
|
21
|
+
.#.#..
|
22
|
+
EOS
|
23
|
+
|
24
|
+
|
25
|
+
let(:light_cyan) { RPiet::Color.color_for('0x0000c0') }
|
26
|
+
let(:black) { RPiet::Color.color_for('0x000000') }
|
27
|
+
let(:blue) { RPiet::Color.color_for('0x0000ff') }
|
28
|
+
let(:square_group) { create_group(light_cyan, SQUARE) }
|
29
|
+
let(:wacky_group) { create_group(black, WACKY) }
|
30
|
+
let(:hooky_group) { create_group(blue, HOOKY) }
|
31
|
+
|
32
|
+
it "knows its color" do
|
33
|
+
expect(square_group.color).to eq light_cyan
|
34
|
+
expect(wacky_group.color).to eq black
|
35
|
+
expect(hooky_group.color).to eq blue
|
24
36
|
end
|
25
37
|
|
26
38
|
it "knows its size" do
|
27
|
-
|
39
|
+
expect(square_group.size).to eq(9)
|
40
|
+
expect(wacky_group.size).to eq(9)
|
41
|
+
expect(hooky_group.size).to eq(11)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'picks the right points (wacky)' do
|
45
|
+
expect(wacky_group.rr).to eq([4,1])
|
46
|
+
expect(wacky_group.rl).to eq([4,1])
|
47
|
+
expect(wacky_group.lr).to eq([0,1])
|
48
|
+
expect(wacky_group.ll).to eq([0,1])
|
49
|
+
expect(wacky_group.dr).to eq([1,2])
|
50
|
+
expect(wacky_group.dl).to eq([3,2])
|
51
|
+
expect(wacky_group.ur).to eq([3,0])
|
52
|
+
expect(wacky_group.ul).to eq([1,0])
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'picks the right points (simple)' do
|
56
|
+
expect(square_group.rr).to eq([3,2])
|
57
|
+
expect(square_group.rl).to eq([3,0])
|
58
|
+
expect(square_group.lr).to eq([1,0])
|
59
|
+
expect(square_group.ll).to eq([1,2])
|
60
|
+
expect(square_group.dr).to eq([1,2])
|
61
|
+
expect(square_group.dl).to eq([3,2])
|
62
|
+
expect(square_group.ur).to eq([3,0])
|
63
|
+
expect(square_group.ul).to eq([1,0])
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'picks the right points (hooky)' do
|
67
|
+
expect(hooky_group.rr).to eq([5,1])
|
68
|
+
expect(hooky_group.rl).to eq([5,0])
|
69
|
+
expect(hooky_group.lr).to eq([0,1])
|
70
|
+
expect(hooky_group.ll).to eq([0,1])
|
71
|
+
expect(hooky_group.dr).to eq([1,2])
|
72
|
+
expect(hooky_group.dl).to eq([3,2])
|
73
|
+
expect(hooky_group.ur).to eq([5,0])
|
74
|
+
expect(hooky_group.ul).to eq([1,0])
|
28
75
|
end
|
29
76
|
|
30
|
-
it
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@pvm.dp.rotate! # dp: RIGHT -> DOWN
|
35
|
-
@pvm.cc.switch! # cc: RIGHT -> LEFT
|
36
|
-
@group.point_for(@pvm).should == [0, 7] # dp: DOWN cc: LEFT -> LR
|
37
|
-
@pvm.cc.switch! # cc: LEFT -> RIGHT
|
38
|
-
@group.point_for(@pvm).should == [0, 7] # dp: DOWN cc: RIGHT -> LL
|
39
|
-
@pvm.dp.rotate! # dp: DOWN -> LEFT
|
40
|
-
@pvm.cc.switch! # cc: RIGHT -> LEFT
|
41
|
-
@group.point_for(@pvm).should == [0, 7] # dp: LEFT cc: LEFT -> LL
|
42
|
-
@pvm.cc.switch! # cc: LEFT -> RIGHT
|
43
|
-
@group.point_for(@pvm).should == [0, 3] # dp: LEFT cc: RIGHT -> UL
|
44
|
-
@pvm.dp.rotate! # dp: LEFT -> UP
|
45
|
-
@pvm.cc.switch!
|
46
|
-
@group.point_for(@pvm).should == [0, 3] # dp: UP cc: LEFT -> UL
|
47
|
-
@pvm.cc.switch! # cc: LEFT -> RIGHT
|
48
|
-
@group.point_for(@pvm).should == [4, 3] # dp: UP cc: RIGHT -> UR
|
49
|
-
|
50
|
-
# Since last group only has single wide bottom let's try another
|
51
|
-
@pvm.cc.switch! # cc: RIGHT -> LEFT
|
52
|
-
@pvm.dp.rotate! 2 # dp: UP -> DOWN
|
53
|
-
@group2.point_for(@pvm).should == [7, 3] # dp: DOWN cc: LEFT -> LR
|
54
|
-
@pvm.cc.switch! # cc: RIGHT -> LEFT
|
55
|
-
@group2.point_for(@pvm).should == [6, 3] # dp: DOWN cc: RIGHT -> LL
|
77
|
+
it 'has edges' do
|
78
|
+
expect(square_group.edges.to_a).to match_array([[1,0,:left], [1,0,:up], [2,0,:up], [3,0,:up], [3,0,:right],
|
79
|
+
[1,1,:left], [3,1,:right],
|
80
|
+
[1,2,:left], [1,2,:down], [2,2,:down], [3,2,:down],[3,2,:right]])
|
56
81
|
end
|
57
82
|
end
|
data/spec/interpreter_spec.rb
CHANGED
@@ -1,14 +1,163 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/rpiet/asg/graph_interpreter'
|
3
|
+
require_relative '../lib/rpiet/interpreter'
|
4
|
+
|
5
|
+
describe "RPiet Runtimes" do
|
6
|
+
|
7
|
+
let(:push_pop) do # [push 2, pop]*
|
8
|
+
create_image <<-EOS
|
9
|
+
nb db ++
|
10
|
+
nb ++ ++
|
11
|
+
++ ++ ++
|
12
|
+
EOS
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:push_add) do # [push 2, push 1, add, ...]
|
16
|
+
create_image <<-EOS
|
17
|
+
nb db lb lm ++
|
18
|
+
nb ++ ++ lm ++
|
19
|
+
++ ++ ++ ++ ++
|
20
|
+
EOS
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:push_subtract) do # [push 2, push 1, subtract, ...]
|
24
|
+
create_image <<-EOS
|
25
|
+
nb db lb nm ++
|
26
|
+
nb ++ ++ nm ++
|
27
|
+
++ ++ ++ ++ ++
|
28
|
+
EOS
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:push_multiply) do # [push 2, push 2, multiply, ...]
|
32
|
+
create_image <<-EOS
|
33
|
+
nb db lb dm ++
|
34
|
+
nb db ++ dm ++
|
35
|
+
++ ++ ++ ++ ++
|
36
|
+
EOS
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:push_divide) do # [push 2, push 2, divide, ...]
|
40
|
+
create_image <<-EOS
|
41
|
+
nb db lb lr ++
|
42
|
+
nb db ++ lr ++
|
43
|
+
++ ++ ++ ++ ++
|
44
|
+
EOS
|
45
|
+
end
|
46
|
+
|
47
|
+
let(:divide_by_zero) do # [push 2, push 1, push 1, subtract, divide]
|
48
|
+
create_image <<-EOS
|
49
|
+
nb db lb nb dm dy ++
|
50
|
+
nb ++ ++ ++ ++ dy ++
|
51
|
+
++ ++ ++ ++ ++ ++ ++
|
52
|
+
EOS
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:push_mod) do # [push 2, push 2, mod, ...]
|
56
|
+
create_image <<-EOS
|
57
|
+
nb db lb nr ++
|
58
|
+
nb db ++ nr ++
|
59
|
+
++ ++ ++ ++ ++
|
60
|
+
EOS
|
61
|
+
end
|
62
|
+
|
63
|
+
let(:push_not) do # [push 2, push 2, mod, not, ...]
|
64
|
+
create_image <<-EOS
|
65
|
+
nb db lb nr lg ++
|
66
|
+
nb db ++ nr lg ++
|
67
|
+
++ ++ ++ ++ ++ ++
|
68
|
+
EOS
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:skip_white) do
|
72
|
+
create_image <<-EOS
|
73
|
+
nb .. .. db ++
|
74
|
+
nb .. .. ++ ++
|
75
|
+
++ .. .. ++ ++
|
76
|
+
EOS
|
77
|
+
end
|
78
|
+
|
79
|
+
[RPiet::Interpreter, RPiet::ASG::GraphInterpreter].each do |runtime|
|
80
|
+
describe runtime do
|
81
|
+
it "Can push and pop" do
|
82
|
+
interpreter = runtime.new push_pop
|
83
|
+
interpreter.reset
|
84
|
+
interpreter.next_step
|
85
|
+
expect(interpreter.stack).to eq [2]
|
86
|
+
interpreter.next_step
|
87
|
+
expect(interpreter.stack).to eq []
|
88
|
+
end
|
89
|
+
|
90
|
+
it "Can push and add" do
|
91
|
+
interpreter = runtime.new push_add
|
92
|
+
interpreter.reset
|
93
|
+
2.times { interpreter.next_step }
|
94
|
+
expect(interpreter.stack).to eq [2, 1]
|
95
|
+
interpreter.next_step
|
96
|
+
expect(interpreter.stack).to eq [3]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "Can push and subtract" do
|
100
|
+
interpreter = runtime.new push_subtract
|
101
|
+
interpreter.reset
|
102
|
+
2.times { interpreter.next_step }
|
103
|
+
expect(interpreter.stack).to eq [2, 1]
|
104
|
+
interpreter.next_step
|
105
|
+
expect(interpreter.stack).to eq [1]
|
106
|
+
end
|
107
|
+
|
108
|
+
it "Can push and multiply" do
|
109
|
+
interpreter = runtime.new push_multiply
|
110
|
+
interpreter.reset
|
111
|
+
2.times { interpreter.next_step }
|
112
|
+
expect(interpreter.stack).to eq [2, 2]
|
113
|
+
interpreter.next_step
|
114
|
+
expect(interpreter.stack).to eq [4]
|
115
|
+
end
|
116
|
+
|
117
|
+
it "Can push and divide" do
|
118
|
+
interpreter = runtime.new push_divide
|
119
|
+
interpreter.reset
|
120
|
+
2.times { interpreter.next_step }
|
121
|
+
expect(interpreter.stack).to eq [2, 2]
|
122
|
+
interpreter.next_step
|
123
|
+
expect(interpreter.stack).to eq [1]
|
124
|
+
end
|
125
|
+
|
126
|
+
it "Can divide by zero" do
|
127
|
+
interpreter = runtime.new divide_by_zero
|
128
|
+
interpreter.reset
|
129
|
+
4.times { interpreter.next_step }
|
130
|
+
expect(interpreter.stack).to eq [2, 0]
|
131
|
+
interpreter.next_step
|
132
|
+
expect(interpreter.stack).to eq [99999999]
|
133
|
+
end
|
134
|
+
|
135
|
+
it "Can push and mod" do
|
136
|
+
interpreter = runtime.new push_mod
|
137
|
+
interpreter.reset
|
138
|
+
2.times { interpreter.next_step }
|
139
|
+
expect(interpreter.stack).to eq [2, 2]
|
140
|
+
interpreter.next_step
|
141
|
+
expect(interpreter.stack).to eq [0]
|
142
|
+
end
|
143
|
+
|
144
|
+
it "Can push and not" do
|
145
|
+
interpreter = runtime.new push_not
|
146
|
+
interpreter.reset
|
147
|
+
2.times { interpreter.next_step }
|
148
|
+
expect(interpreter.stack).to eq [2, 2]
|
149
|
+
2.times { interpreter.next_step }
|
150
|
+
expect(interpreter.stack).to eq [1]
|
151
|
+
end
|
152
|
+
|
153
|
+
it "Can skip white and push and pop" do
|
154
|
+
interpreter = runtime.new push_pop
|
155
|
+
interpreter.reset
|
156
|
+
interpreter.next_step
|
157
|
+
expect(interpreter.stack).to eq [2]
|
158
|
+
interpreter.next_step
|
159
|
+
expect(interpreter.stack).to eq []
|
160
|
+
end
|
161
|
+
end
|
13
162
|
end
|
14
163
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
include RPiet::IR::Instructions
|
4
|
+
|
5
|
+
describe "RPiet::IR::Assembler" do
|
6
|
+
context "individual instructions" do
|
7
|
+
it "can load copy" do
|
8
|
+
instr = assemble("v1 = copy 1\n").first
|
9
|
+
expect(instr.operation).to eq(:copy)
|
10
|
+
expect(instr.operand).to be_numeric_operand(1)
|
11
|
+
expect(instr.result).to be_variable_operand("v1")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can load push" do
|
15
|
+
instr = assemble("push 10\n").first
|
16
|
+
expect(instr.operation).to eq(:push)
|
17
|
+
expect(instr.operand).to be_numeric_operand(10)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can load pop" do
|
21
|
+
instr = assemble("v1 = pop\n").first
|
22
|
+
expect(instr.operation).to eq(:pop)
|
23
|
+
expect(instr.result).to be_variable_operand("v1")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can load nout" do
|
27
|
+
instr = assemble("nout 12\n").first
|
28
|
+
expect(instr.operation).to eq(:nout)
|
29
|
+
expect(instr.operand).to be_numeric_operand(12)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "can load cout" do
|
33
|
+
instr = assemble("cout 'a'\n").first
|
34
|
+
expect(instr.operation).to eq(:cout)
|
35
|
+
expect(instr.operand).to be_string_operand("a")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "can load nin" do
|
39
|
+
instr = assemble("v1 = nin\n").first
|
40
|
+
expect(instr.operation).to eq(:nin)
|
41
|
+
expect(instr.result).to be_variable_operand("v1")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "can load roll" do
|
45
|
+
instr = assemble("roll 1 10\n").first
|
46
|
+
expect(instr.operation).to eq(:roll)
|
47
|
+
expect(instr.depth).to be_numeric_operand(1)
|
48
|
+
expect(instr.num).to be_numeric_operand(10)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "can load label" do
|
52
|
+
instr = assemble("label foo\n").first
|
53
|
+
expect(instr.operation).to eq(:label)
|
54
|
+
expect(instr.operand).to be_label_operand(:jump_reduction)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "cannot load label with non-label operand" do
|
58
|
+
expect { assemble("label 1\n") }.to raise_error(ArgumentError)
|
59
|
+
expect { assemble("label 'a'\n") }.to raise_error(ArgumentError)
|
60
|
+
expect { assemble("v1 = copy 1\nlabel v1\n") }.to raise_error(ArgumentError)
|
61
|
+
end
|
62
|
+
|
63
|
+
context "can load infix math" do
|
64
|
+
%w[+ - * / % **].zip(%i[add sub mult div mod pow]).each do |oper, type|
|
65
|
+
it "can load #{oper}" do
|
66
|
+
instr = assemble("v1 = copy 2\nv2 = 1 #{oper} v1\n")[1]
|
67
|
+
expect(instr.operation).to eq(type)
|
68
|
+
expect(instr.operand1).to be_numeric_operand(1)
|
69
|
+
expect(instr.operand2).to be_variable_operand("v1")
|
70
|
+
expect(instr.result).to be_variable_operand("v2")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "cannot load non-numeric/variable operands" do
|
74
|
+
expect { assemble("v1 = 10 #{oper} label\n")}.to raise_error(ArgumentError)
|
75
|
+
expect { assemble("v1 = 10 #{oper} 'a'\n")}.to raise_error(ArgumentError)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "can process gt(>)" do
|
81
|
+
instr = assemble("v1 = 1 > 2\n").first
|
82
|
+
expect(instr.operation).to eq(:gt)
|
83
|
+
expect(instr.result).to be_variable_operand("v1")
|
84
|
+
expect(instr.operand1).to be_numeric_operand(1)
|
85
|
+
expect(instr.operand2).to be_numeric_operand(2)
|
86
|
+
end
|
87
|
+
|
88
|
+
context "can process branches" do
|
89
|
+
%w[!= ==].zip(%i[bne beq]).each do |oper, type|
|
90
|
+
it "can load #{oper}" do
|
91
|
+
instr = assemble("1 #{oper} 2 label\n").first
|
92
|
+
expect(instr.operation).to eq(type)
|
93
|
+
expect(instr.operand1).to be_numeric_operand(1)
|
94
|
+
expect(instr.operand2).to be_numeric_operand(2)
|
95
|
+
expect(instr.label).to be_label_operand(:label)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it "can load jump" do
|
101
|
+
instr = assemble("jump label\n").first
|
102
|
+
expect(instr.operation).to eq(:jump)
|
103
|
+
expect(instr.label).to be_label_operand(:label)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "can load multiple instructions" do
|
107
|
+
instrs = assemble("push 10\nv1 = pop\n")
|
108
|
+
expect(instrs.size).to eq(2)
|
109
|
+
expect(instrs[0].operation).to eq(:push)
|
110
|
+
expect(instrs[1].operation).to eq(:pop)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "is in single-static-assignment form (SSA)" do
|
114
|
+
expect { assemble("v1 = pop\nv2 = pop\nv1 = pop\n") }.to raise_error(ArgumentError)
|
115
|
+
expect { assemble("push v1\n") }.to raise_error(ArgumentError)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "cannot use a non-variable as a result" do
|
119
|
+
expect { assemble("10 = pop\n")}.to raise_error(ArgumentError)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/rpiet/asg/parser'
|
3
|
+
require_relative '../../lib/rpiet/ir/builder'
|
4
|
+
|
5
|
+
describe "RPiet::Builder" do
|
6
|
+
let(:cycle) do
|
7
|
+
create_image <<-EOS
|
8
|
+
nb db nb
|
9
|
+
db ++ nb
|
10
|
+
db db db
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can visit all nodes once plus one extra visit for a cycle" do
|
15
|
+
graph = RPiet::ASG::Parser.new(cycle).run
|
16
|
+
builder = RPiet::Builder.new
|
17
|
+
builder.run graph
|
18
|
+
#p builder.instructions
|
19
|
+
end
|
20
|
+
end
|
data/spec/ir/cfg_spec.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/rpiet/asg/parser'
|
3
|
+
require_relative '../../lib/rpiet/ir/builder'
|
4
|
+
require_relative '../../lib/rpiet/ir/cfg'
|
5
|
+
|
6
|
+
|
7
|
+
describe "RPiet::IR::CFG" do
|
8
|
+
let(:push_divide) {
|
9
|
+
assemble("push 10\npush 2\nv1 = pop\nv2 = pop\nv3 = v2 / v1; push v3")
|
10
|
+
}
|
11
|
+
|
12
|
+
let(:gtr) {
|
13
|
+
assemble <<~EOS
|
14
|
+
10 != 2 true
|
15
|
+
push 0
|
16
|
+
jump end
|
17
|
+
label true
|
18
|
+
push 1
|
19
|
+
label end
|
20
|
+
exit
|
21
|
+
EOS
|
22
|
+
}
|
23
|
+
|
24
|
+
let(:pntr) {
|
25
|
+
assemble <<~EOS
|
26
|
+
dpset 0
|
27
|
+
push 2
|
28
|
+
v25 = pop
|
29
|
+
v26 = dpget
|
30
|
+
v27 = v26 + v25
|
31
|
+
v28 = v27 % 4
|
32
|
+
dpset v28
|
33
|
+
v28 != 0 pntr[0]43
|
34
|
+
push 0
|
35
|
+
jump re.4008
|
36
|
+
label pntr[0]43
|
37
|
+
v28 != 1 pntr[1]43
|
38
|
+
push 1
|
39
|
+
jump re.4008
|
40
|
+
label pntr[1]43
|
41
|
+
v28 != 2 pntr[2]43
|
42
|
+
push 2
|
43
|
+
jump re.4008
|
44
|
+
label pntr[2]43
|
45
|
+
v28 != 3 re.4008
|
46
|
+
push 3
|
47
|
+
label re.4008
|
48
|
+
v29 = pop
|
49
|
+
exit
|
50
|
+
EOS
|
51
|
+
}
|
52
|
+
|
53
|
+
let(:diamond) {
|
54
|
+
assemble <<~EOS
|
55
|
+
push 10
|
56
|
+
push 5
|
57
|
+
10 != 2 true
|
58
|
+
push 0
|
59
|
+
jump end
|
60
|
+
label true
|
61
|
+
push 1
|
62
|
+
label end
|
63
|
+
v1 = pop
|
64
|
+
v2 = pop
|
65
|
+
v3 = pop
|
66
|
+
v4 = v3 / v2
|
67
|
+
push v4
|
68
|
+
exit
|
69
|
+
EOS
|
70
|
+
}
|
71
|
+
|
72
|
+
let(:graph1) {
|
73
|
+
assemble <<~EOS
|
74
|
+
push 10
|
75
|
+
push 5
|
76
|
+
10 != 2 true
|
77
|
+
label foo
|
78
|
+
push 0
|
79
|
+
jump end
|
80
|
+
label true
|
81
|
+
push 1
|
82
|
+
label end
|
83
|
+
v1 = pop
|
84
|
+
v2 = pop
|
85
|
+
v3 = pop
|
86
|
+
v4 = v3 / v2
|
87
|
+
push v4
|
88
|
+
1 != 2 foo
|
89
|
+
push 1
|
90
|
+
exit
|
91
|
+
EOS
|
92
|
+
}
|
93
|
+
|
94
|
+
context "outgoing_edges" do
|
95
|
+
it "can see all edges in a simple graph" do
|
96
|
+
cfg = RPiet::IR::CFG.new(gtr)
|
97
|
+
|
98
|
+
entry_bb = cfg.entry_bb
|
99
|
+
fall_through = cfg.outgoing_target(entry_bb, :fall_through)
|
100
|
+
expect(fall_through.label).to start_with("fall_thru_")
|
101
|
+
|
102
|
+
jump = cfg.outgoing_target(entry_bb, :jump)
|
103
|
+
expect(jump.label).to eq(:true)
|
104
|
+
|
105
|
+
end_bb = cfg.outgoing_target(jump, :fall_through)
|
106
|
+
expect(end_bb.label).to eq(:end)
|
107
|
+
|
108
|
+
end_bb2 = cfg.outgoing_target(fall_through, :jump)
|
109
|
+
expect(end_bb.label).to eq(:end)
|
110
|
+
|
111
|
+
expect(end_bb).to eq(end_bb2)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "can remove an edge" do
|
115
|
+
cfg = RPiet::IR::CFG.new(gtr)
|
116
|
+
|
117
|
+
entry_bb = cfg.entry_bb
|
118
|
+
jump = cfg.outgoing_target(entry_bb, :jump)
|
119
|
+
expect(cfg.outgoing_targets(entry_bb).size).to eq(2)
|
120
|
+
cfg.remove_edge(entry_bb, jump)
|
121
|
+
expect(cfg.outgoing_targets(entry_bb).size).to eq(1)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "can see see outgoing edges with a block" do
|
125
|
+
cfg = RPiet::IR::CFG.new(gtr)
|
126
|
+
|
127
|
+
entry_bb = cfg.entry_bb
|
128
|
+
results = []
|
129
|
+
cfg.outgoing_edges(entry_bb) do |edge|
|
130
|
+
results << edge.target.label.to_s
|
131
|
+
end
|
132
|
+
results.sort!
|
133
|
+
expect(results[0]).to start_with("fall_thru_")
|
134
|
+
expect(results[1]).to eq("true")
|
135
|
+
end
|
136
|
+
|
137
|
+
it "can generate postorder traversal" do
|
138
|
+
cfg = RPiet::IR::CFG.new(diamond)
|
139
|
+
puts cfg.postorder_bbs.map { |bb| bb.label }.join(", ")
|
140
|
+
puts cfg.preorder_bbs.map { |bb| bb.label }.join(", ")
|
141
|
+
end
|
142
|
+
|
143
|
+
it "can generate postorder traversal" do
|
144
|
+
cfg = RPiet::IR::CFG.new(graph1)
|
145
|
+
cfg.write_to_dot_file
|
146
|
+
puts cfg.postorder_bbs.map { |bb| bb.label }.join(", ")
|
147
|
+
puts cfg.preorder_bbs.map { |bb| bb.label }.join(", ")
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe "RPiet::IR::IRInterpreter" do
|
4
|
+
it "can exec push" do
|
5
|
+
interp = ir_interp(assemble("push 10\n"))
|
6
|
+
expect(interp.stack).to eq([])
|
7
|
+
interp.next_step
|
8
|
+
expect(interp.stack).to eq([10])
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can exec pop" do
|
12
|
+
interp = ir_interp(assemble("push 10\nv1 = pop\n"))
|
13
|
+
interp.next_step
|
14
|
+
expect(interp.stack).to eq([10])
|
15
|
+
interp.next_step
|
16
|
+
expect(interp.stack).to eq([])
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can exec add" do
|
20
|
+
interp = ir_interp(assemble("v1 = 10 + 2\npush v1\n"))
|
21
|
+
2.times { interp.next_step }
|
22
|
+
expect(interp.stack).to eq([12])
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can exec add with variable" do
|
26
|
+
interp = ir_interp(assemble("v1 = copy 10\nv2 = v1 + 2\npush v2\n"))
|
27
|
+
3.times { interp.next_step }
|
28
|
+
expect(interp.stack).to eq([12])
|
29
|
+
end
|
30
|
+
|
31
|
+
it "can exec sub" do
|
32
|
+
interp = ir_interp(assemble("v1 = 10 - 2\npush v1\n"))
|
33
|
+
2.times { interp.next_step }
|
34
|
+
expect(interp.stack).to eq([8])
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can exec mult" do
|
38
|
+
interp = ir_interp(assemble("v1 = 10 * 2\npush v1\n"))
|
39
|
+
2.times { interp.next_step }
|
40
|
+
expect(interp.stack).to eq([20])
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can exec div" do
|
44
|
+
interp = ir_interp(assemble("v1 = 10 / 2\npush v1\n"))
|
45
|
+
2.times { interp.next_step }
|
46
|
+
expect(interp.stack).to eq([5])
|
47
|
+
end
|
48
|
+
|
49
|
+
it "can exec mod" do
|
50
|
+
interp = ir_interp(assemble("v1 = 10 % 2\npush v1\n"))
|
51
|
+
2.times { interp.next_step }
|
52
|
+
expect(interp.stack).to eq([0])
|
53
|
+
end
|
54
|
+
|
55
|
+
it "can exec pow" do
|
56
|
+
interp = ir_interp(assemble("v1 = 10 ** 2\npush v1\n"))
|
57
|
+
2.times { interp.next_step }
|
58
|
+
expect(interp.stack).to eq([100])
|
59
|
+
end
|
60
|
+
|
61
|
+
it "can exec jump" do
|
62
|
+
interp = ir_interp(assemble("jump label\npush 1\nlabel label\npush 0\n"))
|
63
|
+
2.times { interp.next_step }
|
64
|
+
expect(interp.stack).to eq([0])
|
65
|
+
end
|
66
|
+
|
67
|
+
it "can exec bne" do
|
68
|
+
interp = ir_interp(assemble("1 != 2 label\npush 1\nlabel label\npush 2\n"))
|
69
|
+
2.times { interp.next_step }
|
70
|
+
expect(interp.stack).to eq([2])
|
71
|
+
end
|
72
|
+
|
73
|
+
it "can exec beq" do
|
74
|
+
interp = ir_interp(assemble("1 == 1 label\npush 1\nlabel label\npush 2\n"))
|
75
|
+
2.times { interp.next_step }
|
76
|
+
expect(interp.stack).to eq([2])
|
77
|
+
end
|
78
|
+
|
79
|
+
it "can exec gt" do
|
80
|
+
interp = ir_interp(assemble("v1 = 2 > 1\npush v1\n"))
|
81
|
+
2.times { interp.next_step }
|
82
|
+
expect(interp.stack).to eq([1])
|
83
|
+
end
|
84
|
+
|
85
|
+
it "can exec roll" do
|
86
|
+
interp = ir_interp(assemble("push 1\npush 2\npush 3\npush 4\npush 3\npush 1\nv1 = pop\nv2 = pop\nroll v2 v1\n"))
|
87
|
+
9.times { interp.next_step }
|
88
|
+
expect(interp.stack).to eq([1, 4, 2, 3]) # <- [1,2,3,4] roll 3, 1
|
89
|
+
|
90
|
+
interp = ir_interp(assemble("push 1\npush 2\npush 3\npush 4\npush 3\npush 2\nv1 = pop\nv2 = pop\nroll v2 v1\n"))
|
91
|
+
9.times { interp.next_step }
|
92
|
+
expect(interp.stack).to eq([1, 3, 4, 2]) # <- [1,2,3,4] roll 3, 2
|
93
|
+
|
94
|
+
interp = ir_interp(assemble("push 1\npush 2\npush 3\npush 4\npush 4\npush -1\nv1 = pop\nv2 = pop\nroll v2 v1\n"))
|
95
|
+
9.times { interp.next_step; p interp.stack }
|
96
|
+
expect(interp.stack).to eq([2, 3, 4, 1]) # <- [1,2,3,4] roll 4, -1
|
97
|
+
|
98
|
+
interp = ir_interp(assemble("push 1\npush 2\npush 3\npush 4\npush 4\npush -2\nv1 = pop\nv2 = pop\nroll v2 v1\n"))
|
99
|
+
9.times { interp.next_step; p interp.stack }
|
100
|
+
expect(interp.stack).to eq([3, 4, 1, 2]) # <- [1,2,3,4] roll 4, -2
|
101
|
+
end
|
102
|
+
end
|