summaryrefslogtreecommitdiff
path: root/chapter18
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-01-13 16:36:11 -0800
committerCliff Click <cliffc@acm.org>2025-01-15 15:07:30 -0800
commita0bee26d769adf61ed0a292983992a70e4e261c3 (patch)
tree2b1a90d673ebb14492292f167011eb7a71facd47 /chapter18
parentc3559bb04362b948c390b35cac622ce61f494238 (diff)
downloadSimple-a0bee26d769adf61ed0a292983992a70e4e261c3.tar.gz
Simple-a0bee26d769adf61ed0a292983992a70e4e261c3.zip
Prevent self-inlining
Better error message for self-calling functions
Diffstat (limited to 'chapter18')
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java31
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java2
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java12
3 files changed, 33 insertions, 12 deletions
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index a2866d65..07a2b5a3 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -50,24 +50,31 @@ public class CallEndNode extends CFGNode implements MultiNode {
CallNode call = call();
Node fptr = call.fptr();
if( fptr.nOuts() == 1 && // Only user is this call
- fptr instanceof ConstantNode &&
+ fptr instanceof ConstantNode && // We have an immediate call
// Function is being called, and its not-null
- fptr._type instanceof TypeFunPtr tfp && tfp.notNull()) {
+ fptr._type instanceof TypeFunPtr tfp && tfp.notNull() &&
+ // Arguments are correct
+ call.err()==null ) {
ReturnNode ret = (ReturnNode)in(1);
FunNode fun = ret.fun();
// Expecting Start, and the Call
if( fun.nIns()==3 ) {
assert fun.in(1) instanceof StartNode && fun.in(2)==call;
-
- // Trivial inline: rewrite
- _folding = true;
- // Rewrite Fun so the normal RegionNode ideal collapses
- fun._folding = true;
- fun.setDef(1,Parser.XCTRL); // No default/unknown StartNode caller
- fun.setDef(2,call.ctrl()); // Bypass the Call;
- fun.ret().setDef(3,null); // Return is folding also
- IterPeeps.addAll(fun._outputs);
- return this;
+ // Disallow self-recursive inlining (loop unrolling by another name)
+ CFGNode idom = call;
+ while( !(idom instanceof FunNode fun2) )
+ idom = idom.idom();
+ if( idom != fun ) {
+ // Trivial inline: rewrite
+ _folding = true;
+ // Rewrite Fun so the normal RegionNode ideal collapses
+ fun._folding = true;
+ fun.setDef(1,Parser.XCTRL); // No default/unknown StartNode caller
+ fun.setDef(2,call.ctrl()); // Bypass the Call;
+ fun.ret().setDef(3,null); // Return is folding also
+ IterPeeps.addAll(fun._outputs);
+ return this;
+ }
} else {
fun.addDep(this);
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 2fe722c6..e543f9ea 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -117,6 +117,8 @@ public class ReturnNode extends CFGNode {
}
static Parser.ParseException mixerr( boolean ti, boolean tf, boolean tp, boolean tn, Parser.Lexer loc ) {
+ if( !ti && !tf && !tp && !tn )
+ return Parser.error("No defined return type", loc);
SB sb = new SB().p("No common type amongst ");
if( ti ) sb.p("int and ");
if( tf ) sb.p("f64 and ");
diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java
index 0e92c8c0..1d7abde5 100644
--- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java
+++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java
@@ -259,6 +259,18 @@ for(;;) {
catch( Exception e ) { assertEquals("Accessing unknown field 'x' from '*S'",e.getMessage()); }
}
+ @Test
+ public void testErr5() {
+ CodeGen code = new CodeGen(
+"""
+val g = { ->
+ g();
+};
+return 0;
+""");
+ try { code.parse().opto().typeCheck(); fail(); }
+ catch( Exception e ) { assertEquals("No defined return type",e.getMessage()); }
+ }
// Mutual recursion. Fails without SCCP to lift the recursive return types.