--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java Thu Feb 16 15:46:09 2017 -0800
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.sparc;
+
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isGlobalRegister;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
+import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual;
+import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARC.g5;
+import static jdk.vm.ci.sparc.SPARC.i0;
+import static jdk.vm.ci.sparc.SPARC.i7;
+import static jdk.vm.ci.sparc.SPARC.l0;
+import static jdk.vm.ci.sparc.SPARC.l7;
+import static jdk.vm.ci.sparc.SPARC.o0;
+import static jdk.vm.ci.sparc.SPARC.o7;
+import static jdk.vm.ci.sparc.SPARC.sp;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.graalvm.compiler.asm.Assembler;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.sparc.SPARCAddress;
+import org.graalvm.compiler.asm.sparc.SPARCAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.DataSection;
+import org.graalvm.compiler.code.DataSection.Data;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.core.sparc.SPARCNodeMatchRules;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.hotspot.HotSpotDataBuilder;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.Stub;
+import org.graalvm.compiler.lir.InstructionValueConsumer;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
+import org.graalvm.compiler.lir.asm.DataBuilder;
+import org.graalvm.compiler.lir.asm.FrameContext;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.lir.sparc.SPARCCall;
+import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer;
+import org.graalvm.compiler.lir.sparc.SPARCFrameMap;
+import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin;
+import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate;
+import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * HotSpot SPARC specific backend.
+ */
+public class SPARCHotSpotBackend extends HotSpotHostBackend {
+
+ private static final SizeEstimateStatistics CONSTANT_ESTIMATED_STATS = new SizeEstimateStatistics("ESTIMATE");
+ private static final SizeEstimateStatistics CONSTANT_ACTUAL_STATS = new SizeEstimateStatistics("ACTUAL");
+
+ public SPARCHotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) {
+ super(config, runtime, providers);
+ }
+
+ private static class SizeEstimateStatistics {
+ private static final ConcurrentHashMap<String, DebugCounter> counters = new ConcurrentHashMap<>();
+ private final String suffix;
+
+ SizeEstimateStatistics(String suffix) {
+ super();
+ this.suffix = suffix;
+ }
+
+ public void add(Class<?> c, int count) {
+ String name = SizeEstimateStatistics.class.getSimpleName() + "_" + c.getSimpleName() + "." + suffix;
+ DebugCounter m = counters.computeIfAbsent(name, (n) -> Debug.counter(n));
+ m.add(count);
+ }
+ }
+
+ @Override
+ public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
+ RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+ return new SPARCFrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
+ }
+
+ @Override
+ public FrameMap newFrameMap(RegisterConfig registerConfig) {
+ return new SPARCFrameMap(getCodeCache(), registerConfig, this);
+ }
+
+ @Override
+ public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) {
+ return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getVMConfig(), lirGenRes);
+ }
+
+ @Override
+ public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) {
+ return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub);
+ }
+
+ @Override
+ public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) {
+ return new SPARCHotSpotNodeLIRBuilder(graph, lirGen, new SPARCNodeMatchRules(lirGen));
+ }
+
+ @Override
+ protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) {
+ // Use SPARCAddress to get the final displacement including the stack bias.
+ SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+ SPARCAddress address = new SPARCAddress(sp, -bangOffset);
+ if (SPARCAssembler.isSimm13(address.getDisplacement())) {
+ masm.stx(g0, address);
+ } else {
+ try (ScratchRegister sc = masm.getScratchRegister()) {
+ Register scratch = sc.getRegister();
+ assert isGlobalRegister(scratch) : "Only global (g1-g7) registers are allowed if the frame was not initialized here. Got register " + scratch;
+ masm.setx(address.getDisplacement(), scratch, false);
+ masm.stx(g0, new SPARCAddress(sp, scratch));
+ }
+ }
+ }
+
+ public class HotSpotFrameContext implements FrameContext {
+
+ final boolean isStub;
+
+ HotSpotFrameContext(boolean isStub) {
+ this.isStub = isStub;
+ }
+
+ @Override
+ public boolean hasFrame() {
+ return true;
+ }
+
+ @Override
+ public void enter(CompilationResultBuilder crb) {
+ final int frameSize = crb.frameMap.totalFrameSize();
+ final int stackpoinerChange = -frameSize;
+ SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+ emitStackOverflowCheck(crb);
+
+ if (SPARCAssembler.isSimm13(stackpoinerChange)) {
+ masm.save(sp, stackpoinerChange, sp);
+ } else {
+ try (ScratchRegister sc = masm.getScratchRegister()) {
+ Register scratch = sc.getRegister();
+ assert isGlobalRegister(scratch) : "Only global registers are allowed before save. Got register " + scratch;
+ masm.setx(stackpoinerChange, scratch, false);
+ masm.save(sp, scratch, sp);
+ }
+ }
+
+ if (ZapStackOnMethodEntry.getValue()) {
+ final int slotSize = 8;
+ for (int i = 0; i < frameSize / slotSize; ++i) {
+ // 0xC1C1C1C1
+ masm.stx(g0, new SPARCAddress(sp, i * slotSize));
+ }
+ }
+ }
+
+ @Override
+ public void leave(CompilationResultBuilder crb) {
+ SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+ masm.restoreWindow();
+ }
+ }
+
+ @Override
+ protected Assembler createAssembler(FrameMap frameMap) {
+ return new SPARCMacroAssembler(getTarget());
+ }
+
+ @Override
+ public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) {
+ HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRes;
+ LIR lir = gen.getLIR();
+ assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
+
+ Stub stub = gen.getStub();
+ Assembler masm = createAssembler(frameMap);
+ // On SPARC we always use stack frames.
+ HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null);
+ DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget());
+ CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, dataBuilder, frameContext, compilationResult);
+ crb.setTotalFrameSize(frameMap.totalFrameSize());
+ crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize());
+ StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot();
+ if (deoptimizationRescueSlot != null && stub == null) {
+ crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot);
+ }
+
+ if (stub != null) {
+ // Even on sparc we need to save floating point registers
+ Set<Register> destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir);
+ Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = gen.getCalleeSaveInfo();
+ updateStub(stub, destroyedCallerRegisters, calleeSaveInfo, frameMap);
+ }
+ assert registerSizePredictionValidator(crb);
+ return crb;
+ }
+
+ /**
+ * Registers a verifier which checks if the LIRInstructions estimate of constants size is
+ * greater or equal to the actual one.
+ */
+ private static boolean registerSizePredictionValidator(final CompilationResultBuilder crb) {
+ /**
+ * Used to hold state between beforeOp and afterOp
+ */
+ class ValidationState {
+ LIRInstruction op;
+ int constantSizeBefore;
+
+ public void before(LIRInstruction before) {
+ assert op == null : "LIRInstruction " + op + " no after call received";
+ op = before;
+ constantSizeBefore = calculateDataSectionSize(crb.compilationResult.getDataSection());
+ }
+
+ public void after(LIRInstruction after) {
+ assert after.equals(op) : "Instructions before/after don't match " + op + "/" + after;
+ int constantSizeAfter = calculateDataSectionSize(crb.compilationResult.getDataSection());
+ int actual = constantSizeAfter - constantSizeBefore;
+ if (op instanceof SPARCLIRInstructionMixin) {
+ org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate size = ((SPARCLIRInstructionMixin) op).estimateSize();
+ assert size != null : "No size prediction available for op: " + op;
+ Class<?> c = op.getClass();
+ CONSTANT_ESTIMATED_STATS.add(c, size.constantSize);
+ CONSTANT_ACTUAL_STATS.add(c, actual);
+ assert size.constantSize >= actual : "Op " + op + " exceeded estimated constant size; predicted: " + size.constantSize + " actual: " + actual;
+ } else {
+ assert actual == 0 : "Op " + op + " emitted to DataSection without any estimate.";
+ }
+ op = null;
+ constantSizeBefore = 0;
+ }
+ }
+ final ValidationState state = new ValidationState();
+ crb.setOpCallback(op -> state.before(op), op -> state.after(op));
+ return true;
+ }
+
+ private static int calculateDataSectionSize(DataSection ds) {
+ int sum = 0;
+ for (Data d : ds) {
+ sum += d.getSize();
+ }
+ return sum;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) {
+ SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm;
+ // TODO: (sa) Fold the two traversals into one
+ stuffDelayedControlTransfers(lir);
+ int constantSize = calculateConstantSize(lir);
+ boolean canUseImmediateConstantLoad = constantSize < (1 << 13);
+ masm.setImmediateConstantLoad(canUseImmediateConstantLoad);
+ FrameMap frameMap = crb.frameMap;
+ RegisterConfig regConfig = frameMap.getRegisterConfig();
+ Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label();
+ for (int i = 0; i < 2; i++) {
+ if (i > 0) {
+ crb.resetForEmittingCode();
+ lir.resetLabels();
+ resetDelayedControlTransfers(lir);
+ }
+
+ // Emit the prefix
+ if (unverifiedStub != null) {
+ crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
+ // We need to use JavaCall here because we haven't entered the frame yet.
+ CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, this);
+ Register inlineCacheKlass = g5; // see MacroAssembler::ic_call
+
+ try (ScratchRegister sc = masm.getScratchRegister()) {
+ Register scratch = sc.getRegister();
+ Register receiver = asRegister(cc.getArgument(0));
+ SPARCAddress src = new SPARCAddress(receiver, config.hubOffset);
+
+ masm.ldx(src, scratch);
+ masm.cmp(scratch, inlineCacheKlass);
+ }
+ BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, unverifiedStub);
+ masm.nop(); // delay slot
+ }
+
+ masm.align(config.codeEntryAlignment);
+ crb.recordMark(config.MARKID_OSR_ENTRY);
+ crb.recordMark(config.MARKID_VERIFIED_ENTRY);
+
+ // Emit code for the LIR
+ crb.emit(lir);
+ }
+ profileInstructions(lir, crb);
+
+ HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
+ HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls();
+ if (!frameContext.isStub) {
+ crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
+ SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null);
+ crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
+ SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER), null, null);
+ } else {
+ // No need to emit the stubs for entries back into the method since
+ // it has no calls that can cause such "return" entries
+ }
+
+ if (unverifiedStub != null) {
+ masm.bind(unverifiedStub);
+ try (ScratchRegister sc = masm.getScratchRegister()) {
+ Register scratch = sc.getRegister();
+ SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER));
+ }
+ }
+ masm.peephole();
+ }
+
+ private static int calculateConstantSize(LIR lir) {
+ int size = 0;
+ for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+ if (block == null) {
+ continue;
+ }
+ for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+ if (inst instanceof SPARCLIRInstructionMixin) {
+ SizeEstimate pred = ((SPARCLIRInstructionMixin) inst).estimateSize();
+ if (pred != null) {
+ size += pred.constantSize;
+ }
+ }
+ }
+ }
+ return size;
+ }
+
+ private static void resetDelayedControlTransfers(LIR lir) {
+ for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+ if (block == null) {
+ continue;
+ }
+ for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+ if (inst instanceof SPARCDelayedControlTransfer) {
+ ((SPARCDelayedControlTransfer) inst).resetState();
+ }
+ }
+ }
+ }
+
+ /**
+ * Fix-up over whole LIR.
+ *
+ * @see #stuffDelayedControlTransfers(LIR, AbstractBlockBase)
+ * @param l
+ */
+ private static void stuffDelayedControlTransfers(LIR l) {
+ for (AbstractBlockBase<?> b : l.codeEmittingOrder()) {
+ if (b != null) {
+ stuffDelayedControlTransfers(l, b);
+ }
+ }
+ }
+
+ /**
+ * Tries to put DelayedControlTransfer instructions and DelayableLIRInstructions together. Also
+ * it tries to move the DelayedLIRInstruction to the DelayedControlTransfer instruction, if
+ * possible.
+ */
+ private static void stuffDelayedControlTransfers(LIR l, AbstractBlockBase<?> block) {
+ List<LIRInstruction> instructions = l.getLIRforBlock(block);
+ if (instructions.size() >= 2) {
+ LIRDependencyAccumulator acc = new LIRDependencyAccumulator();
+ SPARCDelayedControlTransfer delayedTransfer = null;
+ int delayTransferPosition = -1;
+ for (int i = instructions.size() - 1; i >= 0; i--) {
+ LIRInstruction inst = instructions.get(i);
+ boolean adjacent = delayTransferPosition - i == 1;
+ if (!adjacent || inst.destroysCallerSavedRegisters() || leavesRegisterWindow(inst)) {
+ delayedTransfer = null;
+ }
+ if (inst instanceof SPARCDelayedControlTransfer) {
+ delayedTransfer = (SPARCDelayedControlTransfer) inst;
+ acc.start(inst);
+ delayTransferPosition = i;
+ } else if (delayedTransfer != null) {
+ boolean overlap = acc.add(inst);
+ if (!overlap && inst instanceof SPARCTailDelayedLIRInstruction) {
+ // We have found a non overlapping LIR instruction which can be delayed
+ ((SPARCTailDelayedLIRInstruction) inst).setDelayedControlTransfer(delayedTransfer);
+ delayedTransfer = null;
+ }
+ }
+ }
+ }
+ }
+
+ private static boolean leavesRegisterWindow(LIRInstruction inst) {
+ return inst instanceof SPARCLIRInstructionMixin && ((SPARCLIRInstructionMixin) inst).leavesRegisterWindow();
+ }
+
+ /**
+ * Accumulates inputs/outputs/temp/alive in a set along we walk back the LIRInstructions and
+ * detects, if there is any overlap. In this way LIRInstructions can be detected, which can be
+ * moved nearer to the DelayedControlTransfer instruction.
+ */
+ private static class LIRDependencyAccumulator {
+ private final Set<Object> inputs = new HashSet<>(10);
+ private boolean overlap = false;
+
+ private final InstructionValueConsumer valueConsumer = (instruction, value, mode, flags) -> {
+ Object valueObject = value;
+ if (isRegister(value)) { // Canonicalize registers
+ valueObject = asRegister(value);
+ }
+ if (!inputs.add(valueObject)) {
+ overlap = true;
+ }
+ };
+
+ public void start(LIRInstruction initial) {
+ inputs.clear();
+ overlap = false;
+ initial.visitEachInput(valueConsumer);
+ initial.visitEachTemp(valueConsumer);
+ initial.visitEachAlive(valueConsumer);
+ }
+
+ /**
+ * Adds the inputs of lir instruction to the accumulator and returns, true if there was any
+ * overlap of parameters.
+ *
+ * @param inst
+ * @return true if an overlap was found
+ */
+ public boolean add(LIRInstruction inst) {
+ overlap = false;
+ inst.visitEachOutput(valueConsumer);
+ inst.visitEachTemp(valueConsumer);
+ inst.visitEachInput(valueConsumer);
+ inst.visitEachAlive(valueConsumer);
+ return overlap;
+ }
+ }
+
+ @Override
+ public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig) {
+ RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
+ return new SPARCHotSpotRegisterAllocationConfig(registerConfigNonNull);
+ }
+
+ @Override
+ public Set<Register> translateToCallerRegisters(Set<Register> calleeRegisters) {
+ HashSet<Register> callerRegisters = new HashSet<>(calleeRegisters.size());
+ for (Register register : calleeRegisters) {
+ if (l0.number <= register.number && register.number <= l7.number) {
+ // do nothing
+ } else if (o0.number <= register.number && register.number <= o7.number) {
+ // do nothing
+ } else if (i0.number <= register.number && register.number <= i7.number) {
+ // translate input to output registers
+ callerRegisters.add(translateInputToOutputRegister(register));
+ } else {
+ callerRegisters.add(register);
+ }
+ }
+ return callerRegisters;
+ }
+
+ private Register translateInputToOutputRegister(Register register) {
+ assert i0.number <= register.number && register.number <= i7.number : "Not an input register " + register;
+ return getTarget().arch.getRegisters().get(o0.number + register.number - i0.number);
+ }
+}