summaryrefslogtreecommitdiff
path: root/chapter25/src
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-05 15:38:06 -0700
committerCliff Click <cliffc@acm.org>2026-10-05 15:38:06 -0700
commit81b654d76444d747fdf1d053760e507b50f26e18 (patch)
tree594fa806fc31d848f172d0413de0e431fde6e22a /chapter25/src
parent3b8ad2977ef3911aed7c681037e4640dca59749b (diff)
downloadSimple-81b654d76444d747fdf1d053760e507b50f26e18.tar.gz
Simple-81b654d76444d747fdf1d053760e507b50f26e18.zip
Small peep to drop simple store-updates out of loops
Diffstat (limited to 'chapter25/src')
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java40
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java4
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter23Test.java4
5 files changed, 53 insertions, 5 deletions
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index 3e618472..dfe8794d 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -104,6 +104,9 @@ public class MemMergeNode extends Node {
// Collapse stacked merged-mem
if( in(1) instanceof MemMergeNode mem ) {
+ // A dead memory cycle can lose its last use when we bypass mem.
+ // Keep the peephole's result alive until the worklist sees it.
+ keep();
// Goal is to swap my default mem with mem's default mem
for( int i=2; i<mem.nIns(); i++ ) {
if( mem.in(i) != null ) {
@@ -114,7 +117,7 @@ public class MemMergeNode extends Node {
}
CodeGen.CODE.add(mem.in(1));
setDef(1,mem.in(1));
- return this;
+ return unkeep();
}
return progress ? this : null;
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java
index e8e2592c..cdfaaf97 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/MemPhiNode.java
@@ -61,6 +61,11 @@ public class MemPhiNode extends PhiNode {
setDef(i,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/chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 415ade34..4917e890 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -249,6 +249,46 @@ public class StoreNode extends MemOpNode {
};
}
+ // 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 || _alias==1 || _size==0 || _init ) 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,null,mem,ptr(),off()).peephole();
+ Node value = CodeGen.CODE.add(new PhiNode(_name,loop,init,val()).peephole());
+ Node sink = new StoreNode(_loc,_name,_alias,_con,null,mem,ptr(),off(),value,_init,_size);
+ // 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;
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index bfce93b9..4d610a42 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -283,8 +283,8 @@ return new _s0.v1;
@Test public void testInfinite() {
String src = "struct _S { int i; }; !_S !s = new _S; while(1) s.i++; return s.i;";
testCPU(src,"x86_64_v2", "SystemV",0,"return Top;");
- testCPU(src,"riscv" , "SystemV",2,"return Top;");
- testCPU(src,"arm" , "SystemV",2,"return Top;");
+ testCPU(src,"riscv" , "SystemV",0,"return Top;");
+ testCPU(src,"arm" , "SystemV",0,"return Top;");
}
@Test
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter23Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter23Test.java
index 7c46567a..053621bd 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter23Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter23Test.java
@@ -279,7 +279,7 @@ return _s.peek('q');
CodeGen code = new CodeGen(src).parse().opto().typeCheck();
assertEquals("return Phi(Region,0,1);", code.print());
assertEquals("1", Eval2.eval(code, 0));
- testCPU(src,"x86_64_v2", "win64",1,null);
+ testCPU(src,"x86_64_v2", "win64",23,null);
};
@Test
@@ -334,7 +334,7 @@ return _s.require('[');
CodeGen code = new CodeGen(src).parse().opto().typeCheck();
assertEquals("return (.[]==91);", code.print());
assertEquals("1", Eval2.eval(code, 0));
- testCPU(src,"x86_64_v2", "win64", 0, null);
+ testCPU(src,"x86_64_v2", "win64",4, null);
};