summaryrefslogtreecommitdiff
path: root/chapter21/src
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-01 15:47:15 -0700
committerCliff Click <cliffc@acm.org>2026-10-01 15:47:15 -0700
commitbd0ef17d0f9563ed9579fe060b785211e8378006 (patch)
treed8f45cdfd6e7ee295997d11ff948ca4950153721 /chapter21/src
parent5dd5b7a2d03885cb767bbf2b609d56f8ef897301 (diff)
downloadSimple-bd0ef17d0f9563ed9579fe060b785211e8378006.tar.gz
Simple-bd0ef17d0f9563ed9579fe060b785211e8378006.zip
Restore missing anti-dependence walk
Diffstat (limited to 'chapter21/src')
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java25
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java2
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java2
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java18
4 files changed, 35 insertions, 12 deletions
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
index 9945374a..447a6df1 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
@@ -267,22 +267,22 @@ public abstract class GlobalCodeMotion {
switch( mem ) {
case MemOpNode st:
assert late[st._nid]!=null;
- lca = anti_dep(load,late[st._nid],lca,st,anti);
+ lca = anti_dep(load,late[st._nid],st.cfg0(),lca,st,anti);
break;
case CallNode st:
assert late[st._nid]!=null;
- lca = anti_dep(load,late[st._nid],lca,st,anti);
+ lca = anti_dep(load,late[st._nid],st.cfg0(),lca,st,anti);
break;
case PhiNode phi:
// Repeat anti-dep for matching Phi inputs.
// No anti-dep edges but may raise the LCA.
for( int i=1; i<phi.nIns(); i++ )
if( phi.in(i)==load.mem() )
- lca = anti_dep(load,phi.region().cfg(i),lca,null,anti);
+ lca = anti_dep(load,phi.region().cfg(i),load.mem().cfg0(),lca,null,anti);
break;
case NewNode st:
assert late[st._nid]!=null;
- lca = anti_dep(load,late[st._nid],lca,st,anti);
+ lca = anti_dep(load,late[st._nid],st.cfg0(),lca,st,anti);
break;
default: throw Utils.TODO();
}
@@ -291,12 +291,17 @@ public abstract class GlobalCodeMotion {
}
//
- private static CFGNode anti_dep( MemOpNode load, CFGNode stblk, CFGNode lca, Node st, int[] anti ) {
- // Stores are already placed. Constrain the load at that block only.
- if( anti[stblk._nid]==load._nid ) {
- lca = stblk.domLCA(lca,null);
- if( lca==stblk && st!=null && !(st instanceof CallNode) && st._inputs.find(load) == -1 )
- st.addDef(load); // Same-block load must precede the store.
+ private static CFGNode anti_dep( MemOpNode load, CFGNode stblk, CFGNode defblk, CFGNode lca, Node st, int[] anti ) {
+ // A conditional writer can precede the load without dominating its late block.
+ // Walk back to the first overlap with the load's placement range.
+ for( ; stblk != defblk.idom(); stblk = stblk.idom() ) {
+ // Store and Load overlap, need anti-dependence
+ if( anti[stblk._nid]==load._nid ) {
+ lca = stblk.domLCA(lca,null); // Raise Loads LCA
+ if( lca == stblk && st != null && !(st instanceof CallNode) && st._inputs.find(load) == -1 ) // And if something moved,
+ st.addDef(load); // Add anti-dep as well; Calls already end their block.
+ return lca; // Cap this stores' anti-dep to here
+ }
}
return lca;
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
index 97d33b70..aa6fada0 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
@@ -20,7 +20,7 @@ public class BrainFuckTest {
String brain_fuck = "Hello World!\n";
TestC.run("brain_fuck", brain_fuck, 40);
- EvalRisc5 R5 = TestRisc5.build("brain_fuck", 0, 42, false);
+ EvalRisc5 R5 = TestRisc5.build("brain_fuck", 0, 146, false);
int trap = R5.step(100000);
assertEquals(0,trap);
int ptr = (int)R5.regs[riscv.A0];
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index 250acaa2..8112917e 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -306,7 +306,7 @@ for( int pc = 0; pc < program#; pc++ ) {
return output;
""";
testTarget(src,"x86_64_v2", "SystemV",40,null);
- testTarget(src,"riscv" , "SystemV",42,null);
+ testTarget(src,"riscv" , "SystemV",146,null);
testTarget(src,"arm" , "SystemV",34,null);
//assertEquals("Hello World!\n", Eval2.eval(code, 0, 10000));
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index 94170fcb..f431feeb 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -16,6 +16,24 @@ import static org.junit.Assert.*;
public class Chapter21Test {
+ @Test public void testReadBeforeConditionalStore() {
+ var code = new CodeGen("""
+ struct S { int x; }; S !a=new S; S !b=new S;
+ a.x=10; b.x=20; S !p=a; if(arg&1) p=b;
+ int sum=0;
+ for(int i=0; i<6; i++) {
+ sum+=a.x;
+ if(i==2) p.x=30;
+ else if(i==4) b.x=40;
+ }
+ return sum;
+ """).parse().opto();
+ // The i==2 read still sees 10: three reads of 10, then three of 30.
+ assertEquals("120",Eval2.eval(code,0));
+ assertEquals("60",Eval2.eval(code,1));
+ }
+
+
@Test public void testArmBitfieldExtracts() {
// Independent SXT/UXT instruction words, plus ASR, LSR and LSL aliases.
int[] ops = {0x93401c20,0xd3401c20,0x93403c20,0xd3403c20,