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.Debug; 63 import org.graalvm.compiler.debug.DebugCounter; 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, DebugCounter> 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) { 129 String name = SizeEstimateStatistics.class.getSimpleName() + "_" + c.getSimpleName() + "." + suffix; 130 DebugCounter m = counters.computeIfAbsent(name, (n) -> Debug.counter(n)); 131 m.add(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 CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, dataBuilder, frameContext, options, compilationResult); 243 crb.setTotalFrameSize(frameMap.totalFrameSize()); 244 crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize()); 245 StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot(); 246 if (deoptimizationRescueSlot != null && stub == null) { 247 crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot); 248 } 249 250 if (stub != null) { 251 // Even on sparc we need to save floating point registers 252 EconomicSet<Register> destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir); 253 EconomicMap<LIRFrameState, SaveRegistersOp> calleeSaveInfo = gen.getCalleeSaveInfo(); 254 updateStub(stub, destroyedCallerRegisters, calleeSaveInfo, frameMap); 255 } 256 assert registerSizePredictionValidator(crb); 257 return crb; 258 } 259 260 /** 261 * Registers a verifier which checks if the LIRInstructions estimate of constants size is 262 * greater or equal to the actual one. 263 */ 264 private static boolean registerSizePredictionValidator(final CompilationResultBuilder crb) { 265 /** 266 * Used to hold state between beforeOp and afterOp 267 */ 268 class ValidationState { 269 LIRInstruction op; 270 int constantSizeBefore; 271 272 public void before(LIRInstruction before) { 273 assert op == null : "LIRInstruction " + op + " no after call received"; 274 op = before; 275 constantSizeBefore = calculateDataSectionSize(crb.compilationResult.getDataSection()); 276 } 277 278 public void after(LIRInstruction after) { 279 assert after.equals(op) : "Instructions before/after don't match " + op + "/" + after; 280 int constantSizeAfter = calculateDataSectionSize(crb.compilationResult.getDataSection()); 281 int actual = constantSizeAfter - constantSizeBefore; 282 if (op instanceof SPARCLIRInstructionMixin) { 283 org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate size = ((SPARCLIRInstructionMixin) op).estimateSize(); 284 assert size != null : "No size prediction available for op: " + op; 285 Class<?> c = op.getClass(); 286 CONSTANT_ESTIMATED_STATS.add(c, size.constantSize); 287 CONSTANT_ACTUAL_STATS.add(c, actual); 288 assert size.constantSize >= actual : "Op " + op + " exceeded estimated constant size; predicted: " + size.constantSize + " actual: " + actual; 289 } else { 290 assert actual == 0 : "Op " + op + " emitted to DataSection without any estimate."; 291 } 292 op = null; 293 constantSizeBefore = 0; 294 } 295 } 296 final ValidationState state = new ValidationState(); 297 crb.setOpCallback(op -> state.before(op), op -> state.after(op)); 298 return true; 299 } 300 301 private static int calculateDataSectionSize(DataSection ds) { 302 int sum = 0; 303 for (Data d : ds) { 304 sum += d.getSize(); 305 } 306 return sum; 307 } 308 309 @Override 310 public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { 311 SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; 312 // TODO: (sa) Fold the two traversals into one 313 stuffDelayedControlTransfers(lir); 314 int constantSize = calculateConstantSize(lir); 315 boolean canUseImmediateConstantLoad = constantSize < (1 << 13); 316 masm.setImmediateConstantLoad(canUseImmediateConstantLoad); 317 FrameMap frameMap = crb.frameMap; 318 RegisterConfig regConfig = frameMap.getRegisterConfig(); 319 Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label(); 320 for (int i = 0; i < 2; i++) { 321 if (i > 0) { 322 crb.resetForEmittingCode(); 323 lir.resetLabels(); 324 resetDelayedControlTransfers(lir); 325 } 326 327 // Emit the prefix 328 if (unverifiedStub != null) { 329 crb.recordMark(config.MARKID_UNVERIFIED_ENTRY); 330 // We need to use JavaCall here because we haven't entered the frame yet. 331 CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, this); 332 Register inlineCacheKlass = g5; // see MacroAssembler::ic_call 333 334 try (ScratchRegister sc = masm.getScratchRegister()) { 335 Register scratch = sc.getRegister(); 336 Register receiver = asRegister(cc.getArgument(0)); 337 SPARCAddress src = new SPARCAddress(receiver, config.hubOffset); 338 339 masm.ldx(src, scratch); 340 masm.cmp(scratch, inlineCacheKlass); 341 } 342 BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, unverifiedStub); 343 masm.nop(); // delay slot 344 } 345 346 masm.align(config.codeEntryAlignment); 347 crb.recordMark(config.MARKID_OSR_ENTRY); 348 crb.recordMark(config.MARKID_VERIFIED_ENTRY); 349 350 // Emit code for the LIR 351 crb.emit(lir); 352 } 353 profileInstructions(lir, crb); 354 355 HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; 356 HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls(); 357 if (!frameContext.isStub) { 358 crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); 359 SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null); 360 crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); 361 SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, null); 362 } else { 363 // No need to emit the stubs for entries back into the method since 364 // it has no calls that can cause such "return" entries 365 } 366 367 if (unverifiedStub != null) { 368 masm.bind(unverifiedStub); 369 try (ScratchRegister sc = masm.getScratchRegister()) { 370 Register scratch = sc.getRegister(); 371 SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER)); 372 } 373 } 374 masm.peephole(); 375 } 376 377 private static int calculateConstantSize(LIR lir) { 378 int size = 0; 379 for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) { 380 if (block == null) { 381 continue; 382 } 383 for (LIRInstruction inst : lir.getLIRforBlock(block)) { 384 if (inst instanceof SPARCLIRInstructionMixin) { 385 SizeEstimate pred = ((SPARCLIRInstructionMixin) inst).estimateSize(); 386 if (pred != null) { 387 size += pred.constantSize; 388 } 389 } 390 } 391 } 392 return size; 393 } 394 395 private static void resetDelayedControlTransfers(LIR lir) { 396 for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) { 397 if (block == null) { 398 continue; 399 } 400 for (LIRInstruction inst : lir.getLIRforBlock(block)) { 401 if (inst instanceof SPARCDelayedControlTransfer) { 402 ((SPARCDelayedControlTransfer) inst).resetState(); 403 } 404 } 405 } 406 } 407 408 /** 409 * Fix-up over whole LIR. 410 * 411 * @see #stuffDelayedControlTransfers(LIR, AbstractBlockBase) 412 * @param l 413 */ 414 private static void stuffDelayedControlTransfers(LIR l) { 415 for (AbstractBlockBase<?> b : l.codeEmittingOrder()) { 416 if (b != null) { 417 stuffDelayedControlTransfers(l, b); 418 } 419 } 420 } 421 422 /** 423 * Tries to put DelayedControlTransfer instructions and DelayableLIRInstructions together. Also 424 * it tries to move the DelayedLIRInstruction to the DelayedControlTransfer instruction, if 425 * possible. 426 */ 427 private static void stuffDelayedControlTransfers(LIR l, AbstractBlockBase<?> block) { 428 ArrayList<LIRInstruction> instructions = l.getLIRforBlock(block); 429 if (instructions.size() >= 2) { 430 LIRDependencyAccumulator acc = new LIRDependencyAccumulator(); 431 SPARCDelayedControlTransfer delayedTransfer = null; 432 int delayTransferPosition = -1; 433 for (int i = instructions.size() - 1; i >= 0; i--) { 434 LIRInstruction inst = instructions.get(i); 435 boolean adjacent = delayTransferPosition - i == 1; 436 if (!adjacent || inst.destroysCallerSavedRegisters() || leavesRegisterWindow(inst)) { 437 delayedTransfer = null; 438 } 439 if (inst instanceof SPARCDelayedControlTransfer) { 440 delayedTransfer = (SPARCDelayedControlTransfer) inst; 441 acc.start(inst); 442 delayTransferPosition = i; 443 } else if (delayedTransfer != null) { 444 boolean overlap = acc.add(inst); 445 if (!overlap && inst instanceof SPARCTailDelayedLIRInstruction) { 446 // We have found a non overlapping LIR instruction which can be delayed 447 ((SPARCTailDelayedLIRInstruction) inst).setDelayedControlTransfer(delayedTransfer); 448 delayedTransfer = null; 449 } 450 } 451 } 452 } 453 } 454 455 private static boolean leavesRegisterWindow(LIRInstruction inst) { 456 return inst instanceof SPARCLIRInstructionMixin && ((SPARCLIRInstructionMixin) inst).leavesRegisterWindow(); 457 } 458 459 /** 460 * Accumulates inputs/outputs/temp/alive in a set along we walk back the LIRInstructions and 461 * detects, if there is any overlap. In this way LIRInstructions can be detected, which can be 462 * moved nearer to the DelayedControlTransfer instruction. 463 */ 464 private static class LIRDependencyAccumulator { 465 private final Set<Object> inputs = new HashSet<>(10); 466 private boolean overlap = false; 467 468 private final InstructionValueConsumer valueConsumer = (instruction, value, mode, flags) -> { 469 Object valueObject = value; 470 if (isRegister(value)) { // Canonicalize registers 471 valueObject = asRegister(value); 472 } 473 if (!inputs.add(valueObject)) { 474 overlap = true; 475 } 476 }; 477 478 public void start(LIRInstruction initial) { 479 inputs.clear(); 480 overlap = false; 481 initial.visitEachInput(valueConsumer); 482 initial.visitEachTemp(valueConsumer); 483 initial.visitEachAlive(valueConsumer); 484 } 485 486 /** 487 * Adds the inputs of lir instruction to the accumulator and returns, true if there was any 488 * overlap of parameters. 489 * 490 * @param inst 491 * @return true if an overlap was found 492 */ 493 public boolean add(LIRInstruction inst) { 494 overlap = false; 495 inst.visitEachOutput(valueConsumer); 496 inst.visitEachTemp(valueConsumer); 497 inst.visitEachInput(valueConsumer); 498 inst.visitEachAlive(valueConsumer); 499 return overlap; 500 } 501 } 502 503 @Override 504 public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) { 505 RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; 506 return new SPARCHotSpotRegisterAllocationConfig(registerConfigNonNull, allocationRestrictedTo); 507 } 508 509 @Override 510 public EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters) { 511 EconomicSet<Register> callerRegisters = EconomicSet.create(Equivalence.IDENTITY, calleeRegisters.size()); 512 for (Register register : calleeRegisters) { 513 if (l0.number <= register.number && register.number <= l7.number) { 514 // do nothing 515 } else if (o0.number <= register.number && register.number <= o7.number) { 516 // do nothing 517 } else if (i0.number <= register.number && register.number <= i7.number) { 518 // translate input to output registers 519 callerRegisters.add(translateInputToOutputRegister(register)); 520 } else { 521 callerRegisters.add(register); 522 } 523 } 524 return callerRegisters; 525 } 526 527 private Register translateInputToOutputRegister(Register register) { 528 assert i0.number <= register.number && register.number <= i7.number : "Not an input register " + register; 529 return getTarget().arch.getRegisters().get(o0.number + register.number - i0.number); 530 } 531 }