1 /* 2 * Copyright (c) 2013, 2018, 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 62 public SPARCMacroAssembler(TargetDescription target) { 63 super(target); 64 } 65 66 /** 67 * @see #immediateConstantLoad 68 */ 69 public void setImmediateConstantLoad(boolean immediateConstantLoad) { 70 this.immediateConstantLoad = immediateConstantLoad; 71 } 72 73 @Override 74 public void align(int modulus) { 75 while (position() % modulus != 0) { 76 nop(); 77 } 78 } 79 80 @Override 81 public void jmp(Label l) { 82 BPCC.emit(this, Xcc, Always, NOT_ANNUL, PREDICT_NOT_TAKEN, l); 83 nop(); // delay slot 84 } 85 86 public void bz(Label l) { 87 BPCC.emit(this, Xcc, ConditionFlag.Zero, NOT_ANNUL, PREDICT_NOT_TAKEN, l); 88 } 89 90 @Override 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 100 public AbstractAddress makeAddress(Register base, int displacement) { 101 return new SPARCAddress(base, displacement); 102 } 103 104 @Override 105 public AbstractAddress getPlaceholder(int instructionStartPosition) { 106 return Placeholder; 107 } 108 109 @Override 110 public final void ensureUniquePC() { 111 nop(); 112 } 113 114 public void cas(Register rs1, Register rs2, Register rd) { 115 casa(rs1, rs2, rd, Asi.ASI_PRIMARY); 116 } 117 118 public void casx(Register rs1, Register rs2, Register rd) { 119 casxa(rs1, rs2, rd, Asi.ASI_PRIMARY); 120 } 121 122 public void clr(Register dst) { 123 or(g0, g0, dst); 124 } 125 126 public void clrb(SPARCAddress addr) { 127 stb(g0, addr); 128 } 129 130 public void clrh(SPARCAddress addr) { 131 sth(g0, addr); 132 } 133 134 public void clrx(SPARCAddress addr) { 135 stx(g0, addr); 136 } 137 138 public void cmp(Register rs1, Register rs2) { 139 subcc(rs1, rs2, g0); 140 } 141 142 public void cmp(Register rs1, int simm13) { 143 subcc(rs1, simm13, g0); 144 } 145 146 public void dec(Register rd) { 147 sub(rd, 1, rd); 148 } 149 150 public void dec(int simm13, Register rd) { 151 sub(rd, simm13, rd); 152 } 153 154 public void jmp(SPARCAddress address) { 155 jmpl(address.getBase(), address.getDisplacement(), g0); 156 } 157 158 public void jmp(Register rd) { 159 jmpl(rd, 0, g0); 160 } 161 162 public void neg(Register rs1, Register rd) { 163 sub(g0, rs1, rd); 164 } 165 166 public void neg(Register rd) { 167 sub(g0, rd, rd); 168 } 169 170 public void mov(Register rs, Register rd) { 171 or(g0, rs, rd); 172 } 173 174 public void mov(int simm13, Register rd) { 175 or(g0, simm13, rd); 176 } 177 178 public void not(Register rs1, Register rd) { 179 xnor(rs1, g0, rd); 180 } 181 182 public void not(Register rd) { 183 xnor(rd, g0, rd); 184 } 185 186 public void restoreWindow() { 187 restore(g0, g0, g0); 188 } 189 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 */ 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 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 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 266 public void signx(Register rs, Register rd) { 267 sra(rs, g0, rd); 268 } 269 270 public void signx(Register rd) { 271 sra(rd, g0, rd); 272 } 273 274 public boolean isImmediateConstantLoad() { 275 return immediateConstantLoad; 276 } 277 278 public ScratchRegister getScratchRegister() { 279 return scratchRegister[nextFreeScratchRegister++]; 280 } 281 282 public class ScratchRegister implements AutoCloseable { 283 private final Register register; 284 285 public ScratchRegister(Register register) { 286 super(); 287 this.register = register; 288 } 289 290 public Register getRegister() { 291 return register; 292 } 293 294 @Override 295 public void close() { 296 assert nextFreeScratchRegister > 0 : "Close called too often"; 297 nextFreeScratchRegister--; 298 } 299 } 300 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 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 }