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