diff options
| author | Cliff Click <cliffc@acm.org> | 2026-08-10 15:21:17 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-08-10 15:21:17 -0700 |
| commit | 628452bb9f6137d433395fae5a9f5d780fb0f1e1 (patch) | |
| tree | 6fbf9916aa0b1bed55fd14a0613445048d89eb9a /chapter25/src/main/java/com/seaofnodes | |
| parent | 43dd950c4e3c9e17b619af56dd34394e0a4779b6 (diff) | |
| download | Simple-628452bb9f6137d433395fae5a9f5d780fb0f1e1.tar.gz Simple-628452bb9f6137d433395fae5a9f5d780fb0f1e1.zip | |
More hardening
Allow setting random seeds to not fail tests due to e.g. spill-counts or exact graph shapes.
A few missing addDeps or stalling-for-constants fixed.
Diffstat (limited to 'chapter25/src/main/java/com/seaofnodes')
6 files changed, 45 insertions, 18 deletions
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/IterPeeps.java b/chapter25/src/main/java/com/seaofnodes/simple/IterPeeps.java index 608f368d..9fac7a99 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/IterPeeps.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/IterPeeps.java @@ -81,11 +81,14 @@ public class IterPeeps { // Everybody gets a free "go again" in case they didn't get // made in their final form. _work.push(x); + // A self-returning peephole can have rewritten its input + // edges. The new defs gained a user and may have + // backwards, user-sensitive peepholes of their own. + for( Node z : x._inputs ) _work.push(z); // If the result is not self, revisit all inputs (because // there's a new user), and replace in the graph. if( x != n ) { for( Node z : n. _inputs ) _work.push(z); - for( Node z : x. _inputs ) _work.push(z); for( Node z : x._outputs ) _work.push(z); n.subsume(x); } diff --git a/chapter25/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter25/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java index 85407ddc..85d8143b 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java @@ -42,6 +42,9 @@ public class CodeGen { } public Phase _phase; + /** True when tests deliberately randomize Iter worklist order. */ + public static boolean iterSeedOverridden() { return System.getProperty("simple.iter.seed") != null; } + // --------------------------- // Module Source Root public final String _modDir; @@ -196,7 +199,10 @@ public class CodeGen { _phase = null; // Start GVN table _gvn = new HashMap<>(); - _iter = new IterPeeps(workListSeed); + // Allow whole-suite worklist-order sweeps without rewriting the many + // explicit seeds used by tests and command-line compilation. + String iterSeed = System.getProperty("simple.iter.seed"); + _iter = new IterPeeps(iterSeed == null ? workListSeed : Long.parseLong(iterSeed)); // End points of graph _stop = new StopNode().init(); _start = new StartNode(null,_stop,arg).init(); diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/BulkMemPhiNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/BulkMemPhiNode.java index c4a13375..cab85e44 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/node/BulkMemPhiNode.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/node/BulkMemPhiNode.java @@ -140,6 +140,7 @@ public class BulkMemPhiNode extends PhiNode { return true; } + // True if the MemMerge has no precise slice still covered by this Phi. private boolean canPeek(MemMergeNode mmm) { return missingAlias(mmm,false)==0; @@ -165,7 +166,11 @@ public class BulkMemPhiNode extends PhiNode { // Return an alias required by a user but still covered by this Phi, or 0. private int outputAlias(Node use) { - use = addDep(use); // User alias sharpening changes this decision + // This decision depends backwards on an immediate user's alias/set. + // Normal graph-neighbor enqueueing flows from defs to uses, so retain + // an explicit forward dependency to revisit this Phi when the user + // sharpens. + use = addDepForwards(use); return switch(use) { case ScopeNode scope -> 0; case ParmNode parm -> 0; @@ -217,6 +222,11 @@ public class BulkMemPhiNode extends PhiNode { for( int i=0; i<nIns(); i++ ) mphi.addDef(in(i)); Node mem = mphi.peephole(); assert ((TypeMem)mem._type)._alias==alias; + // The precise Phi is a new alias-sensitive user of every memory + // input. Revisit those defs: a predecessor BulkMemPhi may now need + // to split this alias even though none of its inputs or types changed. + for( int i=1; i<mphi.nIns(); i++ ) + CodeGen.CODE.add(mphi.in(i)); BitSet aliases = ((BitSet)_aliases.clone()); aliases.set(alias); @@ -271,9 +281,20 @@ public class BulkMemPhiNode extends PhiNode { if( found==null ) { MemPhiNode mphi = new MemPhiNode("$"+alias,alias); mphi.addDef(region()); + // Publishing the Phi on the Region makes it visible to recursive + // precisePhi lookups before all loop inputs have been installed. + // Give that recursion a valid lattice value until peephole computes + // the completed precise-memory Phi. + mphi.setType(TypeMem.BOT.makeFrom(alias)); for( int i=1; i<nIns(); i++ ) mphi.addDef(preciseInput(in(i),alias)); found = mphi.peephole(); + // A newly reconstructed precise Phi also creates new users of + // its memory inputs. In particular, a BulkMemPhi input may now + // need to split this alias, a backwards (user-to-def) change not + // covered by processing the new Phi itself. + for( int i=1; i<mphi.nIns(); i++ ) + CodeGen.CODE.add(mphi.in(i)); CodeGen.CODE.add(found); } return found; diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/LoadNode.java index 8b8bcaac..f67f2b97 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/node/LoadNode.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/node/LoadNode.java @@ -317,12 +317,14 @@ public class LoadNode extends MemOpNode { int shift = Long.numberOfLeadingZeros(ti._max)-1; Node shf = con(shift); if( shf._type==TypeInteger.ZERO ) { - // Val can be stale and on worklist. Preserve momnotoncity and bring it up to date - if( val._type.isa(_type) ) - return val; - Node val2 = val.peephole(); - assert val._type.isa(_type); - return val2; + // A freshly exposed Store value can still be globally unknown. + // Revisit this Load when it settles instead of replacing a typed + // Load with the weaker transient value. + 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/chapter25/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter25/src/main/java/com/seaofnodes/simple/node/Node.java index 986754f4..1ce8382a 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/node/Node.java @@ -501,6 +501,10 @@ public abstract class Node implements Cloneable { // A high Load through a bad pointer still owns the source error; // do not replace it with an unlocated constant before typeCheck. !(this instanceof LoadNode && err()!=null) && + // A CallEnd can be temporarily high while optimistic call-graph + // linking is still discovering its target Returns. Its result + // projections must remain attached so they can sharpen later. + !(this instanceof ProjNode proj && proj.in(0) instanceof CallEndNode && _type.isHigh()) && _type.isHighOrConst() ) return ConstantNode.make(_type).peephole(); diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ReturnNode.java index 93cf1b91..b60d27d7 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/node/ReturnNode.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/node/ReturnNode.java @@ -60,15 +60,6 @@ public class ReturnNode extends CFGNode { if( ret != fcn.ret() && ret.isa(fcn.ret()) ) _fun.setSig(fcn.makeFrom(ret)); - // If dead (cannot be reached; infinite loop), kill the exit values - if( ctrl()._type==Type.XCONTROL && - !(mem() instanceof ConstantNode && expr() instanceof ConstantNode) ) { - Node top = ConstantNode.make(Type.TOP).peephole(); - setDef(1,top); - setDef(2,top); - return this; - } - return null; } |
