001/* 002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.lir.sparc; 024 025import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; 026import static jdk.internal.jvmci.code.ValueUtil.*; 027import static jdk.internal.jvmci.sparc.SPARC.*; 028import jdk.internal.jvmci.code.*; 029import jdk.internal.jvmci.common.*; 030import jdk.internal.jvmci.meta.*; 031 032import com.oracle.graal.asm.sparc.*; 033import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; 034import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Sethix; 035import com.oracle.graal.compiler.common.spi.*; 036import com.oracle.graal.lir.*; 037import com.oracle.graal.lir.asm.*; 038 039public class SPARCCall { 040 041 public abstract static class CallOp extends SPARCLIRInstruction { 042 @Def({REG, ILLEGAL}) protected Value result; 043 @Use({REG, STACK}) protected Value[] parameters; 044 @Temp protected Value[] temps; 045 @State protected LIRFrameState state; 046 047 protected CallOp(LIRInstructionClass<? extends CallOp> c, SizeEstimate size, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 048 super(c, size); 049 this.result = result; 050 this.parameters = parameters; 051 this.state = state; 052 this.temps = temps; 053 assert temps != null; 054 } 055 056 @Override 057 public boolean destroysCallerSavedRegisters() { 058 return true; 059 } 060 } 061 062 public abstract static class MethodCallOp extends CallOp { 063 064 protected final ResolvedJavaMethod callTarget; 065 066 protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 067 super(c, size, result, parameters, temps, state); 068 this.callTarget = callTarget; 069 } 070 071 } 072 073 @Opcode("CALL_DIRECT") 074 public abstract static class DirectCallOp extends MethodCallOp { 075 private boolean emitted = false; 076 private int before = -1; 077 078 public DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 079 super(c, size, callTarget, result, parameters, temps, state); 080 } 081 082 @Override 083 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 084 if (!emitted) { 085 emitCallPrefixCode(crb, masm); 086 directCall(crb, masm, callTarget, null, state); 087 } else { 088 int after = masm.position(); 089 if (after - before == 4) { 090 masm.nop(); 091 } else if (after - before == 8) { 092 // everything is fine; 093 } else { 094 JVMCIError.shouldNotReachHere("" + (after - before)); 095 } 096 after = masm.position(); 097 crb.recordDirectCall(before, after, callTarget, state); 098 crb.recordExceptionHandlers(after, state); 099 masm.ensureUniquePC(); 100 } 101 } 102 103 @SuppressWarnings("unused") 104 public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 105 // 106 } 107 108 public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 109 assert !emitted; 110 emitCallPrefixCode(crb, masm); 111 before = masm.call(0); 112 emitted = true; 113 } 114 115 public void resetState() { 116 emitted = false; 117 before = -1; 118 } 119 } 120 121 @Opcode("CALL_INDIRECT") 122 public abstract static class IndirectCallOp extends MethodCallOp { 123 @Use({REG}) protected Value targetAddress; 124 125 protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, 126 Value targetAddress, LIRFrameState state) { 127 super(c, size, callTarget, result, parameters, temps, state); 128 this.targetAddress = targetAddress; 129 } 130 131 @Override 132 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 133 indirectCall(crb, masm, asRegister(targetAddress), callTarget, state); 134 } 135 136 @Override 137 public void verify() { 138 super.verify(); 139 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"; 140 } 141 } 142 143 public abstract static class ForeignCallOp extends CallOp { 144 public static final LIRInstructionClass<ForeignCallOp> TYPE = LIRInstructionClass.create(ForeignCallOp.class); 145 146 protected final ForeignCallLinkage callTarget; 147 148 public ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, SizeEstimate size, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 149 super(c, size, result, parameters, temps, state); 150 this.callTarget = callTarget; 151 } 152 153 @Override 154 public boolean destroysCallerSavedRegisters() { 155 return callTarget.destroysRegisters(); 156 } 157 } 158 159 @Opcode("NEAR_FOREIGN_CALL") 160 public static final class DirectNearForeignCallOp extends ForeignCallOp { 161 public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class); 162 public static final SizeEstimate SIZE = SizeEstimate.create(1); 163 164 public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 165 super(TYPE, SIZE, linkage, result, parameters, temps, state); 166 } 167 168 @Override 169 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 170 directCall(crb, masm, callTarget, null, state); 171 } 172 } 173 174 @Opcode("FAR_FOREIGN_CALL") 175 public static final class DirectFarForeignCallOp extends ForeignCallOp { 176 public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class); 177 public static final SizeEstimate SIZE = SizeEstimate.create(1); 178 179 public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 180 super(TYPE, SIZE, callTarget, result, parameters, temps, state); 181 } 182 183 @Override 184 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 185 try (ScratchRegister scratch = masm.getScratchRegister()) { 186 directCall(crb, masm, callTarget, scratch.getRegister(), state); 187 } 188 } 189 } 190 191 public static void directCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) { 192 int before; 193 if (scratch != null) { 194 // offset might not fit a 30-bit displacement, generate an 195 // indirect call with a 64-bit immediate 196 before = masm.position(); 197 new Sethix(0L, scratch, true).emit(masm); 198 masm.jmpl(scratch, 0, o7); 199 } else { 200 before = masm.call(0); 201 } 202 masm.nop(); // delay slot 203 int after = masm.position(); 204 crb.recordDirectCall(before, after, callTarget, info); 205 crb.recordExceptionHandlers(after, info); 206 masm.ensureUniquePC(); 207 } 208 209 public static void indirectJmp(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget target) { 210 int before = masm.position(); 211 new Sethix(0L, dst, true).emit(masm); 212 masm.jmp(new SPARCAddress(dst, 0)); 213 masm.nop(); // delay slot 214 int after = masm.position(); 215 crb.recordIndirectCall(before, after, target, null); 216 masm.ensureUniquePC(); 217 } 218 219 public static void indirectCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { 220 int before = masm.jmpl(dst, 0, o7); 221 masm.nop(); // delay slot 222 int after = masm.position(); 223 crb.recordIndirectCall(before, after, callTarget, info); 224 crb.recordExceptionHandlers(after, info); 225 masm.ensureUniquePC(); 226 } 227}