Skip to content

Commit b67b871

Browse files
authored
Merge pull request #1290 from Thirumalai-Shaktivel/loop_stmt
Implement Loop statement
2 parents a7b33cd + b7faf79 commit b67b871

File tree

8 files changed

+158
-27
lines changed

8 files changed

+158
-27
lines changed

integration_tests/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ RUN(NAME expr_13 LABELS llvm c
210210
EXTRAFILES expr_13b.c)
211211
RUN(NAME expr_14 LABELS cpython llvm c)
212212
RUN(NAME loop_01 LABELS cpython llvm c)
213+
RUN(NAME loop_02 LABELS cpython llvm wasm wasm_x86)
214+
RUN(NAME if_01 LABELS cpython llvm wasm wasm_x86)
215+
RUN(NAME if_02 LABELS cpython llvm wasm wasm_x86)
213216
RUN(NAME print_02 LABELS cpython llvm)
214217
RUN(NAME test_types_01 LABELS cpython llvm c)
215218
RUN(NAME test_str_01 LABELS cpython llvm c)

integration_tests/if_01.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,46 @@
11
def Test_if_01():
2+
z: i32 = 0
23
if True:
3-
print(1)
4+
assert True
45

56
if False:
6-
print(0)
7+
assert False
78

89
if 1 < 0:
9-
print(0)
10+
assert False
1011
else:
11-
print(1)
12+
assert True
1213

1314
if 1 > 0:
14-
print(1)
15+
assert True
1516
else:
16-
print(0)
17+
assert False
1718

1819
if 1 < 0:
19-
print(1)
20+
assert False
2021
elif 1 > 0:
21-
print(1)
22+
assert True
2223
else:
23-
print(0)
24+
assert False
2425

2526
def Test_if_02():
2627
if True:
2728
print(1)
2829
if True:
2930
print(2)
3031
if False:
31-
print(3)
32+
assert False
3233
elif True:
3334
print(4)
3435
else:
35-
print(5)
36+
assert False
3637
else:
37-
print(6)
38+
assert False
3839

3940
if True:
4041
print(7)
4142
if False:
42-
print(8)
43+
assert False
4344
if False:
4445
print(9)
4546
else:
@@ -48,7 +49,7 @@ def Test_if_02():
4849
if True:
4950
print(11)
5051
else:
51-
print(12)
52+
assert False
5253
print(13)
5354
print(14)
5455

integration_tests/if_02.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from ltypes import bool, i32
1+
from ltypes import i32
22

33
def test_if_01():
44
x: bool = True
@@ -33,8 +33,7 @@ def test_if_01():
3333
if y >= 2:
3434
z += 1
3535

36-
# TODO: replace this an assert statement
37-
print(z)
36+
assert z == 9
3837

3938
def verify():
4039
test_if_01()

integration_tests/loop_02.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from ltypes import i32
2+
def test_loop_01():
3+
i: i32 = 0
4+
j: i32 = 0
5+
6+
while False:
7+
assert False
8+
9+
while i < 0:
10+
assert False
11+
12+
while i < 10:
13+
i += 1
14+
assert i == 10
15+
16+
while i < 20:
17+
while i < 15:
18+
i += 1
19+
i += 1
20+
assert i == 20
21+
22+
for i in range(5):
23+
assert i == j
24+
j += 1
25+
26+
def test_loop_02():
27+
i: i32 = 0
28+
j: i32 = 0
29+
30+
j = 0
31+
for i in range(10, 0, -1):
32+
j = j + i
33+
assert j == 55
34+
35+
for i in range(5):
36+
if i == 3:
37+
break
38+
assert i == 3
39+
40+
j = 0
41+
for i in range(5):
42+
if i == 3:
43+
continue
44+
j += 1
45+
assert j == 4
46+
47+
def test_loop_03():
48+
i: i32 = 0
49+
j: i32 = 0
50+
k: i32 = 0
51+
while i < 10:
52+
j = 0
53+
while j < 10:
54+
k += 1
55+
if i == 0:
56+
if j == 3:
57+
continue
58+
else:
59+
j += 1
60+
j += 1
61+
i += 1
62+
assert k == 95
63+
64+
i = 0; j = 0; k = 0
65+
while i < 10:
66+
j = 0
67+
while j < 10:
68+
k += i + j
69+
if i == 5:
70+
if j == 4:
71+
break
72+
else:
73+
j += 1
74+
j += 1
75+
i += 1
76+
assert k == 826
77+
78+
79+
def verify():
80+
test_loop_01()
81+
test_loop_02()
82+
test_loop_03()
83+
84+
verify()

src/libasr/codegen/asr_to_wasm.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,6 +2032,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor<ASRToWASMVisitor> {
20322032
m_code_section, m_al,
20332033
nesting_level -
20342034
cur_loop_nesting_level); // emit_branch and label the loop
2035+
wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else
20352036
wasm::emit_expr_end(m_code_section, m_al); // end if
20362037

20372038
nesting_level--;

