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