1 /*
   2  * Copyright (c) 2013, 2018, 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.hotspot.sparc;
  26 
  27 import static jdk.vm.ci.code.ValueUtil.asRegister;
  28 import static jdk.vm.ci.code.ValueUtil.isRegister;
  29 import static jdk.vm.ci.sparc.SPARC.g0;
  30 import static jdk.vm.ci.sparc.SPARC.g5;
  31 import static jdk.vm.ci.sparc.SPARC.i0;
  32 import static jdk.vm.ci.sparc.SPARC.i7;
  33 import static jdk.vm.ci.sparc.SPARC.l0;
  34 import static jdk.vm.ci.sparc.SPARC.l7;
  35 import static jdk.vm.ci.sparc.SPARC.o0;
  36 import static jdk.vm.ci.sparc.SPARC.o7;
  37 import static jdk.vm.ci.sparc.SPARC.sp;
  38 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
  39 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isGlobalRegister;
  40 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
  41 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
  42 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
  43 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual;
  44 import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
  45 
  46 import java.util.ArrayList;
  47 import java.util.HashSet;
  48 import java.util.Set;
  49 import java.util.concurrent.ConcurrentHashMap;
  50 
  51 import jdk.internal.vm.compiler.collections.EconomicMap;
  52 import jdk.internal.vm.compiler.collections.EconomicSet;
  53 import jdk.internal.vm.compiler.collections.Equivalence;
  54 import org.graalvm.compiler.asm.Assembler;
  55 import org.graalvm.compiler.asm.Label;
  56 import org.graalvm.compiler.asm.sparc.SPARCAddress;
  57 import org.graalvm.compiler.asm.sparc.SPARCAssembler;
  58 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
  59 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
  60 import org.graalvm.compiler.code.CompilationResult;
  61 import org.graalvm.compiler.code.DataSection;
  62 import org.graalvm.compiler.code.DataSection.Data;
  63 import org.graalvm.compiler.core.common.CompilationIdentifier;
  64 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
  65 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  66 import org.graalvm.compiler.core.gen.LIRGenerationProvider;
  67 import org.graalvm.compiler.core.sparc.SPARCNodeMatchRules;
  68 import org.graalvm.compiler.debug.CounterKey;
  69 import org.graalvm.compiler.debug.DebugContext;
  70 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  71 import org.graalvm.compiler.hotspot.HotSpotDataBuilder;
  72 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
  73 import org.graalvm.compiler.hotspot.HotSpotHostBackend;
  74 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
  75 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
  76 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
  77 import org.graalvm.compiler.hotspot.stubs.Stub;
  78 import org.graalvm.compiler.lir.InstructionValueConsumer;
  79 import org.graalvm.compiler.lir.LIR;
  80 import org.graalvm.compiler.lir.LIRFrameState;
  81 import org.graalvm.compiler.lir.LIRInstruction;
  82 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
  83 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
  84 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
  85 import org.graalvm.compiler.lir.asm.DataBuilder;
  86 import org.graalvm.compiler.lir.asm.FrameContext;
  87 import org.graalvm.compiler.lir.framemap.FrameMap;
  88 import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
  89 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  90 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
  91 import org.graalvm.compiler.lir.sparc.SPARCCall;
  92 import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer;
  93 import org.graalvm.compiler.lir.sparc.SPARCFrameMap;
  94 import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder;
  95 import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin;
  96 import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate;
  97 import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction;
  98 import org.graalvm.compiler.nodes.StructuredGraph;
  99 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 100 import org.graalvm.compiler.options.OptionValues;
 101 
 102 import jdk.vm.ci.code.CallingConvention;
 103 import jdk.vm.ci.code.Register;
 104 import jdk.vm.ci.code.RegisterConfig;
 105 import jdk.vm.ci.code.StackSlot;
 106 import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
 107 import jdk.vm.ci.meta.JavaType;
 108 import jdk.vm.ci.meta.ResolvedJavaMethod;
 109 
 110 /**
 111  * HotSpot SPARC specific backend.
 112  */
 113 public class SPARCHotSpotBackend extends HotSpotHostBackend implements LIRGenerationProvider {
 114 
 115     private static final SizeEstimateStatistics CONSTANT_ESTIMATED_STATS = new SizeEstimateStatistics("ESTIMATE");
 116     private static final SizeEstimateStatistics CONSTANT_ACTUAL_STATS = new SizeEstimateStatistics("ACTUAL");
 117 
 118     public SPARCHotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
 119         super(config, runtime, providers);
 120     }
 121 
 122     private static class SizeEstimateStatistics {
 123         private static final ConcurrentHashMap<String, CounterKey> counters = new ConcurrentHashMap<>();
 124         private final String suffix;
 125 
 126         SizeEstimateStatistics(String suffix) {
 127             super();
 128             this.suffix = suffix;
 129         }
 130 
 131         public void add(Class<?> c, int count, DebugContext debug) {
 132             String name = SizeEstimateStatistics.class.getSimpleName() + "_" + c.getSimpleName() + "." + suffix;
 133             CounterKey m = counters.computeIfAbsent(name, (n) -> DebugContext.counter(n));
 134             m.add(debug, count);
 135         }
 136     }
 137 
 138     private FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
 139         RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
 140         FrameMap frameMap = new SPARCFrameMap(getCodeCache(), registerConfigNonNull, this);
 141         return new SPARCFrameMapBuilder(frameMap, getCodeCache(), registerConfigNonNull);
 142     }
 143 
 144     @Override
 145     public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) {
 146         return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getVMConfig(), lirGenRes);
 147     }
 148 
 149     @Override
 150     public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, RegisterConfig registerConfig, StructuredGraph graph, Object stub) {
 151         return new HotSpotLIRGenerationResult(compilationId, lir, newFrameMapBuilder(registerConfig), makeCallingConvention(graph, (Stub) stub), stub,
 152                         config.requiresReservedStackCheck(graph.getMethods()));
 153     }
 154 
 155     @Override
 156     public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
 157         return new SPARCHotSpotNodeLIRBuilder(graph, lirGen, new SPARCNodeMatchRules(lirGen));
 158     }
 159 
 160     @Override
 161     protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) {
 162         // Use SPARCAddress to get the final displacement including the stack bias.
 163         SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
 164         SPARCAddress address = new SPARCAddress(sp, -bangOffset);
 165         if (SPARCAssembler.isSimm13(address.getDisplacement())) {
 166             masm.stx(g0, address);
 167         } else {
 168             try (ScratchRegister sc = masm.getScratchRegister()) {
 169                 Register scratch = sc.getRegister();
 170                 assert isGlobalRegister(scratch) : "Only global (g1-g7) registers are allowed if the frame was not initialized here. Got register " + scratch;
 171                 masm.setx(address.getDisplacement(), scratch, false);
 172                 masm.stx(g0, new SPARCAddress(sp, scratch));
 173             }
 174         }
 175     }
 176 
 177     public class HotSpotFrameContext implements FrameContext {
 178 
 179         final boolean isStub;
 180 
 181         HotSpotFrameContext(boolean isStub) {
 182             this.isStub = isStub;
 183         }
 184 
 185         @Override
 186         public boolean hasFrame() {
 187             return true;
 188         }
 189 
 190         @Override
 191         public void enter(CompilationResultBuilder crb) {
 192             final int frameSize = crb.frameMap.totalFrameSize();
 193             final int stackpointerChange = -frameSize;
 194             SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
 195             if (!isStub) {
 196                 emitStackOverflowCheck(crb);
 197             }
 198 
 199             if (SPARCAssembler.isSimm13(stackpointerChange)) {
 200                 masm.save(sp, stackpointerChange, sp);
 201             } else {
 202                 try (ScratchRegister sc = masm.getScratchRegister()) {
 203                     Register scratch = sc.getRegister();
 204                     assert isGlobalRegister(scratch) : "Only global registers are allowed before save. Got register " + scratch;
 205                     masm.setx(stackpointerChange, scratch, false);
 206                     masm.save(sp, scratch, sp);
 207                 }
 208             }
 209 
 210             if (ZapStackOnMethodEntry.getValue(crb.getOptions())) {
 211                 final int slotSize = 8;
 212                 for (int i = 0; i < frameSize / slotSize; ++i) {
 213                     // 0xC1C1C1C1
 214                     masm.stx(g0, new SPARCAddress(sp, i * slotSize));
 215                 }
 216             }
 217         }
 218 
 219         @Override
 220         public void leave(CompilationResultBuilder crb) {
 221             SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
 222             masm.restoreWindow();
 223         }
 224     }
 225 
 226     @Override
 227     public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
 228         HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRes;
 229         LIR lir = gen.getLIR();
 230         assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
 231 
 232         Stub stub = gen.getStub();
 233         Assembler masm = new SPARCMacroAssembler(getTarget());
 234         // On SPARC we always use stack frames.
 235         HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null);
 236         DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget());
 237         OptionValues options = lir.getOptions();
 238         DebugContext debug = lir.getDebug();
 239         CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, dataBuilder, frameContext, options, debug,
 240                         compilationResult, Register.None);
 241         crb.setTotalFrameSize(frameMap.totalFrameSize());
 242         crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize());
 243         StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
 244         if (deoptimizationRescueSlot != null && stub == null) {
 245             crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot);
 246         }
 247 
 248         if (stub != null) {
 249             // Even on sparc we need to save floating point registers
 250             EconomicSet<Register> destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir);
 251             EconomicMap<LIRFrameState, SaveRegistersOp> calleeSaveInfo = gen.getCalleeSaveInfo();
 252             updateStub(stub, destroyedCallerRegisters, calleeSaveInfo, frameMap);
 253         }
 254         assert registerSizePredictionValidator(crb, debug);
 255         return crb;
 256     }
 257 
 258     /**
 259      * Registers a verifier which checks if the LIRInstructions estimate of constants size is
 260      * greater or equal to the actual one.
 261      */
 262     private static boolean registerSizePredictionValidator(final CompilationResultBuilder crb, DebugContext debug) {
 263         /**
 264          * Used to hold state between beforeOp and afterOp
 265          */
 266         class ValidationState {
 267             LIRInstruction op;
 268             final DebugContext debug;
 269             int constantSizeBefore;
 270 
 271             ValidationState(DebugContext debug) {
 272                 this.debug = debug;
 273             }
 274 
 275             public void before(LIRInstruction before) {
 276                 assert op == null : "LIRInstruction " + op + " no after call received";
 277                 op = before;
 278                 constantSizeBefore = calculateDataSectionSize(crb.compilationResult.getDataSection());
 279             }
 280 
 281             public void after(LIRInstruction after) {
 282                 assert after.equals(op) : "Instructions before/after don't match " + op + "/" + after;
 283                 int constantSizeAfter = calculateDataSectionSize(crb.compilationResult.getDataSection());
 284                 int actual = constantSizeAfter - constantSizeBefore;
 285                 if (op instanceof SPARCLIRInstructionMixin) {
 286                     org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate size = ((SPARCLIRInstructionMixin) op).estimateSize();
 287                     assert size != null : "No size prediction available for op: " + op;
 288                     Class<?> c = op.getClass();
 289                     CONSTANT_ESTIMATED_STATS.add(c, size.constantSize, debug);
 290                     CONSTANT_ACTUAL_STATS.add(c, actual, debug);
 291                     assert size.constantSize >= actual : "Op " + op + " exceeded estimated constant size; predicted: " + size.constantSize + " actual: " + actual;
 292                 } else {
 293                     assert actual == 0 : "Op " + op + " emitted to DataSection without any estimate.";
 294                 }
 295                 op = null;
 296                 constantSizeBefore = 0;
 297             }
 298         }
 299         final ValidationState state = new ValidationState(debug);
 300         crb.setOpCallback(op -> state.before(op), op -> state.after(op));
 301         return true;
 302     }
 303 
 304     private static int calculateDataSectionSize(DataSection ds) {
 305         int sum = 0;
 306         for (Data d : ds) {
 307             sum += d.getSize();
 308         }
 309         return sum;
 310     }
 311 
 312     @Override
 313     public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
 314         SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
 315         // TODO: (sa) Fold the two traversals into one
 316         stuffDelayedControlTransfers(lir);
 317         int constantSize = calculateConstantSize(lir);
 318         boolean canUseImmediateConstantLoad = constantSize < (1 << 13);
 319         masm.setImmediateConstantLoad(canUseImmediateConstantLoad);
 320         FrameMap frameMap = crb.frameMap;
 321         RegisterConfig regConfig = frameMap.getRegisterConfig();
 322         Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label();
 323         for (int i = 0; i < 2; i++) {
 324             if (i > 0) {
 325                 crb.resetForEmittingCode();
 326                 lir.resetLabels();
 327                 resetDelayedControlTransfers(lir);
 328             }
 329 
 330             // Emit the prefix
 331             if (unverifiedStub != null) {
 332                 crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
 333                 // We need to use JavaCall here because we haven't entered the frame yet.
 334                 CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, this);
 335                 Register inlineCacheKlass = g5; // see MacroAssembler::ic_call
 336 
 337                 try (ScratchRegister sc = masm.getScratchRegister()) {
 338                     Register scratch = sc.getRegister();
 339                     Register receiver = asRegister(cc.getArgument(0));
 340                     SPARCAddress src = new SPARCAddress(receiver, config.hubOffset);
 341 
 342                     masm.ldx(src, scratch);
 343                     masm.cmp(scratch, inlineCacheKlass);
 344                 }
 345                 BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, unverifiedStub);
 346                 masm.nop();  // delay slot
 347             }
 348 
 349             masm.align(config.codeEntryAlignment);
 350             crb.recordMark(config.MARKID_OSR_ENTRY);
 351             crb.recordMark(config.MARKID_VERIFIED_ENTRY);
 352 
 353             // Emit code for the LIR
 354             crb.emit(lir);
 355         }
 356         profileInstructions(lir, crb);
 357 
 358         HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
 359         HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls();
 360         if (!frameContext.isStub) {
 361             crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
 362             SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null);
 363             crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
 364             SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, null);
 365         } else {
 366             // No need to emit the stubs for entries back into the method since
 367             // it has no calls that can cause such "return" entries
 368         }
 369 
 370         if (unverifiedStub != null) {
 371             masm.bind(unverifiedStub);
 372             try (ScratchRegister sc = masm.getScratchRegister()) {
 373                 Register scratch = sc.getRegister();
 374                 SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER));
 375             }
 376         }
 377         masm.peephole();
 378     }
 379 
 380     private static int calculateConstantSize(LIR lir) {
 381         int size = 0;
 382         for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
 383             if (block == null) {
 384                 continue;
 385             }
 386             for (LIRInstruction inst : lir.getLIRforBlock(block)) {
 387                 if (inst instanceof SPARCLIRInstructionMixin) {
 388                     SizeEstimate pred = ((SPARCLIRInstructionMixin) inst).estimateSize();
 389                     if (pred != null) {
 390                         size += pred.constantSize;
 391                     }
 392                 }
 393             }
 394         }
 395         return size;
 396     }
 397 
 398     private static void resetDelayedControlTransfers(LIR lir) {
 399         for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
 400             if (block == null) {
 401                 continue;
 402             }
 403             for (LIRInstruction inst : lir.getLIRforBlock(block)) {
 404                 if (inst instanceof SPARCDelayedControlTransfer) {
 405                     ((SPARCDelayedControlTransfer) inst).resetState();
 406                 }
 407             }
 408         }
 409     }
 410 
 411     /**
 412      * Fix-up over whole LIR.
 413      *
 414      * @see #stuffDelayedControlTransfers(LIR, AbstractBlockBase)
 415      * @param l
 416      */
 417     private static void stuffDelayedControlTransfers(LIR l) {
 418         for (AbstractBlockBase<?> b : l.codeEmittingOrder()) {
 419             if (b != null) {
 420                 stuffDelayedControlTransfers(l, b);
 421             }
 422         }
 423     }
 424 
 425     /**
 426      * Tries to put DelayedControlTransfer instructions and DelayableLIRInstructions together. Also
 427      * it tries to move the DelayedLIRInstruction to the DelayedControlTransfer instruction, if
 428      * possible.
 429      */
 430     private static void stuffDelayedControlTransfers(LIR l, AbstractBlockBase<?> block) {
 431         ArrayList<LIRInstruction> instructions = l.getLIRforBlock(block);
 432         if (instructions.size() >= 2) {
 433             LIRDependencyAccumulator acc = new LIRDependencyAccumulator();
 434             SPARCDelayedControlTransfer delayedTransfer = null;
 435             int delayTransferPosition = -1;
 436             for (int i = instructions.size() - 1; i >= 0; i--) {
 437                 LIRInstruction inst = instructions.get(i);
 438                 boolean adjacent = delayTransferPosition - i == 1;
 439                 if (!adjacent || inst.destroysCallerSavedRegisters() || leavesRegisterWindow(inst)) {
 440                     delayedTransfer = null;
 441                 }
 442                 if (inst instanceof SPARCDelayedControlTransfer) {
 443                     delayedTransfer = (SPARCDelayedControlTransfer) inst;
 444                     acc.start(inst);
 445                     delayTransferPosition = i;
 446                 } else if (delayedTransfer != null) {
 447                     boolean overlap = acc.add(inst);
 448                     if (!overlap && inst instanceof SPARCTailDelayedLIRInstruction) {
 449                         // We have found a non overlapping LIR instruction which can be delayed
 450                         ((SPARCTailDelayedLIRInstruction) inst).setDelayedControlTransfer(delayedTransfer);
 451                         delayedTransfer = null;
 452                     }
 453                 }
 454             }
 455         }
 456     }
 457 
 458     private static boolean leavesRegisterWindow(LIRInstruction inst) {
 459         return inst instanceof SPARCLIRInstructionMixin && ((SPARCLIRInstructionMixin) inst).leavesRegisterWindow();
 460     }
 461 
 462     /**
 463      * Accumulates inputs/outputs/temp/alive in a set along we walk back the LIRInstructions and
 464      * detects, if there is any overlap. In this way LIRInstructions can be detected, which can be
 465      * moved nearer to the DelayedControlTransfer instruction.
 466      */
 467     private static class LIRDependencyAccumulator {
 468         private final Set<Object> inputs = new HashSet<>(10);
 469         private boolean overlap = false;
 470 
 471         private final InstructionValueConsumer valueConsumer = (instruction, value, mode, flags) -> {
 472             Object valueObject = value;
 473             if (isRegister(value)) { // Canonicalize registers
 474                 valueObject = asRegister(value);
 475             }
 476             if (!inputs.add(valueObject)) {
 477                 overlap = true;
 478             }
 479         };
 480 
 481         public void start(LIRInstruction initial) {
 482             inputs.clear();
 483             overlap = false;
 484             initial.visitEachInput(valueConsumer);
 485             initial.visitEachTemp(valueConsumer);
 486             initial.visitEachAlive(valueConsumer);
 487         }
 488 
 489         /**
 490          * Adds the inputs of lir instruction to the accumulator and returns, true if there was any
 491          * overlap of parameters.
 492          *
 493          * @param inst
 494          * @return true if an overlap was found
 495          */
 496         public boolean add(LIRInstruction inst) {
 497             overlap = false;
 498             inst.visitEachOutput(valueConsumer);
 499             inst.visitEachTemp(valueConsumer);
 500             inst.visitEachInput(valueConsumer);
 501             inst.visitEachAlive(valueConsumer);
 502             return overlap;
 503         }
 504     }
 505 
 506     @Override
 507     public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) {
 508         RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
 509         return new SPARCHotSpotRegisterAllocationConfig(registerConfigNonNull, allocationRestrictedTo);
 510     }
 511 
 512     @Override
 513     public EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters) {
 514         EconomicSet<Register> callerRegisters = EconomicSet.create(Equivalence.IDENTITY, calleeRegisters.size());
 515         for (Register register : calleeRegisters) {
 516             if (l0.number <= register.number && register.number <= l7.number) {
 517                 // do nothing
 518             } else if (o0.number <= register.number && register.number <= o7.number) {
 519                 // do nothing
 520             } else if (i0.number <= register.number && register.number <= i7.number) {
 521                 // translate input to output registers
 522                 callerRegisters.add(translateInputToOutputRegister(register));
 523             } else {
 524                 callerRegisters.add(register);
 525             }
 526         }
 527         return callerRegisters;
 528     }
 529 
 530     private Register translateInputToOutputRegister(Register register) {
 531         assert i0.number <= register.number && register.number <= i7.number : "Not an input register " + register;
 532         return getTarget().arch.getRegisters().get(o0.number + register.number - i0.number);
 533     }
 534 }