001/*
002 * Copyright (c) 2009, 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 */
023
024package com.oracle.graal.compiler.sparc;
025
026import static com.oracle.graal.lir.sparc.SPARCArithmetic.*;
027import static com.oracle.graal.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.*;
028import static com.oracle.graal.lir.sparc.SPARCCompare.*;
029import static com.oracle.graal.lir.sparc.SPARCMathIntrinsicOp.IntrinsicOpcode.*;
030import static jdk.internal.jvmci.code.ValueUtil.*;
031import jdk.internal.jvmci.code.*;
032import jdk.internal.jvmci.common.*;
033import jdk.internal.jvmci.meta.*;
034import jdk.internal.jvmci.sparc.*;
035import jdk.internal.jvmci.sparc.SPARC.CPUFeature;
036
037import com.oracle.graal.asm.sparc.*;
038import com.oracle.graal.asm.sparc.SPARCAssembler.CC;
039import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag;
040import com.oracle.graal.compiler.common.calc.*;
041import com.oracle.graal.compiler.common.spi.*;
042import com.oracle.graal.lir.*;
043import com.oracle.graal.lir.StandardOp.NoOp;
044import com.oracle.graal.lir.gen.*;
045import com.oracle.graal.lir.sparc.*;
046import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegConst;
047import com.oracle.graal.lir.sparc.SPARCArithmetic.BinaryRegReg;
048import com.oracle.graal.lir.sparc.SPARCArithmetic.MulHighOp;
049import com.oracle.graal.lir.sparc.SPARCArithmetic.RemOp;
050import com.oracle.graal.lir.sparc.SPARCArithmetic.SPARCLMulccOp;
051import com.oracle.graal.lir.sparc.SPARCArithmetic.Unary2Op;
052import com.oracle.graal.lir.sparc.SPARCCompare.CompareOp;
053import com.oracle.graal.lir.sparc.SPARCControlFlow.BranchOp;
054import com.oracle.graal.lir.sparc.SPARCControlFlow.CondMoveOp;
055import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp;
056import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp;
057import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp;
058import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp;
059import com.oracle.graal.lir.sparc.SPARCMove.LoadDataAddressOp;
060import com.oracle.graal.lir.sparc.SPARCMove.LoadOp;
061import com.oracle.graal.lir.sparc.SPARCMove.MembarOp;
062import com.oracle.graal.lir.sparc.SPARCMove.Move;
063import com.oracle.graal.lir.sparc.SPARCMove.MoveFpGp;
064import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
065import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
066import com.oracle.graal.phases.util.*;
067
068/**
069 * This class implements the SPARC specific portion of the LIR generator.
070 */
071public abstract class SPARCLIRGenerator extends LIRGenerator {
072
073    private StackSlotValue tmpStackSlot;
074    private SPARCSpillMoveFactory moveFactory;
075    private Variable constantTableBase;
076    private SPARCLoadConstantTableBaseOp loadConstantTableBaseOp;
077
078    private class SPARCSpillMoveFactory extends SpillMoveFactoryBase {
079
080        @Override
081        protected LIRInstruction createMoveIntern(AllocatableValue result, Value input) {
082            return SPARCLIRGenerator.this.createMove(result, input);
083        }
084
085        @Override
086        protected LIRInstruction createStackMoveIntern(AllocatableValue result, Value input) {
087            return SPARCLIRGenerator.this.createStackMove(result, input);
088        }
089    }
090
091    public SPARCLIRGenerator(LIRKindTool lirKindTool, Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) {
092        super(lirKindTool, providers, cc, lirGenRes);
093    }
094
095    public SpillMoveFactory getSpillMoveFactory() {
096        if (moveFactory == null) {
097            moveFactory = new SPARCSpillMoveFactory();
098        }
099        return moveFactory;
100    }
101
102    @Override
103    public boolean canInlineConstant(JavaConstant c) {
104        switch (c.getKind()) {
105            case Boolean:
106            case Byte:
107            case Char:
108            case Short:
109            case Int:
110                return SPARCAssembler.isSimm13(c.asInt()) && !getCodeCache().needsDataPatch(c);
111            case Long:
112                return SPARCAssembler.isSimm13(c.asLong()) && !getCodeCache().needsDataPatch(c);
113            case Object:
114                return c.isNull();
115            default:
116                return false;
117        }
118    }
119
120    protected SPARCLIRInstruction createMove(AllocatableValue dst, Value src) {
121        boolean srcIsSlot = isStackSlotValue(src);
122        boolean dstIsSlot = isStackSlotValue(dst);
123        if (src instanceof SPARCAddressValue) {
124            return new LoadAddressOp(dst, (SPARCAddressValue) src);
125        } else if (src instanceof JavaConstant) {
126            JavaConstant javaConstant = (JavaConstant) src;
127            if (canInlineConstant(javaConstant)) {
128                return new SPARCMove.LoadInlineConstant(javaConstant, dst);
129            } else {
130                return new SPARCMove.LoadConstantFromTable(javaConstant, getConstantTableBase(), dst);
131            }
132        } else if (!srcIsSlot && !dstIsSlot) {
133            return new Move(dst, src);
134        } else if (srcIsSlot != dstIsSlot) {
135            return new Move(dst, src);
136        } else {
137            throw JVMCIError.shouldNotReachHere(src.getClass() + " " + dst.getClass());
138        }
139    }
140
141    protected LIRInstruction createStackMove(AllocatableValue result, Value input) {
142        return new SPARCMove.Move(result, input);
143    }
144
145    @Override
146    public void emitMove(AllocatableValue dst, Value src) {
147        append(createMove(dst, src));
148    }
149
150    @Override
151    public void emitData(AllocatableValue dst, byte[] data) {
152        append(new LoadDataAddressOp(dst, data));
153    }
154
155    protected SPARCAddressValue asAddressValue(Value address) {
156        if (address instanceof SPARCAddressValue) {
157            return (SPARCAddressValue) address;
158        } else {
159            LIRKind kind = address.getLIRKind();
160            if (address instanceof JavaConstant) {
161                long displacement = ((JavaConstant) address).asLong();
162                if (SPARCAssembler.isSimm13(displacement)) {
163                    return new SPARCImmediateAddressValue(kind, SPARC.g0.asValue(kind), (int) displacement);
164                }
165            }
166            return new SPARCImmediateAddressValue(kind, asAllocatable(address), 0);
167        }
168    }
169
170    @Override
171    public Variable emitAddress(StackSlotValue address) {
172        Variable result = newVariable(LIRKind.value(target().wordKind));
173        append(new StackLoadAddressOp(result, address));
174        return result;
175    }
176
177    @Override
178    public void emitReturn(Value input) {
179        AllocatableValue operand = Value.ILLEGAL;
180        if (input != null) {
181            operand = resultOperandFor(input.getLIRKind());
182            emitMove(operand, input);
183        }
184        append(new ReturnOp(operand));
185    }
186
187    @Override
188    public void emitJump(LabelRef label) {
189        append(new SPARCJumpOp(label));
190    }
191
192    @Override
193    public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
194                    double trueDestinationProbability) {
195        Value left;
196        Value right;
197        Condition actualCondition;
198        if (isConstant(x)) {
199            left = load(y);
200            right = loadNonConst(x);
201            actualCondition = cond.mirror();
202        } else {
203            left = load(x);
204            right = loadNonConst(y);
205            actualCondition = cond;
206        }
207        SPARCCompare opcode;
208        Kind actualCmpKind = (Kind) cmpKind;
209        switch (actualCmpKind) {
210            case Byte:
211                left = emitSignExtend(left, 8, 32);
212                right = emitSignExtend(right, 8, 32);
213                actualCmpKind = Kind.Int;
214                opcode = ICMP;
215                break;
216            case Short:
217                left = emitSignExtend(left, 16, 32);
218                right = emitSignExtend(right, 16, 32);
219                actualCmpKind = Kind.Int;
220                opcode = ICMP;
221                break;
222            case Object:
223                opcode = ACMP;
224                break;
225            case Long:
226                opcode = LCMP;
227                break;
228            case Int:
229                opcode = ICMP;
230                break;
231            case Float:
232                opcode = FCMP;
233                break;
234            case Double:
235                opcode = DCMP;
236                break;
237            default:
238                throw JVMCIError.shouldNotReachHere(actualCmpKind.toString());
239        }
240        append(new SPARCControlFlow.CompareBranchOp(opcode, left, right, actualCondition, trueDestination, falseDestination, actualCmpKind, unorderedIsTrue, trueDestinationProbability));
241    }
242
243    @Override
244    public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) {
245        Kind cmpKind = (Kind) cmpLIRKind.getPlatformKind();
246        append(new BranchOp(ConditionFlag.OverflowSet, overflow, noOverflow, cmpKind, overflowProbability));
247    }
248
249    @Override
250    public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
251        emitIntegerTest(left, right);
252        append(new BranchOp(ConditionFlag.Equal, trueDestination, falseDestination, left.getKind().getStackKind(), trueDestinationProbability));
253    }
254
255    private void emitIntegerTest(Value a, Value b) {
256        assert a.getKind().isNumericInteger();
257        if (LIRValueUtil.isVariable(b)) {
258            append(new SPARCTestOp(load(b), loadNonConst(a)));
259        } else {
260            append(new SPARCTestOp(load(a), loadNonConst(b)));
261        }
262    }
263
264    private Value loadSimm11(Value value) {
265        if (isConstant(value)) {
266            JavaConstant c = asConstant(value);
267            if (c.isNull() || SPARCAssembler.isSimm11(c)) {
268                return value;
269            }
270        }
271        return load(value);
272    }
273
274    @Override
275    public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
276        boolean mirrored = emitCompare(cmpKind, left, right);
277        CC conditionFlags;
278        Value actualTrueValue = trueValue;
279        Value actualFalseValue = falseValue;
280        // TODO: (sa) Review this loadSimm11 if it is really necessary
281        switch ((Kind) left.getLIRKind().getPlatformKind()) {
282            case Byte:
283            case Short:
284            case Char:
285            case Int:
286                conditionFlags = CC.Icc;
287                actualTrueValue = loadSimm11(trueValue);
288                actualFalseValue = loadSimm11(falseValue);
289                break;
290            case Object:
291            case Long:
292                conditionFlags = CC.Xcc;
293                actualTrueValue = loadSimm11(trueValue);
294                actualFalseValue = loadSimm11(falseValue);
295                break;
296            case Float:
297            case Double:
298                conditionFlags = CC.Fcc0;
299                actualTrueValue = load(trueValue); // Floats cannot be immediate at all
300                actualFalseValue = load(falseValue);
301                break;
302            default:
303                throw JVMCIError.shouldNotReachHere();
304        }
305        Variable result = newVariable(trueValue.getLIRKind());
306        ConditionFlag finalCondition = SPARCControlFlow.fromCondition(conditionFlags, mirrored ? cond.mirror() : cond, unorderedIsTrue);
307        append(new CondMoveOp(result, conditionFlags, finalCondition, actualTrueValue, actualFalseValue));
308        return result;
309    }
310
311    /**
312     * This method emits the compare instruction, and may reorder the operands. It returns true if
313     * it did so.
314     *
315     * @param cmpKind Kind how a and b have to be compared
316     * @param a the left operand of the comparison
317     * @param b the right operand of the comparison
318     * @return true if the left and right operands were switched, false otherwise
319     */
320    protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b) {
321        Variable left;
322        Value right;
323        boolean mirrored;
324        if (LIRValueUtil.isVariable(b)) {
325            left = load(b);
326            right = loadNonConst(a);
327            mirrored = true;
328        } else {
329            left = load(a);
330            right = loadNonConst(b);
331            mirrored = false;
332        }
333        switch ((Kind) cmpKind) {
334            case Short:
335            case Char:
336                append(new CompareOp(ICMP, emitSignExtend(left, 16, 32), emitSignExtend(right, 16, 32)));
337                break;
338            case Byte:
339                append(new CompareOp(ICMP, emitSignExtend(left, 8, 32), emitSignExtend(right, 8, 32)));
340                break;
341            case Int:
342                append(new CompareOp(ICMP, left, right));
343                break;
344            case Long:
345                append(new CompareOp(LCMP, left, right));
346                break;
347            case Object:
348                append(new CompareOp(ACMP, left, right));
349                break;
350            case Float:
351                append(new CompareOp(FCMP, left, right));
352                break;
353            case Double:
354                append(new CompareOp(DCMP, left, right));
355                break;
356            default:
357                throw JVMCIError.shouldNotReachHere();
358        }
359        return mirrored;
360    }
361
362    @Override
363    public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
364        emitIntegerTest(left, right);
365        Variable result = newVariable(trueValue.getLIRKind());
366        Kind kind = left.getKind().getStackKind();
367        CC conditionCode;
368        switch (kind) {
369            case Object:
370            case Long:
371                conditionCode = CC.Xcc;
372                break;
373            case Int:
374            case Short:
375            case Char:
376            case Byte:
377                conditionCode = CC.Icc;
378                break;
379            default:
380                throw JVMCIError.shouldNotReachHere();
381        }
382        ConditionFlag flag = SPARCControlFlow.fromCondition(conditionCode, Condition.EQ, false);
383        // TODO: (sa) Review this loadSimm11 if it is really necessary
384        append(new CondMoveOp(result, conditionCode, flag, loadSimm11(trueValue), loadSimm11(falseValue)));
385        return result;
386    }
387
388    @Override
389    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
390        long maxOffset = linkage.getMaxCallTargetOffset();
391        if (SPARCAssembler.isWordDisp30(maxOffset)) {
392            append(new SPARCCall.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
393        } else {
394            append(new SPARCCall.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
395        }
396    }
397
398    @Override
399    public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
400        Value scratchValue = newVariable(key.getLIRKind());
401        AllocatableValue base = AllocatableValue.ILLEGAL;
402        for (JavaConstant c : strategy.keyConstants) {
403            if (!canInlineConstant(c)) {
404                base = getConstantTableBase();
405                break;
406            }
407        }
408        append(new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue));
409    }
410
411    @Override
412    protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
413        // Making a copy of the switch value is necessary because jump table destroys the input
414        // value
415        Variable tmp = newVariable(key.getLIRKind());
416        emitMove(tmp, key);
417        append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(LIRKind.value(target().wordKind))));
418    }
419
420    @Override
421    public Variable emitBitCount(Value operand) {
422        Variable result = newVariable(LIRKind.combine(operand).changeType(Kind.Int));
423        if (operand.getKind().getStackKind() == Kind.Int) {
424            append(new SPARCBitManipulationOp(IPOPCNT, result, asAllocatable(operand), this));
425        } else {
426            append(new SPARCBitManipulationOp(LPOPCNT, result, asAllocatable(operand), this));
427        }
428        return result;
429    }
430
431    @Override
432    public Variable emitBitScanForward(Value operand) {
433        Variable result = newVariable(LIRKind.combine(operand).changeType(Kind.Int));
434        append(new SPARCBitManipulationOp(BSF, result, asAllocatable(operand), this));
435        return result;
436    }
437
438    @Override
439    public Variable emitBitScanReverse(Value operand) {
440        Variable result = newVariable(LIRKind.combine(operand).changeType(Kind.Int));
441        if (operand.getKind().getStackKind() == Kind.Int) {
442            append(new SPARCBitManipulationOp(IBSR, result, asAllocatable(operand), this));
443        } else {
444            append(new SPARCBitManipulationOp(LBSR, result, asAllocatable(operand), this));
445        }
446        return result;
447    }
448
449    @Override
450    public Value emitMathAbs(Value input) {
451        Variable result = newVariable(LIRKind.combine(input));
452        append(new SPARCMathIntrinsicOp(ABS, result, asAllocatable(input)));
453        return result;
454    }
455
456    @Override
457    public Value emitMathSqrt(Value input) {
458        Variable result = newVariable(LIRKind.combine(input));
459        append(new SPARCMathIntrinsicOp(SQRT, result, asAllocatable(input)));
460        return result;
461    }
462
463    @Override
464    public Variable emitByteSwap(Value input) {
465        Variable result = newVariable(LIRKind.combine(input));
466        append(new SPARCByteSwapOp(this, result, input));
467        return result;
468    }
469
470    @Override
471    public Variable emitArrayEquals(Kind kind, Value array1, Value array2, Value length) {
472        Variable result = newVariable(LIRKind.value(Kind.Int));
473        append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length)));
474        return result;
475    }
476
477    @Override
478    public Value emitNegate(Value input) {
479        switch (input.getKind().getStackKind()) {
480            case Long:
481                return emitUnary(LNEG, input);
482            case Int:
483                return emitUnary(INEG, input);
484            case Float:
485                return emitUnary(FNEG, input);
486            case Double:
487                return emitUnary(DNEG, input);
488            default:
489                throw JVMCIError.shouldNotReachHere();
490        }
491    }
492
493    @Override
494    public Value emitNot(Value input) {
495        switch (input.getKind().getStackKind()) {
496            case Int:
497                return emitUnary(INOT, input);
498            case Long:
499                return emitUnary(LNOT, input);
500            default:
501                throw JVMCIError.shouldNotReachHere();
502        }
503    }
504
505    private Variable emitUnary(SPARCArithmetic op, Value input) {
506        Variable result = newVariable(LIRKind.combine(input));
507        append(new Unary2Op(op, result, load(input)));
508        return result;
509    }
510
511    private Variable emitBinary(LIRKind resultKind, SPARCArithmetic op, boolean commutative, Value a, Value b) {
512        return emitBinary(resultKind, op, commutative, a, b, null);
513    }
514
515    private Variable emitBinary(LIRKind resultKind, SPARCArithmetic op, boolean commutative, Value a, Value b, LIRFrameState state) {
516        if (isConstant(b) && canInlineConstant(asConstant(b))) {
517            return emitBinaryConst(resultKind, op, load(a), asConstant(b), state);
518        } else if (commutative && isConstant(a) && canInlineConstant(asConstant(a))) {
519            return emitBinaryConst(resultKind, op, load(b), asConstant(a), state);
520        } else {
521            return emitBinaryVar(resultKind, op, load(a), load(b), state);
522        }
523    }
524
525    private Variable emitBinaryConst(LIRKind resultKind, SPARCArithmetic op, AllocatableValue a, JavaConstant b, LIRFrameState state) {
526        switch (op) {
527            case IADD:
528            case LADD:
529            case ISUB:
530            case LSUB:
531            case IAND:
532            case LAND:
533            case IOR:
534            case LOR:
535            case IXOR:
536            case LXOR:
537            case IMUL:
538            case LMUL:
539                if (canInlineConstant(b)) {
540                    Variable result = newVariable(resultKind);
541                    append(new BinaryRegConst(op, result, a, b, state));
542                    return result;
543                }
544                break;
545        }
546        return emitBinaryVar(resultKind, op, a, asAllocatable(b), state);
547    }
548
549    private Variable emitBinaryVar(LIRKind resultKind, SPARCArithmetic op, AllocatableValue a, AllocatableValue b, LIRFrameState state) {
550        Variable result = newVariable(resultKind);
551        append(new BinaryRegReg(op, result, a, b, state));
552        return result;
553    }
554
555    @Override
556    public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
557        switch (a.getKind().getStackKind()) {
558            case Int:
559                return emitBinary(resultKind, setFlags ? IADDCC : IADD, true, a, b);
560            case Long:
561                return emitBinary(resultKind, setFlags ? LADDCC : LADD, true, a, b);
562            case Float:
563                return emitBinary(resultKind, FADD, true, a, b);
564            case Double:
565                return emitBinary(resultKind, DADD, true, a, b);
566            default:
567                throw JVMCIError.shouldNotReachHere();
568        }
569    }
570
571    @Override
572    public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
573        switch (a.getKind().getStackKind()) {
574            case Int:
575                return emitBinary(resultKind, setFlags ? ISUBCC : ISUB, false, a, b);
576            case Long:
577                return emitBinary(resultKind, setFlags ? LSUBCC : LSUB, false, a, b);
578            case Float:
579                return emitBinary(resultKind, FSUB, false, a, b);
580            case Double:
581                return emitBinary(resultKind, DSUB, false, a, b);
582            default:
583                throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
584        }
585    }
586
587    @Override
588    public Variable emitMul(Value a, Value b, boolean setFlags) {
589        LIRKind resultKind = LIRKind.combine(a, b);
590        switch (a.getKind().getStackKind()) {
591            case Int:
592                return emitBinary(resultKind, setFlags ? IMULCC : IMUL, true, a, b);
593            case Long:
594                if (setFlags) {
595                    Variable result = newVariable(LIRKind.combine(a, b));
596                    append(new SPARCLMulccOp(result, load(a), load(b), this));
597                    return result;
598                } else {
599                    return emitBinary(resultKind, LMUL, true, a, b);
600                }
601            case Float:
602                return emitBinary(resultKind, FMUL, true, a, b);
603            case Double:
604                return emitBinary(resultKind, DMUL, true, a, b);
605            default:
606                throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
607        }
608    }
609
610    @Override
611    public Value emitMulHigh(Value a, Value b) {
612        switch (a.getKind().getStackKind()) {
613            case Int:
614                return emitMulHigh(IMUL, a, b);
615            case Long:
616                return emitMulHigh(LMUL, a, b);
617            default:
618                throw JVMCIError.shouldNotReachHere();
619        }
620    }
621
622    @Override
623    public Value emitUMulHigh(Value a, Value b) {
624        switch (a.getKind().getStackKind()) {
625            case Int:
626                return emitMulHigh(IUMUL, a, b);
627            case Long:
628                return emitMulHigh(LUMUL, a, b);
629            default:
630                throw JVMCIError.shouldNotReachHere();
631        }
632    }
633
634    private Value emitMulHigh(SPARCArithmetic opcode, Value a, Value b) {
635        Variable result = newVariable(LIRKind.combine(a, b));
636        MulHighOp mulHigh = new MulHighOp(opcode, load(a), load(b), result, newVariable(LIRKind.combine(a, b)));
637        append(mulHigh);
638        return result;
639    }
640
641    @Override
642    public Value emitDiv(Value a, Value b, LIRFrameState state) {
643        LIRKind resultKind = LIRKind.combine(a, b);
644        switch (a.getKind().getStackKind()) {
645            case Int:
646                return emitBinary(resultKind, IDIV, false, a, b, state);
647            case Long:
648                return emitBinary(resultKind, LDIV, false, a, b, state);
649            case Float:
650                return emitBinary(resultKind, FDIV, false, a, b, state);
651            case Double:
652                return emitBinary(resultKind, DDIV, false, a, b, state);
653            default:
654                throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
655        }
656    }
657
658    @Override
659    public Value emitRem(Value a, Value b, LIRFrameState state) {
660        Variable result = newVariable(LIRKind.combine(a, b));
661        Variable q1; // Intermediate values
662        Variable q2;
663        Variable q3;
664        Variable q4;
665        switch (a.getKind().getStackKind()) {
666            case Int:
667                append(new RemOp(IREM, result, load(a), loadNonConst(b), state, this));
668                break;
669            case Long:
670                append(new RemOp(LREM, result, load(a), loadNonConst(b), state, this));
671                break;
672            case Float:
673                q1 = newVariable(LIRKind.value(Kind.Float));
674                append(new BinaryRegReg(FDIV, q1, a, b, state));
675                q2 = newVariable(LIRKind.value(Kind.Float));
676                append(new Unary2Op(F2I, q2, q1));
677                q3 = newVariable(LIRKind.value(Kind.Float));
678                append(new Unary2Op(I2F, q3, q2));
679                q4 = newVariable(LIRKind.value(Kind.Float));
680                append(new BinaryRegReg(FMUL, q4, q3, b));
681                append(new BinaryRegReg(FSUB, result, a, q4));
682                break;
683            case Double:
684                q1 = newVariable(LIRKind.value(Kind.Double));
685                append(new BinaryRegReg(DDIV, q1, a, b, state));
686                q2 = newVariable(LIRKind.value(Kind.Double));
687                append(new Unary2Op(D2L, q2, q1));
688                q3 = newVariable(LIRKind.value(Kind.Double));
689                append(new Unary2Op(L2D, q3, q2));
690                q4 = newVariable(LIRKind.value(Kind.Double));
691                append(new BinaryRegReg(DMUL, q4, q3, b));
692                append(new BinaryRegReg(DSUB, result, a, q4));
693                break;
694            default:
695                throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
696        }
697        return result;
698    }
699
700    @Override
701    public Value emitURem(Value a, Value b, LIRFrameState state) {
702        Variable result = newVariable(LIRKind.combine(a, b));
703        switch (a.getKind().getStackKind()) {
704            case Int:
705                append(new RemOp(IUREM, result, load(a), load(b), state, this));
706                break;
707            case Long:
708                append(new RemOp(LUREM, result, load(a), loadNonConst(b), state, this));
709                break;
710            default:
711                throw JVMCIError.shouldNotReachHere();
712        }
713        return result;
714
715    }
716
717    @Override
718    public Value emitUDiv(Value a, Value b, LIRFrameState state) {
719        SPARCArithmetic op;
720        Value actualA = a;
721        Value actualB = b;
722        switch (a.getKind().getStackKind()) {
723            case Int:
724                op = LUDIV;
725                actualA = emitZeroExtend(actualA, 32, 64);
726                actualB = emitZeroExtend(actualB, 32, 64);
727                break;
728            case Long:
729                op = LUDIV;
730                break;
731            default:
732                throw JVMCIError.shouldNotReachHere();
733        }
734        return emitBinary(LIRKind.combine(actualA, actualB), op, false, actualA, actualB, state);
735    }
736
737    @Override
738    public Variable emitAnd(Value a, Value b) {
739        LIRKind resultKind = LIRKind.combine(a, b);
740        switch (a.getKind().getStackKind()) {
741            case Int:
742                return emitBinary(resultKind, IAND, true, a, b);
743            case Long:
744                return emitBinary(resultKind, LAND, true, a, b);
745
746            default:
747                throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
748        }
749    }
750
751    @Override
752    public Variable emitOr(Value a, Value b) {
753        LIRKind resultKind = LIRKind.combine(a, b);
754        switch (a.getKind().getStackKind()) {
755            case Int:
756                return emitBinary(resultKind, IOR, true, a, b);
757            case Long:
758                return emitBinary(resultKind, LOR, true, a, b);
759            default:
760                throw JVMCIError.shouldNotReachHere("missing: " + a.getKind());
761        }
762    }
763
764    @Override
765    public Variable emitXor(Value a, Value b) {
766        LIRKind resultKind = LIRKind.combine(a, b);
767        switch (a.getKind().getStackKind()) {
768            case Int:
769                return emitBinary(resultKind, IXOR, true, a, b);
770            case Long:
771                return emitBinary(resultKind, LXOR, true, a, b);
772            default:
773                throw JVMCIError.shouldNotReachHere();
774        }
775    }
776
777    private Variable emitShift(SPARCArithmetic op, Value a, Value b) {
778        Variable result = newVariable(LIRKind.combine(a, b).changeType(a.getPlatformKind()));
779        if (isConstant(b) && canInlineConstant((JavaConstant) b)) {
780            append(new BinaryRegConst(op, result, load(a), asConstant(b), null));
781        } else {
782            append(new BinaryRegReg(op, result, load(a), load(b)));
783        }
784        return result;
785    }
786
787    @Override
788    public Variable emitShl(Value a, Value b) {
789        switch (a.getKind().getStackKind()) {
790            case Int:
791                return emitShift(ISHL, a, b);
792            case Long:
793                return emitShift(LSHL, a, b);
794            default:
795                throw JVMCIError.shouldNotReachHere();
796        }
797    }
798
799    @Override
800    public Variable emitShr(Value a, Value b) {
801        switch (a.getKind().getStackKind()) {
802            case Int:
803                return emitShift(ISHR, a, b);
804            case Long:
805                return emitShift(LSHR, a, b);
806            default:
807                throw JVMCIError.shouldNotReachHere();
808        }
809    }
810
811    @Override
812    public Variable emitUShr(Value a, Value b) {
813        switch (a.getKind().getStackKind()) {
814            case Int:
815                return emitShift(IUSHR, a, b);
816            case Long:
817                return emitShift(LUSHR, a, b);
818            default:
819                throw JVMCIError.shouldNotReachHere();
820        }
821    }
822
823    private AllocatableValue emitConvertMove(LIRKind kind, AllocatableValue input) {
824        Variable result = newVariable(kind);
825        emitMove(result, input);
826        return result;
827    }
828
829    private AllocatableValue emitConvert2Op(LIRKind kind, SPARCArithmetic op, AllocatableValue input) {
830        Variable result = newVariable(kind);
831        append(new Unary2Op(op, result, input));
832        return result;
833    }
834
835    @Override
836    public Value emitFloatConvert(FloatConvert op, Value inputVal) {
837        AllocatableValue input = asAllocatable(inputVal);
838        switch (op) {
839            case D2F:
840                return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Float), D2F, input);
841            case F2D:
842                return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Double), F2D, input);
843            case I2F: {
844                AllocatableValue intEncodedFloatReg = newVariable(LIRKind.combine(input).changeType(Kind.Float));
845                moveBetweenFpGp(intEncodedFloatReg, input);
846                AllocatableValue convertedFloatReg = newVariable(intEncodedFloatReg.getLIRKind());
847                append(new Unary2Op(I2F, convertedFloatReg, intEncodedFloatReg));
848                return convertedFloatReg;
849            }
850            case I2D: {
851                // Unfortunately we must do int -> float -> double because fitod has float
852                // and double encoding in one instruction
853                AllocatableValue convertedFloatReg = newVariable(LIRKind.combine(input).changeType(Kind.Float));
854                moveBetweenFpGp(convertedFloatReg, input);
855                AllocatableValue convertedDoubleReg = newVariable(LIRKind.combine(input).changeType(Kind.Double));
856                append(new Unary2Op(I2D, convertedDoubleReg, convertedFloatReg));
857                return convertedDoubleReg;
858            }
859            case L2D: {
860                AllocatableValue longEncodedDoubleReg = newVariable(LIRKind.combine(input).changeType(Kind.Double));
861                moveBetweenFpGp(longEncodedDoubleReg, input);
862                AllocatableValue convertedDoubleReg = newVariable(longEncodedDoubleReg.getLIRKind());
863                append(new Unary2Op(L2D, convertedDoubleReg, longEncodedDoubleReg));
864                return convertedDoubleReg;
865            }
866            case D2I: {
867                AllocatableValue convertedFloatReg = emitConvert2Op(LIRKind.combine(input).changeType(Kind.Float), D2I, input);
868                AllocatableValue convertedIntReg = newVariable(LIRKind.combine(convertedFloatReg).changeType(Kind.Int));
869                moveBetweenFpGp(convertedIntReg, convertedFloatReg);
870                return convertedIntReg;
871            }
872            case F2L: {
873                AllocatableValue convertedDoubleReg = emitConvert2Op(LIRKind.combine(input).changeType(Kind.Double), F2L, input);
874                AllocatableValue convertedLongReg = newVariable(LIRKind.combine(convertedDoubleReg).changeType(Kind.Long));
875                moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
876                return convertedLongReg;
877            }
878            case F2I: {
879                AllocatableValue convertedFloatReg = emitConvert2Op(LIRKind.combine(input).changeType(Kind.Float), F2I, input);
880                AllocatableValue convertedIntReg = newVariable(LIRKind.combine(convertedFloatReg).changeType(Kind.Int));
881                moveBetweenFpGp(convertedIntReg, convertedFloatReg);
882                return convertedIntReg;
883            }
884            case D2L: {
885                AllocatableValue convertedDoubleReg = emitConvert2Op(LIRKind.combine(input).changeType(Kind.Double), D2L, input);
886                AllocatableValue convertedLongReg = newVariable(LIRKind.combine(convertedDoubleReg).changeType(Kind.Long));
887                moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
888                return convertedLongReg;
889            }
890            case L2F: {
891                // long -> double -> float see above
892                AllocatableValue convertedDoubleReg = newVariable(LIRKind.combine(input).changeType(Kind.Double));
893                moveBetweenFpGp(convertedDoubleReg, input);
894                AllocatableValue convertedFloatReg = newVariable(LIRKind.combine(input).changeType(Kind.Float));
895                append(new Unary2Op(L2F, convertedFloatReg, convertedDoubleReg));
896                return convertedFloatReg;
897            }
898            default:
899                throw JVMCIError.shouldNotReachHere();
900        }
901    }
902
903    private void moveBetweenFpGp(AllocatableValue dst, AllocatableValue src) {
904        AllocatableValue tempSlot;
905        if (getArchitecture().getFeatures().contains(CPUFeature.VIS3)) {
906            tempSlot = AllocatableValue.ILLEGAL;
907        } else {
908            tempSlot = getTempSlot(LIRKind.value(Kind.Long));
909        }
910        append(new MoveFpGp(dst, src, tempSlot));
911    }
912
913    private StackSlotValue getTempSlot(LIRKind kind) {
914        if (tmpStackSlot == null) {
915            tmpStackSlot = getResult().getFrameMapBuilder().allocateSpillSlot(kind);
916        }
917        return tmpStackSlot;
918    }
919
920    protected SPARC getArchitecture() {
921        return (SPARC) target().arch;
922    }
923
924    @Override
925    public Value emitNarrow(Value inputVal, int bits) {
926        if (inputVal.getKind() == Kind.Long && bits <= 32) {
927            return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Int), L2I, asAllocatable(inputVal));
928        } else {
929            return inputVal;
930        }
931    }
932
933    @Override
934    public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
935        assert fromBits <= toBits && toBits <= 64;
936        if (fromBits == toBits) {
937            return inputVal;
938        } else if (toBits > 32) {
939            // sign extend to 64 bits
940            switch (fromBits) {
941                case 8:
942                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Long), B2L, asAllocatable(inputVal));
943                case 16:
944                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Long), S2L, asAllocatable(inputVal));
945                case 32:
946                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Long), I2L, asAllocatable(inputVal));
947                default:
948                    throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
949            }
950        } else {
951            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
952            switch (fromBits) {
953                case 8:
954                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Int), B2I, asAllocatable(inputVal));
955                case 16:
956                    return emitConvert2Op(LIRKind.combine(inputVal).changeType(Kind.Int), S2I, asAllocatable(inputVal));
957                case 32:
958                    return inputVal;
959                default:
960                    throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
961            }
962        }
963    }
964
965    @Override
966    public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
967        assert fromBits <= toBits && toBits <= 64;
968        if (fromBits == toBits) {
969            return inputVal;
970        } else if (fromBits > 32) {
971            assert inputVal.getKind() == Kind.Long;
972            Variable result = newVariable(LIRKind.combine(inputVal).changeType(Kind.Long));
973            long mask = CodeUtil.mask(fromBits);
974            append(new BinaryRegConst(SPARCArithmetic.LAND, result, asAllocatable(inputVal), JavaConstant.forLong(mask), null));
975            return result;
976        } else {
977            assert inputVal.getKind() == Kind.Int || inputVal.getKind() == Kind.Short || inputVal.getKind() == Kind.Byte || inputVal.getKind() == Kind.Char : inputVal.getKind();
978            Variable result = newVariable(LIRKind.combine(inputVal).changeType(Kind.Int));
979            long mask = CodeUtil.mask(fromBits);
980            JavaConstant constant = JavaConstant.forInt((int) mask);
981            if (fromBits == 32) {
982                append(new BinaryRegConst(IUSHR, result, inputVal, JavaConstant.forInt(0)));
983            } else if (canInlineConstant(constant)) {
984                append(new BinaryRegConst(SPARCArithmetic.IAND, result, asAllocatable(inputVal), constant, null));
985            } else {
986                Variable maskVar = newVariable(LIRKind.combine(inputVal).changeType(Kind.Int));
987                emitMove(maskVar, constant);
988                append(new BinaryRegReg(IAND, result, maskVar, asAllocatable(inputVal)));
989            }
990            if (toBits > 32) {
991                Variable longResult = newVariable(LIRKind.combine(inputVal).changeType(Kind.Long));
992                emitMove(longResult, result);
993                return longResult;
994            } else {
995                return result;
996            }
997        }
998    }
999
1000    @Override
1001    public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) {
1002        Kind from = inputVal.getKind();
1003        AllocatableValue input = asAllocatable(inputVal);
1004        Variable result = newVariable(to);
1005        // These cases require a move between CPU and FPU registers:
1006        switch ((Kind) to.getPlatformKind()) {
1007            case Int:
1008                switch (from) {
1009                    case Float:
1010                    case Double:
1011                        moveBetweenFpGp(result, input);
1012                        return result;
1013                }
1014                break;
1015            case Long:
1016                switch (from) {
1017                    case Float:
1018                    case Double:
1019                        moveBetweenFpGp(result, input);
1020                        return result;
1021                }
1022                break;
1023            case Float:
1024                switch (from) {
1025                    case Int:
1026                    case Long:
1027                        moveBetweenFpGp(result, input);
1028                        return result;
1029                }
1030                break;
1031            case Double:
1032                switch (from) {
1033                    case Int:
1034                    case Long:
1035                        moveBetweenFpGp(result, input);
1036                        return result;
1037                }
1038                break;
1039        }
1040
1041        // Otherwise, just emit an ordinary move instruction.
1042        // Instructions that move or generate 32-bit register values also set the upper 32
1043        // bits of the register to zero.
1044        // Consequently, there is no need for a special zero-extension move.
1045        return emitConvertMove(to, input);
1046    }
1047
1048    @Override
1049    public void emitMembar(int barriers) {
1050        int necessaryBarriers = target().arch.requiredBarriers(barriers);
1051        if (target().isMP && necessaryBarriers != 0) {
1052            append(new MembarOp(necessaryBarriers));
1053        }
1054    }
1055
1056    @Override
1057    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
1058        append(new ReturnOp(Value.ILLEGAL));
1059    }
1060
1061    public Value emitSignExtendLoad(LIRKind kind, Value address, LIRFrameState state) {
1062        SPARCAddressValue loadAddress = asAddressValue(address);
1063        Variable result = newVariable(kind);
1064        append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state, true));
1065        return result;
1066    }
1067
1068    public void emitNullCheck(Value address, LIRFrameState state) {
1069        PlatformKind kind = address.getPlatformKind();
1070        assert kind == Kind.Object || kind == Kind.Long : address + " - " + kind + " not an object!";
1071        append(new NullCheckOp(asAddressValue(address), state));
1072    }
1073
1074    public void emitLoadConstantTableBase() {
1075        constantTableBase = newVariable(LIRKind.value(Kind.Long));
1076        int nextPosition = getResult().getLIR().getLIRforBlock(getCurrentBlock()).size();
1077        NoOp placeHolder = append(new NoOp(getCurrentBlock(), nextPosition));
1078        loadConstantTableBaseOp = new SPARCLoadConstantTableBaseOp(constantTableBase, placeHolder);
1079    }
1080
1081    boolean useConstantTableBase = false;
1082
1083    protected Variable getConstantTableBase() {
1084        useConstantTableBase = true;
1085        return constantTableBase;
1086    }
1087
1088    @Override
1089    public void beforeRegisterAllocation() {
1090        LIR lir = getResult().getLIR();
1091        loadConstantTableBaseOp.setAlive(lir, useConstantTableBase);
1092    }
1093}