summaryrefslogtreecommitdiff
path: root/chapter18/src/main/java
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-01-13 15:09:59 -0800
committerCliff Click <cliffc@acm.org>2025-01-15 15:07:30 -0800
commit3a3d469154846b648b09c708bfe3e8c16a203654 (patch)
tree3b7b5ce189a0129da352d4106ee34f3fd7eafdee /chapter18/src/main/java
parente491c528e8d9380bdef823889f0b0a8e08a34f55 (diff)
downloadSimple-3a3d469154846b648b09c708bfe3e8c16a203654.tar.gz
Simple-3a3d469154846b648b09c708bfe3e8c16a203654.zip
Some dead inf call bug fixes
More comments about meeting nil above the center line falls - but does not (can not) dual. This implies have TFPs with *no* allowed functions that are below centerline; if allowed null then its basically an alternate null. If not allowed null and not allowed any functions, its basically a high value (not executable). IfNode folds. Do not remove a dead infinite loop - it needs to remain as a CFG sink.
Diffstat (limited to 'chapter18/src/main/java')
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/Parser.java3
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/LoopNode.java14
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java6
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java7
8 files changed, 33 insertions, 19 deletions
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
index 649145fd..8f0cf493 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java
@@ -708,7 +708,8 @@ public class Parser {
if( inferType ) {
if( expr._type==Type.NIL )
throw error("a not-null/non-zero expression");
- t = expr._type.glb();
+ t = expr._type;
+ if( !xfinal ) t = t.glb(); // Widen if not final
}
if( t instanceof TypeFunPtr && expr._type instanceof TypeFunPtr tfp && tfp.isConstant() )
tfp.setName(name);
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index c9ea2f1f..48edc0eb 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -26,8 +26,7 @@ public class CallEndNode extends CFGNode implements MultiNode {
@Override
StringBuilder _print1(StringBuilder sb, BitSet visited) {
sb.append("cend( ");
- if( call()==null ) sb.append("---, ");
- else sb.append("Call, ");
+ sb.append( in(0) instanceof CallNode ? "Call, " : "----, ");
for( int i=1; i<nIns()-1; i++ )
in(i)._print0(sb,visited).append(",");
sb.setLength(sb.length()-1);
@@ -36,8 +35,10 @@ public class CallEndNode extends CFGNode implements MultiNode {
@Override
public Type compute() {
- Type ret = call().fptr()._type instanceof TypeFunPtr tfp ? tfp.ret() : Type.BOTTOM;
- return TypeTuple.make(call()._type,TypeMem.BOT,ret);
+ if( !(in(0) instanceof CallNode call) )
+ return TypeTuple.RET.dual();
+ Type ret = call.fptr().addDep(this)._type instanceof TypeFunPtr tfp ? tfp.ret() : Type.BOTTOM;
+ return TypeTuple.make(call._type,TypeMem.BOT,ret);
}
@Override
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 1e6b2878..c49ee662 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -43,7 +43,7 @@ public class IfNode extends CFGNode implements MultiNode {
// If constant is 0 then false branch is reachable
// Else true branch is reachable
if( t.isConstant() )
- return (t==Type.NIL || t==TypeInteger.ZERO) ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE;
+ return (t==Type.NIL || t==TypeInteger.ZERO || (t instanceof TypeFunPtr tfp && tfp._fidxs==0) ) ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE;
// If adding a zero makes a difference, the predicate must not have a zero/null
if( !t.makeZero().isa(t) )
return TypeTuple.IF_TRUE;
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/LoopNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/LoopNode.java
index b54403b7..a31c8ac8 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/LoopNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/LoopNode.java
@@ -25,7 +25,19 @@ public class LoopNode extends RegionNode {
@Override
public Node idealize() {
- return inProgress() ? null : super.idealize();
+ if( inProgress() ) return null;
+ // Dead infinite loops with NO control flow out stick around - as a
+ // dead infinite loop, to signal that control stops and spins here.
+ if( nIns()==2 && !hasPhi() && !hasCFG() )
+ return null;
+ return super.idealize();
+ }
+
+ private boolean hasCFG() {
+ for( Node phi : _outputs )
+ if( phi instanceof CFGNode )
+ return true;
+ return false;
}
// Bypass Region idom, same as the default idom() using use in(1) instead of in(0)
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 5045b43b..d8e24964 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -86,7 +86,7 @@ public class RegionNode extends CFGNode {
return 0; // All inputs alive
}
- private boolean hasPhi() {
+ boolean hasPhi() {
for( Node phi : _outputs )
if( phi instanceof PhiNode )
return true;
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index f42adcf6..2fe722c6 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -45,12 +45,14 @@ public class ReturnNode extends CFGNode {
@Override
public Type compute() {
- if( inProgress() ) return TypeTuple.RET; // In progress
+ if( inProgress () ) return TypeTuple.RET; // In progress
+ if( _fun.isDead() ) return TypeTuple.RET.dual(); // Dead another way
return TypeTuple.make(ctrl()._type,mem()._type,expr()._type);
}
@Override public Node idealize() {
- if( inProgress() ) return null;
+ if( inProgress () ) return null;
+ if( _fun.isDead() ) return null;
// Upgrade signature based on return type
Type ret = expr()._type;
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
index 5799fea9..cf92d3d7 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
@@ -24,7 +24,7 @@ public class TypeFunPtr extends TypeNil {
// Cheesy easy implementation for a small set; 1 bit per unique function
// within the TypeTuple. Can be upgraded to a BitSet for larger classes of
// functions. Negative means "these 63 concrete bits plus infinite unknown more"
- private final long _fidxs; // 63 unique functions per signature
+ public final long _fidxs; // 63 unique functions per signature
public String _name; // Optional debug function name; only for named single function
private TypeFunPtr(byte nil, TypeTuple sig, Type ret, long fidxs) {
@@ -69,12 +69,13 @@ public class TypeFunPtr extends TypeNil {
@Override
public TypeFunPtr dual() { return TypeFunPtr.make(dual0(), _sig.dual(), _ret.dual(), ~_fidxs); }
- // RHS is NIL
+ // RHS is NIL; do not deep-dual when crossing the centerline
@Override public Type meet0() { return _nil==3 ? this : make((byte)3,_sig,_ret,_fidxs); }
- @Override public TypeFunPtr glb() { return make(_nil,_sig,_ret,_fidxs); }
+ @Override public TypeFunPtr glb() { return make((byte)3,_sig,_ret,-1L); }
- @Override public boolean isConstant() { return _nil==2 && Long.bitCount(_fidxs)==1; }
+ @Override public boolean isHigh () { return _nil <= 1 || (_nil==2 && _fidxs==0); }
+ @Override public boolean isConstant() { return (_nil==2 && Long.bitCount(_fidxs)==1) || (_nil==3 && _fidxs==0); }
@Override public int log_size() { return 2; } // (1<<2)==4-byte pointers
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
index c8a5c1f4..d7a8b17d 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
@@ -58,11 +58,8 @@ public class TypeMemPtr extends TypeNil {
@Override
public TypeMemPtr dual() { return TypeMemPtr.make( dual0(), _obj.dual()); }
- // RHS is NIL
- @Override Type meet0() {
- // NOT DOING DUAL
- return _nil==3 ? this : make((byte)3,_obj);
- }
+ // RHS is NIL; do not deep-dual when crossing the centerline
+ @Override Type meet0() { return _nil==3 ? this : make((byte)3,_obj); }
// True if this "isa" t up to named structures