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