1 /* 2 * Copyright (c) 2015, 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 package jdk.vm.ci.code.test.sparc; 25 26 import jdk.vm.ci.code.CallingConvention; 27 import jdk.vm.ci.code.CodeCacheProvider; 28 import jdk.vm.ci.code.DebugInfo; 29 import jdk.vm.ci.code.Register; 30 import jdk.vm.ci.code.Register.RegisterCategory; 31 import jdk.vm.ci.code.RegisterValue; 32 import jdk.vm.ci.code.StackSlot; 33 import jdk.vm.ci.code.site.ConstantReference; 34 import jdk.vm.ci.code.site.DataSectionReference; 35 import jdk.vm.ci.code.test.TestAssembler; 36 import jdk.vm.ci.code.test.TestHotSpotVMConfig; 37 import jdk.vm.ci.hotspot.HotSpotCallingConventionType; 38 import jdk.vm.ci.hotspot.HotSpotCompiledCode; 39 import jdk.vm.ci.hotspot.HotSpotConstant; 40 import jdk.vm.ci.hotspot.HotSpotForeignCallTarget; 41 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; 42 import jdk.vm.ci.meta.AllocatableValue; 43 import jdk.vm.ci.meta.JavaKind; 44 import jdk.vm.ci.meta.VMConstant; 45 import jdk.vm.ci.sparc.SPARC; 46 import jdk.vm.ci.sparc.SPARCKind; 47 48 public class SPARCTestAssembler extends TestAssembler { 49 50 private static final int MASK13 = (1 << 13) - 1; 51 private static final Register scratchRegister = SPARC.g5; 52 private static final Register floatScratch = SPARC.f30; 53 private static final Register doubleScratch = SPARC.d62; 54 55 public SPARCTestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) { 56 super(codeCache, config, 0, 16, SPARCKind.WORD, SPARC.l0, SPARC.l1, SPARC.l2, SPARC.l3, SPARC.l4, SPARC.l5, SPARC.l6, SPARC.l7); 57 } 58 59 private void emitOp2(Register rd, int op2, int imm22) { 60 assert isSimm(imm22, 22); 61 code.emitInt((0b00 << 30) | (rd.encoding << 25) | (op2 << 22) | imm22); 62 } 63 64 private void emitOp3(int op, Register rd, int op3, Register rs1, Register rs2) { 65 code.emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | rs2.encoding); 66 } 67 68 private void emitOp3(int op, Register rd, int op3, Register rs1, int simm13) { 69 assert isSimm(simm13, 13); 70 code.emitInt((op << 30) | (rd.encoding << 25) | (op3 << 19) | (rs1.encoding << 14) | (1 << 13) | (simm13 & MASK13)); 71 } 72 73 private void emitNop() { 74 code.emitInt(1 << 24); 75 } 76 77 /** 78 * Minimum value for signed immediate ranges. 79 */ 80 public static long minSimm(long nbits) { 81 return -(1L << (nbits - 1)); 82 } 83 84 /** 85 * Maximum value for signed immediate ranges. 86 */ 87 public static long maxSimm(long nbits) { 88 return (1L << (nbits - 1)) - 1; 89 } 90 91 /** 92 * Test if imm is within signed immediate range for nbits. 93 */ 94 public static boolean isSimm(long imm, int nbits) { 95 return minSimm(nbits) <= imm && imm <= maxSimm(nbits); 96 } 97 98 @Override 99 public void emitPrologue() { 100 // SAVE sp, -128, sp 101 emitOp3(0b10, SPARC.sp, 0b111100, SPARC.sp, -SPARC.REGISTER_SAFE_AREA_SIZE); 102 setDeoptRescueSlot(newStackSlot(SPARCKind.XWORD)); 103 } 104 105 @Override 106 public void emitEpilogue() { 107 recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); 108 recordCall(new HotSpotForeignCallTarget(config.handleDeoptStub), 4, true, null); 109 code.emitInt(1 << 30); // CALL 110 } 111 112 @Override 113 public HotSpotCompiledCode finish(HotSpotResolvedJavaMethod method) { 114 frameSize += SPARC.REGISTER_SAFE_AREA_SIZE; 115 return super.finish(method); 116 } 117 118 @Override 119 public void emitGrowStack(int size) { 120 frameSize += size; 121 if (isSimm(size, 13)) { 122 emitOp3(0b10, SPARC.sp, 0b000100, SPARC.sp, size); // SUB sp, size, sp 123 } else { 124 Register r = emitLoadInt(size); 125 emitOp3(0b10, SPARC.sp, 0b000100, SPARC.sp, r); // SUB sp, size, sp 126 } 127 } 128 129 @Override 130 public Register emitIntArg0() { 131 return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCallee, JavaKind.Int).get(0); 132 } 133 134 @Override 135 public Register emitIntArg1() { 136 return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCallee, JavaKind.Int).get(1); 137 } 138 139 @Override 140 public Register emitLoadInt(int c) { 141 Register ret = newRegister(); 142 loadIntToRegister(c, ret); 143 return ret; 144 } 145 146 private Register loadIntToRegister(int c, Register ret) { 147 int hi = c >>> 10; 148 int lo = c & ((1 << 10) - 1); 149 if (hi == 0) { 150 emitOp3(0b10, ret, 0b000010, SPARC.g0, lo); // OR g0, lo, ret 151 } else { 152 emitOp2(ret, 0b100, hi); // SETHI hi, ret 153 if (lo != 0) { 154 emitOp3(0b10, ret, 0b000010, ret, lo); // OR ret, lo, ret 155 } 156 } 157 return ret; 158 } 159 160 @Override 161 public Register emitLoadLong(long c) { 162 Register ret = newRegister(); 163 emitLoadLongToRegister(c, ret); 164 return ret; 165 } 166 167 private void loadLongToRegister(long c, Register ret) { 168 DataSectionReference ref = new DataSectionReference(); 169 data.align(8); 170 ref.setOffset(data.position()); 171 data.emitLong(c); 172 emitLoadPointerToRegister(ref, ret); 173 } 174 175 public Register emitLoadLongToRegister(long c, Register r) { 176 if ((c & 0xFFFF_FFFFL) == c) { 177 loadIntToRegister((int) c, r); 178 } else { 179 loadLongToRegister(c, r); 180 } 181 return r; 182 } 183 184 private void emitPatchableSethi(Register ret, boolean wide) { 185 int startPos = code.position(); 186 emitOp2(ret, 0b100, 0); // SETHI 0, ret 187 if (wide) { 188 // pad for later patching 189 while (code.position() < (startPos + 28)) { 190 emitNop(); 191 } 192 } 193 } 194 195 @Override 196 public Register emitLoadFloat(float c) { 197 return emitLoadFloat(SPARC.f0, c); 198 } 199 200 public Register emitLoadFloat(Register reg, float c) { 201 return emitLoadFloat(reg, c, newRegister()); 202 } 203 204 public Register emitLoadFloat(Register reg, float c, Register scratch) { 205 DataSectionReference ref = new DataSectionReference(); 206 data.align(4); 207 ref.setOffset(data.position()); 208 data.emitFloat(c); 209 210 recordDataPatchInCode(ref); 211 emitPatchableSethi(scratch, true); 212 emitOp3(0b11, reg, 0b100000, scratch, 0); // LDF [scratch+0], f0 213 return reg; 214 } 215 216 public Register emitLoadDouble(Register reg, double c) { 217 return emitLoadDouble(reg, c, newRegister()); 218 } 219 220 public Register emitLoadDouble(Register reg, double c, Register scratch) { 221 DataSectionReference ref = new DataSectionReference(); 222 data.align(8); 223 ref.setOffset(data.position()); 224 data.emitDouble(c); 225 226 recordDataPatchInCode(ref); 227 emitPatchableSethi(scratch, true); 228 emitOp3(0b11, reg, 0b100011, scratch, 0); // LDDF [ptr+0], f0 229 return reg; 230 } 231 232 @Override 233 public Register emitLoadPointer(HotSpotConstant c) { 234 Register ret = newRegister(); 235 recordDataPatchInCode(new ConstantReference((VMConstant) c)); 236 237 emitPatchableSethi(ret, !c.isCompressed()); 238 emitOp3(0b10, ret, 0b000010, ret, 0); // OR ret, 0, ret 239 240 return ret; 241 } 242 243 @Override 244 public Register emitLoadPointer(DataSectionReference ref) { 245 Register ret = newRegister(); 246 emitLoadPointerToRegister(ref, ret); 247 return ret; 248 } 249 250 private void emitLoadPointerToRegister(DataSectionReference ref, Register ret) { 251 recordDataPatchInCode(ref); 252 emitPatchableSethi(ret, true); 253 emitOp3(0b11, ret, 0b001011, ret, 0); // LDX [ret+0], ret 254 } 255 256 @Override 257 public Register emitLoadNarrowPointer(DataSectionReference ref) { 258 Register ret = newRegister(); 259 recordDataPatchInCode(ref); 260 emitPatchableSethi(ret, true); 261 emitOp3(0b11, ret, 0b000000, ret, 0); // LDUW [ret+0], ret 262 return ret; 263 } 264 265 @Override 266 public Register emitLoadPointer(Register b, int offset) { 267 Register ret = newRegister(); 268 emitOp3(0b11, ret, 0b001011, b, offset); // LDX [b+offset], ret 269 return ret; 270 } 271 272 @Override 273 public StackSlot emitIntToStack(Register a) { 274 StackSlot ret = newStackSlot(SPARCKind.WORD); 275 intToStack(a, ret); 276 return ret; 277 } 278 279 public void intToStack(Register a, StackSlot ret) { 280 // STW a, [(s|f)p+offset] 281 emitStore(0b000100, a, ret); 282 } 283 284 @Override 285 public StackSlot emitLongToStack(Register a) { 286 StackSlot ret = newStackSlot(SPARCKind.XWORD); 287 longToStack(a, ret); 288 return ret; 289 } 290 291 public void longToStack(Register a, StackSlot ret) { 292 // STX a, [(f|s)p+offset] 293 emitStore(0b001110, a, ret); 294 } 295 296 @Override 297 public StackSlot emitFloatToStack(Register a) { 298 StackSlot ret = newStackSlot(SPARCKind.SINGLE); 299 floatToStack(a, ret); 300 return ret; 301 } 302 303 public void floatToStack(Register a, StackSlot ret) { 304 // STF a, [fp+offset] 305 emitStore(0b100100, a, ret); 306 } 307 308 @Override 309 public StackSlot emitDoubleToStack(Register a) { 310 StackSlot ret = newStackSlot(SPARCKind.DOUBLE); 311 return doubleToStack(a, ret); 312 } 313 314 public StackSlot doubleToStack(Register a, StackSlot ret) { 315 // STD a, [(s|f)p+offset] 316 emitStore(0b100111, a, ret); 317 return ret; 318 } 319 320 @Override 321 public StackSlot emitPointerToStack(Register a) { 322 StackSlot ret = newStackSlot(SPARCKind.XWORD); 323 // STX a, [fp+offset] 324 emitStore(0b001110, a, ret); 325 return ret; 326 } 327 328 @Override 329 public StackSlot emitNarrowPointerToStack(Register a) { 330 StackSlot ret = newStackSlot(SPARCKind.WORD); 331 // STW a, [fp+offset] 332 emitStore(0b000100, a, ret); 333 return ret; 334 } 335 336 private void emitStore(int op3, Register a, StackSlot ret) { 337 Register base; 338 if (ret.getRawOffset() < 0) { 339 base = SPARC.fp; 340 } else { 341 base = SPARC.sp; 342 } 343 int offset = ret.getRawOffset() + SPARC.STACK_BIAS; 344 if (isSimm(offset, 13)) { 345 // op3 a, [sp+offset] 346 emitOp3(0b11, a, op3, base, offset); 347 } else { 348 assert a != SPARC.g3; 349 Register r = SPARC.g3; 350 loadLongToRegister(offset, r); 351 // op3 a, [sp+g3] 352 emitOp3(0b11, a, op3, base, r); 353 } 354 } 355 356 @Override 357 public Register emitUncompressPointer(Register compressed, long base, int shift) { 358 Register ret; 359 if (shift > 0) { 360 ret = newRegister(); 361 emitOp3(0b10, ret, 0b100101, compressed, shift); // SLL compressed, shift, ret 362 } else { 363 ret = compressed; 364 } 365 if (base == 0) { 366 return ret; 367 } else { 368 Register b = emitLoadLong(base); 369 emitOp3(0b10, b, 0b00000, ret, b); // ADD b, ret, b 370 return b; 371 } 372 } 373 374 @Override 375 public Register emitIntAdd(Register a, Register b) { 376 Register ret = newRegister(); 377 emitOp3(0b10, ret, 0b00000, a, b); // ADD a, b, ret 378 return ret; 379 } 380 381 private void emitMove(Register to, Register from) { 382 if (to != from) { 383 emitOp3(0b10, to, 0b000010, from, SPARC.g0); // OR from, g0, to 384 } 385 } 386 387 @Override 388 public void emitIntRet(Register a) { 389 emitPointerRet(a); 390 } 391 392 @Override 393 public void emitFloatRet(Register a) { 394 assert a == SPARC.f0 : "Unimplemented"; 395 emitOp3(0b10, SPARC.g0, 0b111000, SPARC.i7, 8); // JMPL [i7+8], g0 396 emitOp3(0b10, SPARC.g0, 0b111101, SPARC.g0, SPARC.g0); // RESTORE g0, g0, g0 397 } 398 399 @Override 400 public void emitPointerRet(Register a) { 401 emitMove(SPARC.i0, a); 402 emitOp3(0b10, SPARC.g0, 0b111000, SPARC.i7, 8); // JMPL [i7+8], g0 403 emitOp3(0b10, SPARC.g0, 0b111101, SPARC.g0, SPARC.g0); // RESTORE g0, g0, g0 404 } 405 406 @Override 407 public void emitTrap(DebugInfo info) { 408 recordImplicitException(info); 409 emitOp3(0b11, SPARC.g0, 0b001011, SPARC.g0, 0); // LDX [g0+0], g0 410 } 411 412 @Override 413 public DataSectionReference emitDataItem(HotSpotConstant c) { 414 if (c.isCompressed()) { 415 data.align(4); 416 } else { 417 data.align(8); 418 } 419 return super.emitDataItem(c); 420 } 421 422 @Override 423 public void emitCall(long addr) { 424 Register dst = emitLoadLong(addr); 425 emitOp3(0b10, SPARC.o7, 0b111000, dst, 0); // JMPL [dst+0], o7 426 emitNop(); 427 } 428 429 @Override 430 public void emitLoad(AllocatableValue av, Object prim) { 431 if (av instanceof RegisterValue) { 432 Register reg = ((RegisterValue) av).getRegister(); 433 RegisterCategory cat = reg.getRegisterCategory(); 434 if (cat.equals(SPARC.FPUs)) { 435 emitLoadFloat(reg, (Float) prim, scratchRegister); 436 } else if (cat.equals(SPARC.FPUd)) { 437 emitLoadDouble(reg, (Double) prim, scratchRegister); 438 } else if (prim instanceof Integer) { 439 loadIntToRegister((Integer) prim, reg); 440 } else if (prim instanceof Long) { 441 loadLongToRegister((Long) prim, reg); 442 } 443 } else if (av instanceof StackSlot) { 444 StackSlot slot = (StackSlot) av; 445 if (prim instanceof Float) { 446 floatToStack(emitLoadFloat(floatScratch, (Float) prim, scratchRegister), slot); 447 } else if (prim instanceof Double) { 448 doubleToStack(emitLoadDouble(doubleScratch, (Double) prim, scratchRegister), slot); 449 } else if (prim instanceof Integer) { 450 intToStack(loadIntToRegister((Integer) prim, scratchRegister), slot); 451 } else if (prim instanceof Long) { 452 longToStack(emitLoadLongToRegister((Long) prim, scratchRegister), slot); 453 } 454 } else { 455 throw new IllegalArgumentException("Unknown value " + av); 456 } 457 } 458 459 @Override 460 public void emitCallEpilogue(CallingConvention cc) { 461 // Nothing to do here. 462 } 463 464 @Override 465 public void emitCallPrologue(CallingConvention cc, Object... prim) { 466 emitGrowStack(cc.getStackSize()); 467 frameSize += cc.getStackSize(); 468 AllocatableValue[] args = cc.getArguments(); 469 for (int i = 0; i < args.length; i++) { 470 emitLoad(args[i], prim[i]); 471 } 472 } 473 474 }