| /* |
| * 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)); |
| } |
| } |