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}