summaryrefslogtreecommitdiff
path: root/chapter25/src/main/java/com/seaofnodes
diff options
context:
space:
mode:
Diffstat (limited to 'chapter25/src/main/java/com/seaofnodes')
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/IterPeeps.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java8
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/BulkMemPhiNode.java23
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/LoadNode.java14
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/Node.java4
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ReturnNode.java9
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;
}