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