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