001/* 002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.lir.sparc; 024 025import static com.oracle.graal.asm.sparc.SPARCAssembler.*; 026import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; 027import static jdk.internal.jvmci.code.ValueUtil.*; 028import static jdk.internal.jvmci.meta.Kind.*; 029import static jdk.internal.jvmci.sparc.SPARC.*; 030 031import java.util.*; 032 033import jdk.internal.jvmci.code.*; 034import jdk.internal.jvmci.common.*; 035import jdk.internal.jvmci.meta.*; 036import jdk.internal.jvmci.sparc.*; 037import jdk.internal.jvmci.sparc.SPARC.CPUFeature; 038 039import com.oracle.graal.asm.sparc.*; 040import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; 041import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Sethix; 042import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; 043import com.oracle.graal.lir.*; 044import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; 045import com.oracle.graal.lir.StandardOp.MoveOp; 046import com.oracle.graal.lir.StandardOp.NullCheck; 047import com.oracle.graal.lir.asm.*; 048 049public class SPARCMove { 050 051 public static class LoadInlineConstant extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction, MoveOp { 052 public static final LIRInstructionClass<LoadInlineConstant> TYPE = LIRInstructionClass.create(LoadInlineConstant.class); 053 public static final SizeEstimate SIZE = SizeEstimate.create(1); 054 private JavaConstant constant; 055 @Def({REG, STACK}) AllocatableValue result; 056 057 public LoadInlineConstant(JavaConstant constant, AllocatableValue result) { 058 super(TYPE, SIZE); 059 this.constant = constant; 060 this.result = result; 061 } 062 063 @Override 064 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 065 if (isRegister(result)) { 066 const2reg(crb, masm, result, g0, constant, delayedControlTransfer); 067 } else if (isStackSlot(result)) { 068 StackSlot slot = asStackSlot(result); 069 const2stack(crb, masm, slot, g0, constant, delayedControlTransfer, constant); 070 } 071 } 072 073 public Value getInput() { 074 return constant; 075 } 076 077 public AllocatableValue getResult() { 078 return result; 079 } 080 } 081 082 public static class LoadConstantFromTable extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 083 public static final LIRInstructionClass<LoadConstantFromTable> TYPE = LIRInstructionClass.create(LoadConstantFromTable.class); 084 public static final SizeEstimate SIZE = SizeEstimate.create(1, 8); 085 086 private JavaConstant constant; 087 @Def({REG, STACK}) AllocatableValue result; 088 @Use({REG}) private AllocatableValue constantTableBase; 089 090 public LoadConstantFromTable(JavaConstant constant, AllocatableValue constantTableBase, AllocatableValue result) { 091 super(TYPE, SIZE); 092 this.constant = constant; 093 this.result = result; 094 this.constantTableBase = constantTableBase; 095 } 096 097 @Override 098 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 099 final Runnable recordReference; 100 final Kind constantKind = constant.getKind().equals(Object) ? Kind.Long : constant.getKind(); 101 switch (constantKind) { 102 case Object: 103 case Float: 104 case Double: 105 case Char: 106 case Short: 107 case Int: 108 case Long: 109 recordReference = () -> crb.recordDataReferenceInCode(constant, constantKind.getByteCount()); 110 break; 111 case Byte: 112 case Boolean: // Byte and Boolean always fits into simm13 113 throw JVMCIError.shouldNotReachHere("Byte/Boolean must not be loaded via constant table"); 114 default: 115 throw JVMCIError.shouldNotReachHere("Unimplemented constant type: " + constant); 116 } 117 Register baseRegister = asRegister(constantTableBase); 118 if (isRegister(result)) { 119 Register resultRegister = asRegister(result); 120 loadFromConstantTable(crb, masm, constantKind, baseRegister, resultRegister, delayedControlTransfer, recordReference); 121 } else if (isStackSlot(result)) { 122 try (ScratchRegister scratch = masm.getScratchRegister()) { 123 Register scratchRegister = scratch.getRegister(); 124 loadFromConstantTable(crb, masm, constantKind, baseRegister, scratchRegister, delayedControlTransfer, recordReference); 125 StackSlot slot = asStackSlot(result); 126 delayedControlTransfer.emitControlTransfer(crb, masm); 127 masm.stx(scratchRegister, (SPARCAddress) crb.asAddress(slot)); 128 } 129 } 130 } 131 } 132 133 @Opcode("MOVE") 134 public static class Move extends SPARCLIRInstruction implements MoveOp, SPARCTailDelayedLIRInstruction { 135 public static final LIRInstructionClass<Move> TYPE = LIRInstructionClass.create(Move.class); 136 public static final SizeEstimate SIZE = SizeEstimate.create(8); 137 138 @Def({REG, STACK, HINT}) protected AllocatableValue result; 139 @Use({REG, STACK}) protected Value input; 140 141 public Move(AllocatableValue result, Value input) { 142 super(TYPE, SIZE); 143 this.result = result; 144 this.input = input; 145 } 146 147 @Override 148 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 149 assert !isConstant(input); 150 if (isStackSlot(input) && isStackSlot(result)) { 151 stack2stack(crb, masm, reInterpret(asStackSlot(result)), reInterpret(asStackSlot(input)), delayedControlTransfer); 152 } else { 153 move(crb, masm, getResult(), getInput(), delayedControlTransfer); 154 } 155 } 156 157 @Override 158 public Value getInput() { 159 return input; 160 } 161 162 @Override 163 public AllocatableValue getResult() { 164 return result; 165 } 166 167 private static StackSlot reInterpret(StackSlot slot) { 168 switch ((Kind) slot.getPlatformKind()) { 169 case Boolean: 170 case Byte: 171 case Short: 172 case Char: 173 case Int: 174 case Long: 175 case Object: 176 return slot; 177 case Float: 178 return StackSlot.get(LIRKind.value(Kind.Int), slot.getRawOffset(), slot.getRawAddFrameSize()); 179 case Double: 180 return StackSlot.get(LIRKind.value(Kind.Long), slot.getRawOffset(), slot.getRawAddFrameSize()); 181 default: 182 throw JVMCIError.shouldNotReachHere(); 183 } 184 } 185 } 186 187 /** 188 * Move between floating-point and general purpose register domain. 189 */ 190 @Opcode("MOVE_FPGP") 191 public static final class MoveFpGp extends SPARCLIRInstruction implements MoveOp, SPARCTailDelayedLIRInstruction { 192 public static final LIRInstructionClass<MoveFpGp> TYPE = LIRInstructionClass.create(MoveFpGp.class); 193 public static final SizeEstimate SIZE = SizeEstimate.create(2); 194 195 @Def({REG}) protected AllocatableValue result; 196 @Use({REG}) protected AllocatableValue input; 197 @Use({STACK, ILLEGAL}) protected AllocatableValue temp; 198 199 public MoveFpGp(AllocatableValue result, AllocatableValue input, AllocatableValue temp) { 200 super(TYPE, SIZE); 201 this.result = result; 202 this.input = input; 203 this.temp = temp; 204 } 205 206 public Value getInput() { 207 return input; 208 } 209 210 public AllocatableValue getResult() { 211 return result; 212 } 213 214 @Override 215 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 216 Kind inputKind = (Kind) input.getPlatformKind(); 217 Kind resultKind = (Kind) result.getPlatformKind(); 218 if (AllocatableValue.ILLEGAL.equals(temp)) { 219 moveDirect(crb, masm, inputKind, resultKind); 220 } else { 221 moveViaStack(crb, masm, inputKind, resultKind); 222 } 223 } 224 225 private void moveDirect(CompilationResultBuilder crb, SPARCMacroAssembler masm, Kind inputKind, Kind resultKind) { 226 delayedControlTransfer.emitControlTransfer(crb, masm); 227 if (resultKind == Float) { 228 if (inputKind == Int || inputKind == Short || inputKind == Char || inputKind == Byte) { 229 masm.movwtos(asIntReg(input), asFloatReg(result)); 230 } else { 231 throw JVMCIError.shouldNotReachHere(); 232 } 233 } else if (resultKind == Double) { 234 if (inputKind == Int || inputKind == Short || inputKind == Char || inputKind == Byte) { 235 masm.movxtod(asIntReg(input), asDoubleReg(result)); 236 } else { 237 masm.movxtod(asLongReg(input), asDoubleReg(result)); 238 } 239 } else if (inputKind == Float) { 240 if (resultKind == Int || resultKind == Short || resultKind == Byte) { 241 masm.movstosw(asFloatReg(input), asIntReg(result)); 242 } else { 243 masm.movstouw(asFloatReg(input), asIntReg(result)); 244 } 245 } else if (inputKind == Double) { 246 if (resultKind == Long) { 247 masm.movdtox(asDoubleReg(input), asLongReg(result)); 248 } else { 249 throw JVMCIError.shouldNotReachHere(); 250 } 251 } 252 } 253 254 private void moveViaStack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Kind inputKind, Kind resultKind) { 255 int resultKindSize = crb.target.getSizeInBytes(resultKind); 256 try (ScratchRegister sc = masm.getScratchRegister()) { 257 Register scratch = sc.getRegister(); 258 SPARCAddress tempAddress = generateSimm13OffsetLoad((SPARCAddress) crb.asAddress(temp), masm, scratch); 259 switch (inputKind) { 260 case Float: 261 assert resultKindSize == 4; 262 masm.stf(asFloatReg(input), tempAddress); 263 break; 264 case Double: 265 assert resultKindSize == 8; 266 masm.stdf(asDoubleReg(input), tempAddress); 267 break; 268 case Long: 269 case Int: 270 case Short: 271 case Char: 272 case Byte: 273 if (resultKindSize == 8) { 274 masm.stx(asLongReg(input), tempAddress); 275 } else if (resultKindSize == 4) { 276 masm.stw(asIntReg(input), tempAddress); 277 } else if (resultKindSize == 2) { 278 masm.sth(asIntReg(input), tempAddress); 279 } else if (resultKindSize == 1) { 280 masm.stb(asIntReg(input), tempAddress); 281 } else { 282 throw JVMCIError.shouldNotReachHere(); 283 } 284 break; 285 default: 286 JVMCIError.shouldNotReachHere(); 287 } 288 delayedControlTransfer.emitControlTransfer(crb, masm); 289 switch (resultKind) { 290 case Long: 291 masm.ldx(tempAddress, asLongReg(result)); 292 break; 293 case Int: 294 masm.ldsw(tempAddress, asIntReg(result)); 295 break; 296 case Short: 297 masm.ldsh(tempAddress, asIntReg(input)); 298 break; 299 case Char: 300 masm.lduh(tempAddress, asIntReg(input)); 301 break; 302 case Byte: 303 masm.ldsb(tempAddress, asIntReg(input)); 304 break; 305 case Float: 306 masm.ldf(tempAddress, asFloatReg(result)); 307 break; 308 case Double: 309 masm.lddf(tempAddress, asDoubleReg(result)); 310 break; 311 default: 312 JVMCIError.shouldNotReachHere(); 313 break; 314 } 315 } 316 } 317 } 318 319 public abstract static class MemOp extends SPARCLIRInstruction implements ImplicitNullCheck { 320 public static final LIRInstructionClass<MemOp> TYPE = LIRInstructionClass.create(MemOp.class); 321 322 protected final PlatformKind kind; 323 @Use({COMPOSITE}) protected SPARCAddressValue address; 324 @State protected LIRFrameState state; 325 326 public MemOp(LIRInstructionClass<? extends MemOp> c, SizeEstimate size, PlatformKind kind, SPARCAddressValue address, LIRFrameState state) { 327 super(c, size); 328 this.kind = kind; 329 this.address = address; 330 this.state = state; 331 } 332 333 protected abstract void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm); 334 335 @Override 336 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 337 emitMemAccess(crb, masm); 338 } 339 340 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 341 if (state == null && address.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 342 state = nullCheckState; 343 return true; 344 } 345 return false; 346 } 347 } 348 349 public static final class LoadOp extends MemOp implements SPARCTailDelayedLIRInstruction { 350 public static final LIRInstructionClass<LoadOp> TYPE = LIRInstructionClass.create(LoadOp.class); 351 public static final SizeEstimate SIZE = SizeEstimate.create(1); 352 353 @Def({REG}) protected AllocatableValue result; 354 protected boolean signExtend; 355 356 public LoadOp(Kind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state) { 357 this(kind, result, address, state, false); 358 } 359 360 public LoadOp(Kind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state, boolean signExtend) { 361 super(TYPE, SIZE, kind, address, state); 362 this.result = result; 363 this.signExtend = signExtend; 364 } 365 366 @Override 367 public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 368 emitLoad(crb, masm, address.toAddress(), result, signExtend, kind, delayedControlTransfer, state); 369 } 370 } 371 372 public static final class LoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 373 public static final LIRInstructionClass<LoadAddressOp> TYPE = LIRInstructionClass.create(LoadAddressOp.class); 374 public static final SizeEstimate SIZE = SizeEstimate.create(8); 375 376 @Def({REG}) protected AllocatableValue result; 377 @Use({COMPOSITE, UNINITIALIZED}) protected SPARCAddressValue addressValue; 378 379 public LoadAddressOp(AllocatableValue result, SPARCAddressValue address) { 380 super(TYPE, SIZE); 381 this.result = result; 382 this.addressValue = address; 383 } 384 385 @Override 386 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 387 SPARCAddress address = addressValue.toAddress(); 388 loadEffectiveAddress(crb, masm, address, asLongReg(result), delayedControlTransfer); 389 } 390 } 391 392 public static final class LoadDataAddressOp extends SPARCLIRInstruction { 393 public static final LIRInstructionClass<LoadDataAddressOp> TYPE = LIRInstructionClass.create(LoadDataAddressOp.class); 394 395 @Def({REG}) protected AllocatableValue result; 396 private final byte[] data; 397 398 public LoadDataAddressOp(AllocatableValue result, byte[] data) { 399 super(TYPE); 400 this.result = result; 401 this.data = data; 402 } 403 404 @Override 405 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 406 SPARCAddress addr = (SPARCAddress) crb.recordDataReferenceInCode(data, 8); 407 assert addr == masm.getPlaceholder(); 408 final boolean forceRelocatable = true; 409 Register dstReg = asRegister(result); 410 new Setx(0, dstReg, forceRelocatable).emit(masm); 411 } 412 413 @Override 414 public SizeEstimate estimateSize() { 415 return SizeEstimate.create(8, data.length); 416 } 417 } 418 419 public static final class MembarOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 420 public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class); 421 public static final SizeEstimate SIZE = SizeEstimate.create(1); 422 423 private final int barriers; 424 425 public MembarOp(final int barriers) { 426 super(TYPE, SIZE); 427 this.barriers = barriers; 428 } 429 430 @Override 431 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 432 delayedControlTransfer.emitControlTransfer(crb, masm); 433 masm.membar(barriers); 434 } 435 } 436 437 public static final class NullCheckOp extends SPARCLIRInstruction implements NullCheck, SPARCTailDelayedLIRInstruction { 438 public static final LIRInstructionClass<NullCheckOp> TYPE = LIRInstructionClass.create(NullCheckOp.class); 439 public static final SizeEstimate SIZE = SizeEstimate.create(1); 440 441 @Use({COMPOSITE}) protected SPARCAddressValue input; 442 @State protected LIRFrameState state; 443 444 public NullCheckOp(SPARCAddressValue input, LIRFrameState state) { 445 super(TYPE, SIZE); 446 this.input = input; 447 this.state = state; 448 } 449 450 @Override 451 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 452 delayedControlTransfer.emitControlTransfer(crb, masm); 453 SPARCAddress addr = input.toAddress(); 454 crb.recordImplicitException(masm.position(), state); 455 // Just need to check whether this is a valid address or not; alignment is not 456 // checked 457 masm.ldub(addr, g0); 458 } 459 460 public Value getCheckedValue() { 461 return input; 462 } 463 464 public LIRFrameState getState() { 465 return state; 466 } 467 } 468 469 @Opcode("CAS") 470 public static final class CompareAndSwapOp extends SPARCLIRInstruction { 471 public static final LIRInstructionClass<CompareAndSwapOp> TYPE = LIRInstructionClass.create(CompareAndSwapOp.class); 472 public static final SizeEstimate SIZE = SizeEstimate.create(2); 473 474 @Def({REG, HINT}) protected AllocatableValue result; 475 @Alive({REG}) protected AllocatableValue address; 476 @Alive({REG}) protected AllocatableValue cmpValue; 477 @Use({REG}) protected AllocatableValue newValue; 478 479 public CompareAndSwapOp(AllocatableValue result, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue) { 480 super(TYPE, SIZE); 481 this.result = result; 482 this.address = address; 483 this.cmpValue = cmpValue; 484 this.newValue = newValue; 485 } 486 487 @Override 488 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 489 move(crb, masm, result, newValue, SPARCDelayedControlTransfer.DUMMY); 490 compareAndSwap(crb, masm, address, cmpValue, result, delayedControlTransfer); 491 } 492 } 493 494 public static final class StackLoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 495 public static final LIRInstructionClass<StackLoadAddressOp> TYPE = LIRInstructionClass.create(StackLoadAddressOp.class); 496 public static final SizeEstimate SIZE = SizeEstimate.create(2); 497 498 @Def({REG}) protected AllocatableValue result; 499 @Use({STACK, UNINITIALIZED}) protected StackSlotValue slot; 500 501 public StackLoadAddressOp(AllocatableValue result, StackSlotValue address) { 502 super(TYPE, SIZE); 503 this.result = result; 504 this.slot = address; 505 } 506 507 @Override 508 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 509 SPARCAddress address = (SPARCAddress) crb.asAddress(slot); 510 loadEffectiveAddress(crb, masm, address, asLongReg(result), delayedControlTransfer); 511 } 512 } 513 514 private static void loadEffectiveAddress(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCAddress address, Register result, SPARCDelayedControlTransfer delaySlotHolder) { 515 if (address.getIndex().equals(Register.None)) { 516 if (isSimm13(address.getDisplacement())) { 517 delaySlotHolder.emitControlTransfer(crb, masm); 518 masm.add(address.getBase(), address.getDisplacement(), result); 519 } else { 520 assert result.encoding() != address.getBase().encoding(); 521 new Setx(address.getDisplacement(), result).emit(masm); 522 // No relocation, therefore, the add can be delayed as well 523 delaySlotHolder.emitControlTransfer(crb, masm); 524 masm.add(address.getBase(), result, result); 525 } 526 } else { 527 delaySlotHolder.emitControlTransfer(crb, masm); 528 masm.add(address.getBase(), address.getIndex(), result); 529 } 530 } 531 532 public static class StoreOp extends MemOp implements SPARCTailDelayedLIRInstruction { 533 public static final LIRInstructionClass<StoreOp> TYPE = LIRInstructionClass.create(StoreOp.class); 534 public static final SizeEstimate SIZE = SizeEstimate.create(1); 535 536 @Use({REG}) protected AllocatableValue input; 537 538 public StoreOp(Kind kind, SPARCAddressValue address, AllocatableValue input, LIRFrameState state) { 539 super(TYPE, SIZE, kind, address, state); 540 this.input = input; 541 } 542 543 @Override 544 public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 545 emitStore(input, address.toAddress(), kind, delayedControlTransfer, state, crb, masm); 546 } 547 } 548 549 public static final class StoreConstantOp extends MemOp implements SPARCTailDelayedLIRInstruction { 550 public static final LIRInstructionClass<StoreConstantOp> TYPE = LIRInstructionClass.create(StoreConstantOp.class); 551 public static final SizeEstimate SIZE = SizeEstimate.create(2); 552 553 protected final JavaConstant input; 554 555 public StoreConstantOp(Kind kind, SPARCAddressValue address, JavaConstant input, LIRFrameState state) { 556 super(TYPE, SIZE, kind, address, state); 557 this.input = input; 558 if (!input.isDefaultForKind()) { 559 throw JVMCIError.shouldNotReachHere("Can only store null constants to memory"); 560 } 561 } 562 563 @Override 564 public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 565 try (ScratchRegister sc = masm.getScratchRegister()) { 566 Register scratch = sc.getRegister(); 567 SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch); 568 delayedControlTransfer.emitControlTransfer(crb, masm); 569 if (state != null) { 570 crb.recordImplicitException(masm.position(), state); 571 } 572 switch ((Kind) kind) { 573 case Boolean: 574 case Byte: 575 masm.stb(g0, addr); 576 break; 577 case Short: 578 case Char: 579 masm.sth(g0, addr); 580 break; 581 case Int: 582 masm.stw(g0, addr); 583 break; 584 case Long: 585 case Object: 586 masm.stx(g0, addr); 587 break; 588 case Float: 589 case Double: 590 throw JVMCIError.shouldNotReachHere("Cannot store float constants to memory"); 591 default: 592 throw JVMCIError.shouldNotReachHere(); 593 } 594 } 595 } 596 } 597 598 public static void move(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { 599 move(crb, masm, result, g0, input, delaySlotLir); 600 } 601 602 public static void move(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Register constantTableBase, Value input, SPARCDelayedControlTransfer delaySlotLir) { 603 if (isRegister(input)) { 604 if (isRegister(result)) { 605 reg2reg(crb, masm, result, input, delaySlotLir); 606 } else if (isStackSlot(result)) { 607 reg2stack(crb, masm, result, input, delaySlotLir); 608 } else { 609 throw JVMCIError.shouldNotReachHere("Result is a: " + result); 610 } 611 } else if (isStackSlot(input)) { 612 if (isRegister(result)) { 613 SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input); 614 emitLoad(crb, masm, inputAddress, result, false, input.getPlatformKind(), delaySlotLir, null); 615 } else if (isStackSlot(result)) { 616 stack2stack(crb, masm, result, input, delaySlotLir); 617 } else { 618 throw JVMCIError.shouldNotReachHere("Result is a: " + result); 619 } 620 } else if (isConstant(input)) { 621 JavaConstant constant = asConstant(input); 622 if (isRegister(result)) { 623 const2reg(crb, masm, result, constantTableBase, constant, delaySlotLir); 624 } else if (isStackSlot(result)) { 625 const2stack(crb, masm, result, constantTableBase, input, delaySlotLir, constant); 626 } else { 627 throw JVMCIError.shouldNotReachHere("Result is a: " + result); 628 } 629 } else { 630 throw JVMCIError.shouldNotReachHere(); 631 } 632 } 633 634 public static void const2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Register constantTableBase, Value input, SPARCDelayedControlTransfer delaySlotLir, 635 JavaConstant constant) { 636 if (constant.isDefaultForKind() || constant.isNull()) { 637 SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); 638 emitStore(g0.asValue(LIRKind.combine(input)), resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm); 639 } else { 640 try (ScratchRegister sc = masm.getScratchRegister()) { 641 Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(constant)); 642 const2reg(crb, masm, scratchRegisterValue, constantTableBase, constant, SPARCDelayedControlTransfer.DUMMY); 643 SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); 644 emitStore(scratchRegisterValue, resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm); 645 } 646 } 647 } 648 649 public static void stack2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { 650 try (ScratchRegister sc = masm.getScratchRegister()) { 651 SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input); 652 Value scratchRegisterValue = sc.getRegister().asValue(LIRKind.combine(input)); 653 emitLoad(crb, masm, inputAddress, scratchRegisterValue, false, input.getPlatformKind(), SPARCDelayedControlTransfer.DUMMY, null); 654 SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); 655 emitStore(scratchRegisterValue, resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm); 656 } 657 } 658 659 public static void reg2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { 660 SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); 661 emitStore(input, resultAddress, result.getPlatformKind(), delaySlotLir, null, crb, masm); 662 } 663 664 public static void reg2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { 665 final Register src = asRegister(input); 666 final Register dst = asRegister(result); 667 if (src.equals(dst)) { 668 return; 669 } 670 switch (input.getKind()) { 671 case Boolean: 672 case Byte: 673 case Short: 674 case Char: 675 case Int: 676 case Long: 677 case Object: 678 delaySlotLir.emitControlTransfer(crb, masm); 679 masm.mov(src, dst); 680 break; 681 case Float: 682 if (result.getPlatformKind() == Kind.Float) { 683 masm.fsrc2s(src, dst); 684 } else { 685 throw JVMCIError.shouldNotReachHere(); 686 } 687 break; 688 case Double: 689 if (result.getPlatformKind() == Kind.Double) { 690 masm.fsrc2d(src, dst); 691 } else { 692 throw JVMCIError.shouldNotReachHere(); 693 } 694 break; 695 default: 696 throw JVMCIError.shouldNotReachHere("Input is a: " + input.getKind()); 697 } 698 } 699 700 /** 701 * Guarantees that the given SPARCAddress given before is loadable by subsequent load/store 702 * instruction. If the displacement exceeds the simm13 value range, the value is put into a 703 * scratch register. 704 * 705 * @param addr Address to modify 706 * @param masm assembler to output the potential code to store the value in the scratch register 707 * @param scratch The register as scratch to use 708 * @return a loadable SPARCAddress 709 */ 710 public static SPARCAddress generateSimm13OffsetLoad(SPARCAddress addr, SPARCMacroAssembler masm, Register scratch) { 711 boolean displacementOutOfBound = addr.getIndex().equals(Register.None) && !SPARCAssembler.isSimm13(addr.getDisplacement()); 712 if (displacementOutOfBound) { 713 new Setx(addr.getDisplacement(), scratch, false).emit(masm); 714 return new SPARCAddress(addr.getBase(), scratch); 715 } else { 716 return addr; 717 } 718 } 719 720 public static void const2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Register constantTableBase, JavaConstant input, SPARCDelayedControlTransfer delaySlotLir) { 721 try (ScratchRegister sc = masm.getScratchRegister()) { 722 Register scratch = sc.getRegister(); 723 Set<CPUFeature> cpuFeatures = ((SPARC) masm.target.arch).getFeatures(); 724 boolean hasVIS1 = cpuFeatures.contains(CPUFeature.VIS1); 725 boolean hasVIS3 = cpuFeatures.contains(CPUFeature.VIS3); 726 Register resultRegister = asRegister(result); 727 switch (input.getKind().getStackKind()) { 728 case Int: 729 if (input.isDefaultForKind()) { 730 delaySlotLir.emitControlTransfer(crb, masm); 731 masm.clr(resultRegister); 732 } else if (isSimm13(input.asInt())) { 733 delaySlotLir.emitControlTransfer(crb, masm); 734 masm.or(g0, input.asInt(), resultRegister); 735 } else { 736 if (constantTableBase.equals(g0)) { 737 throw JVMCIError.shouldNotReachHere(); 738 } else { 739 Runnable recordReference = () -> crb.recordDataReferenceInCode(input, input.getKind().getByteCount()); 740 loadFromConstantTable(crb, masm, input.getKind(), constantTableBase, resultRegister, delaySlotLir, recordReference); 741 } 742 } 743 break; 744 case Long: 745 if (input.isDefaultForKind()) { 746 delaySlotLir.emitControlTransfer(crb, masm); 747 masm.clr(resultRegister); 748 } else if (isSimm13(input.asLong())) { 749 delaySlotLir.emitControlTransfer(crb, masm); 750 masm.or(g0, (int) input.asLong(), resultRegister); 751 } else { 752 Runnable recordReference = () -> crb.asLongConstRef(input); 753 loadFromConstantTable(crb, masm, Long, constantTableBase, resultRegister, delaySlotLir, recordReference); 754 } 755 break; 756 case Float: { 757 float constant = input.asFloat(); 758 int constantBits = java.lang.Float.floatToIntBits(constant); 759 if (hasVIS1 && constantBits == 0) { 760 delaySlotLir.emitControlTransfer(crb, masm); 761 masm.fzeros(resultRegister); 762 } else { 763 if (hasVIS3 && isSimm13(constantBits)) { 764 masm.or(g0, constantBits, scratch); 765 delaySlotLir.emitControlTransfer(crb, masm); 766 masm.movwtos(scratch, resultRegister); 767 } else { 768 Runnable recordReference = () -> crb.asFloatConstRef(input); 769 // First load the address into the scratch register 770 loadFromConstantTable(crb, masm, Float, constantTableBase, resultRegister, delaySlotLir, recordReference); 771 } 772 } 773 break; 774 } 775 case Double: { 776 double constant = input.asDouble(); 777 long constantBits = java.lang.Double.doubleToRawLongBits(constant); 778 if (hasVIS1 && constantBits == 0) { 779 delaySlotLir.emitControlTransfer(crb, masm); 780 masm.fzerod(resultRegister); 781 } else { 782 if (hasVIS3 && isSimm13(constantBits)) { 783 masm.or(g0, (int) constantBits, scratch); 784 delaySlotLir.emitControlTransfer(crb, masm); 785 masm.movxtod(scratch, resultRegister); 786 } else { 787 Runnable recordReference = () -> crb.asDoubleConstRef(input); 788 loadFromConstantTable(crb, masm, Double, constantTableBase, resultRegister, delaySlotLir, recordReference); 789 } 790 } 791 break; 792 } 793 case Object: 794 if (input.isNull()) { 795 delaySlotLir.emitControlTransfer(crb, masm); 796 masm.clr(resultRegister); 797 } else { 798 Runnable recordReference = () -> crb.recordDataReferenceInCode(input, 8); 799 loadFromConstantTable(crb, masm, Long, constantTableBase, resultRegister, delaySlotLir, recordReference); 800 } 801 break; 802 default: 803 throw JVMCIError.shouldNotReachHere("missing: " + input.getKind()); 804 } 805 } 806 } 807 808 protected static void compareAndSwap(CompilationResultBuilder crb, SPARCMacroAssembler masm, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue, 809 SPARCDelayedControlTransfer delay) { 810 delay.emitControlTransfer(crb, masm); 811 switch (cmpValue.getKind()) { 812 case Int: 813 masm.cas(asRegister(address), asRegister(cmpValue), asRegister(newValue)); 814 break; 815 case Long: 816 case Object: 817 masm.casx(asRegister(address), asRegister(cmpValue), asRegister(newValue)); 818 break; 819 default: 820 throw JVMCIError.shouldNotReachHere(); 821 } 822 } 823 824 private static void emitLoad(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCAddress address, Value result, boolean signExtend, PlatformKind kind, 825 SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state) { 826 try (ScratchRegister sc = masm.getScratchRegister()) { 827 Register scratch = sc.getRegister(); 828 final SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch); 829 final Register dst = asRegister(result); 830 delayedControlTransfer.emitControlTransfer(crb, masm); 831 if (state != null) { 832 crb.recordImplicitException(masm.position(), state); 833 } 834 switch ((Kind) kind) { 835 case Boolean: 836 case Byte: 837 if (signExtend) { 838 masm.ldsb(addr, dst); 839 } else { 840 masm.ldub(addr, dst); 841 } 842 break; 843 case Short: 844 if (signExtend) { 845 masm.ldsh(addr, dst); 846 } else { 847 masm.lduh(addr, dst); 848 } 849 break; 850 case Char: 851 if (signExtend) { 852 masm.ldsh(addr, dst); 853 } else { 854 masm.lduh(addr, dst); 855 } 856 break; 857 case Int: 858 if (signExtend) { 859 masm.ldsw(addr, dst); 860 } else { 861 masm.lduw(addr, dst); 862 } 863 break; 864 case Long: 865 masm.ldx(addr, dst); 866 break; 867 case Float: 868 masm.ldf(addr, dst); 869 break; 870 case Double: 871 masm.lddf(addr, dst); 872 break; 873 case Object: 874 masm.ldx(addr, dst); 875 break; 876 default: 877 throw JVMCIError.shouldNotReachHere(); 878 } 879 } 880 } 881 882 public static void emitStore(Value input, SPARCAddress address, PlatformKind kind, SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state, CompilationResultBuilder crb, 883 SPARCMacroAssembler masm) { 884 try (ScratchRegister sc = masm.getScratchRegister()) { 885 Register scratch = sc.getRegister(); 886 SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch); 887 delayedControlTransfer.emitControlTransfer(crb, masm); 888 if (state != null) { 889 crb.recordImplicitException(masm.position(), state); 890 } 891 switch ((Kind) kind) { 892 case Boolean: 893 case Byte: 894 masm.stb(asRegister(input), addr); 895 break; 896 case Short: 897 case Char: 898 masm.sth(asRegister(input), addr); 899 break; 900 case Int: 901 masm.stw(asRegister(input), addr); 902 break; 903 case Long: 904 masm.stx(asRegister(input), addr); 905 break; 906 case Object: 907 masm.stx(asRegister(input), addr); 908 break; 909 case Float: 910 masm.stf(asRegister(input), addr); 911 break; 912 case Double: 913 masm.stdf(asRegister(input), addr); 914 break; 915 default: 916 throw JVMCIError.shouldNotReachHere("missing: " + kind); 917 } 918 } 919 } 920 921 /** 922 * This method creates a load from the constant section. It automatically respects the different 923 * patterns used for small constant sections (<8k) and large constant sections (>=8k). The 924 * generated patterns by this method must be understood by 925 * CodeInstaller::pd_patch_DataSectionReference (jvmciCodeInstaller_sparc.cpp). 926 */ 927 public static void loadFromConstantTable(CompilationResultBuilder crb, SPARCMacroAssembler masm, Kind kind, Register constantTableBase, Register dest, 928 SPARCDelayedControlTransfer delaySlotInstruction, Runnable recordReference) { 929 SPARCAddress address; 930 ScratchRegister scratch = null; 931 try { 932 if (masm.isImmediateConstantLoad()) { 933 address = new SPARCAddress(constantTableBase, 0); 934 // Make delayed only, when using immediate constant load. 935 delaySlotInstruction.emitControlTransfer(crb, masm); 936 recordReference.run(); 937 } else { 938 scratch = masm.getScratchRegister(); 939 Register sr = scratch.getRegister(); 940 recordReference.run(); 941 new Sethix(0, sr, true).emit(masm); 942 address = new SPARCAddress(sr, 0); 943 } 944 switch (kind) { 945 case Boolean: 946 case Byte: 947 masm.ldub(address, dest); 948 break; 949 case Short: 950 case Char: 951 masm.lduh(address, dest); 952 break; 953 case Int: 954 masm.lduw(address, dest); 955 break; 956 case Long: 957 masm.ldx(address, dest); 958 break; 959 case Float: 960 masm.ldf(address, dest); 961 break; 962 case Double: 963 masm.lddf(address, dest); 964 break; 965 default: 966 throw new InternalError("Unknown constant load kind: " + kind); 967 } 968 } finally { 969 if (scratch != null) { 970 scratch.close(); 971 } 972 } 973 } 974}