/* * 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)); AllocatableValue usedOperand = getLIRGen().asAllocatable(operand); if (operand.getPlatformKind() == SPARCKind.WORD) { // Zero extend AllocatableValue intermediateOperand = getLIRGen().newVariable(operand.getValueKind()); getLIRGen().append(new SPARCOP3Op(Op3s.Srl, usedOperand, g0.asValue(), intermediateOperand)); usedOperand = intermediateOperand; } getLIRGen().append(new SPARCOP3Op(Op3s.Popc, 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 inputValue) { Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue)); SPARCKind kind = (SPARCKind) inputValue.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(), getLIRGen().asAllocatable(inputValue), result)); return result; } @Override public Value emitMathSqrt(Value inputValue) { Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue)); SPARCKind kind = (SPARCKind) inputValue.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(), getLIRGen().asAllocatable(inputValue), 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 inputValue) { Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue)); getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), 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); getLIRGen().append(new SPARCOPFOp(opf, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(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 inputValue) { AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputValue); AllocatableValue result; switch (op) { case D2F: result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(SINGLE)); getLIRGen().append(new SPARCOPFOp(Fdtos, inputAllocatable, result)); break; case F2D: result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(DOUBLE)); getLIRGen().append(new SPARCOPFOp(Fstod, inputAllocatable, result)); break; case I2F: { AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind()); moveBetweenFpGp(intEncodedFloatReg, inputAllocatable); 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(inputAllocatable).changeType(SINGLE)); result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); moveBetweenFpGp(convertedFloatReg, inputAllocatable); getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result)); break; } case L2D: { AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); moveBetweenFpGp(longEncodedDoubleReg, inputAllocatable); AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind()); getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg)); result = convertedDoubleReg; break; } case D2I: { AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, inputAllocatable, convertedFloatReg)); AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD)); moveBetweenFpGp(convertedIntReg, convertedFloatReg); result = convertedIntReg; break; } case F2L: { AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, inputAllocatable, convertedDoubleReg)); AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD)); moveBetweenFpGp(convertedLongReg, convertedDoubleReg); result = convertedLongReg; break; } case F2I: { AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, inputAllocatable, convertedFloatReg)); AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD)); moveBetweenFpGp(convertedIntReg, convertedFloatReg); result = convertedIntReg; break; } case D2L: { AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, inputAllocatable, convertedDoubleReg)); AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD)); moveBetweenFpGp(convertedLongReg, convertedDoubleReg); result = convertedLongReg; break; } case L2F: { AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); moveBetweenFpGp(convertedDoubleReg, inputAllocatable); 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); int shiftCount = XWORD.getSizeInBits() - fromBits; if (fromBits == toBits) { return 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 { AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputVal); Variable result = getLIRGen().newVariable(resultKind); if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) { getLIRGen().append(new SPARCOP3Op(Sra, inputAllocatable, g0.asValue(LIRKind.value(WORD)), result)); } else { Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD)); getLIRGen().append(new SPARCOP3Op(Sllx, inputAllocatable, 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 inputValue, int fromBits, int toBits) { assert fromBits <= toBits && toBits <= 64; if (fromBits == toBits) { return inputValue; } Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD)); AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputValue); if (fromBits == 32) { getLIRGen().append(new SPARCOP3Op(Srl, inputAllocatable, g0.asValue(), result)); } else { Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits))); getLIRGen().append(new SPARCOP3Op(And, inputAllocatable, 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)); } }