From 89dd0a79da85b2c7102b7c8918a1466e6238fe94 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Fri, 13 Jun 2025 15:42:08 -0700 Subject: Chapter 24a: SCCP Within a Function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Co-authored-by: Hsiang-Ying Fu <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: fuhsnn <66062782+fuhsnn@users.noreply.github.com> Co-authored-by: Symious <14933944+symious@users.noreply.github.com> Co-authored-by: Jun Kawasaki Co-authored-by: Hadházy Tamás Co-authored-by: Claude Opus 5 --- .../java/com/seaofnodes/simple/Chapter18Test.java | 43 ++++++++++------------ 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'src/test/java/com/seaofnodes/simple/Chapter18Test.java') diff --git a/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/src/test/java/com/seaofnodes/simple/Chapter18Test.java index 11bdfb9a..e5dd259b 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter18Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter18Test.java @@ -157,7 +157,7 @@ return a; {int -> int}? x2 = null; // null function ptr return x2; """); - code.parse().iter().finalizeIR(); + code.driver(CodeGen.Phase.FinalizeIR); assertEquals("return null;", code._stop.toString()); assertEquals("null", Eval2.eval(code, 0 ) ); } @@ -170,7 +170,7 @@ return x2; x*x; }; """); - code.parse().iter().finalizeIR(); + code.driver(CodeGen.Phase.FinalizeIR); assertEquals("return (Parm_x(sq,i64)*x);", code._stop.toString()); //assertEquals("{ int -> int #1}", Eval2.eval(code, 3)); } @@ -197,7 +197,7 @@ return sq(arg)+sq(3); int cnt=1; return { -> cnt; }; """); - try { code.parse().iter().finalizeIR(); fail(); } + try { code.driver(CodeGen.Phase.FinalizeIR); fail(); } catch( Exception e ) { assertEquals("Variable 'cnt' is out of function scope and must be a final constant",e.getMessage()); } } @@ -209,7 +209,7 @@ return { -> cnt; }; val cnt=2; return { -> cnt; }(); """); - code.parse().iter().finalizeIR(); + code.driver(CodeGen.Phase.FinalizeIR); assertEquals("return 2;", code._stop.toString()); assertEquals("2", Eval2.eval(code, 0)); } @@ -222,8 +222,8 @@ return { -> cnt; }(); var fcn = arg ? { int x -> x*x; } : { int x -> x+x; }; return fcn(3); """); - code.parse().iter().finalizeIR(); - assertEquals("Stop[ return #2; return (Parm_x($fun21,i64,3)*x); return (Parm_x($fun22,i64,3)<<1); ]", code._stop.toString()); + code.driver(CodeGen.Phase.FinalizeIR); + assertEquals("Stop[ return #2; return (Parm_x($fun21,i64)*x); return (Parm_x($fun22,i64)<<1); ]", code._stop.toString()); assertEquals("6", Eval2.eval(code, 0)); assertEquals("9", Eval2.eval(code, 1)); } @@ -233,7 +233,7 @@ return fcn(3); public void testFcn5() { CodeGen code = new CodeGen("val fact = { int x -> x <= 1 ? 1 : x*fact(x-1); }; return fact(arg);"); code.driver(CodeGen.Phase.TypeCheck); - assertEquals("Stop[ return #2; return Phi(Region,1,(Parm_x(fact,i64,arg,(x-1))*#2)); ]", code._stop.toString()); + assertEquals("Stop[ return #2; return Phi(Region,1,(Parm_x(fact,i64)*#2)); ]", code._stop.toString()); assertEquals( "1", Eval2.eval(code, 0)); assertEquals( "1", Eval2.eval(code, 1)); assertEquals( "2", Eval2.eval(code, 2)); @@ -249,7 +249,7 @@ struct S { int i; }; val newS = { int x -> return new S { i=x; }; }; return newS(1).i; """); - code.driver(CodeGen.Phase.Schedule); + code.driver(CodeGen.Phase.TypeCheck); assertEquals("return 1;", code._stop.toString()); assertEquals("1", Eval2.eval(code, 0)); } @@ -264,8 +264,8 @@ val f = {->1;}; val g = {->2;}; return 2; """); - code.driver(CodeGen.Phase.Schedule); - assertEquals("Stop[ return 1; return 1; return 2; ]", code._stop.toString()); + code.driver(CodeGen.Phase.TypeCheck); + assertEquals("return 1;", code._stop.toString()); assertEquals("1", Eval2.eval(code, 0)); } @@ -342,7 +342,7 @@ for(;;) { } return 1; """); - try { code.parse().iter().finalizeIR(); fail(); } + try { code.driver(CodeGen.Phase.FinalizeIR); fail(); } catch( Exception e ) { assertEquals("No active loop for a break or continue",e.getMessage()); } } @@ -399,15 +399,16 @@ for(;;) { val g = { -> g(); }; -return 0; +return g(); """); try { code.driver(CodeGen.Phase.TypeCheck); fail(); } catch( Exception e ) { assertEquals("No defined return type",e.getMessage()); } } - // Mutual recursion. Fails without SCCP to lift the recursive return types. - @Ignore @Test + // Local SCCP cannot infer this recursive return type. The next chapter + // solves across calls and checks the same program's execution results. + @Test public void testFcnMutRec() { CodeGen code = new CodeGen( """ @@ -415,12 +416,8 @@ val is_even = { int x -> x ? is_odd (x-1) : true ; }; val is_odd = { int x -> x ? is_even(x-1) : false; }; return is_even(arg); """); - code.parse().iter().finalizeIR(); - assertEquals("Stop[ return is_even( arg); return Phi(Region,Phi(Region,is_even( ((Parm_x(is_even,int,arg,Sub)-1)-1)),0),1); ]", code._stop.toString()); - assertEquals("1", Eval2.eval(code, 0)); - assertEquals("0", Eval2.eval(code, 1)); - assertEquals("1", Eval2.eval(code, 2)); - assertEquals("0", Eval2.eval(code, 3)); + try { code.driver(CodeGen.Phase.TypeCheck); fail(); } + catch( Parser.ParseException e ) { assertEquals("No defined return type",e.getMessage()); } } // Forward ref to 'x' means that @@ -489,7 +486,7 @@ return p.coffee_count; """; @Test public void testCallMemory() { - var code = new CodeGen(CALL_MEMORY).parse().iter().finalizeIR(); + var code = new CodeGen(CALL_MEMORY).driver(CodeGen.Phase.FinalizeIR); int[] calls={0}; code._stop.walk(n -> { if(n instanceof CallNode) calls[0]++; return null; }); assertEquals(2,calls[0]); // Keep real calls so this checks scheduling across them. @@ -518,7 +515,7 @@ return p.coffee_count; """; @Test public void testRecursiveMemory() { - var code = new CodeGen(RECURSIVE_MEMORY).parse().iter().finalizeIR(); + var code = new CodeGen(RECURSIVE_MEMORY).driver(CodeGen.Phase.FinalizeIR); for(int n=0; n<7; n++) assertEquals(Long.toString((10L*(n+1)+n*(n+1)/2)*100+10+n),Eval2.eval(code,n)); } @@ -536,7 +533,7 @@ return p.coffee_count; """; @Test public void testInlineAllocationMemory() { - var code = new CodeGen(INLINE_MEMORY).parse().iter().finalizeIR(); + var code = new CodeGen(INLINE_MEMORY).driver(CodeGen.Phase.FinalizeIR); assertNull(code._stop.walk(n -> n instanceof CallNode ? n : null)); assertEquals("400944",Eval2.eval(code,0)); assertEquals("420946",Eval2.eval(code,2)); -- cgit v1.2.3