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