|
35 | 35 | import jdk.graal.compiler.graph.Node; |
36 | 36 | import jdk.graal.compiler.graph.NodeClass; |
37 | 37 | import jdk.graal.compiler.nodeinfo.NodeInfo; |
38 | | -import jdk.graal.compiler.nodes.virtual.VirtualArrayNode; |
39 | | -import jdk.graal.compiler.nodes.virtual.VirtualObjectNode; |
| 38 | +import jdk.graal.compiler.nodes.BeginNode; |
40 | 39 | import jdk.graal.compiler.nodes.ConstantNode; |
41 | 40 | import jdk.graal.compiler.nodes.DeoptimizeNode; |
| 41 | +import jdk.graal.compiler.nodes.EndNode; |
42 | 42 | import jdk.graal.compiler.nodes.FixedGuardNode; |
| 43 | +import jdk.graal.compiler.nodes.FixedNode; |
43 | 44 | import jdk.graal.compiler.nodes.FixedWithNextNode; |
| 45 | +import jdk.graal.compiler.nodes.FrameState; |
| 46 | +import jdk.graal.compiler.nodes.IfNode; |
44 | 47 | import jdk.graal.compiler.nodes.LogicNode; |
| 48 | +import jdk.graal.compiler.nodes.MergeNode; |
45 | 49 | import jdk.graal.compiler.nodes.NodeView; |
| 50 | +import jdk.graal.compiler.nodes.ProfileData; |
| 51 | +import jdk.graal.compiler.nodes.StructuredGraph; |
46 | 52 | import jdk.graal.compiler.nodes.ValueNode; |
| 53 | +import jdk.graal.compiler.nodes.ValuePhiNode; |
47 | 54 | import jdk.graal.compiler.nodes.calc.CompareNode; |
| 55 | +import jdk.graal.compiler.nodes.calc.ConditionalNode; |
48 | 56 | import jdk.graal.compiler.nodes.extended.GuardingNode; |
49 | 57 | import jdk.graal.compiler.nodes.memory.MemoryAccess; |
50 | 58 | import jdk.graal.compiler.nodes.spi.Canonicalizable; |
|
54 | 62 | import jdk.graal.compiler.nodes.spi.Virtualizable; |
55 | 63 | import jdk.graal.compiler.nodes.spi.VirtualizerTool; |
56 | 64 | import jdk.graal.compiler.nodes.type.StampTool; |
57 | | - |
| 65 | +import jdk.graal.compiler.nodes.util.GraphUtil; |
| 66 | +import jdk.graal.compiler.nodes.virtual.VirtualArrayNode; |
| 67 | +import jdk.graal.compiler.nodes.virtual.VirtualObjectNode; |
58 | 68 | import jdk.vm.ci.meta.Assumptions; |
59 | 69 | import jdk.vm.ci.meta.ConstantReflectionProvider; |
60 | 70 | import jdk.vm.ci.meta.DeoptimizationAction; |
@@ -181,6 +191,80 @@ public void simplify(SimplifierTool tool) { |
181 | 191 | graph().replaceFixedWithFixed(this, graph().add(fixedGuard)); |
182 | 192 | } |
183 | 193 | } |
| 194 | + |
| 195 | + // Try to simplify loads from constant arrays with the index being a conditional. |
| 196 | + if (array() instanceof ConstantNode && index() instanceof ConditionalNode conditional) { |
| 197 | + StructuredGraph graph = graph(); |
| 198 | + var trueVal = tryConstantFold(array(), conditional.trueValue(), tool.getMetaAccess(), tool.getConstantReflection()); |
| 199 | + var falseVal = tryConstantFold(array(), conditional.falseValue(), tool.getMetaAccess(), tool.getConstantReflection()); |
| 200 | + |
| 201 | + if (trueVal != null && falseVal != null) { |
| 202 | + /*- |
| 203 | + * Both conditional inputs are constant. |
| 204 | + * |
| 205 | + * cond C1 C2 |
| 206 | + * | | | |
| 207 | + * Const(arr) Conditional |
| 208 | + * | / |
| 209 | + * LoadIndexed |
| 210 | + * |
| 211 | + * Replace with: |
| 212 | + * |
| 213 | + * cond arr[C1] arr[C2] |
| 214 | + * | | / |
| 215 | + * Conditional |
| 216 | + */ |
| 217 | + graph.replaceFixedWithFloating(this, graph.addOrUniqueWithInputs(ConditionalNode.create(conditional.condition(), trueVal, falseVal, NodeView.from(tool)))); |
| 218 | + } else if (trueVal != null || falseVal != null) { |
| 219 | + /*- |
| 220 | + * Just one conditional input is constant. |
| 221 | + * |
| 222 | + * cond C1 var |
| 223 | + * | | | |
| 224 | + * Const(arr) Conditional |
| 225 | + * | / |
| 226 | + * LoadIndexed |
| 227 | + * |
| 228 | + * Replace with control flow: |
| 229 | + * cond |
| 230 | + * \ |
| 231 | + * if arr var |
| 232 | + * / \ | / |
| 233 | + * | LoadIndexed----------- |
| 234 | + * \ / | |
| 235 | + * Merge -- Phi (arr[C1], . ) |
| 236 | + */ |
| 237 | + boolean trueValConstant = trueVal != null; |
| 238 | + var lastState = GraphUtil.findLastFrameState(this); |
| 239 | + IfNode ifNode = graph.add(new IfNode(conditional.condition(), graph.add(new BeginNode()), graph.add(new BeginNode()), ProfileData.BranchProbabilityData.unknown())); |
| 240 | + this.replaceAtPredecessor(ifNode); |
| 241 | + |
| 242 | + var trueEnd = graph.add(new EndNode()); |
| 243 | + var falseEnd = graph.add(new EndNode()); |
| 244 | + graph.addAfterFixed(ifNode.trueSuccessor(), trueEnd); |
| 245 | + graph.addAfterFixed(ifNode.falseSuccessor(), falseEnd); |
| 246 | + var merge = graph.add(new MergeNode()); |
| 247 | + merge.addForwardEnd(trueEnd); |
| 248 | + merge.addForwardEnd(falseEnd); |
| 249 | + |
| 250 | + FrameState state = lastState == null ? null : lastState.duplicateWithVirtualState(); |
| 251 | + merge.setStateAfter(state); |
| 252 | + |
| 253 | + var nonConstantIndex = trueValConstant ? conditional.falseValue() : conditional.trueValue(); |
| 254 | + var newLoad = graph.add(LoadIndexedNode.create(graph.getAssumptions(), array(), nonConstantIndex, |
| 255 | + getBoundsCheck(), elementKind(), tool.getMetaAccess(), tool.getConstantReflection())); |
| 256 | + assert newLoad instanceof LoadIndexedNode : "Unexpectedly folding LoadField to: " + newLoad; |
| 257 | + if (trueValConstant) { |
| 258 | + graph.addAfterFixed(ifNode.falseSuccessor(), (FixedNode) newLoad); |
| 259 | + falseVal = newLoad; |
| 260 | + } else { |
| 261 | + graph.addAfterFixed(ifNode.trueSuccessor(), (FixedNode) newLoad); |
| 262 | + trueVal = newLoad; |
| 263 | + } |
| 264 | + this.replaceAtUsages(graph.addOrUniqueWithInputs((new ValuePhiNode(this.stamp, merge, trueVal, falseVal)))); |
| 265 | + graph.replaceFixed(this, merge); |
| 266 | + } |
| 267 | + } |
184 | 268 | } |
185 | 269 |
|
186 | 270 | public static ValueNode tryConstantFold(ValueNode array, ValueNode index, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { |
|
0 commit comments