summaryrefslogtreecommitdiff
path: root/chapter27
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-25 10:24:58 -0700
committerCliff Click <cliffc@acm.org>2026-10-25 10:24:58 -0700
commit69e4a21f71aca4954469063387063434af35e679 (patch)
tree672e81600681625a22ed11f591b53d851f51c7d6 /chapter27
parent4051ce7cd26314f01dc8c0237899a742e0ab2084 (diff)
downloadSimple-69e4a21f71aca4954469063387063434af35e679.tar.gz
Simple-69e4a21f71aca4954469063387063434af35e679.zip
Backport a few missing guard checksmain
Diffstat (limited to 'chapter27')
-rw-r--r--chapter27/src/main/java/com/seaofnodes/simple/node/LoadNode.java16
-rw-r--r--chapter27/src/test/java/com/seaofnodes/simple/ConstructionTest.java17
-rw-r--r--chapter27/src/test/java/com/seaofnodes/simple/IncompleteTypesTest.java13
3 files changed, 44 insertions, 2 deletions
diff --git a/chapter27/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter27/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index b9dd2af6..736d91a2 100644
--- a/chapter27/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter27/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -208,7 +208,12 @@ public class LoadNode extends MemOpNode {
// skipping it can make a compound assignment read the old value.
if( st._alias==1 ) return null;
addDep(st.ptr());
- if( _alias==st._alias && ptr==address(st.ptr()) && off()==st.off() ) return st;
+ if( _alias==st._alias && ptr==address(st.ptr()) && off()==st.off() ) {
+ // A full-width load cannot narrow the forwarded value.
+ if( _declaredType instanceof TypeInteger ti && ti.log_size()==3 &&
+ !addDep(st.val())._type.isa(_type) ) return null;
+ return st;
+ }
if( _alias==st._alias && !neverAlias(ptr,address(st.ptr())) &&
!addDep(off())._type.join(addDep(st.off())._type).isHigh() ) return null;
mem=st.mem();
@@ -313,8 +318,15 @@ public class LoadNode extends MemOpNode {
// Signed extension
int shift = Long.numberOfLeadingZeros(ti._max)-1;
Node shf = con(shift);
- if( shf._type==TypeInteger.ZERO )
+ if( shf._type==TypeInteger.ZERO ) {
+ // A constructor's loop Phi may still have an unsettled type.
+ // Wait for it instead of weakening the typed Load's users.
+ if( !val._type.isa(_type) ) {
+ addDep(val);
+ return null;
+ }
return val;
+ }
Node shl = new ShlNode(null,val,shf.keep()).peephole();
return new SarNode(null,shl,shf.unkeep());
}
diff --git a/chapter27/src/test/java/com/seaofnodes/simple/ConstructionTest.java b/chapter27/src/test/java/com/seaofnodes/simple/ConstructionTest.java
index dd20b746..a3317d09 100644
--- a/chapter27/src/test/java/com/seaofnodes/simple/ConstructionTest.java
+++ b/chapter27/src/test/java/com/seaofnodes/simple/ConstructionTest.java
@@ -7,6 +7,23 @@ import org.junit.Test;
import static org.junit.Assert.*;
public class ConstructionTest {
+ @Test public void testConditionalConstructorLoop() {
+ String[] bodies = {
+ "while(n--) if(n) x=1;",
+ "for(int i=0;i<n;i++) { if(i==1) continue; if(i==3) break; x+=i+1; }"
+ };
+ int[][] expected = {{0,0,1,1,1,1}, {0,1,1,4,4,4}};
+ for( int i=0; i<bodies.length; i++ )
+ for( long seed : new long[]{123,456,789} ) {
+ String src = "struct C { int x; new C={int n -> "+bodies[i]+"}; }; return new C(arg).x;";
+ var code = new CodeGen(src,com.seaofnodes.simple.type.TypeInteger.BOT,seed,true)
+ .driver(CodeGen.Phase.TypeCheck);
+ for( int arg=0; arg<expected[i].length; arg++ )
+ assertEquals("case="+i+" seed="+seed+" arg="+arg,
+ Integer.toString(expected[i][arg]),Eval2.eval(code,arg));
+ }
+ }
+
private static final String CONSTRUCT = """
struct Box {
int x=7;
diff --git a/chapter27/src/test/java/com/seaofnodes/simple/IncompleteTypesTest.java b/chapter27/src/test/java/com/seaofnodes/simple/IncompleteTypesTest.java
index f2f7d882..419cac51 100644
--- a/chapter27/src/test/java/com/seaofnodes/simple/IncompleteTypesTest.java
+++ b/chapter27/src/test/java/com/seaofnodes/simple/IncompleteTypesTest.java
@@ -6,6 +6,19 @@ import com.seaofnodes.simple.type.TypeInteger;
import static org.junit.Assert.assertEquals;
public class IncompleteTypesTest {
+ @Test public void testLoadFromUnsettledLoopPhi() {
+ String src = """
+ struct C { int x; };
+ val f={int n -> return new C { while(n--) if(n) x=1; }; };
+ return f(arg).x;
+ """;
+ for( long seed : new long[]{123,456,789} ) {
+ var code = new CodeGen(src,TypeInteger.BOT,seed,true).driver(CodeGen.Phase.TypeCheck);
+ for( int arg=0; arg<6; arg++ )
+ assertEquals("seed="+seed+" arg="+arg,arg<2 ? "0" : "1",Eval2.eval(code,arg));
+ }
+ }
+
@Test public void testForwardFieldAndNumericMode() {
// At the addition, neither the field's type nor its offset is known.
String src = """