Skip to content

Commit 995d972

Browse files
authored
Support runtime do loop increments in C backend (#1423)
1 parent d3a947f commit 995d972

File tree

9 files changed

+136
-70
lines changed

9 files changed

+136
-70
lines changed

integration_tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ RUN(NAME expr_13 LABELS llvm c
251251
RUN(NAME expr_14 LABELS cpython llvm c)
252252
RUN(NAME loop_01 LABELS cpython llvm c)
253253
RUN(NAME loop_02 LABELS cpython llvm c wasm wasm_x86 wasm_x64)
254+
RUN(NAME loop_03 LABELS cpython llvm c wasm)
254255
RUN(NAME if_01 LABELS cpython llvm c wasm wasm_x86 wasm_x64)
255256
RUN(NAME if_02 LABELS cpython llvm c wasm wasm_x86 wasm_x64)
256257
RUN(NAME print_02 LABELS cpython llvm)

integration_tests/loop_03.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from ltypes import i32
2+
3+
def test_loop_01():
4+
i: i32 = 0
5+
j: i32 = 0
6+
rt_inc: i32
7+
rt_inc = 1
8+
9+
while False:
10+
assert False
11+
12+
while i < 0:
13+
assert False
14+
15+
while i < 10:
16+
i += 1
17+
assert i == 10
18+
19+
while i < 20:
20+
while i < 15:
21+
i += 1
22+
i += 1
23+
assert i == 20
24+
25+
for i in range(0, 5, rt_inc):
26+
assert i == j
27+
j += 1
28+
29+
def test_loop_02():
30+
i: i32 = 0
31+
j: i32 = 0
32+
rt_inc_neg_1: i32 = -1
33+
rt_inc_1: i32 = 1
34+
35+
j = 0
36+
for i in range(10, 0, rt_inc_neg_1):
37+
j = j + i
38+
assert j == 55
39+
40+
for i in range(0, 5, rt_inc_1):
41+
if i == 3:
42+
break
43+
assert i == 3
44+
45+
j = 0
46+
for i in range(0, 5, rt_inc_1):
47+
if i == 3:
48+
continue
49+
j += 1
50+
assert j == 4
51+
52+
def verify():
53+
test_loop_01()
54+
test_loop_02()
55+
56+
verify()

src/libasr/codegen/asr_to_c_cpp.h

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class BaseCCPPVisitor : public ASR::BaseVisitor<Struct>
8383
std::unique_ptr<CCPPDSUtils> c_ds_api;
8484
std::string const_name;
8585
size_t const_vars_count;
86+
size_t loop_end_count;
8687

8788
SymbolTable* current_scope;
8889
bool is_string_concat_present;
@@ -95,7 +96,8 @@ class BaseCCPPVisitor : public ASR::BaseVisitor<Struct>
9596
is_c{is_c}, global_scope{nullptr}, lower_bound{default_lower_bound},
9697
template_number{0}, c_ds_api{std::make_unique<CCPPDSUtils>(is_c, platform)},
9798
const_name{"constname"},
98-
const_vars_count{0}, is_string_concat_present{false} {
99+
const_vars_count{0}, loop_end_count{0},
100+
is_string_concat_present{false} {
99101
}
100102

101103
void visit_TranslationUnit(const ASR::TranslationUnit_t &x) {
@@ -1738,6 +1740,7 @@ R"(#include <stdio.h>
17381740
void visit_DoLoop(const ASR::DoLoop_t &x) {
17391741
std::string current_body_copy = current_body;
17401742
current_body = "";
1743+
std::string loop_end_decl = "";
17411744
std::string indent(indentation_level*indentation_spaces, ' ');
17421745
std::string out = indent + "for (";
17431746
ASR::Variable_t *loop_var = ASRUtils::EXPR2VAR(x.m_head.m_v);
@@ -1748,34 +1751,55 @@ R"(#include <stdio.h>
17481751
LCOMPILERS_ASSERT(a);
17491752
LCOMPILERS_ASSERT(b);
17501753
int increment;
1754+
bool is_c_constant = false;
17511755
if (!c) {
17521756
increment = 1;
1757+
is_c_constant = true;
17531758
} else {
1754-
c = ASRUtils::expr_value(c);
1755-
bool is_c_constant = ASRUtils::extract_value(c, increment);
1756-
if( !is_c_constant ) {
1757-
throw CodeGenError("Do loop increment type not supported");
1758-
}
1759+
ASR::expr_t* c_value = ASRUtils::expr_value(c);
1760+
is_c_constant = ASRUtils::extract_value(c_value, increment);
17591761
}
1760-
std::string cmp_op;
1761-
if (increment > 0) {
1762-
cmp_op = "<=";
1763-
} else {
1764-
cmp_op = ">=";
1765-
}
1766-
1767-
out += lvname + "=";
1768-
self().visit_expr(*a);
1769-
out += src + "; " + lvname + cmp_op;
1770-
self().visit_expr(*b);
1771-
out += src + "; " + lvname;
1772-
if (increment == 1) {
1773-
out += "++";
1774-
} else if (increment == -1) {
1775-
out += "--";
1762+
1763+
if( is_c_constant ) {
1764+
std::string cmp_op;
1765+
if (increment > 0) {
1766+
cmp_op = "<=";
1767+
} else {
1768+
cmp_op = ">=";
1769+
}
1770+
1771+
out += lvname + "=";
1772+
self().visit_expr(*a);
1773+
out += src + "; " + lvname + cmp_op;
1774+
self().visit_expr(*b);
1775+
out += src + "; " + lvname;
1776+
if (increment == 1) {
1777+
out += "++";
1778+
} else if (increment == -1) {
1779+
out += "--";
1780+
} else {
1781+
out += "+=" + std::to_string(increment);
1782+
}
17761783
} else {
1777-
out += "+=" + std::to_string(increment);
1784+
this->visit_expr(*c);
1785+
std::string increment_ = std::move(src);
1786+
self().visit_expr(*b);
1787+
std::string do_loop_end = std::move(src);
1788+
std::string do_loop_end_name = current_scope->get_unique_name(
1789+
"loop_end___" + std::to_string(loop_end_count));
1790+
loop_end_count += 1;
1791+
loop_end_decl = indent + CUtils::get_c_type_from_ttype_t(ASRUtils::expr_type(b), is_c) +
1792+
" " + do_loop_end_name + " = " + do_loop_end + ";\n";
1793+
out += lvname + " = ";
1794+
self().visit_expr(*a);
1795+
out += src + "; ";
1796+
out += "((" + increment_ + " >= 0) && (" +
1797+
lvname + " <= " + do_loop_end_name + ")) || (("
1798+
+ increment_ + " < 0) && (" + lvname + " >= "
1799+
+ do_loop_end_name + ")); " + lvname;
1800+
out += " += " + increment_;
17781801
}
1802+
17791803
out += ") {\n";
17801804
indentation_level += 1;
17811805
for (size_t i=0; i<x.n_body; i++) {
@@ -1785,7 +1809,7 @@ R"(#include <stdio.h>
17851809
out += current_body;
17861810
out += indent + "}\n";
17871811
indentation_level -= 1;
1788-
src = out;
1812+
src = loop_end_decl + out;
17891813
current_body = current_body_copy;
17901814
}
17911815

src/libasr/codegen/asr_to_wasm.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,6 +1798,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor<ASRToWASMVisitor> {
17981798
if (arg_kind > 0 && dest_kind > 0) {
17991799
if (arg_kind == 4 && dest_kind == 8) {
18001800
wasm::emit_i64_extend_i32_s(m_code_section, m_al);
1801+
} else if (arg_kind == 4 && dest_kind == 4) {
18011802
} else {
18021803
std::string msg = "Conversion from kinds " +
18031804
std::to_string(arg_kind) + " to " +

src/lpython/semantics/python_ast_to_asr.cpp

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4261,6 +4261,10 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
42614261
a_kind, nullptr, 0));
42624262
ASR::expr_t *constant_one = ASR::down_cast<ASR::expr_t>(ASR::make_IntegerConstant_t(
42634263
al, loc, 1, a_type));
4264+
ASR::expr_t *constant_neg_one = ASR::down_cast<ASR::expr_t>(ASR::make_IntegerConstant_t(
4265+
al, loc, -1, a_type));
4266+
ASR::expr_t *constant_zero = ASR::down_cast<ASR::expr_t>(ASR::make_IntegerConstant_t(
4267+
al, loc, 0, a_type));
42644268
if (!loop_start) {
42654269
loop_start = ASR::down_cast<ASR::expr_t>(ASR::make_IntegerConstant_t(al, loc, 0, a_type));
42664270
}
@@ -4305,20 +4309,34 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
43054309
ASR::expr_t *inc_value = ASRUtils::expr_value(inc);
43064310
int64_t inc_int = 1;
43074311
bool is_value_present = ASRUtils::extract_value(inc_value, inc_int);
4308-
if (!is_value_present) {
4309-
throw SemanticError("For loop increment should Compile time constant.", loc);
4310-
}
4311-
4312-
// Loop end depends upon the sign of m_increment.
4313-
// if inc > 0 then: loop_end -=1 else loop_end += 1
4314-
ASR::binopType offset_op;
4315-
if (inc_int < 0 ) {
4316-
offset_op = ASR::binopType::Add;
4312+
if (is_value_present) {
4313+
// Loop end depends upon the sign of m_increment.
4314+
// if inc > 0 then: loop_end -=1 else loop_end += 1
4315+
ASR::binopType offset_op;
4316+
if (inc_int < 0 ) {
4317+
offset_op = ASR::binopType::Add;
4318+
} else {
4319+
offset_op = ASR::binopType::Sub;
4320+
}
4321+
make_BinOp_helper(loop_end, constant_one,
4322+
offset_op, loc, false);
43174323
} else {
4318-
offset_op = ASR::binopType::Sub;
4324+
ASR::ttype_t* logical_type = ASRUtils::TYPE(ASR::make_Logical_t(al, inc->base.loc, 4, nullptr, 0));
4325+
ASR::expr_t* inc_pos = ASRUtils::EXPR(ASR::make_IntegerCompare_t(al, inc->base.loc, inc,
4326+
ASR::cmpopType::GtE, constant_zero, logical_type, nullptr));
4327+
ASR::expr_t* inc_neg = ASRUtils::EXPR(ASR::make_IntegerCompare_t(al, inc->base.loc, inc,
4328+
ASR::cmpopType::Lt, constant_zero, logical_type, nullptr));
4329+
cast_helper(a_type, inc_pos, inc->base.loc, true);
4330+
cast_helper(a_type, inc_neg, inc->base.loc, true);
4331+
make_BinOp_helper(inc_pos, constant_neg_one, ASR::binopType::Mul, inc->base.loc, false);
4332+
ASR::expr_t* case_1 = ASRUtils::EXPR(tmp);
4333+
make_BinOp_helper(inc_neg, constant_one, ASR::binopType::Mul, inc->base.loc, false);
4334+
ASR::expr_t* case_2 = ASRUtils::EXPR(tmp);
4335+
make_BinOp_helper(case_1, case_2, ASR::binopType::Add, inc->base.loc, false);
4336+
ASR::expr_t* cases_combined = ASRUtils::EXPR(tmp);
4337+
make_BinOp_helper(loop_end, cases_combined, ASR::binopType::Add, loop_end->base.loc, false);
43194338
}
4320-
make_BinOp_helper(loop_end, constant_one,
4321-
offset_op, loc, false);
4339+
43224340
head.m_end = ASRUtils::EXPR(tmp);
43234341

43244342

tests/errors/test_for1.py

Lines changed: 0 additions & 8 deletions
This file was deleted.

tests/reference/asr-test_for1-260404e.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

tests/reference/asr-test_for1-260404e.stderr

Lines changed: 0 additions & 9 deletions
This file was deleted.

tests/tests.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -885,10 +885,6 @@ asr = true
885885
filename = "errors/test_tuple1.py"
886886
asr = true
887887

888-
[[test]]
889-
filename = "errors/test_for1.py"
890-
asr = true
891-
892888
[[test]]
893889
filename = "errors/test_for2.py"
894890
asr = true

0 commit comments

Comments
 (0)