001/* 002 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.compiler.gen; 024 025import static com.oracle.graal.compiler.common.BackendOptions.*; 026import static com.oracle.graal.compiler.common.GraalOptions.*; 027import static com.oracle.graal.lir.LIR.*; 028import static jdk.internal.jvmci.code.ValueUtil.*; 029import static com.oracle.graal.debug.GraalDebugConfig.*; 030 031import java.util.*; 032import java.util.Map.Entry; 033 034import jdk.internal.jvmci.code.*; 035import jdk.internal.jvmci.common.*; 036import com.oracle.graal.debug.*; 037import com.oracle.graal.debug.Debug.*; 038 039import jdk.internal.jvmci.meta.*; 040 041import com.oracle.graal.compiler.common.calc.*; 042import com.oracle.graal.compiler.common.cfg.*; 043import com.oracle.graal.compiler.common.type.*; 044import com.oracle.graal.compiler.match.*; 045import com.oracle.graal.graph.*; 046import com.oracle.graal.lir.*; 047import com.oracle.graal.lir.StandardOp.JumpOp; 048import com.oracle.graal.lir.StandardOp.LabelOp; 049import com.oracle.graal.lir.debug.*; 050import com.oracle.graal.lir.gen.*; 051import com.oracle.graal.lir.gen.LIRGenerator.Options; 052import com.oracle.graal.lir.gen.LIRGeneratorTool.BlockScope; 053import com.oracle.graal.nodes.*; 054import com.oracle.graal.nodes.calc.*; 055import com.oracle.graal.nodes.cfg.*; 056import com.oracle.graal.nodes.extended.*; 057import com.oracle.graal.nodes.memory.*; 058import com.oracle.graal.nodes.spi.*; 059import com.oracle.graal.nodes.virtual.*; 060 061/** 062 * This class traverses the HIR instructions and generates LIR instructions from them. 063 */ 064@MatchableNode(nodeClass = ConstantNode.class, shareable = true) 065@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"}) 066@MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"address"}) 067@MatchableNode(nodeClass = IfNode.class, inputs = {"condition"}) 068@MatchableNode(nodeClass = SubNode.class, inputs = {"x", "y"}) 069@MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"}) 070@MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"}) 071@MatchableNode(nodeClass = ReadNode.class, inputs = {"address"}) 072@MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"}) 073@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"value"}) 074@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"}) 075@MatchableNode(nodeClass = WriteNode.class, inputs = {"address", "value"}) 076@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"}) 077@MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true) 078@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true) 079@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true) 080@MatchableNode(nodeClass = AddNode.class, inputs = {"x", "y"}, commutative = true) 081@MatchableNode(nodeClass = IntegerBelowNode.class, inputs = {"x", "y"}, commutative = true) 082@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = {"x", "y"}, commutative = true) 083@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = {"x", "y"}, commutative = true) 084@MatchableNode(nodeClass = MulNode.class, inputs = {"x", "y"}, commutative = true) 085@MatchableNode(nodeClass = IntegerTestNode.class, inputs = {"x", "y"}, commutative = true) 086@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = {"x", "y"}, commutative = true) 087@MatchableNode(nodeClass = OrNode.class, inputs = {"x", "y"}, commutative = true) 088@MatchableNode(nodeClass = XorNode.class, inputs = {"x", "y"}, commutative = true) 089@MatchableNode(nodeClass = PiNode.class, inputs = {"object"}) 090public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGenerationDebugContext { 091 092 private final NodeMap<Value> nodeOperands; 093 private final DebugInfoBuilder debugInfoBuilder; 094 095 protected final LIRGeneratorTool gen; 096 097 private ValueNode currentInstruction; 098 private ValueNode lastInstructionPrinted; // Debugging only 099 100 private Map<Class<? extends Node>, List<MatchStatement>> matchRules; 101 102 public NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen) { 103 this.gen = gen; 104 this.nodeOperands = graph.createNodeMap(); 105 this.debugInfoBuilder = createDebugInfoBuilder(graph, this); 106 if (MatchExpressions.getValue()) { 107 matchRules = MatchRuleRegistry.lookup(getClass()); 108 } 109 } 110 111 @SuppressWarnings({"unused"}) 112 protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) { 113 return new DebugInfoBuilder(nodeValueMap); 114 } 115 116 /** 117 * Returns the operand that has been previously initialized by 118 * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code 119 * generation error to ask for the operand of ValueNode that doesn't have one yet. 120 * 121 * @param node A node that produces a result value. 122 */ 123 @Override 124 public Value operand(Node node) { 125 Value operand = getOperand(node); 126 assert operand != null : String.format("missing operand for %1s", node); 127 return operand; 128 } 129 130 @Override 131 public boolean hasOperand(Node node) { 132 return getOperand(node) != null; 133 } 134 135 private Value getOperand(Node node) { 136 if (nodeOperands == null) { 137 return null; 138 } 139 return nodeOperands.get(node); 140 } 141 142 public ValueNode valueForOperand(Value value) { 143 assert nodeOperands != null; 144 for (Entry<Node, Value> entry : nodeOperands.entries()) { 145 if (entry.getValue().equals(value)) { 146 return (ValueNode) entry.getKey(); 147 } 148 } 149 return null; 150 } 151 152 @Override 153 public Object getSourceForOperand(Value value) { 154 return valueForOperand(value); 155 } 156 157 @Override 158 public Value setResult(ValueNode x, Value operand) { 159 assert (!isRegister(operand) || !gen.attributes(asRegister(operand)).isAllocatable()); 160 assert nodeOperands != null && (nodeOperands.get(x) == null || nodeOperands.get(x) instanceof ComplexMatchValue) : "operand cannot be set twice"; 161 assert operand != null && isLegal(operand) : "operand must be legal"; 162 assert !(x instanceof VirtualObjectNode); 163 nodeOperands.set(x, operand); 164 return operand; 165 } 166 167 /** 168 * Used by the {@link MatchStatement} machinery to override the generation LIR for some 169 * ValueNodes. 170 */ 171 public void setMatchResult(Node x, Value operand) { 172 assert operand.equals(ComplexMatchValue.INTERIOR_MATCH) || operand instanceof ComplexMatchValue; 173 assert operand instanceof ComplexMatchValue || x.getUsageCount() == 1 : "interior matches must be single user"; 174 assert nodeOperands != null && nodeOperands.get(x) == null : "operand cannot be set twice"; 175 assert !(x instanceof VirtualObjectNode); 176 nodeOperands.set(x, operand); 177 } 178 179 public LabelRef getLIRBlock(FixedNode b) { 180 assert gen.getResult().getLIR().getControlFlowGraph() instanceof ControlFlowGraph; 181 Block result = ((ControlFlowGraph) gen.getResult().getLIR().getControlFlowGraph()).blockFor(b); 182 int suxIndex = gen.getCurrentBlock().getSuccessors().indexOf(result); 183 assert suxIndex != -1 : "Block not in successor list of current block"; 184 185 assert gen.getCurrentBlock() instanceof Block; 186 return LabelRef.forSuccessor(gen.getResult().getLIR(), gen.getCurrentBlock(), suxIndex); 187 } 188 189 public final void append(LIRInstruction op) { 190 if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) { 191 if (currentInstruction != null && lastInstructionPrinted != currentInstruction) { 192 lastInstructionPrinted = currentInstruction; 193 InstructionPrinter ip = new InstructionPrinter(TTY.out()); 194 ip.printInstructionListing(currentInstruction); 195 } 196 } 197 gen.append(op); 198 } 199 200 protected LIRKind getExactPhiKind(PhiNode phi) { 201 // TODO (je): maybe turn this into generator-style instead of allocating an ArrayList. 202 ArrayList<LIRKind> values = new ArrayList<>(phi.valueCount()); 203 for (int i = 0; i < phi.valueCount(); i++) { 204 ValueNode node = phi.valueAt(i); 205 Value value = node instanceof ConstantNode ? ((ConstantNode) node).asJavaConstant() : getOperand(node); 206 if (value != null) { 207 values.add(value.getLIRKind()); 208 } else { 209 assert node instanceof ConstantNode || 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", 210 node, phi); 211 // non-java constant -> get Kind from stamp. 212 values.add(getLIRGeneratorTool().getLIRKind(node.stamp())); 213 } 214 } 215 LIRKind derivedKind = LIRKind.merge(values); 216 assert verifyPHIKind(derivedKind, gen.getLIRKind(phi.stamp())); 217 return derivedKind; 218 } 219 220 private static boolean verifyPHIKind(LIRKind derivedKind, LIRKind phiKind) { 221 assert derivedKind.getPlatformKind() != Kind.Object || !derivedKind.isUnknownReference(); 222 PlatformKind phiPlatformKind = phiKind.getPlatformKind(); 223 assert derivedKind.equals(phiKind) || derivedKind.getPlatformKind().equals(phiPlatformKind instanceof Kind ? ((Kind) phiPlatformKind).getStackKind() : phiPlatformKind); 224 return true; 225 } 226 227 private static boolean isPhiInputFromBackedge(PhiNode phi, int index) { 228 AbstractMergeNode merge = phi.merge(); 229 AbstractEndNode end = merge.phiPredecessorAt(index); 230 return end instanceof LoopEndNode && ((LoopEndNode) end).loopBegin().equals(merge); 231 } 232 233 private Value[] createPhiIn(AbstractMergeNode merge) { 234 List<Value> values = new ArrayList<>(); 235 for (ValuePhiNode phi : merge.valuePhis()) { 236 assert getOperand(phi) == null; 237 Variable value = gen.newVariable(getExactPhiKind(phi)); 238 values.add(value); 239 setResult(phi, value); 240 } 241 return values.toArray(new Value[values.size()]); 242 } 243 244 private Value[] createPhiOut(AbstractMergeNode merge, AbstractEndNode pred) { 245 List<Value> values = new ArrayList<>(); 246 for (PhiNode phi : merge.valuePhis()) { 247 Value value = operand(phi.valueAt(pred)); 248 assert value != null; 249 if (isRegister(value)) { 250 /* 251 * Fixed register intervals are not allowed at block boundaries so we introduce a 252 * new Variable. 253 */ 254 value = gen.emitMove(value); 255 } 256 values.add(value); 257 } 258 return values.toArray(new Value[values.size()]); 259 } 260 261 public void doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap) { 262 try (BlockScope blockScope = gen.getBlockScope(block)) { 263 264 if (block == gen.getResult().getLIR().getControlFlowGraph().getStartBlock()) { 265 assert block.getPredecessorCount() == 0; 266 emitPrologue(graph); 267 } else { 268 assert block.getPredecessorCount() > 0; 269 if (ConstructionSSAlirDuringLirBuilding.getValue()) { 270 // create phi-in value array 271 AbstractBeginNode begin = block.getBeginNode(); 272 if (begin instanceof AbstractMergeNode) { 273 AbstractMergeNode merge = (AbstractMergeNode) begin; 274 LabelOp label = (LabelOp) gen.getResult().getLIR().getLIRforBlock(block).get(0); 275 label.setIncomingValues(createPhiIn(merge)); 276 if (Options.PrintIRWithLIR.getValue() && !TTY.isSuppressed()) { 277 TTY.println("Created PhiIn: " + label); 278 279 } 280 } 281 } 282 } 283 284 List<Node> nodes = blockMap.get(block); 285 286 // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups 287 // of instructions 288 matchComplexExpressions(nodes); 289 290 for (int i = 0; i < nodes.size(); i++) { 291 Node node = nodes.get(i); 292 if (node instanceof ValueNode) { 293 ValueNode valueNode = (ValueNode) node; 294 if (Options.TraceLIRGeneratorLevel.getValue() >= 3) { 295 TTY.println("LIRGen for " + valueNode); 296 } 297 Value operand = getOperand(valueNode); 298 if (operand == null) { 299 if (!peephole(valueNode)) { 300 try { 301 doRoot(valueNode); 302 } catch (JVMCIError e) { 303 throw GraalGraphJVMCIError.transformAndAddContext(e, valueNode); 304 } catch (Throwable e) { 305 throw new GraalGraphJVMCIError(e).addContext(valueNode); 306 } 307 } 308 } else if (ComplexMatchValue.INTERIOR_MATCH.equals(operand)) { 309 // Doesn't need to be evaluated 310 Debug.log("interior match for %s", valueNode); 311 } else if (operand instanceof ComplexMatchValue) { 312 Debug.log("complex match for %s", valueNode); 313 ComplexMatchValue match = (ComplexMatchValue) operand; 314 operand = match.evaluate(this); 315 if (operand != null) { 316 setResult(valueNode, operand); 317 } 318 } else { 319 // There can be cases in which the result of an instruction is already set 320 // before by other instructions. 321 } 322 } 323 } 324 325 if (!gen.hasBlockEnd(block)) { 326 NodeClassIterable successors = block.getEndNode().successors(); 327 assert successors.count() == block.getSuccessorCount(); 328 if (block.getSuccessorCount() != 1) { 329 /* 330 * If we have more than one successor, we cannot just use the first one. Since 331 * successors are unordered, this would be a random choice. 332 */ 333 throw new JVMCIError("Block without BlockEndOp: " + block.getEndNode()); 334 } 335 gen.emitJump(getLIRBlock((FixedNode) successors.first())); 336 } 337 338 assert verifyBlock(gen.getResult().getLIR(), block); 339 } 340 } 341 342 protected void matchComplexExpressions(List<Node> nodes) { 343 if (matchRules != null) { 344 try (Scope s = Debug.scope("MatchComplexExpressions")) { 345 if (LogVerbose.getValue()) { 346 int i = 0; 347 for (Node node : nodes) { 348 Debug.log("%d: (%s) %1S", i++, node.getUsageCount(), node); 349 } 350 } 351 352 // Match the nodes in backwards order to encourage longer matches. 353 for (int index = nodes.size() - 1; index >= 0; index--) { 354 Node node = nodes.get(index); 355 if (getOperand(node) != null) { 356 continue; 357 } 358 // See if this node is the root of any MatchStatements 359 List<MatchStatement> statements = matchRules.get(node.getClass()); 360 if (statements != null) { 361 for (MatchStatement statement : statements) { 362 if (statement.generate(this, index, node, nodes)) { 363 // Found a match so skip to the next 364 break; 365 } 366 } 367 } 368 } 369 } 370 } 371 } 372 373 protected abstract boolean peephole(ValueNode valueNode); 374 375 private void doRoot(ValueNode instr) { 376 if (Options.TraceLIRGeneratorLevel.getValue() >= 2) { 377 TTY.println("Emitting LIR for instruction " + instr); 378 } 379 currentInstruction = instr; 380 381 Debug.log("Visiting %s", instr); 382 emitNode(instr); 383 Debug.log("Operand for %s = %s", instr, getOperand(instr)); 384 } 385 386 protected void emitNode(ValueNode node) { 387 if (Debug.isLogEnabled() && node.stamp().isEmpty()) { 388 Debug.log("This node has an empty stamp, we are emitting dead code(?): %s", node); 389 } 390 if (node instanceof LIRLowerable) { 391 ((LIRLowerable) node).generate(this); 392 } else if (node instanceof ArithmeticLIRLowerable) { 393 ((ArithmeticLIRLowerable) node).generate(this, gen); 394 } else { 395 throw JVMCIError.shouldNotReachHere("node is not LIRLowerable: " + node); 396 } 397 } 398 399 protected void emitPrologue(StructuredGraph graph) { 400 CallingConvention incomingArguments = gen.getCallingConvention(); 401 402 Value[] params = new Value[incomingArguments.getArgumentCount()]; 403 for (int i = 0; i < params.length; i++) { 404 params[i] = LIRGenerator.toStackKind(incomingArguments.getArgument(i)); 405 if (ValueUtil.isStackSlot(params[i])) { 406 StackSlot slot = ValueUtil.asStackSlot(params[i]); 407 if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) { 408 gen.getResult().getLIR().setHasArgInCallerFrame(); 409 } 410 } 411 } 412 413 gen.emitIncomingValues(params); 414 415 for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { 416 Value paramValue = params[param.index()]; 417 assert paramValue.getLIRKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp())); 418 setResult(param, gen.emitMove(paramValue)); 419 } 420 } 421 422 @Override 423 public void visitMerge(AbstractMergeNode x) { 424 } 425 426 @Override 427 public void visitEndNode(AbstractEndNode end) { 428 AbstractMergeNode merge = end.merge(); 429 JumpOp jump = newJumpOp(getLIRBlock(merge)); 430 if (ConstructionSSAlirDuringLirBuilding.getValue()) { 431 jump.setOutgoingValues(createPhiOut(merge, end)); 432 } else { 433 moveToPhi(merge, end); 434 } 435 append(jump); 436 } 437 438 /** 439 * Runtime specific classes can override this to insert a safepoint at the end of a loop. 440 */ 441 @Override 442 public void visitLoopEnd(LoopEndNode x) { 443 } 444 445 private void moveToPhi(AbstractMergeNode merge, AbstractEndNode pred) { 446 if (Options.TraceLIRGeneratorLevel.getValue() >= 1) { 447 TTY.println("MOVE TO PHI from " + pred + " to " + merge); 448 } 449 PhiResolver resolver = PhiResolver.create(gen); 450 for (PhiNode phi : merge.phis()) { 451 if (phi instanceof ValuePhiNode) { 452 ValueNode curVal = phi.valueAt(pred); 453 resolver.move(operandForPhi((ValuePhiNode) phi), operand(curVal)); 454 } 455 } 456 resolver.dispose(); 457 } 458 459 protected JumpOp newJumpOp(LabelRef ref) { 460 return new JumpOp(ref); 461 } 462 463 protected LIRKind getPhiKind(PhiNode phi) { 464 return gen.getLIRKind(phi.stamp()); 465 } 466 467 private Value operandForPhi(ValuePhiNode phi) { 468 Value result = getOperand(phi); 469 if (result == null) { 470 // allocate a variable for this phi 471 Variable newOperand = gen.newVariable(getPhiKind(phi)); 472 setResult(phi, newOperand); 473 return newOperand; 474 } else { 475 return result; 476 } 477 } 478 479 @Override 480 public void emitIf(IfNode x) { 481 emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor())); 482 } 483 484 public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { 485 if (node instanceof IsNullNode) { 486 emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); 487 } else if (node instanceof CompareNode) { 488 emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); 489 } else if (node instanceof LogicConstantNode) { 490 emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor); 491 } else if (node instanceof IntegerTestNode) { 492 emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor, trueSuccessorProbability); 493 } else { 494 throw JVMCIError.unimplemented(node.toString()); 495 } 496 } 497 498 private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { 499 PlatformKind kind = gen.getLIRKind(node.getValue().stamp()).getPlatformKind(); 500 gen.emitCompareBranch(kind, operand(node.getValue()), kind.getDefaultValue(), Condition.EQ, false, trueSuccessor, falseSuccessor, trueSuccessorProbability); 501 } 502 503 public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { 504 PlatformKind kind = gen.getLIRKind(compare.getX().stamp()).getPlatformKind(); 505 gen.emitCompareBranch(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability); 506 } 507 508 public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { 509 gen.emitIntegerTestBranch(operand(test.getX()), operand(test.getY()), trueSuccessor, falseSuccessor, trueSuccessorProbability); 510 } 511 512 public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) { 513 LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock; 514 gen.emitJump(block); 515 } 516 517 @Override 518 public void emitConditional(ConditionalNode conditional) { 519 Value tVal = operand(conditional.trueValue()); 520 Value fVal = operand(conditional.falseValue()); 521 setResult(conditional, emitConditional(conditional.condition(), tVal, fVal)); 522 } 523 524 public Variable emitConditional(LogicNode node, Value trueValue, Value falseValue) { 525 if (node instanceof IsNullNode) { 526 IsNullNode isNullNode = (IsNullNode) node; 527 PlatformKind kind = gen.getLIRKind(isNullNode.getValue().stamp()).getPlatformKind(); 528 return gen.emitConditionalMove(kind, operand(isNullNode.getValue()), kind.getDefaultValue(), Condition.EQ, false, trueValue, falseValue); 529 } else if (node instanceof CompareNode) { 530 CompareNode compare = (CompareNode) node; 531 PlatformKind kind = gen.getLIRKind(compare.getX().stamp()).getPlatformKind(); 532 return gen.emitConditionalMove(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue); 533 } else if (node instanceof LogicConstantNode) { 534 return gen.emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue); 535 } else if (node instanceof IntegerTestNode) { 536 IntegerTestNode test = (IntegerTestNode) node; 537 return gen.emitIntegerTestMove(operand(test.getX()), operand(test.getY()), trueValue, falseValue); 538 } else { 539 throw JVMCIError.unimplemented(node.toString()); 540 } 541 } 542 543 @Override 544 public void emitInvoke(Invoke x) { 545 LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget(); 546 CallingConvention invokeCc = gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(gen.getMetaAccess()), 547 callTarget.signature(), gen.target(), false); 548 gen.getResult().getFrameMapBuilder().callsMethod(invokeCc); 549 550 Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments()); 551 552 LabelRef exceptionEdge = null; 553 if (x instanceof InvokeWithExceptionNode) { 554 exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()); 555 } 556 LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge); 557 558 Value result = invokeCc.getReturn(); 559 if (callTarget instanceof DirectCallTargetNode) { 560 emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); 561 } else if (callTarget instanceof IndirectCallTargetNode) { 562 emitIndirectCall((IndirectCallTargetNode) callTarget, result, parameters, AllocatableValue.NONE, callState); 563 } else { 564 throw JVMCIError.shouldNotReachHere(); 565 } 566 567 if (isLegal(result)) { 568 setResult(x.asNode(), gen.emitMove(result)); 569 } 570 571 if (x instanceof InvokeWithExceptionNode) { 572 gen.emitJump(getLIRBlock(((InvokeWithExceptionNode) x).next())); 573 } 574 } 575 576 protected abstract void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); 577 578 protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); 579 580 @Override 581 public Value[] visitInvokeArguments(CallingConvention invokeCc, Collection<ValueNode> arguments) { 582 // for each argument, load it into the correct location 583 Value[] result = new Value[arguments.size()]; 584 int j = 0; 585 for (ValueNode arg : arguments) { 586 if (arg != null) { 587 AllocatableValue operand = LIRGenerator.toStackKind(invokeCc.getArgument(j)); 588 gen.emitMove(operand, operand(arg)); 589 result[j] = operand; 590 j++; 591 } else { 592 throw JVMCIError.shouldNotReachHere("I thought we no longer have null entries for two-slot types..."); 593 } 594 } 595 return result; 596 } 597 598 /** 599 * This method tries to create a switch implementation that is optimal for the given switch. It 600 * will either generate a sequential if/then/else cascade, a set of range tests or a table 601 * switch. 602 * 603 * If the given switch does not contain int keys, it will always create a sequential 604 * implementation. 605 */ 606 @Override 607 public void emitSwitch(SwitchNode x) { 608 assert x.defaultSuccessor() != null; 609 LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor()); 610 int keyCount = x.keyCount(); 611 if (keyCount == 0) { 612 gen.emitJump(defaultTarget); 613 } else { 614 Variable value = gen.load(operand(x.value())); 615 if (keyCount == 1) { 616 assert defaultTarget != null; 617 double probability = x.probability(x.keySuccessor(0)); 618 PlatformKind kind = gen.getLIRKind(x.value().stamp()).getPlatformKind(); 619 gen.emitCompareBranch(kind, gen.load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget, probability); 620 } else { 621 LabelRef[] keyTargets = new LabelRef[keyCount]; 622 JavaConstant[] keyConstants = new JavaConstant[keyCount]; 623 double[] keyProbabilities = new double[keyCount]; 624 for (int i = 0; i < keyCount; i++) { 625 keyTargets[i] = getLIRBlock(x.keySuccessor(i)); 626 keyConstants[i] = x.keyAt(i); 627 keyProbabilities[i] = x.keyProbability(i); 628 } 629 if (value.getKind() != Kind.Int || !x.isSorted()) { 630 // hopefully only a few entries 631 gen.emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget); 632 } else { 633 gen.emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value); 634 } 635 } 636 } 637 } 638 639 public DebugInfoBuilder getDebugInfoBuilder() { 640 assert debugInfoBuilder != null; 641 return debugInfoBuilder; 642 } 643 644 private static FrameState getFrameState(DeoptimizingNode deopt) { 645 if (deopt instanceof DeoptimizingNode.DeoptBefore) { 646 assert !(deopt instanceof DeoptimizingNode.DeoptDuring || deopt instanceof DeoptimizingNode.DeoptAfter); 647 return ((DeoptimizingNode.DeoptBefore) deopt).stateBefore(); 648 } else if (deopt instanceof DeoptimizingNode.DeoptDuring) { 649 assert !(deopt instanceof DeoptimizingNode.DeoptAfter); 650 return ((DeoptimizingNode.DeoptDuring) deopt).stateDuring(); 651 } else { 652 assert deopt instanceof DeoptimizingNode.DeoptAfter; 653 return ((DeoptimizingNode.DeoptAfter) deopt).stateAfter(); 654 } 655 } 656 657 public LIRFrameState state(DeoptimizingNode deopt) { 658 if (!deopt.canDeoptimize()) { 659 return null; 660 } 661 return stateFor(getFrameState(deopt)); 662 } 663 664 public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) { 665 if (!deopt.canDeoptimize()) { 666 return null; 667 } 668 return stateForWithExceptionEdge(getFrameState(deopt), exceptionEdge); 669 } 670 671 public LIRFrameState stateFor(FrameState state) { 672 return stateForWithExceptionEdge(state, null); 673 } 674 675 public LIRFrameState stateForWithExceptionEdge(FrameState state, LabelRef exceptionEdge) { 676 if (gen.needOnlyOopMaps()) { 677 return new LIRFrameState(null, null, null); 678 } 679 assert state != null; 680 return getDebugInfoBuilder().build(state, exceptionEdge); 681 } 682 683 @Override 684 public void emitOverflowCheckBranch(AbstractBeginNode overflowSuccessor, AbstractBeginNode next, Stamp stamp, double probability) { 685 LIRKind cmpKind = getLIRGeneratorTool().getLIRKind(stamp); 686 gen.emitOverflowCheckBranch(getLIRBlock(overflowSuccessor), getLIRBlock(next), cmpKind, probability); 687 } 688 689 @Override 690 public void visitFullInfopointNode(FullInfopointNode i) { 691 append(new FullInfopointOp(stateFor(i.getState()), i.getReason())); 692 } 693 694 @Override 695 public void visitSimpleInfopointNode(SimpleInfopointNode i) { 696 append(new SimpleInfopointOp(i.getReason(), i.getPosition())); 697 } 698 699 @Override 700 public LIRGeneratorTool getLIRGeneratorTool() { 701 return gen; 702 } 703}