summaryrefslogtreecommitdiff
path: root/chapter24/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'chapter24/src/main/java')
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java5
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java40
2 files changed, 45 insertions, 0 deletions
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java
index 1c354d5c..787333d9 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java
@@ -36,6 +36,11 @@ public class MemPhiNode extends PhiNode {
setDef(i,CodeGen.CODE.add(mem.alias(_alias)));
return this;
}
+ if( nIns()==3 && region() instanceof LoopNode loop && !loop.inProgress() &&
+ in(2) instanceof StoreNode st && st.mem()==this ) {
+ Node sink = st.sink(this);
+ if( sink!=null ) return sink;
+ }
return super.idealize();
}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 4e4ab202..4e1d7ce3 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -109,6 +109,46 @@ public class StoreNode extends MemOpNode {
return null;
}
+ // Phi(mem, Store(phi,ptr,off,val)) -> Store(mem,ptr,off,Phi(load(mem),val)).
+ // With no observers of the backedge store, only the last value matters.
+ // The entry load preserves the field even when the loop takes zero trips.
+ Node sink(MemPhiNode phi) {
+ phi.addDepForwards(this);
+ if( nOuts()!=1 ) return null;
+ phi.addDep(ptr());
+ // Start with a fixed field of an allocation dominating the loop.
+ // In particular, do not sink stores through a loop-varying address.
+ if( !(ptr() instanceof ProjNode p) || !(p.in(0) instanceof NewNode obj) ||
+ !(ptr()._type instanceof TypeMemPtr tmp) || tmp._obj.isAry() ||
+ !(off() instanceof ConstantNode) || err()!=null ) return null;
+ LoopNode loop = (LoopNode)phi.region();
+ // Bulk splitting identifies precise slices by Region/alias. Finish it
+ // before replacing this memory point with a Store.
+ for( Node use : loop._outputs )
+ if( use instanceof BulkMemPhiNode ) {
+ phi.addDepForwards(use);
+ return null;
+ }
+ phi.addDep(obj);
+ CFGNode ctrl = loop.entry();
+ while( ctrl!=null && ctrl!=obj.cfg0() ) {
+ phi.addDep(ctrl);
+ ctrl=ctrl.idom(phi);
+ }
+ if( ctrl==null ) return null;
+
+ Node mem = phi.in(1);
+ Node init = new LoadNode(_loc,_name,_alias,_declaredType,mem,ptr(),off()).peephole();
+ Node value = CodeGen.CODE.add(new PhiNode(_name,_declaredType,loop,init,val()).peephole());
+ Node sink = new StoreNode(_loc,_name,_alias,_declaredType,mem,ptr(),off(),value,_init);
+ // Break the memory cycle, killing the old store. Keep the Phi alive
+ // even if that store was its last use, until our caller replaces it.
+ phi.keep();
+ phi.setDef(2,mem);
+ phi.unkeep();
+ return sink;
+ }
+
// Check that "mem" has no uses except "this"
private boolean checkOnlyUse(Node mem) {
if( mem.nOuts()==1 ) return true;