summaryrefslogtreecommitdiff
path: root/chapter18/src/test/java/com/seaofnodes
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2024-12-31 16:25:28 -0800
committerCliff Click <cliffc@acm.org>2025-01-15 15:07:30 -0800
commitbac24802e16c93b9f6295f2dea04a6223c211738 (patch)
treea074b7af87ce248e09ba675a9d94fbadc67553e6 /chapter18/src/test/java/com/seaofnodes
parent051cf6520f342003582185fceb4c474e1e7d20dc (diff)
downloadSimple-bac24802e16c93b9f6295f2dea04a6223c211738.tar.gz
Simple-bac24802e16c93b9f6295f2dea04a6223c211738.zip
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.
Diffstat (limited to 'chapter18/src/test/java/com/seaofnodes')
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter18Test.java20
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Eval2.java52
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java2
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java4
4 files changed, 60 insertions, 18 deletions
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<CallEndNode> 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<CallEndNode> 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<Object,Object> 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<Object,Object> 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;
}