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