diff options
| author | Cliff Click <cliffc@acm.org> | 2025-01-13 16:36:11 -0800 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2025-01-15 15:07:30 -0800 |
| commit | a0bee26d769adf61ed0a292983992a70e4e261c3 (patch) | |
| tree | 2b1a90d673ebb14492292f167011eb7a71facd47 /chapter18 | |
| parent | c3559bb04362b948c390b35cac622ce61f494238 (diff) | |
| download | Simple-a0bee26d769adf61ed0a292983992a70e4e261c3.tar.gz Simple-a0bee26d769adf61ed0a292983992a70e4e261c3.zip | |
Prevent self-inlining
Better error message for self-calling functions
Diffstat (limited to 'chapter18')
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. |
