diff options
author | wanglei <wanglei@loongson.cn> | 2022-11-03 11:10:41 +0800 |
---|---|---|
committer | Weining Lu <luweining@loongson.cn> | 2022-11-03 11:40:50 +0800 |
commit | 5adb090795914a4122492117f3af8dacaf69301f (patch) | |
tree | 1ad2eafeaae1340980f4728f2532fd2cbe7fc3b6 /llvm/lib/Target/LoongArch | |
parent | 1024497fffd18bba92485852cfedebb829499953 (diff) | |
download | llvm-5adb090795914a4122492117f3af8dacaf69301f.zip llvm-5adb090795914a4122492117f3af8dacaf69301f.tar.gz llvm-5adb090795914a4122492117f3af8dacaf69301f.tar.bz2 |
[LoongArch] Fix codegen for [su]itofp instructions
This patch fixes codegen for `[su]itofp` instructions.
In LoongArch, a legal int-to-float conversion is done in two steps:
1. Move the data from `GPR` to `FPR`. (FRLen >= GRLen)
2. Conversion in `FPR`. (the data in `FPR` is treated as a signed value)
Based on the above features, when the type's BitWidth meets the
requirements, all `SINT_TO_FP` are legal, all `UINT_TO_FP` are expand
and lowered to libcall when appropriate.
The only special case is, LoongArch64 with `+f,-d` features. At this
point, custom processing is required for `[SU]INT_TO_FP`. Of course, we
can also ignore it and use libcall directly.
Differential Revision: https://reviews.llvm.org/D136916
Diffstat (limited to 'llvm/lib/Target/LoongArch')
5 files changed, 74 insertions, 15 deletions
diff --git a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td index 0e2f575..3767fc1 100644 --- a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td @@ -284,7 +284,11 @@ def : Pat<(loongarch_movgr2fr_w_la64 GPR:$src), (MOVGR2FR_W GPR:$src)>; def : Pat<(loongarch_movfr2gr_s_la64 FPR32:$src), (MOVFR2GR_S FPR32:$src)>; // int -> f32 -def : Pat<(f32 (sint_to_fp GPR:$src)), (FFINT_S_W (MOVGR2FR_W GPR:$src))>; +def : Pat<(f32 (sint_to_fp (i64 (sexti32 (i64 GPR:$src))))), + (FFINT_S_W (MOVGR2FR_W GPR:$src))>; +// uint -> f32 +def : Pat<(f32 (uint_to_fp (i64 (sexti32 (i64 GPR:$src))))), + (FFINT_S_W (MOVGR2FR_W GPR:$src))>; } // Predicates = [HasBasicF, IsLA64] // FP Rounding diff --git a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td index d061b64..44a8005 100644 --- a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td @@ -288,13 +288,11 @@ def : Pat<(f64 fpimm1), (FCVT_D_S (FFINT_S_W (MOVGR2FR_W (ADDI_W R0, 1))))>; /// Convert int to FP let Predicates = [HasBasicD, IsLA64] in { +def : Pat<(f32 (sint_to_fp GPR:$src)), (FFINT_S_L (MOVGR2FR_D GPR:$src))>; def : Pat<(f64 (sint_to_fp (i64 (sexti32 (i64 GPR:$src))))), (FFINT_D_W (MOVGR2FR_W GPR:$src))>; def : Pat<(f64 (sint_to_fp GPR:$src)), (FFINT_D_L (MOVGR2FR_D GPR:$src))>; -def : Pat<(f64 (uint_to_fp (i64 (zexti32 (i64 GPR:$src))))), - (FFINT_D_W (MOVGR2FR_W GPR:$src))>; - def : Pat<(bitconvert GPR:$src), (MOVGR2FR_D GPR:$src)>; } // Predicates = [HasBasicD, IsLA64] let Predicates = [HasBasicD, IsLA32] in { diff --git a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp index 415ca4d..8ba1f9c 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp @@ -213,6 +213,12 @@ bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) { Val = N.getOperand(0); return true; } + if (N.getOpcode() == LoongArchISD::BSTRPICK && + N.getConstantOperandVal(1) < UINT64_C(0X1F) && + N.getConstantOperandVal(2) == UINT64_C(0)) { + Val = N; + return true; + } MVT VT = N.getSimpleValueType(); if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) { Val = N; diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index 6f47741..49e8ce0 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -21,6 +21,7 @@ #include "MCTargetDesc/LoongArchMCTargetDesc.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/ISDOpcodes.h" +#include "llvm/CodeGen/RuntimeLibcalls.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/IntrinsicsLoongArch.h" #include "llvm/Support/Debug.h" @@ -160,7 +161,12 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM, setLibcallName(RTLIB::MUL_I128, nullptr); setOperationAction(ISD::FP_TO_UINT, GRLenVT, Custom); - setOperationAction(ISD::UINT_TO_FP, GRLenVT, Custom); + setOperationAction(ISD::UINT_TO_FP, GRLenVT, Expand); + if ((Subtarget.is64Bit() && Subtarget.hasBasicF() && + !Subtarget.hasBasicD())) { + setOperationAction(ISD::SINT_TO_FP, GRLenVT, Custom); + setOperationAction(ISD::UINT_TO_FP, GRLenVT, Custom); + } // Compute derived properties from the register classes. computeRegisterProperties(STI.getRegisterInfo()); @@ -220,6 +226,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op, return lowerBITCAST(Op, DAG); case ISD::UINT_TO_FP: return lowerUINT_TO_FP(Op, DAG); + case ISD::SINT_TO_FP: + return lowerSINT_TO_FP(Op, DAG); case ISD::VASTART: return lowerVASTART(Op, DAG); case ISD::FRAMEADDR: @@ -302,19 +310,61 @@ SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op, SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG) const { + assert(Subtarget.is64Bit() && Subtarget.hasBasicF() && + !Subtarget.hasBasicD() && "unexpected target features"); + + SDLoc DL(Op); + SDValue Op0 = Op.getOperand(0); + if (Op0->getOpcode() == ISD::AND) { + auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1)); + if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF)) + return Op; + } + + if (Op0->getOpcode() == LoongArchISD::BSTRPICK && + Op0.getConstantOperandVal(1) < UINT64_C(0X1F) && + Op0.getConstantOperandVal(2) == UINT64_C(0)) + return Op; + + if (Op0.getOpcode() == ISD::AssertZext && + dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32)) + return Op; + + EVT OpVT = Op0.getValueType(); + EVT RetVT = Op.getValueType(); + RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT); + MakeLibCallOptions CallOptions; + CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true); + SDValue Chain = SDValue(); + SDValue Result; + std::tie(Result, Chain) = + makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain); + return Result; +} + +SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op, + SelectionDAG &DAG) const { + assert(Subtarget.is64Bit() && Subtarget.hasBasicF() && + !Subtarget.hasBasicD() && "unexpected target features"); SDLoc DL(Op); - auto &TLI = DAG.getTargetLoweringInfo(); - SDValue Tmp1, Tmp2; - SDValue Op1 = Op.getOperand(0); - if (Op1->getOpcode() == ISD::AssertZext || - Op1->getOpcode() == ISD::AssertSext) + SDValue Op0 = Op.getOperand(0); + + if ((Op0.getOpcode() == ISD::AssertSext || + Op0.getOpcode() == ISD::SIGN_EXTEND_INREG) && + dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32)) return Op; - SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Op.getOperand(0)); - SDValue Res = DAG.getNode(ISD::UINT_TO_FP, DL, MVT::f64, Trunc); - SDNode *N = Res.getNode(); - TLI.expandUINT_TO_FP(N, Tmp1, Tmp2, DAG); - return Tmp1; + + EVT OpVT = Op0.getValueType(); + EVT RetVT = Op.getValueType(); + RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT); + MakeLibCallOptions CallOptions; + CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true); + SDValue Chain = SDValue(); + SDValue Result; + std::tie(Result, Chain) = + makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain); + return Result; } SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op, diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h index 1e411fb..358da7f 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -171,6 +171,7 @@ private: SDValue lowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const; SDValue lowerBITCAST(SDValue Op, SelectionDAG &DAG) const; SDValue lowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; |