summaryrefslogtreecommitdiff
path: root/chapter29/src/test/java/com/seaofnodes/simple/CallEndTest.java
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-11-01 10:33:55 -0800
committerCliff Click <cliffc@acm.org>2026-11-01 10:33:55 -0800
commitf4bd723d929e53475f7990374dca7b7dfcbbdc42 (patch)
tree7bb080119e7b88ad4ac9b30af019fe6a5e4ba9dd /chapter29/src/test/java/com/seaofnodes/simple/CallEndTest.java
parent0ac0c9e10287972ac3af5a4ee43d26f0d5b318fe (diff)
downloadSimple-main.tar.gz
Simple-main.zip
Add Chapter 29 for tech debt cleanup with the parser splitmain
Keep Chapter 28b intact and carry the grammar-oriented parser package, Var move, IterPeeps move, and parser regression tests into Chapter 29. Defer privacy and exclude its experimental tests and fixture changes. Register the chapter in the indexes, IntelliJ modules and run configurations, Maven reactor, roadmap, and linear-history publisher. Windows and Linux each pass 573 tests, release builds, 199 allocation replays, and 29 native checks.
Diffstat (limited to 'chapter29/src/test/java/com/seaofnodes/simple/CallEndTest.java')
-rw-r--r--chapter29/src/test/java/com/seaofnodes/simple/CallEndTest.java85
1 files changed, 85 insertions, 0 deletions
diff --git a/chapter29/src/test/java/com/seaofnodes/simple/CallEndTest.java b/chapter29/src/test/java/com/seaofnodes/simple/CallEndTest.java
new file mode 100644
index 00000000..a174bdf7
--- /dev/null
+++ b/chapter29/src/test/java/com/seaofnodes/simple/CallEndTest.java
@@ -0,0 +1,85 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.*;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class CallEndTest {
+ @Test public void testReturnWideningMonotonicity() {
+ new CodeGen("return 0;").parse();
+ TypeFunPtr sig = TypeFunPtr.make1((byte)2,true,TypeFunPtr.TEMPTY,TypeInteger.I32,100);
+ FunNode fun = new FunNode(null,sig,"f",null);
+ Node value = ConstantNode.raw(Type.TOP);
+ ReturnNode ret = new ReturnNode(ConstantNode.raw(Type.CONTROL),
+ ConstantNode.raw(TypeMem.START),value,null,fun);
+ Type[] inputs = new Type[]{Type.TOP,TypeInteger.TOP,TypeInteger.I32.dual(),
+ TypeInteger.ZERO,TypeInteger.constant(Long.MAX_VALUE),
+ TypeInteger.make(-1,1,(byte)0),TypeInteger.make(-1,1,(byte)1),
+ TypeInteger.make(-1,1,(byte)2),TypeInteger.make(-1,1,(byte)3),
+ TypeInteger.I32,TypeInteger.BOT,TypeScalar.BOT,Type.BOTTOM};
+ Type[] outputs = new Type[inputs.length];
+ for( int i=0; i<inputs.length; i++ ) {
+ value._type = inputs[i];
+ outputs[i] = ret.compute();
+ }
+ for( int i=0; i<inputs.length; i++ )
+ for( int j=0; j<inputs.length; j++ )
+ if( inputs[i].isa(inputs[j]) )
+ assertTrue(inputs[i]+" -> "+inputs[j],outputs[i].isa(outputs[j]));
+ }
+
+ // Growing the target set must not narrow the result, even when the linked
+ // return has exhausted its integer widening budget.
+ @Test public void testUnknownTargetMonotonicity() {
+ CodeGen code = new CodeGen("return 0;").parse();
+ TypeFunPtr sig = TypeFunPtr.make1((byte)2,true,TypeFunPtr.TEMPTY,TypeInteger.BOT,100);
+ FunNode fun = new FunNode(null,sig,"f",null);
+ code._linker.setX(100,fun);
+ Node ctrl = ConstantNode.raw(Type.CONTROL);
+ Node mem = ConstantNode.raw(TypeMem.START);
+ Node value = ConstantNode.raw(TypeInteger.I32);
+ ReturnNode ret = new ReturnNode(ctrl,mem,value,null,fun);
+ ret._type = ret.compute();
+ Node fptr = ConstantNode.raw(sig.makeFrom(TypeInteger.I32));
+ CallNode call = new CallNode(null,ctrl,mem,fptr).init();
+ CallEndNode end = new CallEndNode(call,TypeRPC.BOT);
+ end.addDef(ret);
+ Type linked = end.compute();
+ TypeFunPtr unknown = TypeFunPtr.make(false,TypeFunPtr.TEMPTY,TypeInteger.I32);
+ assertTrue(fptr._type.isa(unknown));
+ fptr._type = unknown;
+ assertTrue("Adding unknown targets must only lose precision",linked.isa(end.compute()));
+ }
+
+ @Test public void testUnlinkedCallIsPhaseIndependent() {
+ CodeGen code = new CodeGen("return 0;").parse();
+ TypeFunPtr sig = TypeFunPtr.make1((byte)2,true,TypeFunPtr.TEMPTY,TypeInteger.I32,100);
+ CallNode call = new CallNode(null,ConstantNode.raw(Type.CONTROL),
+ ConstantNode.raw(TypeMem.START),ConstantNode.raw(sig)).init();
+ CallEndNode end = new CallEndNode(call,TypeRPC.BOT);
+ Type expected = TypeTuple.make(Type.CONTROL,TypeMem.BOT,TypeInteger.I32);
+ for( CodeGen.Phase phase : new CodeGen.Phase[]{CodeGen.Phase.Parse,
+ CodeGen.Phase.Opto,CodeGen.Phase.IterPostOpto} ) {
+ code._phase = phase;
+ assertSame(phase.toString(),expected,end.compute());
+ }
+ }
+
+ @Test public void testExternalTargets() {
+ CodeGen code = new CodeGen("return 0;").parse();
+ code.externFunc(100,"first");
+ code.externFunc(101,"second");
+ TypeFunPtr sig = TypeFunPtr.make1((byte)2,true,TypeFunPtr.TEMPTY,TypeInteger.I32,100);
+ Node fptr = ConstantNode.raw(sig);
+ CallNode call = new CallNode(null,ConstantNode.raw(Type.CONTROL),
+ ConstantNode.raw(TypeMem.START),fptr).init();
+ CallEndNode end = new CallEndNode(call,TypeRPC.BOT);
+ Type first = end.compute();
+ fptr._type = sig.meet(sig.makeFrom(101));
+ assertTrue(first.isa(end.compute()));
+ assertSame(TypeInteger.I32,((TypeTuple)end.compute()).ret());
+ assertSame(Type.BOTTOM,((TypeMem)((TypeTuple)end.compute()).mem())._t);
+ }
+}