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