1 /*
2  * Copyright (c) 2009, 2019, 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.lir.gen;
26 
27 import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
28 import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
29 import static jdk.vm.ci.code.ValueUtil.isLegal;
30 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
31 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
32 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
33 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
34 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
35 
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.Optional;
39 
40 import org.graalvm.compiler.asm.Label;
41 import org.graalvm.compiler.core.common.LIRKind;
42 import org.graalvm.compiler.core.common.calc.Condition;
43 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
44 import org.graalvm.compiler.core.common.spi.CodeGenProviders;
45 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
46 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
47 import org.graalvm.compiler.core.common.spi.LIRKindTool;
48 import org.graalvm.compiler.core.common.type.Stamp;
49 import org.graalvm.compiler.debug.DebugCloseable;
50 import org.graalvm.compiler.debug.GraalError;
51 import org.graalvm.compiler.debug.TTY;
52 import org.graalvm.compiler.graph.NodeSourcePosition;
53 import org.graalvm.compiler.lir.ConstantValue;
54 import org.graalvm.compiler.lir.LIR;
55 import org.graalvm.compiler.lir.LIRFrameState;
56 import org.graalvm.compiler.lir.LIRInstruction;
57 import org.graalvm.compiler.lir.LIRVerifier;
58 import org.graalvm.compiler.lir.LabelRef;
59 import org.graalvm.compiler.lir.StandardOp;
60 import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
61 import org.graalvm.compiler.lir.StandardOp.LabelOp;
62 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
63 import org.graalvm.compiler.lir.hashing.Hasher;
64 import org.graalvm.compiler.lir.SwitchStrategy;
65 import org.graalvm.compiler.lir.Variable;
66 import org.graalvm.compiler.options.Option;
67 import org.graalvm.compiler.options.OptionKey;
68 import org.graalvm.compiler.options.OptionType;
69 import org.graalvm.compiler.options.OptionValues;
70 
71 import jdk.vm.ci.code.CallingConvention;
72 import jdk.vm.ci.code.CodeCacheProvider;
73 import jdk.vm.ci.code.Register;
74 import jdk.vm.ci.code.RegisterAttributes;
75 import jdk.vm.ci.code.RegisterConfig;
76 import jdk.vm.ci.code.StackSlot;
77 import jdk.vm.ci.code.TargetDescription;
78 import jdk.vm.ci.meta.AllocatableValue;
79 import jdk.vm.ci.meta.Constant;
80 import jdk.vm.ci.meta.JavaConstant;
81 import jdk.vm.ci.meta.JavaKind;
82 import jdk.vm.ci.meta.MetaAccessProvider;
83 import jdk.vm.ci.meta.PlatformKind;
84 import jdk.vm.ci.meta.Value;
85 import jdk.vm.ci.meta.ValueKind;
86 
87 /**
88  * This class traverses the HIR instructions and generates LIR instructions from them.
89  */
90 public abstract class LIRGenerator implements LIRGeneratorTool {
91 
92     public static class Options {
93         // @formatter:off
94         @Option(help = "Print HIR along side LIR as the latter is generated", type = OptionType.Debug)
95         public static final OptionKey<Boolean> PrintIRWithLIR = new OptionKey<>(false);
96         @Option(help = "The trace level for the LIR generator", type = OptionType.Debug)
97         public static final OptionKey<Integer> TraceLIRGeneratorLevel = new OptionKey<>(0);
98         // @formatter:on
99     }
100 
101     private final LIRKindTool lirKindTool;
102 
103     private final CodeGenProviders providers;
104 
105     private AbstractBlockBase<?> currentBlock;
106 
107     private LIRGenerationResult res;
108 
109     protected final ArithmeticLIRGenerator arithmeticLIRGen;
110     private final MoveFactory moveFactory;
111 
112     private final boolean printIrWithLir;
113     private final int traceLIRGeneratorLevel;
114 
LIRGenerator(LIRKindTool lirKindTool, ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, CodeGenProviders providers, LIRGenerationResult res)115     public LIRGenerator(LIRKindTool lirKindTool, ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, CodeGenProviders providers, LIRGenerationResult res) {
116         this.lirKindTool = lirKindTool;
117         this.arithmeticLIRGen = arithmeticLIRGen;
118         this.res = res;
119         this.providers = providers;
120         OptionValues options = res.getLIR().getOptions();
121         this.printIrWithLir = !TTY.isSuppressed() && Options.PrintIRWithLIR.getValue(options);
122         this.traceLIRGeneratorLevel = TTY.isSuppressed() ? 0 : Options.TraceLIRGeneratorLevel.getValue(options);
123 
124         assert arithmeticLIRGen.lirGen == null;
125         arithmeticLIRGen.lirGen = this;
126         this.moveFactory = moveFactory;
127     }
128 
129     @Override
getArithmetic()130     public ArithmeticLIRGeneratorTool getArithmetic() {
131         return arithmeticLIRGen;
132     }
133 
134     @Override
getMoveFactory()135     public MoveFactory getMoveFactory() {
136         return moveFactory;
137     }
138 
139     private MoveFactory spillMoveFactory;
140 
141     @Override
getSpillMoveFactory()142     public MoveFactory getSpillMoveFactory() {
143         if (spillMoveFactory == null) {
144             boolean verify = false;
145             assert (verify = true) == true;
146             if (verify) {
147                 spillMoveFactory = new VerifyingMoveFactory(moveFactory);
148             } else {
149                 spillMoveFactory = moveFactory;
150             }
151         }
152         return spillMoveFactory;
153     }
154 
155     @Override
getValueKind(JavaKind javaKind)156     public LIRKind getValueKind(JavaKind javaKind) {
157         return LIRKind.fromJavaKind(target().arch, javaKind);
158     }
159 
160     @Override
target()161     public TargetDescription target() {
162         return getCodeCache().getTarget();
163     }
164 
165     @Override
getProviders()166     public CodeGenProviders getProviders() {
167         return providers;
168     }
169 
170     @Override
getMetaAccess()171     public MetaAccessProvider getMetaAccess() {
172         return providers.getMetaAccess();
173     }
174 
175     @Override
getCodeCache()176     public CodeCacheProvider getCodeCache() {
177         return providers.getCodeCache();
178     }
179 
180     @Override
getForeignCalls()181     public ForeignCallsProvider getForeignCalls() {
182         return providers.getForeignCalls();
183     }
184 
getLIRKindTool()185     public LIRKindTool getLIRKindTool() {
186         return lirKindTool;
187     }
188 
189     /**
190      * Hide {@link #nextVariable()} from other users.
191      */
192     public abstract static class VariableProvider {
193         private int numVariables;
194 
numVariables()195         public int numVariables() {
196             return numVariables;
197         }
198 
nextVariable()199         private int nextVariable() {
200             return numVariables++;
201         }
202     }
203 
204     @Override
newVariable(ValueKind<?> valueKind)205     public Variable newVariable(ValueKind<?> valueKind) {
206         return new Variable(valueKind, ((VariableProvider) res.getLIR()).nextVariable());
207     }
208 
209     @Override
getRegisterConfig()210     public RegisterConfig getRegisterConfig() {
211         return res.getRegisterConfig();
212     }
213 
214     @Override
attributes(Register register)215     public RegisterAttributes attributes(Register register) {
216         return getRegisterConfig().getAttributesMap()[register.number];
217     }
218 
219     @Override
emitMove(Value input)220     public Variable emitMove(Value input) {
221         assert !(input instanceof Variable) : "Creating a copy of a variable via this method is not supported (and potentially a bug): " + input;
222         Variable result = newVariable(input.getValueKind());
223         emitMove(result, input);
224         return result;
225     }
226 
227     @Override
emitMove(AllocatableValue dst, Value src)228     public void emitMove(AllocatableValue dst, Value src) {
229         append(moveFactory.createMove(dst, src));
230     }
231 
232     @Override
emitMoveConstant(AllocatableValue dst, Constant src)233     public void emitMoveConstant(AllocatableValue dst, Constant src) {
234         append(moveFactory.createLoad(dst, src));
235     }
236 
237     @Override
emitConstant(LIRKind kind, Constant constant)238     public Value emitConstant(LIRKind kind, Constant constant) {
239         if (moveFactory.canInlineConstant(constant)) {
240             return new ConstantValue(toRegisterKind(kind), constant);
241         } else {
242             return emitLoadConstant(toRegisterKind(kind), constant);
243         }
244     }
245 
246     @Override
emitJavaConstant(JavaConstant constant)247     public Value emitJavaConstant(JavaConstant constant) {
248         return emitConstant(getValueKind(constant.getJavaKind()), constant);
249     }
250 
251     @Override
emitLoadConstant(ValueKind<?> kind, Constant constant)252     public AllocatableValue emitLoadConstant(ValueKind<?> kind, Constant constant) {
253         Variable result = newVariable(kind);
254         emitMoveConstant(result, constant);
255         return result;
256     }
257 
258     @Override
asAllocatable(Value value)259     public AllocatableValue asAllocatable(Value value) {
260         if (isAllocatableValue(value)) {
261             return asAllocatableValue(value);
262         } else if (isConstantValue(value)) {
263             return emitLoadConstant(value.getValueKind(), asConstant(value));
264         } else {
265             return emitMove(value);
266         }
267     }
268 
269     @Override
load(Value value)270     public Variable load(Value value) {
271         if (!isVariable(value)) {
272             return emitMove(value);
273         }
274         return (Variable) value;
275     }
276 
277     @Override
loadNonConst(Value value)278     public Value loadNonConst(Value value) {
279         if (isConstantValue(value) && !moveFactory.canInlineConstant(asConstant(value))) {
280             return emitMove(value);
281         }
282         return value;
283     }
284 
285     /**
286      * Determines if only oop maps are required for the code generated from the LIR.
287      */
288     @Override
needOnlyOopMaps()289     public boolean needOnlyOopMaps() {
290         return false;
291     }
292 
293     /**
294      * Gets the ABI specific operand used to return a value of a given kind from a method.
295      *
296      * @param javaKind the kind of value being returned
297      * @param valueKind the backend type of the value being returned
298      * @return the operand representing the ABI defined location used return a value of kind
299      *         {@code kind}
300      */
301     @Override
resultOperandFor(JavaKind javaKind, ValueKind<?> valueKind)302     public AllocatableValue resultOperandFor(JavaKind javaKind, ValueKind<?> valueKind) {
303         Register reg = getRegisterConfig().getReturnRegister(javaKind);
304         assert target().arch.canStoreValue(reg.getRegisterCategory(), valueKind.getPlatformKind()) : reg.getRegisterCategory() + " " + valueKind.getPlatformKind();
305         return reg.asValue(valueKind);
306     }
307 
308     NodeSourcePosition currentPosition;
309 
310     @Override
setSourcePosition(NodeSourcePosition position)311     public void setSourcePosition(NodeSourcePosition position) {
312         currentPosition = position;
313     }
314 
315     @Override
append(I op)316     public <I extends LIRInstruction> I append(I op) {
317         LIR lir = res.getLIR();
318         if (printIrWithLir) {
319             TTY.println(op.toStringWithIdPrefix());
320             TTY.println();
321         }
322         assert LIRVerifier.verify(op);
323         ArrayList<LIRInstruction> lirForBlock = lir.getLIRforBlock(getCurrentBlock());
324         op.setPosition(currentPosition);
325         lirForBlock.add(op);
326         return op;
327     }
328 
329     @Override
hasBlockEnd(AbstractBlockBase<?> block)330     public boolean hasBlockEnd(AbstractBlockBase<?> block) {
331         ArrayList<LIRInstruction> ops = getResult().getLIR().getLIRforBlock(block);
332         if (ops.size() == 0) {
333             return false;
334         }
335         return ops.get(ops.size() - 1) instanceof BlockEndOp;
336     }
337 
338     private final class BlockScopeImpl extends BlockScope {
339 
BlockScopeImpl(AbstractBlockBase<?> block)340         private BlockScopeImpl(AbstractBlockBase<?> block) {
341             currentBlock = block;
342         }
343 
doBlockStart()344         private void doBlockStart() {
345             if (printIrWithLir) {
346                 TTY.print(currentBlock.toString());
347             }
348 
349             // set up the list of LIR instructions
350             assert res.getLIR().getLIRforBlock(currentBlock) == null : "LIR list already computed for this block";
351             res.getLIR().setLIRforBlock(currentBlock, new ArrayList<LIRInstruction>());
352 
353             append(new LabelOp(new Label(currentBlock.getId()), currentBlock.isAligned()));
354 
355             if (traceLIRGeneratorLevel >= 1) {
356                 TTY.println("BEGIN Generating LIR for block B" + currentBlock.getId());
357             }
358         }
359 
doBlockEnd()360         private void doBlockEnd() {
361             if (traceLIRGeneratorLevel >= 1) {
362                 TTY.println("END Generating LIR for block B" + currentBlock.getId());
363             }
364 
365             if (printIrWithLir) {
366                 TTY.println();
367             }
368             currentBlock = null;
369         }
370 
371         @Override
getCurrentBlock()372         public AbstractBlockBase<?> getCurrentBlock() {
373             return currentBlock;
374         }
375 
376         @Override
close()377         public void close() {
378             doBlockEnd();
379         }
380 
381     }
382 
383     @Override
getBlockScope(AbstractBlockBase<?> block)384     public final BlockScope getBlockScope(AbstractBlockBase<?> block) {
385         BlockScopeImpl blockScope = new BlockScopeImpl(block);
386         blockScope.doBlockStart();
387         return blockScope;
388     }
389 
390     private final class MatchScope implements DebugCloseable {
391 
MatchScope(AbstractBlockBase<?> block)392         private MatchScope(AbstractBlockBase<?> block) {
393             currentBlock = block;
394         }
395 
396         @Override
close()397         public void close() {
398             currentBlock = null;
399         }
400 
401     }
402 
getMatchScope(AbstractBlockBase<?> block)403     public final DebugCloseable getMatchScope(AbstractBlockBase<?> block) {
404         MatchScope matchScope = new MatchScope(block);
405         return matchScope;
406     }
407 
408     @Override
emitIncomingValues(Value[] params)409     public void emitIncomingValues(Value[] params) {
410         ((LabelOp) res.getLIR().getLIRforBlock(getCurrentBlock()).get(0)).setIncomingValues(params);
411     }
412 
413     @Override
emitJump(LabelRef label)414     public abstract void emitJump(LabelRef label);
415 
416     @Override
emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability)417     public abstract void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
418                     double trueDestinationProbability);
419 
420     @Override
emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability)421     public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability);
422 
423     @Override
emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability)424     public abstract void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
425 
426     @Override
emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue)427     public abstract Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
428 
429     @Override
emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue)430     public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
431 
432     /**
433      * Emits the single call operation at the heart of generating LIR for a
434      * {@linkplain #emitForeignCall(ForeignCallLinkage, LIRFrameState, Value...) foreign call}.
435      */
emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info)436     protected abstract void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
437 
438     @Override
emitForeignCall(ForeignCallLinkage linkage, LIRFrameState frameState, Value... args)439     public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState frameState, Value... args) {
440         LIRFrameState state = null;
441         if (linkage.needsDebugInfo()) {
442             if (frameState != null) {
443                 state = frameState;
444             } else {
445                 assert needOnlyOopMaps();
446                 state = new LIRFrameState(null, null, null);
447             }
448         }
449 
450         // move the arguments into the correct location
451         CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
452         res.getFrameMapBuilder().callsMethod(linkageCc);
453         assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
454         Value[] argLocations = new Value[args.length];
455         for (int i = 0; i < args.length; i++) {
456             Value arg = args[i];
457             AllocatableValue loc = linkageCc.getArgument(i);
458             emitMove(loc, arg);
459             argLocations[i] = loc;
460         }
461         res.setForeignCall(true);
462         emitForeignCallOp(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
463 
464         if (isLegal(linkageCc.getReturn())) {
465             return emitMove(linkageCc.getReturn());
466         } else {
467             return null;
468         }
469     }
470 
471     @Override
emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value)472     public void emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
473         SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
474 
475         int keyCount = keyConstants.length;
476         double minDensity = 1 / Math.sqrt(strategy.getAverageEffort());
477         Optional<Hasher> hasher = hasherFor(keyConstants, minDensity);
478         double hashTableSwitchDensity = hasher.map(h -> keyCount / (double) h.cardinality()).orElse(0d);
479         // The value range computation below may overflow, so compute it as a long.
480         long valueRange = (long) keyConstants[keyCount - 1].asInt() - (long) keyConstants[0].asInt() + 1;
481         double tableSwitchDensity = keyCount / (double) valueRange;
482 
483         /*
484          * This heuristic tries to find a compromise between the effort for the best switch strategy
485          * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
486          * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
487          * gradually with additional effort.
488          */
489         if (strategy.getAverageEffort() < 4d || (tableSwitchDensity < minDensity && hashTableSwitchDensity < minDensity)) {
490             emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
491         } else {
492             if (hashTableSwitchDensity > tableSwitchDensity) {
493                 Hasher h = hasher.get();
494                 int cardinality = h.cardinality();
495                 LabelRef[] targets = new LabelRef[cardinality];
496                 JavaConstant[] keys = new JavaConstant[cardinality];
497                 for (int i = 0; i < cardinality; i++) {
498                     keys[i] = JavaConstant.INT_0;
499                     targets[i] = defaultTarget;
500                 }
501                 for (int i = 0; i < keyCount; i++) {
502                     int idx = h.hash(keyConstants[i].asInt());
503                     keys[idx] = keyConstants[i];
504                     targets[idx] = keyTargets[i];
505                 }
506                 emitHashTableSwitch(h, keys, defaultTarget, targets, value);
507             } else {
508                 int minValue = keyConstants[0].asInt();
509                 assert valueRange < Integer.MAX_VALUE;
510                 LabelRef[] targets = new LabelRef[(int) valueRange];
511                 for (int i = 0; i < valueRange; i++) {
512                     targets[i] = defaultTarget;
513                 }
514                 for (int i = 0; i < keyCount; i++) {
515                     targets[keyConstants[i].asInt() - minValue] = keyTargets[i];
516                 }
517                 emitTableSwitch(minValue, defaultTarget, targets, value);
518             }
519         }
520     }
521 
522     @Override
523     public abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
524 
525     protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
526 
527     @SuppressWarnings("unused")
528     protected Optional<Hasher> hasherFor(JavaConstant[] keyConstants, double minDensity) {
529         return Optional.empty();
530     }
531 
532     @SuppressWarnings("unused")
533     protected void emitHashTableSwitch(Hasher hasher, JavaConstant[] keys, LabelRef defaultTarget, LabelRef[] targets, Value value) {
534         throw new UnsupportedOperationException(getClass().getSimpleName() + " doesn't support hash table switches");
535     }
536 
537     @Override
538     public void beforeRegisterAllocation() {
539     }
540 
541     /**
542      * Gets a garbage value for a given kind.
543      */
544     protected abstract JavaConstant zapValueForKind(PlatformKind kind);
545 
546     @Override
547     public LIRKind getLIRKind(Stamp stamp) {
548         return stamp.getLIRKind(lirKindTool);
549     }
550 
551     protected LIRKind getAddressKind(Value base, long displacement, Value index) {
552         if (LIRKind.isValue(base) && (index.equals(Value.ILLEGAL) || LIRKind.isValue(index))) {
553             return LIRKind.value(target().arch.getWordKind());
554         } else if (base.getValueKind() instanceof LIRKind && base.getValueKind(LIRKind.class).isReference(0) && displacement == 0L && index.equals(Value.ILLEGAL)) {
555             return LIRKind.reference(target().arch.getWordKind());
556         } else {
557             return LIRKind.unknownReference(target().arch.getWordKind());
558         }
559     }
560 
561     @Override
562     public AbstractBlockBase<?> getCurrentBlock() {
563         return currentBlock;
564     }
565 
566     @Override
567     public LIRGenerationResult getResult() {
568         return res;
569     }
570 
571     @Override
572     public void emitBlackhole(Value operand) {
573         append(new StandardOp.BlackholeOp(operand));
574     }
575 
576     @Override
577     public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
578         throw GraalError.unimplemented();
579     }
580 
581     @Override
582     public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
583         throw GraalError.unimplemented();
584     }
585 
586     @Override
587     public abstract SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues);
588 
589     @Override
590     public SaveRegistersOp createZapRegisters() {
591         Register[] zappedRegisters = getResult().getFrameMap().getRegisterConfig().getAllocatableRegisters().toArray();
592         JavaConstant[] zapValues = new JavaConstant[zappedRegisters.length];
593         for (int i = 0; i < zappedRegisters.length; i++) {
594             PlatformKind kind = target().arch.getLargestStorableKind(zappedRegisters[i].getRegisterCategory());
595             zapValues[i] = zapValueForKind(kind);
596         }
597         return createZapRegisters(zappedRegisters, zapValues);
598     }
599 
600     @Override
601     public abstract LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues);
602 
603     @Override
604     public LIRInstruction zapArgumentSpace() {
605         List<StackSlot> slots = null;
606         for (AllocatableValue arg : res.getCallingConvention().getArguments()) {
607             if (isStackSlot(arg)) {
608                 if (slots == null) {
609                     slots = new ArrayList<>();
610                 }
611                 slots.add((StackSlot) arg);
612             } else {
613                 assert !isVirtualStackSlot(arg);
614             }
615         }
616         if (slots == null) {
617             return null;
618         }
619         StackSlot[] zappedStack = slots.toArray(new StackSlot[slots.size()]);
620         JavaConstant[] zapValues = new JavaConstant[zappedStack.length];
621         for (int i = 0; i < zappedStack.length; i++) {
622             PlatformKind kind = zappedStack[i].getPlatformKind();
623             zapValues[i] = zapValueForKind(kind);
624         }
625         return createZapArgumentSpace(zappedStack, zapValues);
626     }
627 }
628