SPARCCall.java revision 12651:6ef01bd40ce2
165692Sroger/* 2130356Sschweikh * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 365692Sroger * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 465692Sroger * 565692Sroger * This code is free software; you can redistribute it and/or modify it 665692Sroger * under the terms of the GNU General Public License version 2 only, as 765692Sroger * published by the Free Software Foundation. 865692Sroger * 965692Sroger * This code is distributed in the hope that it will be useful, but WITHOUT 1065692Sroger * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1165692Sroger * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1265692Sroger * version 2 for more details (a copy is included in the LICENSE file that 1365692Sroger * accompanied this code). 14139749Simp * 1565692Sroger * You should have received a copy of the GNU General Public License version 1665692Sroger * 2 along with this work; if not, write to the Free Software Foundation, 1765692Sroger * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1865692Sroger * 1965692Sroger * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2065692Sroger * or visit www.oracle.com if you need additional information or have any 2165692Sroger * questions. 2265692Sroger */ 2365692Srogerpackage org.graalvm.compiler.lir.sparc; 2465692Sroger 2565692Srogerimport static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; 2665692Srogerimport static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 2765692Srogerimport static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; 2865692Srogerimport static jdk.vm.ci.code.ValueUtil.asRegister; 2965692Srogerimport static jdk.vm.ci.code.ValueUtil.isRegister; 3065692Srogerimport static jdk.vm.ci.sparc.SPARC.o7; 3165692Sroger 3265692Srogerimport org.graalvm.compiler.asm.sparc.SPARCAddress; 3365692Srogerimport org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; 3465692Srogerimport org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; 3565692Srogerimport org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 3665692Srogerimport org.graalvm.compiler.debug.GraalError; 3765692Srogerimport org.graalvm.compiler.lir.LIRFrameState; 3865692Srogerimport org.graalvm.compiler.lir.LIRInstructionClass; 3965692Srogerimport org.graalvm.compiler.lir.Opcode; 4065692Srogerimport org.graalvm.compiler.lir.asm.CompilationResultBuilder; 4165692Sroger 4265692Srogerimport jdk.vm.ci.code.Register; 4365692Srogerimport jdk.vm.ci.meta.InvokeTarget; 4465692Srogerimport jdk.vm.ci.meta.ResolvedJavaMethod; 4565692Srogerimport jdk.vm.ci.meta.Value; 46130359Sschweikh 47130359Sschweikhpublic class SPARCCall { 4865692Sroger 4965692Sroger public abstract static class CallOp extends SPARCLIRInstruction { 5065692Sroger @Def({REG, ILLEGAL}) protected Value result; 51129879Sphk @Use({REG, STACK}) protected Value[] parameters; 5286903Srwatson @Temp({REG, STACK}) protected Value[] temps; 5365692Sroger @State protected LIRFrameState state; 5465692Sroger 5565692Sroger protected CallOp(LIRInstructionClass<? extends CallOp> c, SizeEstimate size, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 56130359Sschweikh super(c, size); 57130359Sschweikh this.result = result; 58130359Sschweikh this.parameters = parameters; 59130359Sschweikh this.state = state; 60130359Sschweikh this.temps = addStackSlotsToTemporaries(parameters, temps); 61130359Sschweikh assert temps != null; 6265692Sroger } 6365692Sroger 6465692Sroger @Override 6565692Sroger public boolean destroysCallerSavedRegisters() { 6665692Sroger return true; 6765692Sroger } 6865692Sroger } 6965692Sroger 7065692Sroger public abstract static class MethodCallOp extends CallOp { 7165692Sroger 7265692Sroger protected final ResolvedJavaMethod callTarget; 73130359Sschweikh 74130359Sschweikh protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 75130359Sschweikh super(c, size, result, parameters, temps, state); 76130359Sschweikh this.callTarget = callTarget; 77130359Sschweikh } 7865692Sroger 79130359Sschweikh } 80130359Sschweikh 81130359Sschweikh @Opcode("CALL_DIRECT") 82130359Sschweikh public abstract static class DirectCallOp extends MethodCallOp { 83130359Sschweikh private boolean emitted = false; 84130359Sschweikh private int before = -1; 8565692Sroger 8665692Sroger public DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 8765692Sroger super(c, size, callTarget, result, parameters, temps, state); 8865743Sroger } 8965743Sroger 9065692Sroger @Override 91132199Sphk public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 9265692Sroger if (!emitted) { 9365692Sroger emitCallPrefixCode(crb, masm); 94130359Sschweikh directCall(crb, masm, callTarget, null, state); 95130356Sschweikh } else { 9665692Sroger int after = masm.position(); 9765692Sroger if (after - before == 4) { 9865692Sroger masm.nop(); 9965692Sroger } else if (after - before == 8) { 100130359Sschweikh // everything is fine; 101130359Sschweikh } else { 10265692Sroger GraalError.shouldNotReachHere("" + (after - before)); 103130359Sschweikh } 104130359Sschweikh after = masm.position(); 10565692Sroger crb.recordDirectCall(before, after, callTarget, state); 10665692Sroger crb.recordExceptionHandlers(after, state); 10765692Sroger masm.ensureUniquePC(); 10865692Sroger } 10965692Sroger } 11065692Sroger 11165692Sroger @SuppressWarnings("unused") 11265692Sroger public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 11365692Sroger // 114130359Sschweikh } 115130359Sschweikh 11665692Sroger public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 117130359Sschweikh assert !emitted; 118140883Simp emitCallPrefixCode(crb, masm); 119140883Simp before = masm.call(0); 12065692Sroger emitted = true; 12165692Sroger } 12265692Sroger 12365692Sroger public void resetState() { 124130359Sschweikh emitted = false; 125130359Sschweikh before = -1; 126130359Sschweikh } 127130359Sschweikh } 128130359Sschweikh 129130359Sschweikh @Opcode("CALL_INDIRECT") 130130359Sschweikh public abstract static class IndirectCallOp extends MethodCallOp { 131130359Sschweikh @Use({REG}) protected Value targetAddress; 132130359Sschweikh 133130359Sschweikh protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, 134130359Sschweikh Value targetAddress, LIRFrameState state) { 135130359Sschweikh super(c, size, callTarget, result, parameters, temps, state); 136130359Sschweikh this.targetAddress = targetAddress; 137130359Sschweikh } 138130359Sschweikh 139130359Sschweikh @Override 140130359Sschweikh public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 141130359Sschweikh indirectCall(crb, masm, asRegister(targetAddress), callTarget, state); 142130359Sschweikh } 143130359Sschweikh 144130359Sschweikh @Override 145140883Simp public void verify() { 146140883Simp super.verify(); 147130359Sschweikh assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, it must be in a fixed register for now"; 14865692Sroger } 14965692Sroger } 15065692Sroger 15165692Sroger public abstract static class ForeignCallOp extends CallOp { 15265692Sroger public static final LIRInstructionClass<ForeignCallOp> TYPE = LIRInstructionClass.create(ForeignCallOp.class); 15365692Sroger 154130359Sschweikh protected final ForeignCallLinkage callTarget; 155130359Sschweikh 15665692Sroger public ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, SizeEstimate size, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 157130359Sschweikh super(c, size, result, parameters, temps, state); 158130359Sschweikh this.callTarget = callTarget; 159130359Sschweikh } 160130359Sschweikh 16165692Sroger @Override 16265692Sroger public boolean destroysCallerSavedRegisters() { 163130359Sschweikh return callTarget.destroysRegisters(); 164130359Sschweikh } 165130359Sschweikh } 166130359Sschweikh 167130359Sschweikh @Opcode("NEAR_FOREIGN_CALL") 168130359Sschweikh public static final class DirectNearForeignCallOp extends ForeignCallOp { 169130359Sschweikh public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class); 170130359Sschweikh public static final SizeEstimate SIZE = SizeEstimate.create(1); 171130359Sschweikh 172130359Sschweikh public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 173130359Sschweikh super(TYPE, SIZE, linkage, result, parameters, temps, state); 174130359Sschweikh } 175130359Sschweikh 176130359Sschweikh @Override 17765692Sroger public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 17865692Sroger directCall(crb, masm, callTarget, null, state); 17965692Sroger } 18065692Sroger } 18165692Sroger 18265692Sroger @Opcode("FAR_FOREIGN_CALL") 183130359Sschweikh public static final class DirectFarForeignCallOp extends ForeignCallOp { 184130359Sschweikh public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class); 185241394Skevlo public static final SizeEstimate SIZE = SizeEstimate.create(1); 18665692Sroger 187130359Sschweikh public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 188130359Sschweikh super(TYPE, SIZE, callTarget, result, parameters, temps, state); 189130359Sschweikh } 190130359Sschweikh 191130359Sschweikh @Override 19265743Sroger public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 19365728Sroger try (ScratchRegister scratch = masm.getScratchRegister()) { 194 directCall(crb, masm, callTarget, scratch.getRegister(), state); 195 } 196 } 197 } 198 199 public static void directCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) { 200 int before; 201 if (scratch != null) { 202 // offset might not fit a 30-bit displacement, generate an 203 // indirect call with a 64-bit immediate 204 before = masm.position(); 205 masm.sethix(0L, scratch, true); 206 masm.jmpl(scratch, 0, o7); 207 } else { 208 before = masm.call(0); 209 } 210 masm.nop(); // delay slot 211 int after = masm.position(); 212 crb.recordDirectCall(before, after, callTarget, info); 213 crb.recordExceptionHandlers(after, info); 214 masm.ensureUniquePC(); 215 } 216 217 public static void indirectJmp(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget target) { 218 int before = masm.position(); 219 masm.sethix(0L, dst, true); 220 masm.jmp(new SPARCAddress(dst, 0)); 221 masm.nop(); // delay slot 222 int after = masm.position(); 223 crb.recordIndirectCall(before, after, target, null); 224 masm.ensureUniquePC(); 225 } 226 227 public static void indirectCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { 228 int before = masm.jmpl(dst, 0, o7); 229 masm.nop(); // delay slot 230 int after = masm.position(); 231 crb.recordIndirectCall(before, after, callTarget, info); 232 crb.recordExceptionHandlers(after, info); 233 masm.ensureUniquePC(); 234 } 235} 236