1 /*
2  * Copyright (c) 2013, 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 
24 
25 package org.graalvm.compiler.asm.sparc;
26 
27 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL;
28 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
29 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc;
30 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
31 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always;
32 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal;
33 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z;
34 import static jdk.vm.ci.sparc.SPARC.g0;
35 import static jdk.vm.ci.sparc.SPARC.g3;
36 import static jdk.vm.ci.sparc.SPARC.i7;
37 import static jdk.vm.ci.sparc.SPARC.o7;
38 
39 import org.graalvm.compiler.asm.AbstractAddress;
40 import org.graalvm.compiler.asm.Label;
41 
42 import jdk.vm.ci.code.Register;
43 import jdk.vm.ci.code.TargetDescription;
44 import jdk.vm.ci.sparc.SPARC.CPUFeature;
45 
46 public class SPARCMacroAssembler extends SPARCAssembler {
47 
48     /**
49      * A sentinel value used as a place holder in an instruction stream for an address that will be
50      * patched.
51      */
52     private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0);
53     private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g3), new ScratchRegister(o7)};
54     // Points to the next free scratch register
55     private int nextFreeScratchRegister = 0;
56     /**
57      * Use ld [reg+simm13], reg for loading constants (User has to make sure, that the size of the
58      * constant table does not exceed simm13).
59      */
60     private boolean immediateConstantLoad;
61 
SPARCMacroAssembler(TargetDescription target)62     public SPARCMacroAssembler(TargetDescription target) {
63         super(target);
64     }
65 
66     /**
67      * @see #immediateConstantLoad
68      */
setImmediateConstantLoad(boolean immediateConstantLoad)69     public void setImmediateConstantLoad(boolean immediateConstantLoad) {
70         this.immediateConstantLoad = immediateConstantLoad;
71     }
72 
73     @Override
align(int modulus)74     public void align(int modulus) {
75         while (position() % modulus != 0) {
76             nop();
77         }
78     }
79 
80     @Override
jmp(Label l)81     public void jmp(Label l) {
82         BPCC.emit(this, Xcc, Always, NOT_ANNUL, PREDICT_NOT_TAKEN, l);
83         nop();  // delay slot
84     }
85 
bz(Label l)86     public void bz(Label l) {
87         BPCC.emit(this, Xcc, ConditionFlag.Zero, NOT_ANNUL, PREDICT_NOT_TAKEN, l);
88     }
89 
90     @Override
patchJumpTarget(int branch, int branchTarget)91     protected final void patchJumpTarget(int branch, int branchTarget) {
92         final int disp = (branchTarget - branch) / 4;
93         final int inst = getInt(branch);
94         ControlTransferOp op = (ControlTransferOp) getSPARCOp(inst);
95         int newInst = op.setDisp(inst, disp);
96         emitInt(newInst, branch);
97     }
98 
99     @Override
makeAddress(Register base, int displacement)100     public AbstractAddress makeAddress(Register base, int displacement) {
101         return new SPARCAddress(base, displacement);
102     }
103 
104     @Override
getPlaceholder(int instructionStartPosition)105     public AbstractAddress getPlaceholder(int instructionStartPosition) {
106         return Placeholder;
107     }
108 
109     @Override
ensureUniquePC()110     public final void ensureUniquePC() {
111         nop();
112     }
113 
cas(Register rs1, Register rs2, Register rd)114     public void cas(Register rs1, Register rs2, Register rd) {
115         casa(rs1, rs2, rd, Asi.ASI_PRIMARY);
116     }
117 
casx(Register rs1, Register rs2, Register rd)118     public void casx(Register rs1, Register rs2, Register rd) {
119         casxa(rs1, rs2, rd, Asi.ASI_PRIMARY);
120     }
121 
clr(Register dst)122     public void clr(Register dst) {
123         or(g0, g0, dst);
124     }
125 
clrb(SPARCAddress addr)126     public void clrb(SPARCAddress addr) {
127         stb(g0, addr);
128     }
129 
clrh(SPARCAddress addr)130     public void clrh(SPARCAddress addr) {
131         sth(g0, addr);
132     }
133 
clrx(SPARCAddress addr)134     public void clrx(SPARCAddress addr) {
135         stx(g0, addr);
136     }
137 
cmp(Register rs1, Register rs2)138     public void cmp(Register rs1, Register rs2) {
139         subcc(rs1, rs2, g0);
140     }
141 
cmp(Register rs1, int simm13)142     public void cmp(Register rs1, int simm13) {
143         subcc(rs1, simm13, g0);
144     }
145 
dec(Register rd)146     public void dec(Register rd) {
147         sub(rd, 1, rd);
148     }
149 
dec(int simm13, Register rd)150     public void dec(int simm13, Register rd) {
151         sub(rd, simm13, rd);
152     }
153 
jmp(SPARCAddress address)154     public void jmp(SPARCAddress address) {
155         jmpl(address.getBase(), address.getDisplacement(), g0);
156     }
157 
jmp(Register rd)158     public void jmp(Register rd) {
159         jmpl(rd, 0, g0);
160     }
161 
neg(Register rs1, Register rd)162     public void neg(Register rs1, Register rd) {
163         sub(g0, rs1, rd);
164     }
165 
neg(Register rd)166     public void neg(Register rd) {
167         sub(g0, rd, rd);
168     }
169 
mov(Register rs, Register rd)170     public void mov(Register rs, Register rd) {
171         or(g0, rs, rd);
172     }
173 
mov(int simm13, Register rd)174     public void mov(int simm13, Register rd) {
175         or(g0, simm13, rd);
176     }
177 
not(Register rs1, Register rd)178     public void not(Register rs1, Register rd) {
179         xnor(rs1, g0, rd);
180     }
181 
not(Register rd)182     public void not(Register rd) {
183         xnor(rd, g0, rd);
184     }
185 
restoreWindow()186     public void restoreWindow() {
187         restore(g0, g0, g0);
188     }
189 
ret()190     public void ret() {
191         jmpl(i7, 8, g0);
192     }
193 
194     /**
195      * Generates sethi hi22(value), dst; or dst, lo10(value), dst; code.
196      */
setw(int value, Register dst, boolean forceRelocatable)197     public void setw(int value, Register dst, boolean forceRelocatable) {
198         if (!forceRelocatable && isSimm13(value)) {
199             or(g0, value, dst);
200         } else {
201             sethi(hi22(value), dst);
202             or(dst, lo10(value), dst);
203         }
204     }
205 
setx(long value, Register dst, boolean forceRelocatable)206     public void setx(long value, Register dst, boolean forceRelocatable) {
207         int lo = (int) (value & ~0);
208         sethix(value, dst, forceRelocatable);
209         if (lo10(lo) != 0 || forceRelocatable) {
210             add(dst, lo10(lo), dst);
211         }
212     }
213 
sethix(long value, Register dst, boolean forceRelocatable)214     public void sethix(long value, Register dst, boolean forceRelocatable) {
215         final int hi = (int) (value >> 32);
216         final int lo = (int) (value & ~0);
217 
218         // This is the same logic as MacroAssembler::internal_set.
219         final int startPc = position();
220         if (hi == 0 && lo >= 0) {
221             sethi(hi22(lo), dst);
222         } else if (hi == -1) {
223             sethi(hi22(~lo), dst);
224             xor(dst, ~lo10(~0), dst);
225         } else {
226             final int shiftcnt;
227             final int shiftcnt2;
228             sethi(hi22(hi), dst);
229             if ((hi & 0x3ff) != 0) {                                  // Any bits?
230                 // msb 32-bits are now in lsb 32
231                 or(dst, hi & 0x3ff, dst);
232             }
233             if ((lo & 0xFFFFFC00) != 0) {                             // done?
234                 if (((lo >> 20) & 0xfff) != 0) {                      // Any bits set?
235                     // Make room for next 12 bits
236                     sllx(dst, 12, dst);
237                     // Or in next 12
238                     or(dst, (lo >> 20) & 0xfff, dst);
239                     shiftcnt = 0;                                     // We already shifted
240                 } else {
241                     shiftcnt = 12;
242                 }
243                 if (((lo >> 10) & 0x3ff) != 0) {
244                     // Make room for last 10 bits
245                     sllx(dst, shiftcnt + 10, dst);
246                     // Or in next 10
247                     or(dst, (lo >> 10) & 0x3ff, dst);
248                     shiftcnt2 = 0;
249                 } else {
250                     shiftcnt2 = 10;
251                 }
252                 // Shift leaving disp field 0'd
253                 sllx(dst, shiftcnt2 + 10, dst);
254             } else {
255                 sllx(dst, 32, dst);
256             }
257         }
258         // Pad out the instruction sequence so it can be patched later.
259         if (forceRelocatable) {
260             while (position() < (startPc + (INSTRUCTION_SIZE * 7))) {
261                 nop();
262             }
263         }
264     }
265 
signx(Register rs, Register rd)266     public void signx(Register rs, Register rd) {
267         sra(rs, g0, rd);
268     }
269 
signx(Register rd)270     public void signx(Register rd) {
271         sra(rd, g0, rd);
272     }
273 
isImmediateConstantLoad()274     public boolean isImmediateConstantLoad() {
275         return immediateConstantLoad;
276     }
277 
getScratchRegister()278     public ScratchRegister getScratchRegister() {
279         return scratchRegister[nextFreeScratchRegister++];
280     }
281 
282     public class ScratchRegister implements AutoCloseable {
283         private final Register register;
284 
ScratchRegister(Register register)285         public ScratchRegister(Register register) {
286             super();
287             this.register = register;
288         }
289 
getRegister()290         public Register getRegister() {
291             return register;
292         }
293 
294         @Override
close()295         public void close() {
296             assert nextFreeScratchRegister > 0 : "Close called too often";
297             nextFreeScratchRegister--;
298         }
299     }
300 
compareBranch(Register rs1, Register rs2, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction)301     public void compareBranch(Register rs1, Register rs2, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) {
302         assert isCPURegister(rs1, rs2);
303         assert ccRegister == Icc || ccRegister == Xcc;
304         if (hasFeature(CPUFeature.CBCOND)) {
305             if (delaySlotInstruction != null) {
306                 delaySlotInstruction.run();
307             }
308             CBCOND.emit(this, cond, ccRegister == Xcc, rs1, rs2, label);
309         } else {
310             if (cond == Equal && rs1.equals(g0)) {
311                 BPR.emit(this, Rc_z, NOT_ANNUL, predict, rs1, label);
312             } else {
313                 cmp(rs1, rs2);
314                 BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label);
315             }
316             if (delaySlotInstruction != null) {
317                 int positionBefore = position();
318                 delaySlotInstruction.run();
319                 int positionAfter = position();
320                 assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot";
321             } else {
322                 nop();
323             }
324         }
325     }
326 
compareBranch(Register rs1, int simm, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction)327     public void compareBranch(Register rs1, int simm, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) {
328         assert isCPURegister(rs1);
329         assert ccRegister == Icc || ccRegister == Xcc;
330         if (hasFeature(CPUFeature.CBCOND)) {
331             if (delaySlotInstruction != null) {
332                 delaySlotInstruction.run();
333             }
334             CBCOND.emit(this, cond, ccRegister == Xcc, rs1, simm, label);
335         } else {
336             if (cond == Equal && simm == 0) {
337                 BPR.emit(this, Rc_z, NOT_ANNUL, PREDICT_NOT_TAKEN, rs1, label);
338             } else {
339                 cmp(rs1, simm);
340                 BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label);
341             }
342             if (delaySlotInstruction != null) {
343                 int positionBefore = position();
344                 delaySlotInstruction.run();
345                 int positionAfter = position();
346                 assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot";
347             } else {
348                 nop();
349             }
350         }
351     }
352 }
353