src/libasr/codegen/wasm_to_x86.cpp

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ class X86Visitor : public WASMDecoder<X86Visitor>,
3232
public:
3333
X86Assembler &m_a;
3434
uint32_t cur_func_idx;
35-
std::vector<std::string> unique_id;
35+
std::vector<std::string> if_unique_id;
36+
std::vector<std::string> loop_unique_id;
3637
int32_t last_vis_i32_const, last_last_vis_i32_const;
3738
std::unordered_map<int32_t, std::string> loc_to_str;
3839

@@ -129,23 +130,59 @@ class X86Visitor : public WASMDecoder<X86Visitor>,
129130

130131
void visit_EmtpyBlockType() {}
131132

133+
void visit_Br(uint32_t label_index) {
134+
// Branch is used to jump to the `loop.head` or `loop.end`.
135+
if (if_unique_id.size() - loop_unique_id.size() == label_index - 1) {
136+
// cycle/continue or loop.end
137+
m_a.asm_jmp_label(".loop.head_" + loop_unique_id.back());
138+
} else {
139+
// exit/break
140+
m_a.asm_jmp_label(".loop.end_" + loop_unique_id.back());
141+
}
142+
}
143+
144+
void visit_Loop() {
145+
loop_unique_id.push_back(std::to_string(offset));
146+
/*
147+
The loop statement starts with `loop.head`. The `loop.body` and
148+
`loop.branch` are enclosed within the `if.block`. If the condition
149+
fails, the loop is exited through `else.block`.
150+
.head
151+
.If
152+
# Statements
153+
.Br
154+
.Else
155+
.endIf
156+
.end
157+
*/
158+
m_a.add_label(".loop.head_" + loop_unique_id.back());
159+
{
160+
decode_instructions();
161+
}
162+
// end
163+
m_a.add_label(".loop.end_" + loop_unique_id.back());
164+
loop_unique_id.pop_back();
165+
}
166+
132167
void visit_If() {
133-
unique_id.push_back(std::to_string(offset));
168+
if_unique_id.push_back(std::to_string(offset));
169+
// `eax` contains the logical value (true = 1, false = 0)
170+
// of the if condition
134171
m_a.asm_pop_r32(X86Reg::eax);
135172
m_a.asm_cmp_r32_imm8(LFortran::X86Reg::eax, 1);
136-
m_a.asm_je_label(".then_" + unique_id.back());
137-
m_a.asm_jmp_label(".else_" + unique_id.back());
138-
m_a.add_label(".then_" + unique_id.back());
173+
m_a.asm_je_label(".then_" + if_unique_id.back());
174+
m_a.asm_jmp_label(".else_" + if_unique_id.back());
175+
m_a.add_label(".then_" + if_unique_id.back());
139176
{
140177
decode_instructions();
141178
}
142-
m_a.add_label(".endif_" + unique_id.back());
143-
unique_id.pop_back();
179+
m_a.add_label(".endif_" + if_unique_id.back());
180+
if_unique_id.pop_back();
144181
}
145182

146183
void visit_Else() {
147-
m_a.asm_jmp_label(".endif_" + unique_id.back());
148-
m_a.add_label(".else_" + unique_id.back());
184+
m_a.asm_jmp_label(".endif_" + if_unique_id.back());
185+
m_a.add_label(".else_" + if_unique_id.back());
149186
}
150187

151188
void visit_LocalGet(uint32_t localidx) {
@@ -225,6 +262,7 @@ class X86Visitor : public WASMDecoder<X86Visitor>,
225262
std::string label = std::to_string(offset);
226263
m_a.asm_pop_r32(X86Reg::ebx);
227264
m_a.asm_pop_r32(X86Reg::eax);
265+
// `eax` and `ebx` contain the left and right operands, respectively
228266
m_a.asm_cmp_r32_r32(X86Reg::eax, X86Reg::ebx);
229267
if (compare_op == "Eq") {
230268
m_a.asm_je_label(".compare_1" + label);
@@ -241,6 +279,8 @@ class X86Visitor : public WASMDecoder<X86Visitor>,
241279
} else {
242280
throw CodeGenError("Comparison operator not implemented");
243281
}
282+
// if the `compare` condition in `true`, jump to compare_1
283+
// and assign `1` else assign `0`
244284
m_a.asm_push_imm8(0);
245285
m_a.asm_jmp_label(".compare.end_" + label);
246286
m_a.add_label(".compare_1" + label);

tests/reference/wat-loop1-e0046d4.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"outfile": null,
77
"outfile_hash": null,
88
"stdout": "wat-loop1-e0046d4.stdout",
9-
"stdout_hash": "72c18793b437f96f1f96c9f8fc8cc253601fb360929216a4de1cb2f1",
9+
"stdout_hash": "f2518c3df21a94fba3afb27274ecfae56de7beaaaa8b54b4c1fd84fa",
1010
"stderr": null,
1111
"stderr_hash": null,
1212
"returncode": 0

tests/reference/wat-loop1-e0046d4.stdout

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
i32.sub
4949
local.set 0
5050
br 1
51+
else
5152
end
5253
end
5354
local.get 2
@@ -83,6 +84,7 @@
8384
i32.mul
8485
local.set 3
8586
br 1
87+
else
8688
end
8789
end
8890
local.get 3
@@ -121,6 +123,7 @@
121123
i32.sub
122124
local.set 0
123125
br 1
126+
else
124127
end
125128
end
126129
local.get 2

0 commit comments

Comments
 (0)