1/*
2 * Copyright (c) 2009, 2017, 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
24package org.graalvm.compiler.core.sparc;
25
26import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Add;
27import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addcc;
28import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.And;
29import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Mulx;
30import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sdivx;
31import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sllx;
32import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sra;
33import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srax;
34import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srl;
35import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sub;
36import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
37import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Udivx;
38import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xnor;
39import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Faddd;
40import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fadds;
41import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtos;
42import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitod;
43import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitos;
44import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuld;
45import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuls;
46import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegd;
47import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegs;
48import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstod;
49import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtod;
50import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.UMulxhi;
51import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM;
52import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM;
53import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
54import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
55import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.BSF;
56import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.IBSR;
57import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.LBSR;
58import static jdk.vm.ci.code.CodeUtil.mask;
59import static jdk.vm.ci.meta.JavaConstant.forLong;
60import static jdk.vm.ci.sparc.SPARC.g0;
61import static jdk.vm.ci.sparc.SPARCKind.DOUBLE;
62import static jdk.vm.ci.sparc.SPARCKind.SINGLE;
63import static jdk.vm.ci.sparc.SPARCKind.WORD;
64import static jdk.vm.ci.sparc.SPARCKind.XWORD;
65
66import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s;
67import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs;
68import org.graalvm.compiler.core.common.LIRKind;
69import org.graalvm.compiler.core.common.calc.FloatConvert;
70import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
71import org.graalvm.compiler.debug.GraalError;
72import org.graalvm.compiler.lir.ConstantValue;
73import org.graalvm.compiler.lir.LIRFrameState;
74import org.graalvm.compiler.lir.Variable;
75import org.graalvm.compiler.lir.VirtualStackSlot;
76import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
77import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
78import org.graalvm.compiler.lir.sparc.SPARCArithmetic;
79import org.graalvm.compiler.lir.sparc.SPARCArithmetic.FloatConvertOp;
80import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp;
81import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp.MulHigh;
82import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp;
83import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp.Rem;
84import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCIMulccOp;
85import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCLMulccOp;
86import org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp;
87import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp;
88import org.graalvm.compiler.lir.sparc.SPARCMove.MoveFpGp;
89import org.graalvm.compiler.lir.sparc.SPARCMove.StoreConstantOp;
90import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp;
91import org.graalvm.compiler.lir.sparc.SPARCOP3Op;
92import org.graalvm.compiler.lir.sparc.SPARCOPFOp;
93
94import jdk.vm.ci.meta.AllocatableValue;
95import jdk.vm.ci.meta.JavaConstant;
96import jdk.vm.ci.meta.PlatformKind;
97import jdk.vm.ci.meta.Value;
98import jdk.vm.ci.meta.ValueKind;
99import jdk.vm.ci.sparc.SPARC;
100import jdk.vm.ci.sparc.SPARC.CPUFeature;
101import jdk.vm.ci.sparc.SPARCKind;
102
103/**
104 * This class implements the SPARC specific portion of the LIR generator.
105 */
106public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
107
108    @Override
109    public SPARCLIRGenerator getLIRGen() {
110        return (SPARCLIRGenerator) super.getLIRGen();
111    }
112
113    @Override
114    public Variable emitBitCount(Value operand) {
115        Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
116        AllocatableValue usedOperand = getLIRGen().asAllocatable(emitZeroExtend(operand));
117        getLIRGen().append(new SPARCOP3Op(Op3s.Popc, g0.asValue(), usedOperand, result));
118        return result;
119    }
120
121    @Override
122    public Variable emitBitScanForward(Value operand) {
123        Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
124        getLIRGen().append(new SPARCBitManipulationOp(BSF, result, getLIRGen().asAllocatable(operand), getLIRGen()));
125        return result;
126    }
127
128    @Override
129    public Variable emitBitScanReverse(Value operand) {
130        Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
131        if (operand.getPlatformKind() == SPARCKind.XWORD) {
132            getLIRGen().append(new SPARCBitManipulationOp(LBSR, result, getLIRGen().asAllocatable(operand), getLIRGen()));
133        } else {
134            getLIRGen().append(new SPARCBitManipulationOp(IBSR, result, getLIRGen().asAllocatable(operand), getLIRGen()));
135        }
136        return result;
137    }
138
139    @Override
140    public Value emitMathAbs(Value inputValue) {
141        Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
142        SPARCKind kind = (SPARCKind) inputValue.getPlatformKind();
143        Opfs opf;
144        switch (kind) {
145            case SINGLE:
146                opf = Opfs.Fabss;
147                break;
148            case DOUBLE:
149                opf = Opfs.Fabsd;
150                break;
151            default:
152                throw GraalError.shouldNotReachHere("Input kind: " + kind);
153        }
154        getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), result));
155        return result;
156    }
157
158    @Override
159    public Value emitMathSqrt(Value inputValue) {
160        Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
161        SPARCKind kind = (SPARCKind) inputValue.getPlatformKind();
162        Opfs opf;
163        switch (kind) {
164            case SINGLE:
165                opf = Opfs.Fsqrts;
166                break;
167            case DOUBLE:
168                opf = Opfs.Fsqrtd;
169                break;
170            default:
171                throw GraalError.shouldNotReachHere("Input kind: " + kind);
172        }
173        getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), result));
174        return result;
175    }
176
177    @Override
178    public Value emitNegate(Value input) {
179        PlatformKind inputKind = input.getPlatformKind();
180        if (isNumericInteger(inputKind)) {
181            return emitUnary(Sub, input);
182        } else {
183            return emitUnary(inputKind.equals(DOUBLE) ? Fnegd : Fnegs, input);
184        }
185    }
186
187    @Override
188    public Value emitNot(Value input) {
189        return emitUnary(Xnor, input);
190    }
191
192    private Variable emitUnary(Opfs opf, Value inputValue) {
193        Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
194        getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), result));
195        return result;
196    }
197
198    private Variable emitUnary(Op3s op3, Value input) {
199        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
200        getLIRGen().append(SPARCOP3Op.newUnary(op3, getLIRGen().loadSimm13(input), result));
201        return result;
202    }
203
204    private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b) {
205        return emitBinary(resultKind, opf, a, b, null);
206    }
207
208    private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b, LIRFrameState state) {
209        Variable result = getLIRGen().newVariable(resultKind);
210        getLIRGen().append(new SPARCOPFOp(opf, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b), result, state));
211        return result;
212    }
213
214    private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, int b) {
215        return emitBinary(resultKind, op3, a, new ConstantValue(LIRKind.value(WORD), JavaConstant.forInt(b)));
216    }
217
218    private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b) {
219        return emitBinary(resultKind, op3, a, b, null);
220    }
221
222    private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b, LIRFrameState state) {
223        Variable result = getLIRGen().newVariable(resultKind);
224        if (op3.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) {
225            getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), getLIRGen().loadSimm13(a), result, state));
226        } else {
227            getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), getLIRGen().loadSimm13(b), result, state));
228        }
229        return result;
230    }
231
232    @Override
233    protected boolean isNumericInteger(PlatformKind kind) {
234        return ((SPARCKind) kind).isInteger();
235    }
236
237    @Override
238    public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
239        if (isNumericInteger(a.getPlatformKind())) {
240            return emitBinary(resultKind, setFlags ? Addcc : Add, a, b);
241        } else {
242            boolean isDouble = a.getPlatformKind().equals(DOUBLE);
243            return emitBinary(resultKind, isDouble ? Faddd : Fadds, a, b);
244        }
245    }
246
247    @Override
248    public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
249        if (isNumericInteger(a.getPlatformKind())) {
250            return emitBinary(resultKind, setFlags ? Subcc : Sub, a, b);
251        } else {
252            boolean isDouble = a.getPlatformKind().equals(DOUBLE);
253            return emitBinary(resultKind, isDouble ? Opfs.Fsubd : Opfs.Fsubs, a, b);
254        }
255    }
256
257    @Override
258    public Variable emitMul(Value a, Value b, boolean setFlags) {
259        LIRKind resultKind = LIRKind.combine(a, b);
260        PlatformKind aKind = a.getPlatformKind();
261        if (isNumericInteger(aKind)) {
262            if (setFlags) {
263                Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
264                if (aKind == XWORD) {
265                    getLIRGen().append(new SPARCLMulccOp(result, getLIRGen().load(a), getLIRGen().load(b), getLIRGen()));
266                } else if (aKind == WORD) {
267                    getLIRGen().append(new SPARCIMulccOp(result, getLIRGen().load(a), getLIRGen().load(b)));
268                } else {
269                    throw GraalError.shouldNotReachHere();
270                }
271                return result;
272            } else {
273                return emitBinary(resultKind, Op3s.Mulx, a, b);
274            }
275        } else {
276            boolean isDouble = a.getPlatformKind().equals(DOUBLE);
277            return emitBinary(resultKind, isDouble ? Fmuld : Fmuls, a, b);
278        }
279    }
280
281    @Override
282    public Value emitMulHigh(Value a, Value b) {
283        MulHigh opcode;
284        switch (((SPARCKind) a.getPlatformKind())) {
285            case WORD:
286                opcode = MulHigh.IMUL;
287                break;
288            case XWORD:
289                opcode = MulHigh.LMUL;
290                break;
291            default:
292                throw GraalError.shouldNotReachHere();
293        }
294        return emitMulHigh(opcode, a, b);
295    }
296
297    @Override
298    public Value emitUMulHigh(Value a, Value b) {
299        switch (((SPARCKind) a.getPlatformKind())) {
300            case WORD:
301                Value result = emitBinary(LIRKind.combine(a, b), Mulx, emitZeroExtend(a), emitZeroExtend(b));
302                return emitBinary(LIRKind.combine(a, b), Srax, result, WORD.getSizeInBits());
303            case XWORD:
304                return emitBinary(LIRKind.combine(a, b), UMulxhi, a, b);
305            default:
306                throw GraalError.shouldNotReachHere();
307        }
308    }
309
310    private Value emitMulHigh(MulHigh opcode, Value a, Value b) {
311        Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
312        MulHighOp mulHigh = new MulHighOp(opcode, getLIRGen().load(a), getLIRGen().load(b), result, getLIRGen().newVariable(LIRKind.combine(a, b)));
313        getLIRGen().append(mulHigh);
314        return result;
315    }
316
317    @Override
318    public Value emitDiv(Value a, Value b, LIRFrameState state) {
319        LIRKind resultKind = LIRKind.combine(a, b);
320        if (isJavaConstant(b) && asJavaConstant(b).isDefaultForKind()) { // Div by zero
321            Value zero = SPARC.g0.asValue(LIRKind.value(SPARCKind.WORD));
322            return emitBinary(resultKind, Op3s.Sdivx, zero, zero, state);
323        } else if (isNumericInteger(a.getPlatformKind())) {
324            return emitBinary(resultKind, Op3s.Sdivx, emitSignExtend(a), emitSignExtend(b), state);
325        } else {
326            boolean isDouble = a.getPlatformKind() == DOUBLE;
327            return emitBinary(resultKind, isDouble ? Opfs.Fdivd : Opfs.Fdivs, a, b, state);
328        }
329    }
330
331    @Override
332    public Value emitRem(Value a, Value b, LIRFrameState state) {
333        Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
334        Variable q1; // Intermediate values
335        Variable q2;
336        switch ((SPARCKind) a.getPlatformKind()) {
337            case WORD:
338                // Sign extend a and b
339                Value as = emitSignExtend(a);
340                Value bs = emitSignExtend(b);
341                q1 = emitBinary(as.getValueKind(), Sdivx, as, bs, state);
342                q2 = emitBinary(as.getValueKind(), Mulx, q1, bs);
343                result = emitSub(as, q2, false);
344                break;
345            case XWORD:
346                q1 = emitBinary(result.getValueKind(), Sdivx, a, b, state);
347                q2 = emitBinary(result.getValueKind(), Mulx, q1, b);
348                result = emitSub(a, q2, false);
349                break;
350            case SINGLE:
351                ForeignCallLinkage fremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_FREM);
352                result = getLIRGen().emitForeignCall(fremCall, state, a, b);
353                break;
354            case DOUBLE:
355                ForeignCallLinkage dremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_DREM);
356                result = getLIRGen().emitForeignCall(dremCall, state, a, b);
357                break;
358            default:
359                throw GraalError.shouldNotReachHere("missing: " + a.getPlatformKind());
360        }
361        return result;
362    }
363
364    @Override
365    public Value emitURem(Value a, Value b, LIRFrameState state) {
366        Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
367        Variable scratch1 = getLIRGen().newVariable(LIRKind.combine(a, b));
368        Variable scratch2 = getLIRGen().newVariable(LIRKind.combine(a, b));
369        Rem opcode;
370        switch (((SPARCKind) a.getPlatformKind())) {
371            case WORD:
372                opcode = Rem.IUREM;
373                break;
374            case XWORD:
375                opcode = Rem.LUREM;
376                break;
377            default:
378                throw GraalError.shouldNotReachHere();
379        }
380        getLIRGen().append(new RemOp(opcode, result, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b), scratch1, scratch2, state));
381        return result;
382
383    }
384
385    @Override
386    public Value emitUDiv(Value a, Value b, LIRFrameState state) {
387        return emitBinary(LIRKind.combine(a, b), Udivx, emitZeroExtend(a), emitZeroExtend(b), state);
388    }
389
390    @Override
391    public Variable emitAnd(Value a, Value b) {
392        LIRKind resultKind = LIRKind.combine(a, b);
393        return emitBinary(resultKind, Op3s.And, a, b);
394    }
395
396    @Override
397    public Variable emitOr(Value a, Value b) {
398        LIRKind resultKind = LIRKind.combine(a, b);
399        return emitBinary(resultKind, Op3s.Or, a, b);
400    }
401
402    @Override
403    public Variable emitXor(Value a, Value b) {
404        LIRKind resultKind = LIRKind.combine(a, b);
405        return emitBinary(resultKind, Op3s.Xor, a, b);
406    }
407
408    @Override
409    public Variable emitShl(Value a, Value b) {
410        SPARCKind aKind = (SPARCKind) a.getPlatformKind();
411        LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
412        Op3s op;
413        switch (aKind) {
414            case WORD:
415                op = Op3s.Sll;
416                break;
417            case XWORD:
418                op = Op3s.Sllx;
419                break;
420            default:
421                throw GraalError.shouldNotReachHere(String.format("Unsupported kind %s", aKind));
422        }
423        return emitBinary(resultKind, op, a, b);
424    }
425
426    @Override
427    public Variable emitShr(Value a, Value b) {
428        SPARCKind aKind = (SPARCKind) a.getPlatformKind();
429        LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
430        Op3s op;
431        switch (aKind) {
432            case WORD:
433                op = Op3s.Sra;
434                break;
435            case XWORD:
436                op = Op3s.Srax;
437                break;
438            default:
439                throw GraalError.shouldNotReachHere();
440        }
441        return emitBinary(resultKind, op, a, b);
442    }
443
444    @Override
445    public Variable emitUShr(Value a, Value b) {
446        SPARCKind aKind = (SPARCKind) a.getPlatformKind();
447        LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
448        Op3s op;
449        switch (aKind) {
450            case WORD:
451                op = Op3s.Srl;
452                break;
453            case XWORD:
454                op = Op3s.Srlx;
455                break;
456            default:
457                throw GraalError.shouldNotReachHere();
458        }
459        return emitBinary(resultKind, op, a, b);
460    }
461
462    private AllocatableValue emitConvertMove(LIRKind kind, AllocatableValue input) {
463        Variable result = getLIRGen().newVariable(kind);
464        getLIRGen().emitMove(result, input);
465        return result;
466    }
467
468    @Override
469    public Value emitFloatConvert(FloatConvert op, Value inputValue) {
470        AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputValue);
471        AllocatableValue result;
472        switch (op) {
473            case D2F:
474                result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(SINGLE));
475                getLIRGen().append(new SPARCOPFOp(Fdtos, inputAllocatable, result));
476                break;
477            case F2D:
478                result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(DOUBLE));
479                getLIRGen().append(new SPARCOPFOp(Fstod, inputAllocatable, result));
480                break;
481            case I2F: {
482                AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
483                result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind());
484                moveBetweenFpGp(intEncodedFloatReg, inputAllocatable);
485                getLIRGen().append(new SPARCOPFOp(Fitos, intEncodedFloatReg, result));
486                break;
487            }
488            case I2D: {
489                // Unfortunately we must do int -> float -> double because fitod has float
490                // and double encoding in one instruction
491                AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
492                result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
493                moveBetweenFpGp(convertedFloatReg, inputAllocatable);
494                getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result));
495                break;
496            }
497            case L2D: {
498                AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
499                moveBetweenFpGp(longEncodedDoubleReg, inputAllocatable);
500                AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind());
501                getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg));
502                result = convertedDoubleReg;
503                break;
504            }
505            case D2I: {
506                AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
507                getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, inputAllocatable, convertedFloatReg));
508                AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
509                moveBetweenFpGp(convertedIntReg, convertedFloatReg);
510                result = convertedIntReg;
511                break;
512            }
513            case F2L: {
514                AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
515                getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, inputAllocatable, convertedDoubleReg));
516                AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
517                moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
518                result = convertedLongReg;
519                break;
520            }
521            case F2I: {
522                AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
523                getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, inputAllocatable, convertedFloatReg));
524                AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
525                moveBetweenFpGp(convertedIntReg, convertedFloatReg);
526                result = convertedIntReg;
527                break;
528            }
529            case D2L: {
530                AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
531                getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, inputAllocatable, convertedDoubleReg));
532                AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
533                moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
534                result = convertedLongReg;
535                break;
536            }
537            case L2F: {
538                AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
539                result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
540                moveBetweenFpGp(convertedDoubleReg, inputAllocatable);
541                getLIRGen().append(new SPARCOPFOp(Opfs.Fxtos, convertedDoubleReg, result));
542                break;
543            }
544            default:
545                throw GraalError.shouldNotReachHere();
546        }
547        return result;
548    }
549
550    protected VirtualStackSlot getTempSlot(LIRKind kind) {
551        return getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(kind);
552    }
553
554    private void moveBetweenFpGp(AllocatableValue dst, AllocatableValue src) {
555        AllocatableValue tempSlot;
556        PlatformKind dstKind = dst.getPlatformKind();
557        PlatformKind srcKind = src.getPlatformKind();
558        if (getLIRGen().getArchitecture().getFeatures().contains(CPUFeature.VIS3) && !(srcKind == WORD && dstKind == SINGLE) && !(srcKind == SINGLE && dstKind == WORD)) {
559            tempSlot = AllocatableValue.ILLEGAL;
560        } else {
561            tempSlot = getTempSlot(LIRKind.value(XWORD));
562        }
563        getLIRGen().append(new MoveFpGp(dst, src, tempSlot));
564    }
565
566    @Override
567    public Value emitNarrow(Value inputVal, int bits) {
568        if (inputVal.getPlatformKind() == XWORD && bits <= 32) {
569            LIRKind resultKind = LIRKind.combine(inputVal).changeType(WORD);
570            Variable result = getLIRGen().newVariable(resultKind);
571            getLIRGen().emitMove(result, inputVal);
572            return result;
573        } else {
574            return inputVal;
575        }
576    }
577
578    private Value emitSignExtend(Value inputValue) {
579        int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8;
580        return emitNarrow(emitSignExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits);
581    }
582
583    @Override
584    public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
585        assert fromBits <= toBits && toBits <= XWORD.getSizeInBits();
586        LIRKind shiftKind = LIRKind.value(WORD);
587        LIRKind resultKind = LIRKind.combine(inputVal).changeType(toBits > 32 ? XWORD : WORD);
588        int shiftCount = XWORD.getSizeInBits() - fromBits;
589        if (fromBits == toBits) {
590            return inputVal;
591        } else if (isJavaConstant(inputVal)) {
592            JavaConstant javaConstant = asJavaConstant(inputVal);
593            long constant;
594            if (javaConstant.isNull()) {
595                constant = 0;
596            } else {
597                constant = javaConstant.asLong();
598            }
599            return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount));
600        } else {
601            AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputVal);
602            Variable result = getLIRGen().newVariable(resultKind);
603            if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) {
604                getLIRGen().append(new SPARCOP3Op(Sra, inputAllocatable, g0.asValue(LIRKind.value(WORD)), result));
605            } else {
606                Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD));
607                getLIRGen().append(new SPARCOP3Op(Sllx, inputAllocatable, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp));
608                getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result));
609            }
610            return result;
611        }
612    }
613
614    private Value emitZeroExtend(Value inputValue) {
615        int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8;
616        return emitNarrow(emitZeroExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits);
617    }
618
619    @Override
620    public Value emitZeroExtend(Value inputValue, int fromBits, int toBits) {
621        assert fromBits <= toBits && toBits <= 64;
622        if (fromBits == toBits) {
623            return inputValue;
624        }
625        Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD));
626        AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputValue);
627        if (fromBits == 32) {
628            getLIRGen().append(new SPARCOP3Op(Srl, inputAllocatable, g0.asValue(), result));
629        } else {
630            Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits)));
631            getLIRGen().append(new SPARCOP3Op(And, inputAllocatable, mask, result));
632        }
633        return result;
634    }
635
636    @Override
637    public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) {
638        SPARCKind fromKind = (SPARCKind) inputVal.getPlatformKind();
639        SPARCKind toKind = (SPARCKind) to.getPlatformKind();
640        AllocatableValue input = getLIRGen().asAllocatable(inputVal);
641        Variable result = getLIRGen().newVariable(to);
642        // These cases require a move between CPU and FPU registers:
643        if (fromKind.isFloat() != toKind.isFloat()) {
644            moveBetweenFpGp(result, input);
645            return result;
646        } else {
647            // Otherwise, just emit an ordinary move instruction.
648            // Instructions that move or generate 32-bit register values also set the upper 32
649            // bits of the register to zero.
650            // Consequently, there is no need for a special zero-extension move.
651            return emitConvertMove(to, input);
652        }
653    }
654
655    @Override
656    public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
657        SPARCAddressValue loadAddress = getLIRGen().asAddressValue(address);
658        Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
659        getLIRGen().append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state));
660        return result;
661    }
662
663    @Override
664    public void emitStore(ValueKind<?> kind, Value address, Value inputVal, LIRFrameState state) {
665        SPARCAddressValue storeAddress = getLIRGen().asAddressValue(address);
666        if (isJavaConstant(inputVal)) {
667            JavaConstant c = asJavaConstant(inputVal);
668            if (c.isDefaultForKind()) {
669                getLIRGen().append(new StoreConstantOp(kind.getPlatformKind(), storeAddress, c, state));
670                return;
671            }
672        }
673        Variable input = getLIRGen().load(inputVal);
674        getLIRGen().append(new StoreOp(kind.getPlatformKind(), storeAddress, input, state));
675    }
676}
677