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 }