1 /* 2 * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.core.gen; 26 27 import static jdk.vm.ci.code.ValueUtil.asRegister; 28 import static jdk.vm.ci.code.ValueUtil.isLegal; 29 import static jdk.vm.ci.code.ValueUtil.isRegister; 30 import static org.graalvm.compiler.core.common.GraalOptions.MatchExpressions; 31 import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.AllTargets; 32 import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.Options.MitigateSpeculativeExecutionAttacks; 33 import static org.graalvm.compiler.debug.DebugOptions.LogVerbose; 34 import static org.graalvm.compiler.lir.LIR.verifyBlock; 35 36 import java.util.ArrayList; 37 import java.util.Collection; 38 import java.util.List; 39 40 import jdk.internal.vm.compiler.collections.EconomicMap; 41 import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor; 42 import org.graalvm.compiler.core.common.LIRKind; 43 import org.graalvm.compiler.core.common.calc.Condition; 44 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 45 import org.graalvm.compiler.core.common.cfg.BlockMap; 46 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 47 import org.graalvm.compiler.core.common.type.Stamp; 48 import org.graalvm.compiler.core.match.ComplexMatchValue; 49 import org.graalvm.compiler.core.match.MatchPattern; 50 import org.graalvm.compiler.core.match.MatchRuleRegistry; 51 import org.graalvm.compiler.core.match.MatchStatement; 52 import org.graalvm.compiler.debug.DebugCloseable; 53 import org.graalvm.compiler.debug.DebugContext; 54 import org.graalvm.compiler.debug.GraalError; 55 import org.graalvm.compiler.debug.TTY; 56 import org.graalvm.compiler.graph.GraalGraphError; 57 import org.graalvm.compiler.graph.Node; 58 import org.graalvm.compiler.graph.NodeMap; 59 import org.graalvm.compiler.graph.NodeSourcePosition; 60 import org.graalvm.compiler.graph.iterators.NodeIterable; 61 import org.graalvm.compiler.lir.FullInfopointOp; 62 import org.graalvm.compiler.lir.LIRFrameState; 63 import org.graalvm.compiler.lir.LIRInstruction; 64 import org.graalvm.compiler.lir.LabelRef; 65 import org.graalvm.compiler.lir.StandardOp.JumpOp; 66 import org.graalvm.compiler.lir.StandardOp.LabelOp; 67 import org.graalvm.compiler.lir.SwitchStrategy; 68 import org.graalvm.compiler.lir.Variable; 69 import org.graalvm.compiler.lir.debug.LIRGenerationDebugContext; 70 import org.graalvm.compiler.lir.framemap.FrameMapBuilder; 71 import org.graalvm.compiler.lir.gen.LIRGenerator; 72 import org.graalvm.compiler.lir.gen.LIRGenerator.Options; 73 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 74 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.BlockScope; 75 import org.graalvm.compiler.nodes.AbstractBeginNode; 76 import org.graalvm.compiler.nodes.AbstractEndNode; 77 import org.graalvm.compiler.nodes.AbstractMergeNode; 78 import org.graalvm.compiler.nodes.DeoptimizingNode; 79 import org.graalvm.compiler.nodes.DirectCallTargetNode; 80 import org.graalvm.compiler.nodes.FixedNode; 81 import org.graalvm.compiler.nodes.FrameState; 82 import org.graalvm.compiler.nodes.FullInfopointNode; 83 import org.graalvm.compiler.nodes.IfNode; 84 import org.graalvm.compiler.nodes.IndirectCallTargetNode; 85 import org.graalvm.compiler.nodes.Invoke; 86 import org.graalvm.compiler.nodes.InvokeWithExceptionNode; 87 import org.graalvm.compiler.nodes.LogicConstantNode; 88 import org.graalvm.compiler.nodes.LogicNode; 89 import org.graalvm.compiler.nodes.LoopEndNode; 90 import org.graalvm.compiler.nodes.LoweredCallTargetNode; 91 import org.graalvm.compiler.nodes.NodeView; 92 import org.graalvm.compiler.nodes.ParameterNode; 93 import org.graalvm.compiler.nodes.PhiNode; 94 import org.graalvm.compiler.nodes.StructuredGraph; 95 import org.graalvm.compiler.nodes.ValueNode; 96 import org.graalvm.compiler.nodes.ValuePhiNode; 97 import org.graalvm.compiler.nodes.calc.CompareNode; 98 import org.graalvm.compiler.nodes.calc.ConditionalNode; 99 import org.graalvm.compiler.nodes.calc.IntegerTestNode; 100 import org.graalvm.compiler.nodes.calc.IsNullNode; 101 import org.graalvm.compiler.nodes.cfg.Block; 102 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 103 import org.graalvm.compiler.nodes.extended.ForeignCall; 104 import org.graalvm.compiler.nodes.extended.ForeignCallWithExceptionNode; 105 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; 106 import org.graalvm.compiler.nodes.extended.SwitchNode; 107 import org.graalvm.compiler.nodes.spi.LIRLowerable; 108 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 109 import org.graalvm.compiler.nodes.spi.NodeValueMap; 110 import org.graalvm.compiler.nodes.spi.NodeWithState; 111 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 112 import org.graalvm.compiler.options.OptionValues; 113 114 import jdk.vm.ci.code.CallingConvention; 115 import jdk.vm.ci.code.StackSlot; 116 import jdk.vm.ci.code.ValueUtil; 117 import jdk.vm.ci.meta.AllocatableValue; 118 import jdk.vm.ci.meta.Constant; 119 import jdk.vm.ci.meta.JavaConstant; 120 import jdk.vm.ci.meta.JavaKind; 121 import jdk.vm.ci.meta.PlatformKind; 122 import jdk.vm.ci.meta.Value; 123 124 /** 125 * This class traverses the HIR instructions and generates LIR instructions from them. 126 */ 127 public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGenerationDebugContext { 128 129 private final NodeMap<Value> nodeOperands; 130 private final DebugInfoBuilder debugInfoBuilder; 131 private final int traceLIRGeneratorLevel; 132 133 protected final LIRGenerator gen; 134 135 private ValueNode currentInstruction; 136 private ValueNode lastInstructionPrinted; // Debugging only 137 138 private final NodeMatchRules nodeMatchRules; 139 private EconomicMap<Class<? extends Node>, List<MatchStatement>> matchRules; 140 NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, NodeMatchRules nodeMatchRules)141 public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, NodeMatchRules nodeMatchRules) { 142 this.gen = (LIRGenerator) gen; 143 this.nodeMatchRules = nodeMatchRules; 144 this.nodeOperands = graph.createNodeMap(); 145 this.debugInfoBuilder = createDebugInfoBuilder(graph, this); 146 OptionValues options = graph.getOptions(); 147 if (MatchExpressions.getValue(options)) { 148 matchRules = MatchRuleRegistry.lookup(nodeMatchRules.getClass(), options, graph.getDebug()); 149 } 150 traceLIRGeneratorLevel = TTY.isSuppressed() ? 0 : Options.TraceLIRGeneratorLevel.getValue(options); 151 152 assert nodeMatchRules.lirBuilder == null; 153 nodeMatchRules.lirBuilder = this; 154 } 155 getNodeMatchRules()156 public NodeMatchRules getNodeMatchRules() { 157 return nodeMatchRules; 158 } 159 createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap)160 protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) { 161 return new DebugInfoBuilder(nodeValueMap, gen.getProviders().getMetaAccessExtensionProvider(), graph.getDebug()); 162 } 163 164 /** 165 * Returns the operand that has been previously initialized by 166 * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code 167 * generation error to ask for the operand of ValueNode that doesn't have one yet. 168 * 169 * @param node A node that produces a result value. 170 */ 171 @Override operand(Node node)172 public Value operand(Node node) { 173 Value operand = getOperand(node); 174 assert operand != null : String.format("missing operand for %1s", node); 175 return operand; 176 } 177 178 @Override hasOperand(Node node)179 public boolean hasOperand(Node node) { 180 return getOperand(node) != null; 181 } 182 getOperand(Node node)183 private Value getOperand(Node node) { 184 if (nodeOperands == null) { 185 return null; 186 } 187 return nodeOperands.get(node); 188 } 189 190 @Override valueForOperand(Value value)191 public ValueNode valueForOperand(Value value) { 192 assert nodeOperands != null; 193 UnmodifiableMapCursor<Node, Value> cursor = nodeOperands.getEntries(); 194 while (cursor.advance()) { 195 if (cursor.getValue().equals(value)) { 196 return (ValueNode) cursor.getKey(); 197 } 198 } 199 return null; 200 } 201 202 @Override getSourceForOperand(Value value)203 public Object getSourceForOperand(Value value) { 204 return valueForOperand(value); 205 } 206 207 @Override setResult(ValueNode x, Value operand)208 public Value setResult(ValueNode x, Value operand) { 209 assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable()); 210 assert nodeOperands != null && (nodeOperands.get(x) == null || nodeOperands.get(x) instanceof ComplexMatchValue) : "operand cannot be set twice"; 211 assert operand != null && isLegal(operand) : "operand must be legal"; 212 assert !(x instanceof VirtualObjectNode); 213 nodeOperands.set(x, operand); 214 return operand; 215 } 216 217 /** 218 * Used by the {@link MatchStatement} machinery to override the generation LIR for some 219 * ValueNodes. 220 */ setMatchResult(Node x, Value operand)221 public void setMatchResult(Node x, Value operand) { 222 assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue; 223 assert operand instanceof ComplexMatchValue || MatchPattern.isSingleValueUser(x) : "interior matches must be single user"; 224 assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice"; 225 assert !(x instanceof VirtualObjectNode); 226 nodeOperands.set(x, operand); 227 } 228 getLIRBlock(FixedNode b)229 public LabelRef getLIRBlock(FixedNode b) { 230 assert gen.getResult().getLIR().getControlFlowGraph() instanceof ControlFlowGraph; 231 Block result = ((ControlFlowGraph) gen.getResult().getLIR().getControlFlowGraph()).blockFor(b); 232 int suxIndex = 0; 233 for (AbstractBlockBase<?> succ : gen.getCurrentBlock().getSuccessors()) { 234 if (succ == result) { 235 assert gen.getCurrentBlock() instanceof Block; 236 return LabelRef.forSuccessor(gen.getResult().getLIR(), gen.getCurrentBlock(), suxIndex); 237 } 238 suxIndex++; 239 } 240 throw GraalError.shouldNotReachHere("Block not in successor list of current block"); 241 } 242 append(LIRInstruction op)243 public final void append(LIRInstruction op) { 244 if (Options.PrintIRWithLIR.getValue(nodeOperands.graph().getOptions()) && !TTY.isSuppressed()) { 245 if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { 246 lastInstructionPrinted = currentInstruction; 247 InstructionPrinter ip = new InstructionPrinter(TTY.out()); 248 ip.printInstructionListing(currentInstruction); 249 } 250 } 251 gen.append(op); 252 } 253 getExactPhiKind(PhiNode phi)254 protected LIRKind getExactPhiKind(PhiNode phi) { 255 LIRKind derivedKind = gen.toRegisterKind(gen.getLIRKind(phi.stamp(NodeView.DEFAULT))); 256 /* Collect reference information. */ 257 for (int i = 0; i < phi.valueCount() && !derivedKind.isUnknownReference(); i++) { 258 ValueNode node = phi.valueAt(i); 259 Value value = getOperand(node); 260 261 // get ValueKind for input 262 final LIRKind valueKind; 263 if (value != null && !(value instanceof ComplexMatchValue)) { 264 valueKind = value.getValueKind(LIRKind.class); 265 } else { 266 assert isPhiInputFromBackedge(phi, i) : String.format("Input %s to phi node %s is not yet available although it is not coming from a loop back edge", node, phi); 267 LIRKind kind = gen.getLIRKind(node.stamp(NodeView.DEFAULT)); 268 valueKind = gen.toRegisterKind(kind); 269 } 270 /* Merge the reference information of the derived kind and the input. */ 271 derivedKind = LIRKind.mergeReferenceInformation(derivedKind, valueKind); 272 } 273 return derivedKind; 274 } 275 isPhiInputFromBackedge(PhiNode phi, int index)276 private static boolean isPhiInputFromBackedge(PhiNode phi, int index) { 277 AbstractMergeNode merge = phi.merge(); 278 AbstractEndNode end = merge.phiPredecessorAt(index); 279 return end instanceof LoopEndNode && ((LoopEndNode) end).loopBegin().equals(merge); 280 } 281 createPhiIn(AbstractMergeNode merge)282 private Value[] createPhiIn(AbstractMergeNode merge) { 283 List<Value> values = new ArrayList<>(); 284 for (ValuePhiNode phi : merge.valuePhis()) { 285 assert getOperand(phi) == null; 286 Variable value = gen.newVariable(getExactPhiKind(phi)); 287 values.add(value); 288 setResult(phi, value); 289 } 290 return values.toArray(new Value[values.size()]); 291 } 292 createPhiOut(AbstractMergeNode merge, AbstractEndNode pred)293 private Value[] createPhiOut(AbstractMergeNode merge, AbstractEndNode pred) { 294 List<Value> values = new ArrayList<>(); 295 for (PhiNode phi : merge.valuePhis()) { 296 ValueNode node = phi.valueAt(pred); 297 Value value = operand(node); 298 assert value != null; 299 if (isRegister(value)) { 300 /* 301 * Fixed register intervals are not allowed at block boundaries so we introduce a 302 * new Variable. 303 */ 304 value = gen.emitMove(value); 305 } else if (node.isConstant() && !gen.getSpillMoveFactory().allowConstantToStackMove(node.asConstant()) && !LIRKind.isValue(value)) { 306 /* 307 * Some constants are not allowed as inputs for PHIs in certain backends. Explicitly 308 * create a copy of this value to force it into a register. The new variable is only 309 * used in the PHI. 310 */ 311 Variable result = gen.newVariable(value.getValueKind()); 312 gen.emitMove(result, value); 313 value = result; 314 } 315 values.add(value); 316 } 317 return values.toArray(new Value[values.size()]); 318 } 319 doBlockPrologue(@uppressWarningsR) Block block, @SuppressWarnings(R) OptionValues options)320 public void doBlockPrologue(@SuppressWarnings("unused") Block block, @SuppressWarnings("unused") OptionValues options) { 321 322 if (MitigateSpeculativeExecutionAttacks.getValue(options) == AllTargets) { 323 boolean hasControlSplitPredecessor = false; 324 for (Block b : block.getPredecessors()) { 325 if (b.getSuccessorCount() > 1) { 326 hasControlSplitPredecessor = true; 327 break; 328 } 329 } 330 boolean isStartBlock = block.getPredecessorCount() == 0; 331 if (hasControlSplitPredecessor || isStartBlock) { 332 getLIRGeneratorTool().emitSpeculationFence(); 333 } 334 } 335 } 336 337 @Override 338 @SuppressWarnings("try") doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap)339 public void doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap) { 340 341 OptionValues options = graph.getOptions(); 342 try (BlockScope blockScope = gen.getBlockScope(block)) { 343 setSourcePosition(null); 344 345 if (block == gen.getResult().getLIR().getControlFlowGraph().getStartBlock()) { 346 assert block.getPredecessorCount() == 0; 347 emitPrologue(graph); 348 } else { 349 assert block.getPredecessorCount() > 0; 350 // create phi-in value array 351 AbstractBeginNode begin = block.getBeginNode(); 352 if (begin instanceof AbstractMergeNode) { 353 AbstractMergeNode merge = (AbstractMergeNode) begin; 354 LabelOp label = (LabelOp) gen.getResult().getLIR().getLIRforBlock(block).get(0); 355 label.setPhiValues(createPhiIn(merge)); 356 if (Options.PrintIRWithLIR.getValue(options) && !TTY.isSuppressed()) { 357 TTY.println("Created PhiIn: " + label); 358 359 } 360 } 361 } 362 doBlockPrologue(block, options); 363 364 List<Node> nodes = blockMap.get(block); 365 366 boolean trace = traceLIRGeneratorLevel >= 3; 367 for (int i = 0; i < nodes.size(); i++) { 368 Node node = nodes.get(i); 369 if (node instanceof ValueNode) { 370 setSourcePosition(node.getNodeSourcePosition()); 371 DebugContext debug = node.getDebug(); 372 ValueNode valueNode = (ValueNode) node; 373 if (trace) { 374 TTY.println("LIRGen for " + valueNode); 375 } 376 Value operand = getOperand(valueNode); 377 if (operand == null) { 378 if (!peephole(valueNode)) { 379 try { 380 doRoot(valueNode); 381 } catch (GraalError e) { 382 throw GraalGraphError.transformAndAddContext(e, valueNode); 383 } catch (Throwable e) { 384 throw new GraalGraphError(e).addContext(valueNode); 385 } 386 } 387 } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) { 388 // Doesn't need to be evaluated 389 debug.log("interior match for %s", valueNode); 390 } else if (operand instanceof ComplexMatchValue) { 391 debug.log("complex match for %s", valueNode); 392 // Set current position to the position of the root matched node. 393 setSourcePosition(node.getNodeSourcePosition()); 394 ComplexMatchValue match = (ComplexMatchValue) operand; 395 operand = match.evaluate(this); 396 if (operand != null) { 397 setResult(valueNode, operand); 398 } 399 } else { 400 // There can be cases in which the result of an instruction is already set 401 // before by other instructions. 402 } 403 } 404 } 405 406 if (!gen.hasBlockEnd(block)) { 407 NodeIterable<Node> successors = block.getEndNode().successors(); 408 assert successors.count() == block.getSuccessorCount(); 409 if (block.getSuccessorCount() != 1) { 410 /* 411 * If we have more than one successor, we cannot just use the first one. Since 412 * successors are unordered, this would be a random choice. 413 */ 414 throw new GraalError("Block without BlockEndOp: " + block.getEndNode()); 415 } 416 gen.emitJump(getLIRBlock((FixedNode) successors.first())); 417 } 418 419 assert verifyBlock(gen.getResult().getLIR(), block); 420 } 421 } 422 423 @SuppressWarnings("try") matchBlock(Block block, StructuredGraph.ScheduleResult schedule)424 public void matchBlock(Block block, StructuredGraph.ScheduleResult schedule) { 425 try (DebugCloseable matchScope = gen.getMatchScope(block)) { 426 // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups 427 // of instructions 428 matchComplexExpressions(block, schedule); 429 } 430 } 431 432 @SuppressWarnings("try") matchComplexExpressions(Block block, StructuredGraph.ScheduleResult schedule)433 protected void matchComplexExpressions(Block block, StructuredGraph.ScheduleResult schedule) { 434 435 if (matchRules != null) { 436 DebugContext debug = gen.getResult().getLIR().getDebug(); 437 try (DebugContext.Scope s = debug.scope("MatchComplexExpressions")) { 438 List<Node> nodes = schedule.getBlockToNodesMap().get(block); 439 if (LogVerbose.getValue(nodeOperands.graph().getOptions())) { 440 int i = 0; 441 for (Node node : nodes) { 442 debug.log("%d: (%s) %1S", i++, node.getUsageCount(), node); 443 } 444 } 445 446 // Match the nodes in backwards order to encourage longer matches. 447 for (int index = nodes.size() - 1; index >= 0; index--) { 448 Node node = nodes.get(index); 449 if (getOperand(node) != null) { 450 continue; 451 } 452 // See if this node is the root of any MatchStatements 453 List<MatchStatement> statements = matchRules.get(node.getClass()); 454 if (statements != null) { 455 for (MatchStatement statement : statements) { 456 if (statement.generate(this, index, node, block, schedule)) { 457 // Found a match so skip to the next 458 break; 459 } 460 } 461 } 462 } 463 } 464 } 465 } 466 peephole(ValueNode valueNode)467 protected abstract boolean peephole(ValueNode valueNode); 468 doRoot(ValueNode instr)469 private void doRoot(ValueNode instr) { 470 if (traceLIRGeneratorLevel >= 2) { 471 TTY.println("Emitting LIR for instruction " + instr); 472 } 473 currentInstruction = instr; 474 DebugContext debug = instr.getDebug(); 475 debug.log("Visiting %s", instr); 476 emitNode(instr); 477 debug.log("Operand for %s = %s", instr, getOperand(instr)); 478 } 479 emitNode(ValueNode node)480 protected void emitNode(ValueNode node) { 481 if (node.getDebug().isLogEnabled() && node.stamp(NodeView.DEFAULT).isEmpty()) { 482 node.getDebug().log("This node has an empty stamp, we are emitting dead code(?): %s", node); 483 } 484 if (node instanceof LIRLowerable) { 485 ((LIRLowerable) node).generate(this); 486 } else { 487 throw GraalError.shouldNotReachHere("node is not LIRLowerable: " + node); 488 } 489 } 490 emitPrologue(StructuredGraph graph)491 protected void emitPrologue(StructuredGraph graph) { 492 CallingConvention incomingArguments = gen.getResult().getCallingConvention(); 493 494 Value[] params = new Value[incomingArguments.getArgumentCount()]; 495 for (int i = 0; i < params.length; i++) { 496 params[i] = incomingArguments.getArgument(i); 497 if (ValueUtil.isStackSlot(params[i])) { 498 StackSlot slot = ValueUtil.asStackSlot(params[i]); 499 if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) { 500 gen.getResult().getLIR().setHasArgInCallerFrame(); 501 } 502 } 503 } 504 505 gen.emitIncomingValues(params); 506 507 for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { 508 Value paramValue = params[param.index()]; 509 assert paramValue.getValueKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp(NodeView.DEFAULT))) : paramValue + " " + 510 getLIRGeneratorTool().getLIRKind(param.stamp(NodeView.DEFAULT)); 511 setResult(param, gen.emitMove(paramValue)); 512 } 513 } 514 515 @Override visitMerge(AbstractMergeNode x)516 public void visitMerge(AbstractMergeNode x) { 517 } 518 519 @Override visitEndNode(AbstractEndNode end)520 public void visitEndNode(AbstractEndNode end) { 521 AbstractMergeNode merge = end.merge(); 522 JumpOp jump = newJumpOp(getLIRBlock(merge)); 523 jump.setPhiValues(createPhiOut(merge, end)); 524 append(jump); 525 } 526 527 /** 528 * Runtime specific classes can override this to insert a safepoint at the end of a loop. 529 */ 530 @Override visitLoopEnd(LoopEndNode x)531 public void visitLoopEnd(LoopEndNode x) { 532 } 533 newJumpOp(LabelRef ref)534 protected JumpOp newJumpOp(LabelRef ref) { 535 return new JumpOp(ref); 536 } 537 getPhiKind(PhiNode phi)538 protected LIRKind getPhiKind(PhiNode phi) { 539 return gen.getLIRKind(phi.stamp(NodeView.DEFAULT)); 540 } 541 542 @Override emitIf(IfNode x)543 public void emitIf(IfNode x) { 544 emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor())); 545 } 546 emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability)547 public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { 548 if (node instanceof IsNullNode) { 549 LIRKind kind = gen.getLIRKind(((IsNullNode) node).getValue().stamp(NodeView.DEFAULT)); 550 Value nullValue = gen.emitConstant(kind, ((IsNullNode) node).nullConstant()); 551 gen.emitCompareBranch(kind.getPlatformKind(), operand(((IsNullNode) node).getValue()), nullValue, Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability); 552 } else if (node instanceof CompareNode) { 553 PlatformKind kind = gen.getLIRKind(((CompareNode) node).getX().stamp(NodeView.DEFAULT)).getPlatformKind(); 554 gen.emitCompareBranch(kind, operand(((CompareNode) node).getX()), operand(((CompareNode) node).getY()), ((CompareNode) node).condition().asCondition(), 555 ((CompareNode) node).unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability); 556 } else if (node instanceof LogicConstantNode) { 557 gen.emitJump(((LogicConstantNode) node).getValue() ? trueSuccessor : falseSuccessor); 558 } else if (node instanceof IntegerTestNode) { 559 gen.emitIntegerTestBranch(operand(((IntegerTestNode) node).getX()), operand(((IntegerTestNode) node).getY()), trueSuccessor, falseSuccessor, trueSuccessorProbability); 560 } else { 561 throw GraalError.unimplemented(node.toString()); 562 } 563 } 564 565 @Override emitConditional(ConditionalNode conditional)566 public void emitConditional(ConditionalNode conditional) { 567 Value tVal = operand(conditional.trueValue()); 568 Value fVal = operand(conditional.falseValue()); 569 setResult(conditional, emitConditional(conditional.condition(), tVal, fVal)); 570 } 571 emitConditional(LogicNode node, Value trueValue, Value falseValue)572 public Variable emitConditional(LogicNode node, Value trueValue, Value falseValue) { 573 if (node instanceof IsNullNode) { 574 IsNullNode isNullNode = (IsNullNode) node; 575 LIRKind kind = gen.getLIRKind(isNullNode.getValue().stamp(NodeView.DEFAULT)); 576 Value nullValue = gen.emitConstant(kind, isNullNode.nullConstant()); 577 return gen.emitConditionalMove(kind.getPlatformKind(), operand(isNullNode.getValue()), nullValue, Condition.EQ, false, trueValue, falseValue); 578 } else if (node instanceof CompareNode) { 579 CompareNode compare = (CompareNode) node; 580 PlatformKind kind = gen.getLIRKind(compare.getX().stamp(NodeView.DEFAULT)).getPlatformKind(); 581 return gen.emitConditionalMove(kind, operand(compare.getX()), operand(compare.getY()), compare.condition().asCondition(), compare.unorderedIsTrue(), trueValue, falseValue); 582 } else if (node instanceof LogicConstantNode) { 583 return gen.emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue); 584 } else if (node instanceof IntegerTestNode) { 585 IntegerTestNode test = (IntegerTestNode) node; 586 return gen.emitIntegerTestMove(operand(test.getX()), operand(test.getY()), trueValue, falseValue); 587 } else { 588 throw GraalError.unimplemented(node.toString()); 589 } 590 } 591 592 @Override emitInvoke(Invoke x)593 public void emitInvoke(Invoke x) { 594 LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget(); 595 FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); 596 CallingConvention invokeCc = frameMapBuilder.getRegisterConfig().getCallingConvention(callTarget.callType(), x.asNode().stamp(NodeView.DEFAULT).javaType(gen.getMetaAccess()), 597 callTarget.signature(), gen); 598 frameMapBuilder.callsMethod(invokeCc); 599 600 Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments()); 601 602 LabelRef exceptionEdge = null; 603 if (x instanceof InvokeWithExceptionNode) { 604 exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()); 605 } 606 LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge); 607 608 Value result = invokeCc.getReturn(); 609 if (callTarget instanceof DirectCallTargetNode) { 610 emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); 611 } else if (callTarget instanceof IndirectCallTargetNode) { 612 emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); 613 } else { 614 throw GraalError.shouldNotReachHere(); 615 } 616 617 if (isLegal(result)) { 618 setResult(x.asNode(), gen.emitMove(result)); 619 } 620 621 if (x instanceof InvokeWithExceptionNode) { 622 gen.emitJump(getLIRBlock(((InvokeWithExceptionNode) x).next())); 623 } 624 } 625 626 @Override emitForeignCall(ForeignCall x)627 public void emitForeignCall(ForeignCall x) { 628 ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(x.getDescriptor()); 629 630 LabelRef exceptionEdge = null; 631 if (x instanceof ForeignCallWithExceptionNode) { 632 exceptionEdge = getLIRBlock(((ForeignCallWithExceptionNode) x).exceptionEdge()); 633 } 634 LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge); 635 636 Value[] args = x.operands(this); 637 638 Value result = gen.emitForeignCall(linkage, callState, args); 639 if (result != null) { 640 setResult(x.asNode(), result); 641 } 642 643 if (x instanceof ForeignCallWithExceptionNode) { 644 gen.emitJump(getLIRBlock(((ForeignCallWithExceptionNode) x).next())); 645 } 646 } 647 emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState)648 protected abstract void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); 649 emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState)650 protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); 651 visitInvokeArguments(CallingConvention invokeCc, Collection<ValueNode> arguments)652 public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection<ValueNode> arguments) { 653 // for each argument, load it into the correct location 654 Value[] result = new Value[arguments.size()]; 655 int j = 0; 656 for (ValueNode arg : arguments) { 657 if (arg != null) { 658 AllocatableValue operand = invokeCc.getArgument(j); 659 gen.emitMove(operand, operand(arg)); 660 result[j] = operand; 661 j++; 662 } else { 663 throw GraalError.shouldNotReachHere("I thought we no longer have null entries for two-slot types..."); 664 } 665 } 666 return result; 667 } 668 669 /** 670 * This method tries to create a switch implementation that is optimal for the given switch. It 671 * will either generate a sequential if/then/else cascade, a set of range tests or a table 672 * switch. 673 * 674 * If the given switch does not contain int keys, it will always create a sequential 675 * implementation. 676 */ 677 @Override emitSwitch(SwitchNode x)678 public void emitSwitch(SwitchNode x) { 679 assert x.defaultSuccessor() != null; 680 LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor()); 681 int keyCount = x.keyCount(); 682 if (keyCount == 0) { 683 gen.emitJump(defaultTarget); 684 } else { 685 Variable value = gen.load(operand(x.value())); 686 if (keyCount == 1) { 687 assert defaultTarget != null; 688 double probability = x.probability(x.keySuccessor(0)); 689 LIRKind kind = gen.getLIRKind(x.value().stamp(NodeView.DEFAULT)); 690 Value key = gen.emitConstant(kind, x.keyAt(0)); 691 gen.emitCompareBranch(kind.getPlatformKind(), gen.load(operand(x.value())), key, Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability); 692 } else if (x instanceof IntegerSwitchNode && x.isSorted()) { 693 IntegerSwitchNode intSwitch = (IntegerSwitchNode) x; 694 LabelRef[] keyTargets = new LabelRef[keyCount]; 695 JavaConstant[] keyConstants = new JavaConstant[keyCount]; 696 double[] keyProbabilities = new double[keyCount]; 697 JavaKind keyKind = intSwitch.keyAt(0).getJavaKind(); 698 for (int i = 0; i < keyCount; i++) { 699 keyTargets[i] = getLIRBlock(intSwitch.keySuccessor(i)); 700 keyConstants[i] = intSwitch.keyAt(i); 701 keyProbabilities[i] = intSwitch.keyProbability(i); 702 assert keyConstants[i].getJavaKind() == keyKind; 703 } 704 gen.emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value); 705 } else { 706 // keyKind != JavaKind.Int || !x.isSorted() 707 LabelRef[] keyTargets = new LabelRef[keyCount]; 708 Constant[] keyConstants = new Constant[keyCount]; 709 double[] keyProbabilities = new double[keyCount]; 710 for (int i = 0; i < keyCount; i++) { 711 keyTargets[i] = getLIRBlock(x.keySuccessor(i)); 712 keyConstants[i] = x.keyAt(i); 713 keyProbabilities[i] = x.keyProbability(i); 714 } 715 716 // hopefully only a few entries 717 gen.emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget); 718 } 719 } 720 } 721 getDebugInfoBuilder()722 public DebugInfoBuilder getDebugInfoBuilder() { 723 assert debugInfoBuilder != null; 724 return debugInfoBuilder; 725 } 726 getFrameState(DeoptimizingNode deopt)727 private static FrameState getFrameState(DeoptimizingNode deopt) { 728 if (deopt instanceof DeoptimizingNode.DeoptBefore) { 729 assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter); 730 return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore(); 731 } else if (deopt instanceof DeoptimizingNode.DeoptDuring) { 732 assert !(deopt instanceof DeoptimizingNode.DeoptAfter); 733 return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring(); 734 } else { 735 assert deopt instanceof DeoptimizingNode.DeoptAfter; 736 return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter(); 737 } 738 } 739 740 @Override state(DeoptimizingNode deopt)741 public LIRFrameState state(DeoptimizingNode deopt) { 742 if (!deopt.canDeoptimize()) { 743 return null; 744 } 745 return stateFor(deopt, getFrameState(deopt)); 746 } 747 stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge)748 public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) { 749 if (!deopt.canDeoptimize()) { 750 return null; 751 } 752 return stateForWithExceptionEdge(deopt, getFrameState(deopt), exceptionEdge); 753 } 754 stateFor(NodeWithState deopt, FrameState state)755 public LIRFrameState stateFor(NodeWithState deopt, FrameState state) { 756 return stateForWithExceptionEdge(deopt, state, null); 757 } 758 stateForWithExceptionEdge(NodeWithState deopt, FrameState state, LabelRef exceptionEdge)759 public LIRFrameState stateForWithExceptionEdge(NodeWithState deopt, FrameState state, LabelRef exceptionEdge) { 760 if (gen.needOnlyOopMaps()) { 761 return new LIRFrameState(null, null, null); 762 } 763 assert state != null : "Deopt node=" + deopt + " needs a state "; 764 return getDebugInfoBuilder().build(deopt, state, exceptionEdge); 765 } 766 767 @Override emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, Stamp stamp, double probability)768 public void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, Stamp stamp, double probability) { 769 LIRKind cmpKind = getLIRGeneratorTool().getLIRKind(stamp); 770 gen.emitOverflowCheckBranch(getLIRBlock(overflowSuccessor), getLIRBlock(next), cmpKind, probability); 771 } 772 773 @Override visitFullInfopointNode(FullInfopointNode i)774 public void visitFullInfopointNode(FullInfopointNode i) { 775 append(new FullInfopointOp(stateFor(i, i.getState()), i.getReason())); 776 } 777 setSourcePosition(NodeSourcePosition position)778 private void setSourcePosition(NodeSourcePosition position) { 779 gen.setSourcePosition(position); 780 } 781 782 @Override getLIRGeneratorTool()783 public LIRGenerator getLIRGeneratorTool() { 784 return gen; 785 } 786 787 @Override emitReadExceptionObject(ValueNode node)788 public void emitReadExceptionObject(ValueNode node) { 789 LIRGenerator lirGenTool = getLIRGeneratorTool(); 790 Value returnRegister = lirGenTool.getRegisterConfig().getReturnRegister(node.getStackKind()).asValue( 791 LIRKind.fromJavaKind(lirGenTool.target().arch, node.getStackKind())); 792 lirGenTool.emitIncomingValues(new Value[]{returnRegister}); 793 setResult(node, lirGenTool.emitMove(returnRegister)); 794 } 795 } 796