blob: 5edf7793eb5d4344ee5f789060d441f9d1671c4f [file] [log] [blame]
/*
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.sparc;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Add;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addcc;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.And;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Mulx;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sdivx;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sllx;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sra;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srax;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srl;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sub;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Udivx;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xnor;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Faddd;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fadds;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtos;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitod;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitos;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuld;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuls;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegd;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegs;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstod;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtod;
import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.UMulxhi;
import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM;
import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM;
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.BSF;
import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.IBSR;
import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.LBSR;
import static jdk.vm.ci.code.CodeUtil.mask;
import static jdk.vm.ci.meta.JavaConstant.forLong;
import static jdk.vm.ci.sparc.SPARC.g0;
import static jdk.vm.ci.sparc.SPARCKind.DOUBLE;
import static jdk.vm.ci.sparc.SPARCKind.SINGLE;
import static jdk.vm.ci.sparc.SPARCKind.WORD;
import static jdk.vm.ci.sparc.SPARCKind.XWORD;
import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s;
import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.FloatConvert;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.ConstantValue;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.VirtualStackSlot;
import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
import org.graalvm.compiler.lir.sparc.SPARCArithmetic;
import org.graalvm.compiler.lir.sparc.SPARCArithmetic.FloatConvertOp;
import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp;
import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp.MulHigh;
import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp;
import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp.Rem;
import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCIMulccOp;
import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCLMulccOp;
import org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp;
import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp;
import org.graalvm.compiler.lir.sparc.SPARCMove.MoveFpGp;
import org.graalvm.compiler.lir.sparc.SPARCMove.StoreConstantOp;
import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp;
import org.graalvm.compiler.lir.sparc.SPARCOP3Op;
import org.graalvm.compiler.lir.sparc.SPARCOPFOp;
import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.PlatformKind;
import jdk.vm.ci.meta.Value;
import jdk.vm.ci.meta.ValueKind;
import jdk.vm.ci.sparc.SPARC;
import jdk.vm.ci.sparc.SPARC.CPUFeature;
import jdk.vm.ci.sparc.SPARCKind;
/**
* This class implements the SPARC specific portion of the LIR generator.
*/
public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
@Override
public SPARCLIRGenerator getLIRGen() {
return (SPARCLIRGenerator) super.getLIRGen();
}
@Override
public Variable emitBitCount(Value operand) {
Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
Value usedOperand = operand;
if (operand.getPlatformKind() == SPARCKind.WORD) { // Zero extend
usedOperand = getLIRGen().newVariable(operand.getValueKind());
getLIRGen().append(new SPARCOP3Op(Op3s.Srl, operand, SPARC.g0.asValue(), usedOperand));
}
getLIRGen().append(new SPARCOP3Op(Op3s.Popc, SPARC.g0.asValue(), usedOperand, result));
return result;
}
@Override
public Variable emitBitScanForward(Value operand) {
Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
getLIRGen().append(new SPARCBitManipulationOp(BSF, result, getLIRGen().asAllocatable(operand), getLIRGen()));
return result;
}
@Override
public Variable emitBitScanReverse(Value operand) {
Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
if (operand.getPlatformKind() == SPARCKind.XWORD) {
getLIRGen().append(new SPARCBitManipulationOp(LBSR, result, getLIRGen().asAllocatable(operand), getLIRGen()));
} else {
getLIRGen().append(new SPARCBitManipulationOp(IBSR, result, getLIRGen().asAllocatable(operand), getLIRGen()));
}
return result;
}
@Override
public Value emitMathAbs(Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
SPARCKind kind = (SPARCKind) input.getPlatformKind();
Opfs opf;
switch (kind) {
case SINGLE:
opf = Opfs.Fabss;
break;
case DOUBLE:
opf = Opfs.Fabsd;
break;
default:
throw GraalError.shouldNotReachHere("Input kind: " + kind);
}
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
return result;
}
@Override
public Value emitMathSqrt(Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
SPARCKind kind = (SPARCKind) input.getPlatformKind();
Opfs opf;
switch (kind) {
case SINGLE:
opf = Opfs.Fsqrts;
break;
case DOUBLE:
opf = Opfs.Fsqrtd;
break;
default:
throw GraalError.shouldNotReachHere("Input kind: " + kind);
}
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
return result;
}
@Override
public Value emitNegate(Value input) {
PlatformKind inputKind = input.getPlatformKind();
if (isNumericInteger(inputKind)) {
return emitUnary(Sub, input);
} else {
return emitUnary(inputKind.equals(DOUBLE) ? Fnegd : Fnegs, input);
}
}
@Override
public Value emitNot(Value input) {
return emitUnary(Xnor, input);
}
private Variable emitUnary(Opfs opf, Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
return result;
}
private Variable emitUnary(Op3s op3, Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
getLIRGen().append(SPARCOP3Op.newUnary(op3, input, result));
return result;
}
private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b) {
return emitBinary(resultKind, opf, a, b, null);
}
private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b, LIRFrameState state) {
Variable result = getLIRGen().newVariable(resultKind);
if (opf.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) {
getLIRGen().append(new SPARCOPFOp(opf, b, a, result, state));
} else {
getLIRGen().append(new SPARCOPFOp(opf, a, b, result, state));
}
return result;
}
private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, int b) {
return emitBinary(resultKind, op3, a, new ConstantValue(LIRKind.value(WORD), JavaConstant.forInt(b)));
}
private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b) {
return emitBinary(resultKind, op3, a, b, null);
}
private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b, LIRFrameState state) {
Variable result = getLIRGen().newVariable(resultKind);
if (op3.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) {
getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), a, result, state));
} else {
getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), b, result, state));
}
return result;
}
@Override
protected boolean isNumericInteger(PlatformKind kind) {
return ((SPARCKind) kind).isInteger();
}
@Override
public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
if (isNumericInteger(a.getPlatformKind())) {
return emitBinary(resultKind, setFlags ? Addcc : Add, a, b);
} else {
boolean isDouble = a.getPlatformKind().equals(DOUBLE);
return emitBinary(resultKind, isDouble ? Faddd : Fadds, a, b);
}
}
@Override
public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
if (isNumericInteger(a.getPlatformKind())) {
return emitBinary(resultKind, setFlags ? Subcc : Sub, a, b);
} else {
boolean isDouble = a.getPlatformKind().equals(DOUBLE);
return emitBinary(resultKind, isDouble ? Opfs.Fsubd : Opfs.Fsubs, a, b);
}
}
@Override
public Variable emitMul(Value a, Value b, boolean setFlags) {
LIRKind resultKind = LIRKind.combine(a, b);
PlatformKind aKind = a.getPlatformKind();
if (isNumericInteger(aKind)) {
if (setFlags) {
Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
if (aKind == XWORD) {
getLIRGen().append(new SPARCLMulccOp(result, getLIRGen().load(a), getLIRGen().load(b), getLIRGen()));
} else if (aKind == WORD) {
getLIRGen().append(new SPARCIMulccOp(result, getLIRGen().load(a), getLIRGen().load(b)));
} else {
throw GraalError.shouldNotReachHere();
}
return result;
} else {
return emitBinary(resultKind, setFlags ? Op3s.Mulscc : Op3s.Mulx, a, b);
}
} else {
boolean isDouble = a.getPlatformKind().equals(DOUBLE);
return emitBinary(resultKind, isDouble ? Fmuld : Fmuls, a, b);
}
}
@Override
public Value emitMulHigh(Value a, Value b) {
MulHigh opcode;
switch (((SPARCKind) a.getPlatformKind())) {
case WORD:
opcode = MulHigh.IMUL;
break;
case XWORD:
opcode = MulHigh.LMUL;
break;
default:
throw GraalError.shouldNotReachHere();
}
return emitMulHigh(opcode, a, b);
}
@Override
public Value emitUMulHigh(Value a, Value b) {
switch (((SPARCKind) a.getPlatformKind())) {
case WORD:
Value aExtended = emitBinary(LIRKind.combine(a), Srl, a, 0);
Value bExtended = emitBinary(LIRKind.combine(b), Srl, b, 0);
Value result = emitBinary(LIRKind.combine(a, b), Mulx, aExtended, bExtended);
return emitBinary(LIRKind.combine(a, b), Srax, result, WORD.getSizeInBits());
case XWORD:
return emitBinary(LIRKind.combine(a, b), UMulxhi, a, b);
default:
throw GraalError.shouldNotReachHere();
}
}
private Value emitMulHigh(MulHigh opcode, Value a, Value b) {
Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
MulHighOp mulHigh = new MulHighOp(opcode, getLIRGen().load(a), getLIRGen().load(b), result, getLIRGen().newVariable(LIRKind.combine(a, b)));
getLIRGen().append(mulHigh);
return result;
}
@Override
public Value emitDiv(Value a, Value b, LIRFrameState state) {
LIRKind resultKind = LIRKind.combine(a, b);
PlatformKind aKind = a.getPlatformKind();
PlatformKind bKind = b.getPlatformKind();
if (isJavaConstant(b) && asJavaConstant(b).isDefaultForKind()) { // Div by zero
Value zero = SPARC.g0.asValue(LIRKind.value(SPARCKind.WORD));
return emitBinary(resultKind, Op3s.Sdivx, zero, zero, state);
} else if (isNumericInteger(aKind)) {
Value fixedA = emitSignExtend(a, aKind.getSizeInBytes() * 8, 64);
Value fixedB = emitSignExtend(b, bKind.getSizeInBytes() * 8, 64);
return emitBinary(resultKind, Op3s.Sdivx, fixedA, fixedB, state);
} else {
boolean isDouble = a.getPlatformKind().equals(DOUBLE);
return emitBinary(resultKind, isDouble ? Opfs.Fdivd : Opfs.Fdivs, a, b, state);
}
}
@Override
public Value emitRem(Value a, Value b, LIRFrameState state) {
Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
Value aLoaded;
Variable q1; // Intermediate values
Variable q2;
SPARCKind aKind = (SPARCKind) a.getPlatformKind();
switch (aKind) {
case WORD:
// Sign extend a and b
Variable as = emitBinary(result.getValueKind(), Sra, a, g0.asValue(LIRKind.value(WORD)));
Variable bs = emitBinary(result.getValueKind(), Sra, b, g0.asValue(LIRKind.value(WORD)));
q1 = emitBinary(as.getValueKind(), Sdivx, as, bs, state);
q2 = emitBinary(q1.getValueKind(), Mulx, q1, bs);
result = emitSub(as, q2, false);
break;
case XWORD:
aLoaded = getLIRGen().load(a); // Reuse the loaded value
q1 = emitBinary(result.getValueKind(), Sdivx, aLoaded, b, state);
q2 = emitBinary(result.getValueKind(), Mulx, q1, b);
result = emitSub(aLoaded, q2, false);
break;
case SINGLE:
ForeignCallLinkage fremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_FREM);
result = getLIRGen().emitForeignCall(fremCall, state, a, b);
break;
case DOUBLE:
ForeignCallLinkage dremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_DREM);
result = getLIRGen().emitForeignCall(dremCall, state, a, b);
break;
default:
throw GraalError.shouldNotReachHere("missing: " + a.getPlatformKind());
}
return result;
}
@Override
public Value emitURem(Value a, Value b, LIRFrameState state) {
Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
Variable scratch1 = getLIRGen().newVariable(LIRKind.combine(a, b));
Variable scratch2 = getLIRGen().newVariable(LIRKind.combine(a, b));
Rem opcode;
switch (((SPARCKind) a.getPlatformKind())) {
case WORD:
opcode = Rem.IUREM;
break;
case XWORD:
opcode = Rem.LUREM;
break;
default:
throw GraalError.shouldNotReachHere();
}
getLIRGen().append(new RemOp(opcode, result, getLIRGen().load(a), getLIRGen().load(b), scratch1, scratch2, state));
return result;
}
@Override
public Value emitUDiv(Value a, Value b, LIRFrameState state) {
Value actualA = a;
Value actualB = b;
switch (((SPARCKind) a.getPlatformKind())) {
case WORD:
actualA = emitZeroExtend(actualA, 32, 64);
actualB = emitZeroExtend(actualB, 32, 64);
break;
case XWORD:
break;
default:
throw GraalError.shouldNotReachHere();
}
return emitBinary(LIRKind.combine(actualA, actualB), Udivx, actualA, actualB, state);
}
@Override
public Variable emitAnd(Value a, Value b) {
LIRKind resultKind = LIRKind.combine(a, b);
return emitBinary(resultKind, Op3s.And, a, b);
}
@Override
public Variable emitOr(Value a, Value b) {
LIRKind resultKind = LIRKind.combine(a, b);
return emitBinary(resultKind, Op3s.Or, a, b);
}
@Override
public Variable emitXor(Value a, Value b) {
LIRKind resultKind = LIRKind.combine(a, b);
return emitBinary(resultKind, Op3s.Xor, a, b);
}
@Override
public Variable emitShl(Value a, Value b) {
SPARCKind aKind = (SPARCKind) a.getPlatformKind();
LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
Op3s op;
switch (aKind) {
case WORD:
op = Op3s.Sll;
break;
case XWORD:
op = Op3s.Sllx;
break;
default:
throw GraalError.shouldNotReachHere(String.format("Unsupported kind %s", aKind));
}
return emitBinary(resultKind, op, a, b);
}
@Override
public Variable emitShr(Value a, Value b) {
SPARCKind aKind = (SPARCKind) a.getPlatformKind();
LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
Op3s op;
switch (aKind) {
case WORD:
op = Op3s.Sra;
break;
case XWORD:
op = Op3s.Srax;
break;
default:
throw GraalError.shouldNotReachHere();
}
return emitBinary(resultKind, op, a, b);
}
@Override
public Variable emitUShr(Value a, Value b) {
SPARCKind aKind = (SPARCKind) a.getPlatformKind();
LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind);
Op3s op;
switch (aKind) {
case WORD:
op = Op3s.Srl;
break;
case XWORD:
op = Op3s.Srlx;
break;
default:
throw GraalError.shouldNotReachHere();
}
return emitBinary(resultKind, op, a, b);
}
private AllocatableValue emitConvertMove(LIRKind kind, AllocatableValue input) {
Variable result = getLIRGen().newVariable(kind);
getLIRGen().emitMove(result, input);
return result;
}
@Override
public Value emitFloatConvert(FloatConvert op, Value inputVal) {
AllocatableValue input = getLIRGen().asAllocatable(inputVal);
Value result;
switch (op) {
case D2F:
result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(SINGLE));
getLIRGen().append(new SPARCOPFOp(Fdtos, inputVal, result));
break;
case F2D:
result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(DOUBLE));
getLIRGen().append(new SPARCOPFOp(Fstod, inputVal, result));
break;
case I2F: {
AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind());
moveBetweenFpGp(intEncodedFloatReg, input);
getLIRGen().append(new SPARCOPFOp(Fitos, intEncodedFloatReg, result));
break;
}
case I2D: {
// Unfortunately we must do int -> float -> double because fitod has float
// and double encoding in one instruction
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
result = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
moveBetweenFpGp(convertedFloatReg, input);
getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result));
break;
}
case L2D: {
AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
moveBetweenFpGp(longEncodedDoubleReg, input);
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind());
getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg));
result = convertedDoubleReg;
break;
}
case D2I: {
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, input, convertedFloatReg));
AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
moveBetweenFpGp(convertedIntReg, convertedFloatReg);
result = convertedIntReg;
break;
}
case F2L: {
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, input, convertedDoubleReg));
AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
result = convertedLongReg;
break;
}
case F2I: {
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, input, convertedFloatReg));
AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
moveBetweenFpGp(convertedIntReg, convertedFloatReg);
result = convertedIntReg;
break;
}
case D2L: {
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, input, convertedDoubleReg));
AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
result = convertedLongReg;
break;
}
case L2F: {
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
result = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
moveBetweenFpGp(convertedDoubleReg, input);
getLIRGen().append(new SPARCOPFOp(Opfs.Fxtos, convertedDoubleReg, result));
break;
}
default:
throw GraalError.shouldNotReachHere();
}
return result;
}
protected VirtualStackSlot getTempSlot(LIRKind kind) {
return getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(kind);
}
private void moveBetweenFpGp(AllocatableValue dst, AllocatableValue src) {
AllocatableValue tempSlot;
PlatformKind dstKind = dst.getPlatformKind();
PlatformKind srcKind = src.getPlatformKind();
if (getLIRGen().getArchitecture().getFeatures().contains(CPUFeature.VIS3) && !(srcKind == WORD && dstKind == SINGLE) && !(srcKind == SINGLE && dstKind == WORD)) {
tempSlot = AllocatableValue.ILLEGAL;
} else {
tempSlot = getTempSlot(LIRKind.value(XWORD));
}
getLIRGen().append(new MoveFpGp(dst, src, tempSlot));
}
@Override
public Value emitNarrow(Value inputVal, int bits) {
if (inputVal.getPlatformKind() == XWORD && bits <= 32) {
LIRKind resultKind = LIRKind.combine(inputVal).changeType(WORD);
Variable result = getLIRGen().newVariable(resultKind);
getLIRGen().emitMove(result, inputVal);
return result;
} else {
return inputVal;
}
}
@Override
public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
assert fromBits <= toBits && toBits <= XWORD.getSizeInBits();
LIRKind shiftKind = LIRKind.value(WORD);
LIRKind resultKind = LIRKind.combine(inputVal).changeType(toBits > 32 ? XWORD : WORD);
Value result;
int shiftCount = XWORD.getSizeInBits() - fromBits;
if (fromBits == toBits) {
result = inputVal;
} else if (isJavaConstant(inputVal)) {
JavaConstant javaConstant = asJavaConstant(inputVal);
long constant;
if (javaConstant.isNull()) {
constant = 0;
} else {
constant = javaConstant.asLong();
}
return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount));
} else if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) {
result = getLIRGen().newVariable(resultKind);
getLIRGen().append(new SPARCOP3Op(Sra, inputVal, SPARC.g0.asValue(LIRKind.value(WORD)), result));
} else {
Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD));
result = getLIRGen().newVariable(resultKind);
getLIRGen().append(new SPARCOP3Op(Sllx, inputVal, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp));
getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result));
}
return result;
}
@Override
public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
assert fromBits <= toBits && toBits <= 64;
if (fromBits == toBits) {
return inputVal;
}
Variable result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD));
if (fromBits == 32) {
getLIRGen().append(new SPARCOP3Op(Srl, inputVal, g0.asValue(), result));
} else {
Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits)));
getLIRGen().append(new SPARCOP3Op(And, inputVal, mask, result));
}
return result;
}
@Override
public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) {
SPARCKind fromKind = (SPARCKind) inputVal.getPlatformKind();
SPARCKind toKind = (SPARCKind) to.getPlatformKind();
AllocatableValue input = getLIRGen().asAllocatable(inputVal);
Variable result = getLIRGen().newVariable(to);
// These cases require a move between CPU and FPU registers:
if (fromKind.isFloat() != toKind.isFloat()) {
moveBetweenFpGp(result, input);
return result;
} else {
// Otherwise, just emit an ordinary move instruction.
// Instructions that move or generate 32-bit register values also set the upper 32
// bits of the register to zero.
// Consequently, there is no need for a special zero-extension move.
return emitConvertMove(to, input);
}
}
@Override
public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
SPARCAddressValue loadAddress = getLIRGen().asAddressValue(address);
Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
getLIRGen().append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state));
return result;
}
@Override
public void emitStore(ValueKind<?> kind, Value address, Value inputVal, LIRFrameState state) {
SPARCAddressValue storeAddress = getLIRGen().asAddressValue(address);
if (isJavaConstant(inputVal)) {
JavaConstant c = asJavaConstant(inputVal);
if (c.isDefaultForKind()) {
getLIRGen().append(new StoreConstantOp(kind.getPlatformKind(), storeAddress, c, state));
return;
}
}
Variable input = getLIRGen().load(inputVal);
getLIRGen().append(new StoreOp(kind.getPlatformKind(), storeAddress, input, state));
}
}