From a0bee26d769adf61ed0a292983992a70e4e261c3 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 13 Jan 2025 16:36:11 -0800 Subject: Prevent self-inlining Better error message for self-calling functions --- .../com/seaofnodes/simple/node/CallEndNode.java | 31 +++++++++++++--------- .../com/seaofnodes/simple/node/ReturnNode.java | 2 ++ 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'chapter18/src/main/java/com') 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 "); -- cgit v1.2.3