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}