Skip to content

Commit a985e21

Browse files
authored
Ban early termination inside SCF. (#495)
Just to be safe, I am adding a ban on all terminators for SCF. I also marked tests that failed due to this change as `xfail`.
1 parent c10bf3c commit a985e21

File tree

6 files changed

+47
-16
lines changed

6 files changed

+47
-16
lines changed

src/kirin/dialects/scf/lowering.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,22 @@ def lower_If(self, state: lowering.State, node: ast.If) -> lowering.Result:
7575
and body_frame.curr_block.last_stmt.has_trait(ir.IsTerminator)
7676
):
7777
body_frame.push(Yield(*body_yields))
78+
else:
79+
# TODO: Remove this error when we support early termination in if bodies
80+
raise lowering.BuildError(
81+
"Early returns/terminators in if bodies are not supported with structured control flow"
82+
)
7883

7984
if not (
8085
else_frame.curr_block.last_stmt
8186
and else_frame.curr_block.last_stmt.has_trait(ir.IsTerminator)
8287
):
8388
else_frame.push(Yield(*else_yields))
89+
else:
90+
# TODO: Remove this error when we support early termination in if bodies
91+
raise lowering.BuildError(
92+
"Early returns/terminators in if bodies are not supported with structured control flow"
93+
)
8494

8595
stmt = IfElse(
8696
cond,
@@ -134,6 +144,11 @@ def new_block_arg_if_inside_loop(frame: lowering.Frame, capture: ir.SSAValue):
134144
elif body_has_no_terminator:
135145
# NOTE: no yields, but also no terminator, add empty yield
136146
body_frame.push(Yield())
147+
else:
148+
# TODO: Remove this error when we support early termination in for loops
149+
raise lowering.BuildError(
150+
"Early returns/terminators in for loops are not supported with structured control flow"
151+
)
137152

138153
initializers: list[ir.SSAValue] = []
139154
for name in yields:

test/analysis/dataflow/typeinfer/test_inter_method.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1+
from pytest import mark
2+
13
from kirin import types
24
from kirin.prelude import basic
35

46

5-
@basic
6-
def foo(x: int):
7-
if x > 1:
8-
return x + 1
9-
else:
10-
return x - 1.0
11-
12-
13-
@basic(typeinfer=True, no_raise=False)
14-
def main(x: int):
15-
return foo(x)
16-
7+
@mark.xfail(reason="if with early return not supported in scf lowering")
8+
def test_inter_method_infer():
9+
@basic
10+
def foo(x: int):
11+
if x > 1:
12+
return x + 1
13+
else:
14+
return x - 1.0
1715

18-
@basic(typeinfer=True, no_raise=False)
19-
def moo(x):
20-
return foo(x)
16+
@basic(typeinfer=True, no_raise=False)
17+
def main(x: int):
18+
return foo(x)
2119

20+
@basic(typeinfer=True, no_raise=False)
21+
def moo(x):
22+
return foo(x)
2223

23-
def test_inter_method_infer():
2424
assert main.return_type == (types.Int | types.Float)
2525
# assert moo.arg_types[0] == types.Int # type gets narrowed based on callee
2626
assert moo.return_type == (types.Int | types.Float)
@@ -30,6 +30,7 @@ def test_inter_method_infer():
3030
assert foo.return_type is types.Any
3131

3232

33+
@mark.xfail(reason="if with early return not supported in scf lowering")
3334
def test_infer_if_return():
3435
from kirin.prelude import structural
3536

test/analysis/dataflow/typeinfer/test_selfref_closure.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
from pytest import mark
2+
13
from kirin import types
24
from kirin.prelude import structural_no_opt
35
from kirin.analysis import TypeInference
46

57

8+
@mark.xfail(reason="if with early return not supported in scf lowering")
69
def test_self_ref_closure():
710

811
@structural_no_opt

test/dialects/scf/test_constprop.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from pytest import mark
2+
13
from kirin.prelude import structural_no_opt
24
from kirin.analysis import const
35
from kirin.dialects import scf, func
@@ -69,6 +71,7 @@ def main():
6971
assert frame.frame_is_not_pure is False
7072

7173

74+
@mark.xfail(reason="if with early return not supported in scf lowering")
7275
def test_inside_return():
7376
@structural_no_opt
7477
def simple_loop(x: float):

test/dialects/scf/test_ifelse.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from pytest import mark
2+
13
from kirin import ir
24
from kirin.passes import Fold
35
from kirin.prelude import python_basic
@@ -23,6 +25,7 @@ def run_pass(method):
2325
return run_pass
2426

2527

28+
@mark.xfail(reason="if with early return not supported in scf lowering")
2629
def test_basic_if_else():
2730
@kernel
2831
def main(x):
@@ -112,6 +115,7 @@ def main_nested_if(n: int):
112115
assert main_nested_if(10) == 0 == main_nested_if2(8)
113116

114117

118+
@mark.xfail(reason="if with early return not supported in scf lowering")
115119
def test_def_only_else():
116120
@kernel
117121
def main(n: int):
@@ -127,6 +131,7 @@ def main(n: int):
127131
assert main(0) == 0.0
128132

129133

134+
@mark.xfail(reason="if with early return not supported in scf lowering")
130135
def test_def_only_else_nested():
131136
@kernel
132137
def main(n: int):

test/dialects/scf/test_typeinfer.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
from pytest import mark
2+
13
from kirin import types
24
from kirin.prelude import structural_no_opt
35
from kirin.analysis import TypeInference
46

57
type_infer = TypeInference(structural_no_opt)
68

79

10+
@mark.xfail(reason="for with early return not supported in scf lowering")
811
def test_inside_return_loop():
912
@structural_no_opt
1013
def simple_loop(x: float):
@@ -16,6 +19,7 @@ def simple_loop(x: float):
1619
assert ret.is_subseteq(types.Int | types.Float)
1720

1821

22+
@mark.xfail(reason="if with early return not supported in scf lowering")
1923
def test_simple_ifelse():
2024
@structural_no_opt
2125
def simple_ifelse(x: int):

0 commit comments

Comments
 (0)