1 /*
   2  * Copyright (c) 2013, 2018, 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 
  24 
  25 package org.graalvm.compiler.lir.sparc;
  26 
  27 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
  28 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
  29 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
  30 import static jdk.vm.ci.code.ValueUtil.asRegister;
  31 import static jdk.vm.ci.code.ValueUtil.isRegister;
  32 import static jdk.vm.ci.sparc.SPARC.o7;
  33 
  34 import org.graalvm.compiler.asm.sparc.SPARCAddress;
  35 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
  36 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
  37 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  38 import org.graalvm.compiler.debug.GraalError;
  39 import org.graalvm.compiler.lir.LIRFrameState;
  40 import org.graalvm.compiler.lir.LIRInstructionClass;
  41 import org.graalvm.compiler.lir.Opcode;
  42 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
  43 
  44 import jdk.vm.ci.code.Register;
  45 import jdk.vm.ci.meta.InvokeTarget;
  46 import jdk.vm.ci.meta.ResolvedJavaMethod;
  47 import jdk.vm.ci.meta.Value;
  48 
  49 public class SPARCCall {
  50 
  51     public abstract static class CallOp extends SPARCLIRInstruction {
  52         @Def({REG, ILLEGAL}) protected Value result;
  53         @Use({REG, STACK}) protected Value[] parameters;
  54         @Temp({REG, STACK}) protected Value[] temps;
  55         @State protected LIRFrameState state;
  56 
  57         protected CallOp(LIRInstructionClass<? extends CallOp> c, SizeEstimate size, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
  58             super(c, size);
  59             this.result = result;
  60             this.parameters = parameters;
  61             this.state = state;
  62             this.temps = addStackSlotsToTemporaries(parameters, temps);
  63             assert temps != null;
  64         }
  65 
  66         @Override
  67         public boolean destroysCallerSavedRegisters() {
  68             return true;
  69         }
  70     }
  71 
  72     public abstract static class MethodCallOp extends CallOp {
  73 
  74         protected final ResolvedJavaMethod callTarget;
  75 
  76         protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
  77             super(c, size, result, parameters, temps, state);
  78             this.callTarget = callTarget;
  79         }
  80 
  81     }
  82 
  83     @Opcode("CALL_DIRECT")
  84     public abstract static class DirectCallOp extends MethodCallOp {
  85         private boolean emitted = false;
  86         private int before = -1;
  87 
  88         public DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
  89             super(c, size, callTarget, result, parameters, temps, state);
  90         }
  91 
  92         @Override
  93         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
  94             if (!emitted) {
  95                 emitCallPrefixCode(crb, masm);
  96                 directCall(crb, masm, callTarget, null, state);
  97             } else {
  98                 int after = masm.position();
  99                 if (after - before == 4) {
 100                     masm.nop();
 101                 } else if (after - before == 8) {
 102                     // everything is fine;
 103                 } else {
 104                     GraalError.shouldNotReachHere("" + (after - before));
 105                 }
 106                 after = masm.position();
 107                 crb.recordDirectCall(before, after, callTarget, state);
 108                 crb.recordExceptionHandlers(after, state);
 109                 masm.ensureUniquePC();
 110             }
 111         }
 112 
 113         @SuppressWarnings("unused")
 114         public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
 115             //
 116         }
 117 
 118         public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
 119             assert !emitted;
 120             emitCallPrefixCode(crb, masm);
 121             before = masm.call(0);
 122             emitted = true;
 123         }
 124 
 125         public void resetState() {
 126             emitted = false;
 127             before = -1;
 128         }
 129     }
 130 
 131     @Opcode("CALL_INDIRECT")
 132     public abstract static class IndirectCallOp extends MethodCallOp {
 133         @Use({REG}) protected Value targetAddress;
 134 
 135         protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps,
 136                         Value targetAddress, LIRFrameState state) {
 137             super(c, size, callTarget, result, parameters, temps, state);
 138             this.targetAddress = targetAddress;
 139         }
 140 
 141         @Override
 142         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
 143             indirectCall(crb, masm, asRegister(targetAddress), callTarget, state);
 144         }
 145 
 146         @Override
 147         public void verify() {
 148             super.verify();
 149             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";
 150         }
 151     }
 152 
 153     public abstract static class ForeignCallOp extends CallOp {
 154         public static final LIRInstructionClass<ForeignCallOp> TYPE = LIRInstructionClass.create(ForeignCallOp.class);
 155 
 156         protected final ForeignCallLinkage callTarget;
 157 
 158         public ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, SizeEstimate size, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
 159             super(c, size, result, parameters, temps, state);
 160             this.callTarget = callTarget;
 161         }
 162 
 163         @Override
 164         public boolean destroysCallerSavedRegisters() {
 165             return callTarget.destroysRegisters();
 166         }
 167     }
 168 
 169     @Opcode("NEAR_FOREIGN_CALL")
 170     public static final class DirectNearForeignCallOp extends ForeignCallOp {
 171         public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class);
 172         public static final SizeEstimate SIZE = SizeEstimate.create(1);
 173 
 174         public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
 175             super(TYPE, SIZE, linkage, result, parameters, temps, state);
 176         }
 177 
 178         @Override
 179         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
 180             directCall(crb, masm, callTarget, null, state);
 181         }
 182     }
 183 
 184     @Opcode("FAR_FOREIGN_CALL")
 185     public static final class DirectFarForeignCallOp extends ForeignCallOp {
 186         public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class);
 187         public static final SizeEstimate SIZE = SizeEstimate.create(1);
 188 
 189         public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
 190             super(TYPE, SIZE, callTarget, result, parameters, temps, state);
 191         }
 192 
 193         @Override
 194         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
 195             try (ScratchRegister scratch = masm.getScratchRegister()) {
 196                 directCall(crb, masm, callTarget, scratch.getRegister(), state);
 197             }
 198         }
 199     }
 200 
 201     public static void directCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) {
 202         int before;
 203         if (scratch != null) {
 204             // offset might not fit a 30-bit displacement, generate an
 205             // indirect call with a 64-bit immediate
 206             before = masm.position();
 207             masm.sethix(0L, scratch, true);
 208             masm.jmpl(scratch, 0, o7);
 209         } else {
 210             before = masm.call(0);
 211         }
 212         masm.nop();  // delay slot
 213         int after = masm.position();
 214         crb.recordDirectCall(before, after, callTarget, info);
 215         crb.recordExceptionHandlers(after, info);
 216         masm.ensureUniquePC();
 217     }
 218 
 219     public static void indirectJmp(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget target) {
 220         int before = masm.position();
 221         masm.sethix(0L, dst, true);
 222         masm.jmp(new SPARCAddress(dst, 0));
 223         masm.nop();  // delay slot
 224         int after = masm.position();
 225         crb.recordIndirectCall(before, after, target, null);
 226         masm.ensureUniquePC();
 227     }
 228 
 229     public static void indirectCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
 230         int before = masm.jmpl(dst, 0, o7);
 231         masm.nop();  // delay slot
 232         int after = masm.position();
 233         crb.recordIndirectCall(before, after, callTarget, info);
 234         crb.recordExceptionHandlers(after, info);
 235         masm.ensureUniquePC();
 236     }
 237 }