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.lir.sparc; 24 25 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.MEMBAR_STORE_LOAD; 26 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isCPURegister; 27 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isDoubleFloatRegister; 28 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; 29 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSingleFloatRegister; 30 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; 31 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; 32 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; 33 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 34 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; 35 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED; 36 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; 37 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; 38 import static java.lang.Math.max; 39 import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD; 40 import static jdk.vm.ci.code.ValueUtil.asRegister; 41 import static jdk.vm.ci.code.ValueUtil.asStackSlot; 42 import static jdk.vm.ci.code.ValueUtil.isRegister; 43 import static jdk.vm.ci.code.ValueUtil.isStackSlot; 44 import static jdk.vm.ci.sparc.SPARC.g0; 45 import static jdk.vm.ci.sparc.SPARCKind.DOUBLE; 46 import static jdk.vm.ci.sparc.SPARCKind.SINGLE; 47 import static jdk.vm.ci.sparc.SPARCKind.WORD; 48 import static jdk.vm.ci.sparc.SPARCKind.XWORD; 49 50 import java.util.Set; 51 52 import org.graalvm.compiler.asm.sparc.SPARCAddress; 53 import org.graalvm.compiler.asm.sparc.SPARCAssembler; 54 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; 55 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; 56 import org.graalvm.compiler.core.common.LIRKind; 57 import org.graalvm.compiler.core.common.type.DataPointerConstant; 58 import org.graalvm.compiler.debug.GraalError; 59 import org.graalvm.compiler.lir.LIRFrameState; 60 import org.graalvm.compiler.lir.LIRInstructionClass; 61 import org.graalvm.compiler.lir.Opcode; 62 import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck; 63 import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; 64 import org.graalvm.compiler.lir.StandardOp.NullCheck; 65 import org.graalvm.compiler.lir.StandardOp.ValueMoveOp; 66 import org.graalvm.compiler.lir.VirtualStackSlot; 67 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 68 69 import jdk.vm.ci.code.Register; 70 import jdk.vm.ci.code.StackSlot; 71 import jdk.vm.ci.meta.AllocatableValue; 72 import jdk.vm.ci.meta.Constant; 73 import jdk.vm.ci.meta.JavaConstant; 74 import jdk.vm.ci.meta.PlatformKind; 75 import jdk.vm.ci.meta.Value; 76 import jdk.vm.ci.sparc.SPARC; 77 import jdk.vm.ci.sparc.SPARC.CPUFeature; 78 import jdk.vm.ci.sparc.SPARCKind; 79 80 public class SPARCMove { 81 82 public static class LoadInlineConstant extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction, LoadConstantOp { 83 public static final LIRInstructionClass<LoadInlineConstant> TYPE = LIRInstructionClass.create(LoadInlineConstant.class); 84 public static final SizeEstimate SIZE = SizeEstimate.create(1); 85 private JavaConstant constant; 86 @Def({REG, STACK}) AllocatableValue result; 87 88 public LoadInlineConstant(JavaConstant constant, AllocatableValue result) { 89 super(TYPE, SIZE); 90 this.constant = constant; 91 this.result = result; 92 } 93 94 @Override 95 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 96 if (isRegister(result)) { 97 const2reg(crb, masm, result, g0, constant, getDelayedControlTransfer()); 98 } else if (isStackSlot(result)) { 99 StackSlot slot = asStackSlot(result); 100 const2stack(crb, masm, slot, g0, getDelayedControlTransfer(), constant); 101 } 102 } 103 104 @Override 105 public Constant getConstant() { 106 return constant; 107 } 108 109 @Override 110 public AllocatableValue getResult() { 111 return result; 112 } 113 } 114 115 public static class LoadConstantFromTable extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 116 public static final LIRInstructionClass<LoadConstantFromTable> TYPE = LIRInstructionClass.create(LoadConstantFromTable.class); 117 public static final SizeEstimate SIZE = SizeEstimate.create(1, 8); 118 119 private Constant constant; 120 @Def({REG, STACK}) AllocatableValue result; 121 @Use({REG}) private AllocatableValue constantTableBase; 122 123 public LoadConstantFromTable(Constant constant, AllocatableValue constantTableBase, AllocatableValue result) { 124 super(TYPE, SIZE); 125 this.constant = constant; 126 this.result = result; 127 this.constantTableBase = constantTableBase; 128 } 129 130 @Override 131 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 132 final int byteCount = result.getPlatformKind().getSizeInBytes(); 133 assert byteCount > 1 : "Byte values must not be loaded via constant table"; 134 Register baseRegister = asRegister(constantTableBase); 135 if (isRegister(result)) { 136 Register resultRegister = asRegister(result); 137 loadFromConstantTable(crb, masm, byteCount, baseRegister, constant, resultRegister, getDelayedControlTransfer()); 138 } else if (isStackSlot(result)) { 139 try (ScratchRegister scratch = masm.getScratchRegister()) { 140 Register scratchRegister = scratch.getRegister(); 141 loadFromConstantTable(crb, masm, byteCount, baseRegister, constant, scratchRegister, getDelayedControlTransfer()); 142 StackSlot slot = asStackSlot(result); 143 reg2stack(crb, masm, slot, scratchRegister.asValue(), getDelayedControlTransfer()); 144 } 145 } 146 } 147 } 148 149 @Opcode("MOVE") 150 public static class Move extends SPARCLIRInstruction implements ValueMoveOp, SPARCTailDelayedLIRInstruction { 151 public static final LIRInstructionClass<Move> TYPE = LIRInstructionClass.create(Move.class); 152 public static final SizeEstimate SIZE = SizeEstimate.create(8); 153 154 @Def({REG, STACK, HINT}) protected AllocatableValue result; 155 @Use({REG, STACK}) protected AllocatableValue input; 156 157 public Move(AllocatableValue result, AllocatableValue input) { 158 super(TYPE, SIZE); 159 this.result = result; 160 this.input = input; 161 } 162 163 @Override 164 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 165 move(crb, masm, getResult(), getInput(), getDelayedControlTransfer()); 166 } 167 168 @Override 169 public AllocatableValue getInput() { 170 return input; 171 } 172 173 @Override 174 public AllocatableValue getResult() { 175 return result; 176 } 177 } 178 179 /** 180 * Move between floating-point and general purpose register domain. 181 */ 182 @Opcode("MOVE_FPGP") 183 public static final class MoveFpGp extends SPARCLIRInstruction implements ValueMoveOp, SPARCTailDelayedLIRInstruction { 184 public static final LIRInstructionClass<MoveFpGp> TYPE = LIRInstructionClass.create(MoveFpGp.class); 185 public static final SizeEstimate SIZE = SizeEstimate.create(2); 186 187 @Def({REG}) protected AllocatableValue result; 188 @Use({REG}) protected AllocatableValue input; 189 @Temp({STACK, ILLEGAL}) protected AllocatableValue temp; 190 191 public MoveFpGp(AllocatableValue result, AllocatableValue input, AllocatableValue temp) { 192 super(TYPE, SIZE); 193 this.result = result; 194 this.input = input; 195 this.temp = temp; 196 } 197 198 @Override 199 public AllocatableValue getInput() { 200 return input; 201 } 202 203 @Override 204 public AllocatableValue getResult() { 205 return result; 206 } 207 208 @Override 209 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 210 SPARCKind inputKind = (SPARCKind) input.getPlatformKind(); 211 SPARCKind resultKind = (SPARCKind) result.getPlatformKind(); 212 if (AllocatableValue.ILLEGAL.equals(temp)) { 213 moveDirect(crb, masm, inputKind, resultKind); 214 } else { 215 moveViaStack(crb, masm, inputKind, resultKind); 216 } 217 } 218 219 private void moveDirect(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCKind inputKind, SPARCKind resultKind) { 220 getDelayedControlTransfer().emitControlTransfer(crb, masm); 221 if (resultKind == SINGLE) { 222 if (inputKind == WORD) { 223 masm.movwtos(asRegister(input, WORD), asRegister(result, SINGLE)); 224 } else { 225 throw GraalError.shouldNotReachHere("inputKind: " + inputKind); 226 } 227 } else if (resultKind == DOUBLE) { 228 if (inputKind == WORD) { 229 masm.movxtod(asRegister(input, WORD), asRegister(result, DOUBLE)); 230 } else { 231 masm.movxtod(asRegister(input, XWORD), asRegister(result, DOUBLE)); 232 } 233 } else if (inputKind == SINGLE) { 234 if (resultKind == WORD) { 235 masm.movstosw(asRegister(input, SINGLE), asRegister(result, WORD)); 236 } else { 237 masm.movstouw(asRegister(input, SINGLE), asRegister(result, WORD)); 238 } 239 } else if (inputKind == DOUBLE) { 240 if (resultKind == XWORD) { 241 masm.movdtox(asRegister(input, DOUBLE), asRegister(result, XWORD)); 242 } else { 243 throw GraalError.shouldNotReachHere(); 244 } 245 } 246 } 247 248 private void moveViaStack(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCKind inputKind, SPARCKind resultKind) { 249 int resultKindSize = resultKind.getSizeInBytes(); 250 assert inputKind.getSizeInBytes() == resultKindSize; 251 try (ScratchRegister sc = masm.getScratchRegister()) { 252 Register scratch = sc.getRegister(); 253 SPARCAddress tempAddress = generateSimm13OffsetLoad((SPARCAddress) crb.asAddress(temp), masm, scratch); 254 masm.st(asRegister(input), tempAddress, resultKindSize); 255 getDelayedControlTransfer().emitControlTransfer(crb, masm); 256 masm.ld(tempAddress, asRegister(result), resultKindSize, false); 257 } 258 } 259 } 260 261 public abstract static class MemOp extends SPARCLIRInstruction implements ImplicitNullCheck { 262 public static final LIRInstructionClass<MemOp> TYPE = LIRInstructionClass.create(MemOp.class); 263 264 protected final PlatformKind kind; 265 @Use({COMPOSITE}) protected SPARCAddressValue address; 266 @State protected LIRFrameState state; 267 268 public MemOp(LIRInstructionClass<? extends MemOp> c, SizeEstimate size, PlatformKind kind, SPARCAddressValue address, LIRFrameState state) { 269 super(c, size); 270 this.kind = kind; 271 this.address = address; 272 this.state = state; 273 } 274 275 protected abstract void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm); 276 277 @Override 278 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 279 emitMemAccess(crb, masm); 280 } 281 282 @Override 283 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 284 if (state == null && address.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 285 state = nullCheckState; 286 return true; 287 } 288 return false; 289 } 290 } 291 292 public static final class LoadOp extends MemOp implements SPARCTailDelayedLIRInstruction { 293 public static final LIRInstructionClass<LoadOp> TYPE = LIRInstructionClass.create(LoadOp.class); 294 public static final SizeEstimate SIZE = SizeEstimate.create(1); 295 296 @Def({REG}) protected AllocatableValue result; 297 protected boolean signExtend; 298 299 public LoadOp(PlatformKind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state) { 300 this(kind, result, address, state, false); 301 } 302 303 public LoadOp(PlatformKind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state, boolean signExtend) { 304 super(TYPE, SIZE, kind, address, state); 305 this.result = result; 306 this.signExtend = signExtend; 307 } 308 309 @Override 310 public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 311 emitLoad(crb, masm, address.toAddress(), result, signExtend, kind, getDelayedControlTransfer(), state); 312 } 313 } 314 315 public static final class LoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 316 public static final LIRInstructionClass<LoadAddressOp> TYPE = LIRInstructionClass.create(LoadAddressOp.class); 317 public static final SizeEstimate SIZE = SizeEstimate.create(8); 318 319 @Def({REG}) protected AllocatableValue result; 320 @Use({COMPOSITE, UNINITIALIZED}) protected SPARCAddressValue addressValue; 321 322 public LoadAddressOp(AllocatableValue result, SPARCAddressValue address) { 323 super(TYPE, SIZE); 324 this.result = result; 325 this.addressValue = address; 326 } 327 328 @Override 329 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 330 SPARCAddress address = addressValue.toAddress(); 331 loadEffectiveAddress(crb, masm, address, asRegister(result, XWORD), getDelayedControlTransfer()); 332 } 333 } 334 335 public static final class LoadDataAddressOp extends SPARCLIRInstruction { 336 public static final LIRInstructionClass<LoadDataAddressOp> TYPE = LIRInstructionClass.create(LoadDataAddressOp.class); 337 338 @Def({REG}) protected AllocatableValue result; 339 private final DataPointerConstant data; 340 341 public LoadDataAddressOp(AllocatableValue result, DataPointerConstant data) { 342 super(TYPE); 343 this.result = result; 344 this.data = data; 345 } 346 347 @Override 348 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 349 // HotSpot for SPARC requires at least word alignment 350 SPARCAddress addr = (SPARCAddress) crb.recordDataReferenceInCode(data, max(SPARCKind.WORD.getSizeInBytes(), data.getAlignment())); 351 assert addr == masm.getPlaceholder(-1); 352 final boolean forceRelocatable = true; 353 Register dstReg = asRegister(result); 354 masm.setx(0, dstReg, forceRelocatable); 355 } 356 357 @Override 358 public SizeEstimate estimateSize() { 359 return SizeEstimate.create(8, data.getSerializedSize()); 360 } 361 } 362 363 public static final class MembarOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 364 public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class); 365 public static final SizeEstimate SIZE = SizeEstimate.create(1); 366 367 private final int barriers; 368 369 public MembarOp(final int barriers) { 370 super(TYPE, SIZE); 371 this.barriers = barriers; 372 } 373 374 @Override 375 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 376 getDelayedControlTransfer().emitControlTransfer(crb, masm); 377 masm.membar(MEMBAR_STORE_LOAD); 378 } 379 380 @Override 381 public void verify() { 382 assert barriers == STORE_LOAD : String.format("Got barriers 0x%x; On SPARC only STORE_LOAD barriers are accepted; all other barriers are not neccessary due to TSO", barriers); 383 } 384 } 385 386 public static final class NullCheckOp extends SPARCLIRInstruction implements NullCheck, SPARCTailDelayedLIRInstruction { 387 public static final LIRInstructionClass<NullCheckOp> TYPE = LIRInstructionClass.create(NullCheckOp.class); 388 public static final SizeEstimate SIZE = SizeEstimate.create(1); 389 390 @Use({COMPOSITE}) protected SPARCAddressValue input; 391 @State protected LIRFrameState state; 392 393 public NullCheckOp(SPARCAddressValue input, LIRFrameState state) { 394 super(TYPE, SIZE); 395 this.input = input; 396 this.state = state; 397 } 398 399 @Override 400 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 401 getDelayedControlTransfer().emitControlTransfer(crb, masm); 402 SPARCAddress addr = input.toAddress(); 403 crb.recordImplicitException(masm.position(), state); 404 // Just need to check whether this is a valid address or not; alignment is not 405 // checked 406 masm.ldub(addr, g0); 407 } 408 409 @Override 410 public Value getCheckedValue() { 411 return input; 412 } 413 414 @Override 415 public LIRFrameState getState() { 416 return state; 417 } 418 } 419 420 @Opcode("CAS") 421 public static final class CompareAndSwapOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 422 public static final LIRInstructionClass<CompareAndSwapOp> TYPE = LIRInstructionClass.create(CompareAndSwapOp.class); 423 public static final SizeEstimate SIZE = SizeEstimate.create(2); 424 425 @Def({REG, HINT}) protected AllocatableValue result; 426 @Alive({REG}) protected AllocatableValue address; 427 @Alive({REG}) protected AllocatableValue cmpValue; 428 @Use({REG}) protected AllocatableValue newValue; 429 430 public CompareAndSwapOp(AllocatableValue result, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue) { 431 super(TYPE, SIZE); 432 this.result = result; 433 this.address = address; 434 this.cmpValue = cmpValue; 435 this.newValue = newValue; 436 } 437 438 @Override 439 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 440 move(crb, masm, result, newValue, SPARCDelayedControlTransfer.DUMMY); 441 compareAndSwap(crb, masm, address, cmpValue, result, getDelayedControlTransfer()); 442 } 443 } 444 445 public static final class StackLoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 446 public static final LIRInstructionClass<StackLoadAddressOp> TYPE = LIRInstructionClass.create(StackLoadAddressOp.class); 447 public static final SizeEstimate SIZE = SizeEstimate.create(2); 448 449 @Def({REG}) protected AllocatableValue result; 450 @Use({STACK, UNINITIALIZED}) protected AllocatableValue slot; 451 452 public StackLoadAddressOp(AllocatableValue result, AllocatableValue slot) { 453 super(TYPE, SIZE); 454 this.result = result; 455 this.slot = slot; 456 assert slot instanceof VirtualStackSlot || slot instanceof StackSlot; 457 } 458 459 @Override 460 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 461 SPARCAddress address = (SPARCAddress) crb.asAddress(slot); 462 loadEffectiveAddress(crb, masm, address, asRegister(result, XWORD), getDelayedControlTransfer()); 463 } 464 } 465 466 private static void loadEffectiveAddress(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCAddress address, Register result, SPARCDelayedControlTransfer delaySlotHolder) { 467 if (address.getIndex().equals(Register.None)) { 468 if (isSimm13(address.getDisplacement())) { 469 delaySlotHolder.emitControlTransfer(crb, masm); 470 masm.add(address.getBase(), address.getDisplacement(), result); 471 } else { 472 assert result.encoding() != address.getBase().encoding(); 473 masm.setx(address.getDisplacement(), result, false); 474 // No relocation, therefore, the add can be delayed as well 475 delaySlotHolder.emitControlTransfer(crb, masm); 476 masm.add(address.getBase(), result, result); 477 } 478 } else { 479 delaySlotHolder.emitControlTransfer(crb, masm); 480 masm.add(address.getBase(), address.getIndex(), result); 481 } 482 } 483 484 public static class StoreOp extends MemOp implements SPARCTailDelayedLIRInstruction { 485 public static final LIRInstructionClass<StoreOp> TYPE = LIRInstructionClass.create(StoreOp.class); 486 public static final SizeEstimate SIZE = SizeEstimate.create(1); 487 488 @Use({REG}) protected AllocatableValue input; 489 490 public StoreOp(PlatformKind kind, SPARCAddressValue address, AllocatableValue input, LIRFrameState state) { 491 super(TYPE, SIZE, kind, address, state); 492 this.input = input; 493 } 494 495 @Override 496 public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 497 emitStore(input, address.toAddress(), kind, getDelayedControlTransfer(), state, crb, masm); 498 } 499 } 500 501 public static final class StoreConstantOp extends MemOp implements SPARCTailDelayedLIRInstruction { 502 public static final LIRInstructionClass<StoreConstantOp> TYPE = LIRInstructionClass.create(StoreConstantOp.class); 503 public static final SizeEstimate SIZE = SizeEstimate.create(2); 504 505 protected final JavaConstant input; 506 507 public StoreConstantOp(PlatformKind kind, SPARCAddressValue address, JavaConstant input, LIRFrameState state) { 508 super(TYPE, SIZE, kind, address, state); 509 this.input = input; 510 if (!input.isDefaultForKind()) { 511 throw GraalError.shouldNotReachHere("Can only store null constants to memory"); 512 } 513 } 514 515 @Override 516 public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 517 try (ScratchRegister sc = masm.getScratchRegister()) { 518 Register scratch = sc.getRegister(); 519 SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch); 520 getDelayedControlTransfer().emitControlTransfer(crb, masm); 521 if (state != null) { 522 crb.recordImplicitException(masm.position(), state); 523 } 524 int byteCount = kind.getSizeInBytes(); 525 masm.st(g0, addr, byteCount); 526 } 527 } 528 } 529 530 public static void move(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { 531 move(crb, masm, result, g0, input, delaySlotLir); 532 } 533 534 public static void move(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Register constantTableBase, Value input, SPARCDelayedControlTransfer delaySlotLir) { 535 if (isRegister(input)) { 536 if (isRegister(result)) { 537 reg2reg(crb, masm, result, input, delaySlotLir); 538 } else if (isStackSlot(result)) { 539 reg2stack(crb, masm, result, input, delaySlotLir); 540 } else { 541 throw GraalError.shouldNotReachHere("Result is a: " + result); 542 } 543 } else if (isStackSlot(input)) { 544 if (isRegister(result)) { 545 SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input); 546 emitLoad(crb, masm, inputAddress, result, false, input.getPlatformKind(), delaySlotLir, null); 547 } else if (isStackSlot(result)) { 548 stack2stack(crb, masm, result, input, delaySlotLir); 549 } else { 550 throw GraalError.shouldNotReachHere("Result is a: " + result); 551 } 552 } else if (isJavaConstant(input)) { 553 JavaConstant constant = asJavaConstant(input); 554 if (isRegister(result)) { 555 const2reg(crb, masm, result, constantTableBase, constant, delaySlotLir); 556 } else if (isStackSlot(result)) { 557 const2stack(crb, masm, result, constantTableBase, delaySlotLir, constant); 558 } else { 559 throw GraalError.shouldNotReachHere("Result is a: " + result); 560 } 561 } else { 562 throw GraalError.shouldNotReachHere(); 563 } 564 } 565 566 public static void const2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Register constantTableBase, SPARCDelayedControlTransfer delaySlotLir, JavaConstant constant) { 567 if (constant.isDefaultForKind() || constant.isNull()) { 568 SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); 569 emitStore(g0.asValue(LIRKind.combine(result)), resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm); 570 } else { 571 try (ScratchRegister sc = masm.getScratchRegister()) { 572 Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(result)); 573 const2reg(crb, masm, scratchRegisterValue, constantTableBase, constant, SPARCDelayedControlTransfer.DUMMY); 574 SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); 575 emitStore(scratchRegisterValue, resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm); 576 } 577 } 578 } 579 580 public static void stack2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, PlatformKind resultKind, PlatformKind inputKind, Value result, Value input, 581 SPARCDelayedControlTransfer delaySlotLir) { 582 try (ScratchRegister sc = masm.getScratchRegister()) { 583 SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input); 584 Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(input)); 585 emitLoad(crb, masm, inputAddress, scratchRegisterValue, false, inputKind, SPARCDelayedControlTransfer.DUMMY, null); 586 SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); 587 emitStore(scratchRegisterValue, resultAddress, resultKind, delaySlotLir, null, crb, masm); 588 } 589 } 590 591 public static void stack2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { 592 stack2stack(crb, masm, result.getPlatformKind(), input.getPlatformKind(), result, input, delaySlotLir); 593 } 594 595 public static void reg2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { 596 SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); 597 emitStore(input, resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm); 598 } 599 600 public static void reg2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { 601 final Register src = asRegister(input); 602 final Register dst = asRegister(result); 603 if (src.equals(dst)) { 604 return; 605 } 606 delaySlotLir.emitControlTransfer(crb, masm); 607 if (isCPURegister(src) && isCPURegister(dst)) { 608 masm.mov(src, dst); 609 } else if (isSingleFloatRegister(src) && isSingleFloatRegister(dst)) { 610 masm.fsrc2s(src, dst); 611 } else if (isDoubleFloatRegister(src) && isDoubleFloatRegister(dst)) { 612 masm.fsrc2d(src, dst); 613 } else { 614 throw GraalError.shouldNotReachHere(String.format("Trying to move between register domains src: %s dst: %s", src, dst)); 615 } 616 } 617 618 /** 619 * Guarantees that the given SPARCAddress given before is loadable by subsequent load/store 620 * instruction. If the displacement exceeds the simm13 value range, the value is put into a 621 * scratch register. 622 * 623 * @param addr Address to modify 624 * @param masm assembler to output the potential code to store the value in the scratch register 625 * @param scratch The register as scratch to use 626 * @return a loadable SPARCAddress 627 */ 628 public static SPARCAddress generateSimm13OffsetLoad(SPARCAddress addr, SPARCMacroAssembler masm, Register scratch) { 629 boolean displacementOutOfBound = addr.getIndex().equals(Register.None) && !SPARCAssembler.isSimm13(addr.getDisplacement()); 630 if (displacementOutOfBound) { 631 masm.setx(addr.getDisplacement(), scratch, false); 632 return new SPARCAddress(addr.getBase(), scratch); 633 } else { 634 return addr; 635 } 636 } 637 638 public static void const2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Register constantTableBase, JavaConstant input, SPARCDelayedControlTransfer delaySlotLir) { 639 try (ScratchRegister sc = masm.getScratchRegister()) { 640 Register scratch = sc.getRegister(); 641 Set<CPUFeature> cpuFeatures = ((SPARC) masm.target.arch).getFeatures(); 642 boolean hasVIS1 = cpuFeatures.contains(CPUFeature.VIS1); 643 boolean hasVIS3 = cpuFeatures.contains(CPUFeature.VIS3); 644 Register resultRegister = asRegister(result); 645 int byteCount = result.getPlatformKind().getSizeInBytes(); 646 switch (input.getJavaKind().getStackKind()) { 647 case Int: 648 if (input.isDefaultForKind()) { 649 delaySlotLir.emitControlTransfer(crb, masm); 650 masm.clr(resultRegister); 651 } else if (isSimm13(input.asInt())) { 652 delaySlotLir.emitControlTransfer(crb, masm); 653 masm.or(g0, input.asInt(), resultRegister); 654 } else { 655 if (constantTableBase.equals(g0)) { 656 throw GraalError.shouldNotReachHere(); 657 } else { 658 loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir); 659 } 660 } 661 break; 662 case Long: 663 if (input.isDefaultForKind()) { 664 delaySlotLir.emitControlTransfer(crb, masm); 665 masm.clr(resultRegister); 666 } else if (isSimm13(input.asLong())) { 667 delaySlotLir.emitControlTransfer(crb, masm); 668 masm.or(g0, (int) input.asLong(), resultRegister); 669 } else { 670 loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir); 671 } 672 break; 673 case Float: { 674 float constant = input.asFloat(); 675 int constantBits = java.lang.Float.floatToIntBits(constant); 676 if (hasVIS1 && constantBits == 0) { 677 delaySlotLir.emitControlTransfer(crb, masm); 678 masm.fzeros(resultRegister); 679 } else { 680 if (hasVIS3 && isSimm13(constantBits)) { 681 masm.or(g0, constantBits, scratch); 682 delaySlotLir.emitControlTransfer(crb, masm); 683 masm.movwtos(scratch, resultRegister); 684 } else { 685 // First load the address into the scratch register 686 loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir); 687 } 688 } 689 break; 690 } 691 case Double: { 692 double constant = input.asDouble(); 693 long constantBits = java.lang.Double.doubleToRawLongBits(constant); 694 if (hasVIS1 && constantBits == 0) { 695 delaySlotLir.emitControlTransfer(crb, masm); 696 masm.fzerod(resultRegister); 697 } else { 698 if (hasVIS3 && isSimm13(constantBits)) { 699 masm.or(g0, (int) constantBits, scratch); 700 delaySlotLir.emitControlTransfer(crb, masm); 701 masm.movxtod(scratch, resultRegister); 702 } else { 703 loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir); 704 } 705 } 706 break; 707 } 708 case Object: 709 if (input.isNull()) { 710 delaySlotLir.emitControlTransfer(crb, masm); 711 masm.clr(resultRegister); 712 } else { 713 loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir); 714 } 715 break; 716 default: 717 throw GraalError.shouldNotReachHere("missing: " + input.getJavaKind()); 718 } 719 } 720 } 721 722 protected static void compareAndSwap(CompilationResultBuilder crb, SPARCMacroAssembler masm, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue, 723 SPARCDelayedControlTransfer delay) { 724 delay.emitControlTransfer(crb, masm); 725 switch ((SPARCKind) cmpValue.getPlatformKind()) { 726 case WORD: 727 masm.cas(asRegister(address), asRegister(cmpValue), asRegister(newValue)); 728 break; 729 case XWORD: 730 masm.casx(asRegister(address), asRegister(cmpValue), asRegister(newValue)); 731 break; 732 default: 733 throw GraalError.shouldNotReachHere(); 734 } 735 } 736 737 public static void emitLoad(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCAddress address, Value result, boolean signExtend, PlatformKind kind, 738 SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state) { 739 try (ScratchRegister sc = masm.getScratchRegister()) { 740 Register scratch = sc.getRegister(); 741 final SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch); 742 final Register dst = asRegister(result); 743 delayedControlTransfer.emitControlTransfer(crb, masm); 744 if (state != null) { 745 crb.recordImplicitException(masm.position(), state); 746 } 747 int byteCount = kind.getSizeInBytes(); 748 masm.ld(addr, dst, byteCount, signExtend); 749 } 750 } 751 752 public static void emitStore(Value input, SPARCAddress address, PlatformKind kind, SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state, CompilationResultBuilder crb, 753 SPARCMacroAssembler masm) { 754 try (ScratchRegister sc = masm.getScratchRegister()) { 755 Register scratch = sc.getRegister(); 756 SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch); 757 delayedControlTransfer.emitControlTransfer(crb, masm); 758 if (state != null) { 759 crb.recordImplicitException(masm.position(), state); 760 } 761 int byteCount = kind.getSizeInBytes(); 762 masm.st(asRegister(input), addr, byteCount); 763 } 764 } 765 766 /** 767 * This method creates a load from the constant section. It automatically respects the different 768 * patterns used for small constant sections (<8k) and large constant sections (>=8k). The 769 * generated patterns by this method must be understood by 770 * CodeInstaller::pd_patch_DataSectionReference (jvmciCodeInstaller_sparc.cpp). 771 */ 772 public static void loadFromConstantTable(CompilationResultBuilder crb, SPARCMacroAssembler masm, int byteCount, Register constantTableBase, Constant input, Register dest, 773 SPARCDelayedControlTransfer delaySlotInstruction) { 774 SPARCAddress address; 775 ScratchRegister scratch = null; 776 try { 777 if (masm.isImmediateConstantLoad()) { 778 address = new SPARCAddress(constantTableBase, 0); 779 // Make delayed only, when using immediate constant load. 780 delaySlotInstruction.emitControlTransfer(crb, masm); 781 crb.recordDataReferenceInCode(input, byteCount); 782 } else { 783 scratch = masm.getScratchRegister(); 784 Register sr = scratch.getRegister(); 785 crb.recordDataReferenceInCode(input, byteCount); 786 masm.sethix(0, sr, true); 787 address = new SPARCAddress(sr, 0); 788 } 789 masm.ld(address, dest, byteCount, false); 790 } finally { 791 if (scratch != null) { 792 scratch.close(); 793 } 794 } 795 } 796 }