SPARCTestAssembler.java revision 11539:2f096695fd6d
1/*
2 * Copyright (c) 2015, 2016, 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
24package jdk.vm.ci.code.test.sparc;
25
26import jdk.vm.ci.code.CodeCacheProvider;
27import jdk.vm.ci.code.DebugInfo;
28import jdk.vm.ci.code.Register;
29import jdk.vm.ci.code.StackSlot;
30import jdk.vm.ci.code.site.ConstantReference;
31import jdk.vm.ci.code.site.DataSectionReference;
32import jdk.vm.ci.code.test.TestAssembler;
33import jdk.vm.ci.code.test.TestHotSpotVMConfig;
34import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
35import jdk.vm.ci.hotspot.HotSpotCompiledCode;
36import jdk.vm.ci.hotspot.HotSpotConstant;
37import jdk.vm.ci.hotspot.HotSpotForeignCallTarget;
38import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
39import jdk.vm.ci.meta.JavaKind;
40import jdk.vm.ci.meta.VMConstant;
41import jdk.vm.ci.sparc.SPARC;
42import jdk.vm.ci.sparc.SPARCKind;
43
44public class SPARCTestAssembler extends TestAssembler {
45
46    private static final int MASK13 = (1 << 13) - 1;
47
48    public SPARCTestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) {
49        super(codeCache, config, 0, 16, SPARCKind.WORD, SPARC.l0, SPARC.l1, SPARC.l2, SPARC.l3, SPARC.l4, SPARC.l5, SPARC.l6, SPARC.l7);
50    }
51
52    private void emitOp2(Register rd, int op2, int imm22) {
53        assert isSimm(imm22, 22);
54        code.emitInt((0b00 << 30) | (rd.encoding << 25) | (op2 << 22) | imm22);
55    }
56
57    private void emitOp3(int op, Register rd, int op3, Register rs1, Register rs2) {
58        code.emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | rs2.encoding);
59    }
60
61    private void emitOp3(int op, Register rd, int op3, Register rs1, int simm13) {
62        assert isSimm(simm13, 13);
63        code.emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | (1 << 13) | (simm13 & MASK13));
64    }
65
66    private void emitNop() {
67        code.emitInt(1 << 24);
68    }
69
70    /**
71     * Minimum value for signed immediate ranges.
72     */
73    public static long minSimm(long nbits) {
74        return -(1L << (nbits - 1));
75    }
76
77    /**
78     * Maximum value for signed immediate ranges.
79     */
80    public static long maxSimm(long nbits) {
81        return (1L << (nbits - 1)) - 1;
82    }
83
84    /**
85     * Test if imm is within signed immediate range for nbits.
86     */
87    public static boolean isSimm(long imm, int nbits) {
88        return minSimm(nbits) <= imm && imm <= maxSimm(nbits);
89    }
90
91    @Override
92    public void emitPrologue() {
93        // SAVE sp, -128, sp
94        emitOp3(0b10, SPARC.sp, 0b111100, SPARC.sp, -SPARC.REGISTER_SAFE_AREA_SIZE);
95        setDeoptRescueSlot(newStackSlot(SPARCKind.XWORD));
96    }
97
98    @Override
99    public void emitEpilogue() {
100        recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
101        recordCall(new HotSpotForeignCallTarget(config.handleDeoptStub), 4, true, null);
102        code.emitInt(1 << 30); // CALL
103    }
104
105    @Override
106    public HotSpotCompiledCode finish(HotSpotResolvedJavaMethod method) {
107        frameSize += SPARC.REGISTER_SAFE_AREA_SIZE;
108        return super.finish(method);
109    }
110
111    @Override
112    public void emitGrowStack(int size) {
113        frameSize += size;
114        if (isSimm(size, 13)) {
115            emitOp3(0b10, SPARC.sp, 0b000100, SPARC.sp, size); // SUB sp, size, sp
116        } else {
117            Register r = emitLoadInt(size);
118            emitOp3(0b10, SPARC.sp, 0b000100, SPARC.sp, r); // SUB sp, size, sp
119        }
120    }
121
122    @Override
123    public Register emitIntArg0() {
124        return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCallee, JavaKind.Int).get(0);
125    }
126
127    @Override
128    public Register emitIntArg1() {
129        return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCallee, JavaKind.Int).get(1);
130    }
131
132    @Override
133    public Register emitLoadInt(int c) {
134        Register ret = newRegister();
135        loadIntToRegister(c, ret);
136        return ret;
137    }
138
139    private void loadIntToRegister(int c, Register ret) {
140        int hi = c >>> 10;
141        int lo = c & ((1 << 10) - 1);
142        if (hi == 0) {
143            emitOp3(0b10, ret, 0b000010, SPARC.g0, lo); // OR g0, lo, ret
144        } else {
145            emitOp2(ret, 0b100, hi);                    // SETHI hi, ret
146            if (lo != 0) {
147                emitOp3(0b10, ret, 0b000010, ret, lo);  // OR ret, lo, ret
148            }
149        }
150    }
151
152    @Override
153    public Register emitLoadLong(long c) {
154        Register ret = newRegister();
155        emitLoadLongToRegister(c, ret);
156        return ret;
157    }
158
159    private void loadLongToRegister(long c, Register ret) {
160        DataSectionReference ref = new DataSectionReference();
161        data.align(8);
162        ref.setOffset(data.position());
163        data.emitLong(c);
164        emitLoadPointerToRegister(ref, ret);
165    }
166
167    public void emitLoadLongToRegister(long c, Register r) {
168        if ((c & 0xFFFF_FFFFL) == c) {
169            loadIntToRegister((int) c, r);
170        } else {
171            loadLongToRegister(c, r);
172        }
173    }
174
175    private void emitPatchableSethi(Register ret, boolean wide) {
176        int startPos = code.position();
177        emitOp2(ret, 0b100, 0);              // SETHI 0, ret
178        if (wide) {
179            // pad for later patching
180            while (code.position() < (startPos + 28)) {
181                emitNop();
182            }
183        }
184    }
185
186    @Override
187    public Register emitLoadFloat(float c) {
188        DataSectionReference ref = new DataSectionReference();
189        data.align(4);
190        ref.setOffset(data.position());
191        data.emitFloat(c);
192
193        Register ptr = newRegister();
194        recordDataPatchInCode(ref);
195        emitPatchableSethi(ptr, true);
196        emitOp3(0b11, SPARC.f0, 0b100000, ptr, 0); // LDF [ptr+0], f0
197        return SPARC.f0;
198    }
199
200    @Override
201    public Register emitLoadPointer(HotSpotConstant c) {
202        Register ret = newRegister();
203        recordDataPatchInCode(new ConstantReference((VMConstant) c));
204
205        emitPatchableSethi(ret, !c.isCompressed());
206        emitOp3(0b10, ret, 0b000010, ret, 0); // OR ret, 0, ret
207
208        return ret;
209    }
210
211    @Override
212    public Register emitLoadPointer(DataSectionReference ref) {
213        Register ret = newRegister();
214        emitLoadPointerToRegister(ref, ret);
215        return ret;
216    }
217
218    private void emitLoadPointerToRegister(DataSectionReference ref, Register ret) {
219        recordDataPatchInCode(ref);
220        emitPatchableSethi(ret, true);
221        emitOp3(0b11, ret, 0b001011, ret, 0); // LDX [ret+0], ret
222    }
223
224    @Override
225    public Register emitLoadNarrowPointer(DataSectionReference ref) {
226        Register ret = newRegister();
227        recordDataPatchInCode(ref);
228        emitPatchableSethi(ret, true);
229        emitOp3(0b11, ret, 0b000000, ret, 0); // LDUW [ret+0], ret
230        return ret;
231    }
232
233    @Override
234    public Register emitLoadPointer(Register b, int offset) {
235        Register ret = newRegister();
236        emitOp3(0b11, ret, 0b001011, b, offset); // LDX [b+offset], ret
237        return ret;
238    }
239
240    @Override
241    public StackSlot emitIntToStack(Register a) {
242        StackSlot ret = newStackSlot(SPARCKind.WORD);
243        // STW a, [fp+offset]
244        emitStore(0b000100, a, ret);
245        return ret;
246    }
247
248    @Override
249    public StackSlot emitLongToStack(Register a) {
250        StackSlot ret = newStackSlot(SPARCKind.XWORD);
251        // STX a, [sp+offset]
252        emitStore(0b001110, a, ret);
253        return ret;
254    }
255
256    @Override
257    public StackSlot emitFloatToStack(Register a) {
258        StackSlot ret = newStackSlot(SPARCKind.SINGLE);
259        // STF a, [fp+offset]
260        emitStore(0b100100, a, ret);
261        return ret;
262    }
263
264    @Override
265    public StackSlot emitPointerToStack(Register a) {
266        StackSlot ret = newStackSlot(SPARCKind.XWORD);
267        // STX a, [fp+offset]
268        emitStore(0b001110, a, ret);
269        return ret;
270    }
271
272    @Override
273    public StackSlot emitNarrowPointerToStack(Register a) {
274        StackSlot ret = newStackSlot(SPARCKind.WORD);
275        // STW a, [fp+offset]
276        emitStore(0b000100, a, ret);
277        return ret;
278    }
279
280    private void emitStore(int op3, Register a, StackSlot ret) {
281        int offset = ret.getRawOffset() + SPARC.STACK_BIAS;
282        if (isSimm(offset, 13)) {
283            // op3 a, [sp+offset]
284            emitOp3(0b11, a, op3, SPARC.fp, offset);
285        } else {
286            assert a != SPARC.g3;
287            Register r = SPARC.g3;
288            loadLongToRegister(offset, r);
289            // op3 a, [sp+g3]
290            emitOp3(0b11, a, op3, SPARC.fp, r);
291        }
292    }
293
294    @Override
295    public Register emitUncompressPointer(Register compressed, long base, int shift) {
296        Register ret;
297        if (shift > 0) {
298            ret = newRegister();
299            emitOp3(0b10, ret, 0b100101, compressed, shift); // SLL compressed, shift, ret
300        } else {
301            ret = compressed;
302        }
303        if (base == 0) {
304            return ret;
305        } else {
306            Register b = emitLoadLong(base);
307            emitOp3(0b10, b, 0b00000, ret, b); // ADD b, ret, b
308            return b;
309        }
310    }
311
312    @Override
313    public Register emitIntAdd(Register a, Register b) {
314        Register ret = newRegister();
315        emitOp3(0b10, ret, 0b00000, a, b); // ADD a, b, ret
316        return ret;
317    }
318
319    private void emitMove(Register to, Register from) {
320        if (to != from) {
321            emitOp3(0b10, to, 0b000010, from, SPARC.g0); // OR from, g0, to
322        }
323    }
324
325    @Override
326    public void emitIntRet(Register a) {
327        emitPointerRet(a);
328    }
329
330    @Override
331    public void emitPointerRet(Register a) {
332        emitMove(SPARC.i0, a);
333        emitOp3(0b10, SPARC.g0, 0b111000, SPARC.i7, 8);        // JMPL [i7+8], g0
334        emitOp3(0b10, SPARC.g0, 0b111101, SPARC.g0, SPARC.g0); // RESTORE g0, g0, g0
335    }
336
337    @Override
338    public void emitTrap(DebugInfo info) {
339        recordImplicitException(info);
340        emitOp3(0b11, SPARC.g0, 0b001011, SPARC.g0, 0); // LDX [g0+0], g0
341    }
342
343    @Override
344    public DataSectionReference emitDataItem(HotSpotConstant c) {
345        if (c.isCompressed()) {
346            data.align(4);
347        } else {
348            data.align(8);
349        }
350        return super.emitDataItem(c);
351    }
352}
353