From bac24802e16c93b9f6295f2dea04a6223c211738 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Tue, 31 Dec 2024 16:25:28 -0800 Subject: Compile pipeline deals with functions Pretty-print functions. GCM deals with functions. Tighten linker API. CallEnd asserts harder proper graph. Eval2 makes (non recursive) function calls Peeps infer sharper function return sigs. --- .../java/com/seaofnodes/simple/Chapter18Test.java | 20 +++++++-- .../src/test/java/com/seaofnodes/simple/Eval2.java | 52 +++++++++++++++++----- .../com/seaofnodes/simple/evaluator/Evaluator.java | 2 +- .../com/seaofnodes/simple/evaluator/Scheduler.java | 4 +- 4 files changed, 60 insertions(+), 18 deletions(-) (limited to 'chapter18/src/test/java/com') diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java index 7063ef26..6fc2cc98 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java @@ -51,17 +51,29 @@ return x2; assertEquals("null", Eval2.eval(code, 0 ) ); } - @Ignore @Test + @Test public void testFcn0() { CodeGen code = new CodeGen(""" {int -> int}? sq = { int x -> - x*x + x*x; }; return sq; """); code.parse().opto(); - assertEquals("return fcn;", code._stop.toString()); - assertEquals("1", Eval2.eval(code, 0)); + assertEquals("Stop[ return { sq}; return (Parm_x(sq,int)*x); ]", code._stop.toString()); + assertEquals("{ sq}", Eval2.eval(code, 3)); } + @Test + public void testFcn1() { + CodeGen code = new CodeGen(""" +var sq = { int x -> + x*x; +}; +return sq(2)+sq(3); +"""); + code.parse().opto(); + assertEquals("Stop[ return (sq( 3)+sq( 2)); return (Parm_x(sq,int,3,2)*x); ]", code._stop.toString()); + assertEquals("13", Eval2.eval(code, 0)); + } } diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java index 0e5e86a4..ea69bc52 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/Eval2.java @@ -4,6 +4,7 @@ import com.seaofnodes.simple.type.*; import com.seaofnodes.simple.node.*; import java.util.Arrays; +import java.util.Stack; import java.util.IdentityHashMap; import java.util.Objects; @@ -30,6 +31,9 @@ public abstract class Eval2 { // Phi cache; size is limited to number of Phis at a merge point Object[] phiCache = new Object[256]; + Stack stack = new Stack<>(); + + // Evaluate until we return or timeout. Each outer loop step computes // all data nodes under some new Control. SB sb = null; // new SB(); // TRACE @@ -68,27 +72,46 @@ public abstract class Eval2 { prior = C; C = C.uctrl(); // Next unique control target switch( prior ) { - case FunNode fun : if( loopCnt++ > timeout ) return null; break; // Timeout - case LoopNode loop: if( loopCnt++ > timeout ) return null; break; // Timeout - case IfNode iff: C = iff.cproj( val(iff.pred())==null || (val(iff.pred()) instanceof Long x && x==0L) ? 1 : 0); break; - case RegionNode r: break; + case CallNode call : C = call(code,call,stack); break; + case CallEndNode cend: break; case CProjNode cproj: break; - // TODO: Need a Call-stack here - case ReturnNode ret: return prettyPrint(ret.expr()._type,val(ret.expr())); + case FunNode fun : if( loopCnt++ > timeout ) return null; break; // Timeout + case IfNode iff : Object p = val(iff.pred()); C = iff.cproj( p==null || (p instanceof Long x && x==0L) ? 1 : 0); break; + case LoopNode loop : if( loopCnt++ > timeout ) return null; break; // Timeout + case RegionNode r : break; + case ReturnNode ret : + Node expr = ret.expr(); + if( stack.isEmpty() ) + return prettyPrint(expr._type,val(expr)); + DATA[ret._nid] = val(expr); + C = stack.pop(); + DATA[C._nid] = DATA[ret._nid]; + break; default: throw Utils.TODO(); } } + } + + // Make a call. + private static CFGNode call( CodeGen code, CallNode call, Stack stack ) { + stack.push(call.cend()); + // TODO: Stack and unstack all DATA boxes readable by recursive functions + return code.link(tfp(call.fptr())); + } + + private static String exit(ReturnNode ret) { + return prettyPrint(ret.expr()._type,val(ret.expr())); } private static boolean isArg( PhiNode phi ) { // Arg#2 into main. // TODO: Needs some love for recursive main - return phi instanceof ParmNode parm && parm.fun()._sig==TypeFunPtr.MAIN && parm._idx==2; + return phi instanceof ParmNode parm && parm.fun().sig().isa(TypeFunPtr.MAIN) && parm._idx==2; } // Take a worklist step: one data op from the current Control is updated. - private static void step(Node n, SB sb, IdentityHashMap visit) { + private static void step(Node n, SB sb, IdentityHashMap visit) { // Only data nodes if( n instanceof CFGNode ) return; // Compute new value @@ -150,13 +173,19 @@ public abstract class Eval2 { static long x( Node n ) { return DATA[n._nid]==null ? 0 : (Long) DATA[n._nid]; } // Fetch and unbox as primitive double static double d( Node n ) { return DATA[n._nid]==null ? 0 : (Double)DATA[n._nid]; } + // Fetch and unbox a TypeFunPtr + static TypeFunPtr tfp(Node n) { return (TypeFunPtr)DATA[n._nid]; } // Java box ints and floats. Other things can just be null or some informative string private static Object con( Type t ) { if( t instanceof TypeInteger i ) return i.isConstant() ? (Long)i.value() : "INT"; if( t instanceof TypeFloat f ) return f.isConstant() ? (Double)f.value() : "FLT"; - // + if( t instanceof TypeMemPtr tmp ) + throw Utils.TODO(); + if( t instanceof TypeFunPtr tfp ) + { assert tfp.isConstant(); return tfp; } + // Things like Type.NIL, or TypeMem return null; } @@ -223,8 +252,8 @@ public abstract class Eval2 { // Use type to print x as a string - static String prettyPrint( Type t, Object x ) { return _print(t,x,new SB(), new IdentityHashMap()).toString(); } - static SB _print( Type t, Object x, SB sb, IdentityHashMap visit ) { + static String prettyPrint( Type t, Object x ) { return _print(t,x,new SB(), new IdentityHashMap<>()).toString(); } + static SB _print( Type t, Object x, SB sb, IdentityHashMap visit ) { if( x instanceof String s ) return sb.p(s); if( x == null ) return sb.p("null"); return switch( t ) { @@ -261,6 +290,7 @@ public abstract class Eval2 { } yield sb; } + case TypeFunPtr tfp -> sb.p(x.toString()); case TypeMem mem -> sb.p("$mem"); case TypeTuple tt -> { if( tt._types.length>1 && tt._types[1] instanceof TypeMemPtr ) diff --git a/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java index ff9eb1b1..8e25b133 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java @@ -344,7 +344,7 @@ public class Evaluator { assert block != null; for (; i < block.nodes().length; i++) { if (!(block.nodes()[i] instanceof PhiNode phi)) break; - var val = region instanceof FunNode fun && fun._name.equals("main") && ((ParmNode)phi)._idx==2 && exit==1 + var val = region instanceof FunNode fun && "main".equals(fun.sig()._name) && ((ParmNode)phi)._idx==2 && exit==1 ? parameter : val(phi.in(exit)); phiCache.add(val); diff --git a/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java b/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java index 3cf63e0f..52d8f3e3 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java @@ -503,12 +503,12 @@ public class Scheduler { /** * Find the CFG output of a node * @param node The node - * @return THe CFG output of the node. + * @return The CFG output of the node. */ private static CFGNode findSingleCFGOut(Node node) { if (node instanceof StartNode) { for(var n:node._outputs) - if (n instanceof FunNode fun && fun._name.equals("main")) + if (n instanceof FunNode fun && "main".equals(fun.sig()._name) ) return fun; return null; } -- cgit v1.2.3