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