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