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