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