# HG changeset patch # User Lukas Stadler # Date 1374160693 -7200 # Node ID 8b0c8fbbfa1c6749b2a2e86337bdf977b9d0578a # Parent 3d6bd17da6e1bf0808fb1e4cb3d6167f8b7ff1d3 make early read elimination work on read/write nodes (in addition to load/store) diff -r 3d6bd17da6e1 -r 8b0c8fbbfa1c graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Thu Jul 18 17:16:16 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Thu Jul 18 17:18:13 2013 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.virtual.phases.ea.*; public class MidTier extends PhaseSuite { @@ -45,6 +46,10 @@ appendPhase(new ValueAnchorCleanupPhase()); appendPhase(new LockEliminationPhase()); + if (OptReadElimination.getValue()) { + appendPhase(new EarlyReadEliminationPhase(canonicalizer)); + } + if (OptFloatingReads.getValue()) { IncrementalCanonicalizerPhase incCanonicalizer = new IncrementalCanonicalizerPhase<>(); incCanonicalizer.appendPhase(new FloatingReadPhase()); diff -r 3d6bd17da6e1 -r 8b0c8fbbfa1c graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java Thu Jul 18 17:16:16 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java Thu Jul 18 17:18:13 2013 +0200 @@ -26,21 +26,24 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; public class ReadEliminationBlockState extends EffectsBlockState { - final HashMap readCache; + final HashMap, ValueNode> readCache; - static class ReadCacheEntry { + abstract static class CacheEntry { - public final ResolvedJavaField identity; public final ValueNode object; + public final T identity; - public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) { + public CacheEntry(ValueNode object, T identity) { + this.object = object; this.identity = identity; - this.object = object; } + public abstract CacheEntry duplicateWithObject(ValueNode newObject); + @Override public int hashCode() { int result = 31 + ((identity == null) ? 0 : identity.hashCode()); @@ -49,7 +52,7 @@ @Override public boolean equals(Object obj) { - ReadCacheEntry other = (ReadCacheEntry) obj; + CacheEntry other = (CacheEntry) obj; return identity == other.identity && object == other.object; } @@ -57,6 +60,42 @@ public String toString() { return object + ":" + identity; } + + public abstract boolean conflicts(LocationIdentity other); + } + + static class LoadCacheEntry extends CacheEntry { + + public LoadCacheEntry(ValueNode object, ResolvedJavaField identity) { + super(object, identity); + } + + @Override + public CacheEntry duplicateWithObject(ValueNode newObject) { + return new LoadCacheEntry(newObject, identity); + } + + @Override + public boolean conflicts(LocationIdentity other) { + return identity == other; + } + } + + static class ReadCacheEntry extends CacheEntry { + + public ReadCacheEntry(ValueNode object, LocationNode identity) { + super(object, identity); + } + + @Override + public CacheEntry duplicateWithObject(ValueNode newObject) { + return new ReadCacheEntry(newObject, identity); + } + + @Override + public boolean conflicts(LocationIdentity other) { + return identity.getLocationIdentity() == other; + } } public ReadEliminationBlockState() { @@ -81,29 +120,29 @@ return super.equivalentTo(other); } - public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) { - readCache.put(new ReadCacheEntry(identity, object), value); + public void addCacheEntry(CacheEntry identifier, ValueNode value) { + readCache.put(identifier, value); } - public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) { - return readCache.get(new ReadCacheEntry(identity, object)); + public ValueNode getCacheEntry(CacheEntry identifier) { + return readCache.get(identifier); } public void killReadCache() { readCache.clear(); } - public void killReadCache(ResolvedJavaField identity) { - Iterator> iter = readCache.entrySet().iterator(); + public void killReadCache(LocationIdentity identity) { + Iterator, ValueNode>> iter = readCache.entrySet().iterator(); while (iter.hasNext()) { - Map.Entry entry = iter.next(); - if (entry.getKey().identity == identity) { + Map.Entry, ValueNode> entry = iter.next(); + if (entry.getKey().conflicts(identity)) { iter.remove(); } } } - public Map getReadCache() { + public Map, ValueNode> getReadCache() { return readCache; } } diff -r 3d6bd17da6e1 -r 8b0c8fbbfa1c graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Thu Jul 18 17:16:16 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Thu Jul 18 17:18:13 2013 +0200 @@ -35,7 +35,9 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.CacheEntry; import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.ReadCacheEntry; +import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry; public class ReadEliminationClosure extends EffectsClosure { @@ -54,28 +56,59 @@ if (node instanceof LoadFieldNode) { LoadFieldNode load = (LoadFieldNode) node; ValueNode object = GraphUtil.unproxify(load.object()); - ValueNode cachedValue = state.getReadCache(object, load.field()); + LoadCacheEntry identifier = new LoadCacheEntry(object, load.field()); + ValueNode cachedValue = state.getCacheEntry(identifier); if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue); state.addScalarAlias(load, cachedValue); deleted = true; } else { - state.addReadCache(object, load.field(), load); + state.addCacheEntry(identifier, load); } } else if (node instanceof StoreFieldNode) { StoreFieldNode store = (StoreFieldNode) node; ValueNode object = GraphUtil.unproxify(store.object()); - ValueNode cachedValue = state.getReadCache(object, store.field()); + LoadCacheEntry identifier = new LoadCacheEntry(object, store.field()); + ValueNode cachedValue = state.getCacheEntry(identifier); - if (state.getScalarAlias(store.value()) == cachedValue) { + ValueNode value = state.getScalarAlias(store.value()); + if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { effects.deleteFixedNode(store); deleted = true; } - state.killReadCache(store.field()); - state.addReadCache(object, store.field(), store.value()); + state.killReadCache((LocationIdentity) store.field()); + state.addCacheEntry(identifier, value); + } else if (node instanceof ReadNode) { + ReadNode read = (ReadNode) node; + if (read.location() instanceof ConstantLocationNode) { + ValueNode object = GraphUtil.unproxify(read.object()); + ReadCacheEntry identifier = new ReadCacheEntry(object, read.location()); + ValueNode cachedValue = state.getCacheEntry(identifier); + if (cachedValue != null) { + effects.replaceAtUsages(read, cachedValue); + state.addScalarAlias(read, cachedValue); + deleted = true; + } else { + state.addCacheEntry(identifier, read); + } + } + } else if (node instanceof WriteNode) { + WriteNode write = (WriteNode) node; + if (write.location() instanceof ConstantLocationNode) { + ValueNode object = GraphUtil.unproxify(write.object()); + ReadCacheEntry identifier = new ReadCacheEntry(object, write.location()); + ValueNode cachedValue = state.getCacheEntry(identifier); + + ValueNode value = state.getScalarAlias(write.value()); + if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { + effects.deleteFixedNode(write); + deleted = true; + } + state.killReadCache(write.location().getLocationIdentity()); + state.addCacheEntry(identifier, value); + } } else if (node instanceof MemoryCheckpoint.Single) { - LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity(); - processIdentity(state, identity); + processIdentity(state, ((MemoryCheckpoint.Single) node).getLocationIdentity()); } else if (node instanceof MemoryCheckpoint.Multi) { for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) { processIdentity(state, identity); @@ -85,18 +118,18 @@ } private static void processIdentity(ReadEliminationBlockState state, LocationIdentity identity) { - if (identity instanceof ResolvedJavaField) { - state.killReadCache((ResolvedJavaField) identity); - } else if (identity == ANY_LOCATION) { + if (identity == ANY_LOCATION) { state.killReadCache(); + return; } + state.killReadCache(identity); } @Override protected void processLoopExit(LoopExitNode exitNode, ReadEliminationBlockState initialState, ReadEliminationBlockState exitState, GraphEffectList effects) { - for (Map.Entry entry : exitState.getReadCache().entrySet()) { + for (Map.Entry, ValueNode> entry : exitState.getReadCache().entrySet()) { if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) { - ProxyNode proxy = new ProxyNode(exitState.getReadCache(entry.getKey().object, entry.getKey().identity), exitNode, PhiType.Value, null); + ProxyNode proxy = new ProxyNode(exitState.getCacheEntry(entry.getKey()), exitNode, PhiType.Value, null); effects.addFloatingNode(proxy, "readCacheProxy"); entry.setValue(proxy); } @@ -138,8 +171,8 @@ } private void mergeReadCache(List states) { - for (Map.Entry entry : states.get(0).readCache.entrySet()) { - ReadCacheEntry key = entry.getKey(); + for (Map.Entry, ValueNode> entry : states.get(0).readCache.entrySet()) { + CacheEntry key = entry.getKey(); ValueNode value = entry.getValue(); boolean phi = false; for (int i = 1; i < states.size(); i++) { @@ -157,18 +190,18 @@ PhiNode phiNode = getCachedPhi(entry, value.kind()); mergeEffects.addFloatingNode(phiNode, "mergeReadCache"); for (int i = 0; i < states.size(); i++) { - afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity)); + afterMergeEffects.addPhiInput(phiNode, states.get(i).getCacheEntry(key)); } - newState.readCache.put(key, phiNode); + newState.addCacheEntry(key, phiNode); } else if (value != null) { - newState.readCache.put(key, value); + newState.addCacheEntry(key, value); } } for (PhiNode phi : merge.phis()) { if (phi.kind() == Kind.Object) { - for (Map.Entry entry : states.get(0).readCache.entrySet()) { + for (Map.Entry, ValueNode> entry : states.get(0).readCache.entrySet()) { if (entry.getKey().object == phi.valueAt(0)) { - mergeReadCachePhi(phi, entry.getKey().identity, states); + mergeReadCachePhi(phi, entry.getKey(), states); } } @@ -176,22 +209,23 @@ } } - private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List states) { + private void mergeReadCachePhi(PhiNode phi, CacheEntry identifier, List states) { ValueNode[] values = new ValueNode[phi.valueCount()]; for (int i = 0; i < phi.valueCount(); i++) { - ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity); + ValueNode value = states.get(i).getCacheEntry(identifier.duplicateWithObject(phi.valueAt(i))); if (value == null) { return; } values[i] = value; } - PhiNode phiNode = getCachedPhi(new ReadCacheEntry(identity, phi), values[0].kind()); + CacheEntry newIdentifier = identifier.duplicateWithObject(phi); + PhiNode phiNode = getCachedPhi(newIdentifier, values[0].kind()); mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi"); for (int i = 0; i < values.length; i++) { afterMergeEffects.addPhiInput(phiNode, values[i]); } - newState.readCache.put(new ReadCacheEntry(identity, phi), phiNode); + newState.addCacheEntry(newIdentifier, phiNode); } } }