001/* 002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.asm.sparc; 024 025import static com.oracle.graal.asm.sparc.SPARCAssembler.Annul.*; 026import static com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag.*; 027import static jdk.internal.jvmci.sparc.SPARC.*; 028 029import java.util.function.*; 030 031import jdk.internal.jvmci.code.*; 032 033import com.oracle.graal.asm.*; 034 035public class SPARCMacroAssembler extends SPARCAssembler { 036 037 /** 038 * A sentinel value used as a place holder in an instruction stream for an address that will be 039 * patched. 040 */ 041 private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0); 042 private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g3), new ScratchRegister(o7)}; 043 // Points to the next free scratch register 044 private int nextFreeScratchRegister = 0; 045 /** 046 * Use ld [reg+simm13], reg for loading constants (User has to make sure, that the size of the 047 * constant table does not exceed simm13). 048 */ 049 private boolean immediateConstantLoad; 050 051 public SPARCMacroAssembler(TargetDescription target, RegisterConfig registerConfig) { 052 super(target, registerConfig); 053 } 054 055 /** 056 * @see #immediateConstantLoad 057 */ 058 public void setImmediateConstantLoad(boolean immediateConstantLoad) { 059 this.immediateConstantLoad = immediateConstantLoad; 060 } 061 062 @Override 063 public void align(int modulus) { 064 while (position() % modulus != 0) { 065 nop(); 066 } 067 } 068 069 @Override 070 public void jmp(Label l) { 071 bicc(Always, NOT_ANNUL, l); 072 nop(); // delay slot 073 } 074 075 @Override 076 protected final void patchJumpTarget(int branch, int branchTarget) { 077 final int disp = (branchTarget - branch) / 4; 078 final int inst = getInt(branch); 079 ControlTransferOp op = (ControlTransferOp) getSPARCOp(inst); 080 int newInst = op.setDisp(inst, disp); 081 emitInt(newInst, branch); 082 } 083 084 @Override 085 public AbstractAddress makeAddress(Register base, int displacement) { 086 return new SPARCAddress(base, displacement); 087 } 088 089 @Override 090 public AbstractAddress getPlaceholder() { 091 return Placeholder; 092 } 093 094 @Override 095 public final void ensureUniquePC() { 096 nop(); 097 } 098 099 public void cas(Register rs1, Register rs2, Register rd) { 100 casa(rs1, rs2, rd, Asi.ASI_PRIMARY); 101 } 102 103 public void casx(Register rs1, Register rs2, Register rd) { 104 casxa(rs1, rs2, rd, Asi.ASI_PRIMARY); 105 } 106 107 public void clr(Register dst) { 108 or(g0, g0, dst); 109 } 110 111 public void clrb(SPARCAddress addr) { 112 stb(g0, addr); 113 } 114 115 public void clrh(SPARCAddress addr) { 116 sth(g0, addr); 117 } 118 119 public void clrx(SPARCAddress addr) { 120 stx(g0, addr); 121 } 122 123 public void cmp(Register rs1, Register rs2) { 124 subcc(rs1, rs2, g0); 125 } 126 127 public void cmp(Register rs1, int simm13) { 128 subcc(rs1, simm13, g0); 129 } 130 131 public void dec(Register rd) { 132 sub(rd, 1, rd); 133 } 134 135 public void dec(int simm13, Register rd) { 136 sub(rd, simm13, rd); 137 } 138 139 public void jmp(SPARCAddress address) { 140 jmpl(address.getBase(), address.getDisplacement(), g0); 141 } 142 143 public void jmp(Register rd) { 144 jmpl(rd, 0, g0); 145 } 146 147 public void neg(Register rs1, Register rd) { 148 sub(g0, rs1, rd); 149 } 150 151 public void neg(Register rd) { 152 sub(g0, rd, rd); 153 } 154 155 public void mov(Register rs, Register rd) { 156 or(g0, rs, rd); 157 } 158 159 public void mov(int simm13, Register rd) { 160 or(g0, simm13, rd); 161 } 162 163 public void not(Register rs1, Register rd) { 164 xnor(rs1, g0, rd); 165 } 166 167 public void not(Register rd) { 168 xnor(rd, g0, rd); 169 } 170 171 public void restoreWindow() { 172 restore(g0, g0, g0); 173 } 174 175 public void ret() { 176 jmpl(i7, 8, g0); 177 } 178 179 /** 180 * This instruction is like sethi but for 64-bit values. 181 */ 182 public static class Sethix { 183 184 private static final int INSTRUCTION_SIZE = 7; 185 186 private long value; 187 private Register dst; 188 private boolean forceRelocatable; 189 private boolean delayed = false; 190 private Consumer<SPARCAssembler> delayedInstructionEmitter; 191 192 public Sethix(long value, Register dst, boolean forceRelocatable, boolean delayed) { 193 this(value, dst, forceRelocatable); 194 assert !(forceRelocatable && delayed) : "Relocatable sethix cannot be delayed"; 195 this.delayed = delayed; 196 } 197 198 public Sethix(long value, Register dst, boolean forceRelocatable) { 199 this.value = value; 200 this.dst = dst; 201 this.forceRelocatable = forceRelocatable; 202 } 203 204 public Sethix(long value, Register dst) { 205 this(value, dst, false); 206 } 207 208 private void emitInstruction(Consumer<SPARCAssembler> cb, SPARCMacroAssembler masm) { 209 if (delayed) { 210 if (this.delayedInstructionEmitter != null) { 211 delayedInstructionEmitter.accept(masm); 212 } 213 delayedInstructionEmitter = cb; 214 } else { 215 cb.accept(masm); 216 } 217 } 218 219 public void emit(SPARCMacroAssembler masm) { 220 final int hi = (int) (value >> 32); 221 final int lo = (int) (value & ~0); 222 223 // This is the same logic as MacroAssembler::internal_set. 224 final int startPc = masm.position(); 225 226 if (hi == 0 && lo >= 0) { 227 Consumer<SPARCAssembler> cb = eMasm -> eMasm.sethi(hi22(lo), dst); 228 emitInstruction(cb, masm); 229 } else if (hi == -1) { 230 Consumer<SPARCAssembler> cb = eMasm -> eMasm.sethi(hi22(~lo), dst); 231 emitInstruction(cb, masm); 232 cb = eMasm -> eMasm.xor(dst, ~lo10(~0), dst); 233 emitInstruction(cb, masm); 234 } else { 235 final int shiftcnt; 236 final int shiftcnt2; 237 Consumer<SPARCAssembler> cb = eMasm -> eMasm.sethi(hi22(hi), dst); 238 emitInstruction(cb, masm); 239 if ((hi & 0x3ff) != 0) { // Any bits? 240 // msb 32-bits are now in lsb 32 241 cb = eMasm -> eMasm.or(dst, hi & 0x3ff, dst); 242 emitInstruction(cb, masm); 243 } 244 if ((lo & 0xFFFFFC00) != 0) { // done? 245 if (((lo >> 20) & 0xfff) != 0) { // Any bits set? 246 // Make room for next 12 bits 247 cb = eMasm -> eMasm.sllx(dst, 12, dst); 248 emitInstruction(cb, masm); 249 // Or in next 12 250 cb = eMasm -> eMasm.or(dst, (lo >> 20) & 0xfff, dst); 251 emitInstruction(cb, masm); 252 shiftcnt = 0; // We already shifted 253 } else { 254 shiftcnt = 12; 255 } 256 if (((lo >> 10) & 0x3ff) != 0) { 257 // Make room for last 10 bits 258 cb = eMasm -> eMasm.sllx(dst, shiftcnt + 10, dst); 259 emitInstruction(cb, masm); 260 // Or in next 10 261 cb = eMasm -> eMasm.or(dst, (lo >> 10) & 0x3ff, dst); 262 emitInstruction(cb, masm); 263 shiftcnt2 = 0; 264 } else { 265 shiftcnt2 = 10; 266 } 267 // Shift leaving disp field 0'd 268 cb = eMasm -> eMasm.sllx(dst, shiftcnt2 + 10, dst); 269 emitInstruction(cb, masm); 270 } else { 271 cb = eMasm -> eMasm.sllx(dst, 32, dst); 272 emitInstruction(cb, masm); 273 } 274 } 275 // Pad out the instruction sequence so it can be patched later. 276 if (forceRelocatable) { 277 while (masm.position() < (startPc + (INSTRUCTION_SIZE * 4))) { 278 Consumer<SPARCAssembler> cb = eMasm -> eMasm.nop(); 279 emitInstruction(cb, masm); 280 } 281 } 282 } 283 284 public void emitDelayed(SPARCMacroAssembler masm) { 285 assert delayedInstructionEmitter != null; 286 delayedInstructionEmitter.accept(masm); 287 } 288 } 289 290 public static class Setx { 291 292 private long value; 293 private Register dst; 294 private boolean forceRelocatable; 295 private boolean delayed = false; 296 private boolean delayedFirstEmitted = false; 297 private Sethix sethix; 298 private Consumer<SPARCMacroAssembler> delayedAdd; 299 300 public Setx(long value, Register dst, boolean forceRelocatable, boolean delayed) { 301 assert !(forceRelocatable && delayed) : "Cannot use relocatable setx as delayable"; 302 this.value = value; 303 this.dst = dst; 304 this.forceRelocatable = forceRelocatable; 305 this.delayed = delayed; 306 } 307 308 public Setx(long value, Register dst, boolean forceRelocatable) { 309 this(value, dst, forceRelocatable, false); 310 } 311 312 public Setx(long value, Register dst) { 313 this(value, dst, false); 314 } 315 316 public void emit(SPARCMacroAssembler masm) { 317 assert !delayed; 318 doEmit(masm); 319 } 320 321 private void doEmit(SPARCMacroAssembler masm) { 322 sethix = new Sethix(value, dst, forceRelocatable, delayed); 323 sethix.emit(masm); 324 int lo = (int) (value & ~0); 325 if (lo10(lo) != 0 || forceRelocatable) { 326 Consumer<SPARCMacroAssembler> add = eMasm -> eMasm.add(dst, lo10(lo), dst); 327 if (delayed) { 328 sethix.emitDelayed(masm); 329 sethix = null; 330 delayedAdd = add; 331 } else { 332 sethix = null; 333 add.accept(masm); 334 } 335 } 336 } 337 338 public void emitFirstPartOfDelayed(SPARCMacroAssembler masm) { 339 assert !forceRelocatable : "Cannot use delayed mode with relocatable setx"; 340 assert delayed : "Can only be used in delayed mode"; 341 doEmit(masm); 342 delayedFirstEmitted = true; 343 } 344 345 public void emitSecondPartOfDelayed(SPARCMacroAssembler masm) { 346 assert !forceRelocatable : "Cannot use delayed mode with relocatable setx"; 347 assert delayed : "Can only be used in delayed mode"; 348 assert delayedFirstEmitted : "First part has not been emitted so far."; 349 assert delayedAdd == null && sethix != null || delayedAdd != null && sethix == null : "Either add or sethix must be set"; 350 if (delayedAdd != null) { 351 delayedAdd.accept(masm); 352 } else { 353 sethix.emitDelayed(masm); 354 } 355 356 } 357 } 358 359 public void signx(Register rs, Register rd) { 360 sra(rs, g0, rd); 361 } 362 363 public void signx(Register rd) { 364 sra(rd, g0, rd); 365 } 366 367 public boolean isImmediateConstantLoad() { 368 return immediateConstantLoad; 369 } 370 371 public ScratchRegister getScratchRegister() { 372 return scratchRegister[nextFreeScratchRegister++]; 373 } 374 375 public class ScratchRegister implements AutoCloseable { 376 private final Register register; 377 378 public ScratchRegister(Register register) { 379 super(); 380 this.register = register; 381 } 382 383 public Register getRegister() { 384 return register; 385 } 386 387 public void close() { 388 assert nextFreeScratchRegister > 0 : "Close called too often"; 389 nextFreeScratchRegister--; 390 } 391 } 392}