summaryrefslogtreecommitdiff
path: root/chapter16/src/main/java/com
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2024-10-18 08:47:29 -0700
committerCliff Click <cliffc@acm.org>2024-10-21 08:52:01 -0700
commitc4c8ee708c6948dcfa41be61eb96e744d5c6d3f8 (patch)
tree65de12a176d3277a4874d6c9d2550eafedfb96dc /chapter16/src/main/java/com
parent8ecde979dee25f08bdd3360f19eeb85ead5dd2ca (diff)
downloadSimple-c4c8ee708c6948dcfa41be61eb96e744d5c6d3f8.tar.gz
Simple-c4c8ee708c6948dcfa41be61eb96e744d5c6d3f8.zip
Missing init-store-after-new opt
Diffstat (limited to 'chapter16/src/main/java/com')
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java8
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java4
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java41
3 files changed, 38 insertions, 15 deletions
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index be6fba11..c4abed12 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeMem;
-import com.seaofnodes.simple.type.TypeStruct;
+import com.seaofnodes.simple.type.*;
import java.util.BitSet;
/**
@@ -57,7 +55,7 @@ public class LoadNode extends MemOpNode {
// Simple Load-after-New on same address.
if( mem() instanceof ProjNode p && p.in(0) instanceof NewNode nnn &&
ptr == nnn.proj(1) ) // Must check same object
- return nnn.findAlias(_alias); // Load from New init
+ return nnn.in(nnn.findAlias(_alias)); // Load from New init
// Load-after-Store on same address, but bypassing provably unrelated
// stores. This is a more complex superset of the above two peeps.
@@ -81,7 +79,7 @@ public class LoadNode extends MemOpNode {
case ProjNode mproj:
if( mproj.in(0) instanceof NewNode nnn1 ) {
if( ptr instanceof ProjNode pproj && pproj.in(0) == mproj.in(0) )
- return nnn1.findAlias(_alias); // Load from New init
+ return nnn1.in(nnn1.findAlias(_alias)); // Load from New init
if( !(ptr instanceof ProjNode pproj && pproj.in(0) instanceof NewNode nnn2) )
break outer; // Cannot tell, ptr not related to New
mem = nnn1.in(_alias);// Bypass unrelated New
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java
index cb6ee464..1e6d2baa 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -45,8 +45,8 @@ public class NewNode extends Node implements MultiNode {
}
// Find matching alias input
- Node findAlias(int alias) {
- return in(2+_ptr._obj.findAlias(alias)+_len);
+ int findAlias(int alias) {
+ return 2+_ptr._obj.findAlias(alias)+_len;
}
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index b1c74b94..7b1bddd5 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -55,27 +55,52 @@ public class StoreNode extends MemOpNode {
// required init-store being stomped by a first user store.
if( mem() instanceof StoreNode st &&
ptr()==st.ptr() && // Must check same object
- off()==st.off() && // And same offset
+ off()==st.off() && // And same offset (could be "same alias" but this handles arrays to same index)
ptr()._type instanceof TypeMemPtr && // No bother if weird dead pointers
// Must have exactly one use of "this" or you get weird
// non-serializable memory effects in the worse case.
- st.checkNoUseBeyond(this) ) {
+ checkOnlyUse(st) ) {
assert _name.equals(st._name); // Equiv class aliasing is perfect
setDef(1,st.mem());
return this;
}
+ // Simple store-after-new on same address. Should pick up the
+ // an init-store being stomped by a first user store.
+ if( mem() instanceof ProjNode st && st .in(0) instanceof NewNode nnn &&
+ ptr() instanceof ProjNode ptr && ptr.in(0) == nnn &&
+ ptr()._type instanceof TypeMemPtr tmp && // No bother if weird dead pointers
+ // Cannot fold a store of a single element over the array body initializer value
+ !(tmp._obj.isAry() && tmp._obj._fields[1]._alias==_alias) &&
+ // Very sad strong cutout: val has to be legal to hoist to a New
+ // input, which means it cannot depend on the New. Many many
+ // things are legal here but difficult to check without doing a
+ // full dominator check. Example failure:
+ // "struct C { C? c; }; C self = new C { c=self; }"
+ val()._type.isHighOrConst() &&
+ // Must have exactly one use of "this" or you get weird
+ // non-serializable memory effects in the worse case.
+ checkOnlyUse(st) &&
+ // Folding away a broken store
+ err()==null ) {
+ nnn.setDef(nnn.findAlias(_alias),val());
+ // Must retype the NewNode
+ nnn ._type = nnn. compute();
+ mem()._type = mem().compute();
+ return st;
+ }
+
return null;
}
- // Check that `this` has no uses beyond `that`
- private boolean checkNoUseBeyond(Node that) {
- if( nOuts()==1 ) return true;
+ // Check that "mem" has no uses except "this"
+ private boolean checkOnlyUse(Node mem) {
+ if( mem.nOuts()==1 ) return true;
// Add deps on the other uses (can be e.g. ScopeNode mid-parse) so that
// when the other uses go away we can retry.
- for( Node use : _outputs )
- if( use != that )
- use.addDep(that);
+ for( Node use : mem._outputs )
+ if( use != this )
+ use.addDep(this);
return false;
}