[llvm] 5adb090 - [LoongArch] Fix codegen for [su]itofp instructions

Weining Lu via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 2 20:41:28 PDT 2022


Author: wanglei
Date: 2022-11-03T11:40:50+08:00
New Revision: 5adb090795914a4122492117f3af8dacaf69301f

URL: https://github.com/llvm/llvm-project/commit/5adb090795914a4122492117f3af8dacaf69301f
DIFF: https://github.com/llvm/llvm-project/commit/5adb090795914a4122492117f3af8dacaf69301f.diff

LOG: [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

Added: 
    

Modified: 
    llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
    llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
    llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp
    llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
    llvm/lib/Target/LoongArch/LoongArchISelLowering.h
    llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
    llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
index 0e2f57551f334..3767fc1d793ba 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 d061b6426e244..44a80054f0a90 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 415ca4d871cda..8ba1f9c1b27f6 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 6f477413636a9..49e8ce02abccd 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 1e411fb34f727..358da7feb20b6 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -171,6 +171,7 @@ class LoongArchTargetLowering : public TargetLowering {
   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;

diff  --git a/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
index 070027b698436..03a126a736efc 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
@@ -242,16 +242,9 @@ define double @convert_u32_to_double(i32 %a) nounwind {
 ;
 ; LA64-LABEL: convert_u32_to_double:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    pcalau12i $a1, %pc_hi20(.LCPI12_0)
-; LA64-NEXT:    addi.d $a1, $a1, %pc_lo12(.LCPI12_0)
-; LA64-NEXT:    fld.d $fa0, $a1, 0
-; LA64-NEXT:    lu52i.d $a1, $zero, 1107
-; LA64-NEXT:    movgr2fr.d $fa1, $a1
-; LA64-NEXT:    fsub.d $fa0, $fa1, $fa0
-; LA64-NEXT:    lu12i.w $a1, 275200
-; LA64-NEXT:    bstrins.d $a0, $a1, 63, 32
-; LA64-NEXT:    movgr2fr.d $fa1, $a0
-; LA64-NEXT:    fadd.d $fa0, $fa1, $fa0
+; LA64-NEXT:    bstrpick.d $a0, $a0, 31, 0
+; LA64-NEXT:    movgr2fr.d $fa0, $a0
+; LA64-NEXT:    ffint.d.l $fa0, $fa0
 ; LA64-NEXT:    ret
   %1 = uitofp i32 %a to double
   ret double %1

diff  --git a/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll
index 559206a4db5ac..a18cb6f756a60 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll
@@ -376,14 +376,12 @@ define float @convert_i32_to_float(i32 %a) nounwind {
 ;
 ; LA64F-LABEL: convert_i32_to_float:
 ; LA64F:       # %bb.0:
-; LA64F-NEXT:    addi.w $a0, $a0, 0
 ; LA64F-NEXT:    movgr2fr.w $fa0, $a0
 ; LA64F-NEXT:    ffint.s.w $fa0, $fa0
 ; LA64F-NEXT:    ret
 ;
 ; LA64D-LABEL: convert_i32_to_float:
 ; LA64D:       # %bb.0:
-; LA64D-NEXT:    addi.w $a0, $a0, 0
 ; LA64D-NEXT:    movgr2fr.w $fa0, $a0
 ; LA64D-NEXT:    ffint.s.w $fa0, $fa0
 ; LA64D-NEXT:    ret
@@ -412,14 +410,17 @@ define float @convert_i64_to_float(i64 %a) nounwind {
 ;
 ; LA64F-LABEL: convert_i64_to_float:
 ; LA64F:       # %bb.0:
-; LA64F-NEXT:    movgr2fr.w $fa0, $a0
-; LA64F-NEXT:    ffint.s.w $fa0, $fa0
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    bl %plt(__floatdisf)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
 ; LA64F-NEXT:    ret
 ;
 ; LA64D-LABEL: convert_i64_to_float:
 ; LA64D:       # %bb.0:
-; LA64D-NEXT:    movgr2fr.w $fa0, $a0
-; LA64D-NEXT:    ffint.s.w $fa0, $fa0
+; LA64D-NEXT:    movgr2fr.d $fa0, $a0
+; LA64D-NEXT:    ffint.s.l $fa0, $fa0
 ; LA64D-NEXT:    ret
   %1 = sitofp i64 %a to float
   ret float %1
@@ -514,34 +515,19 @@ define float @convert_u32_to_float(i32 %a) nounwind {
 ;
 ; LA64F-LABEL: convert_u32_to_float:
 ; LA64F:       # %bb.0:
-; LA64F-NEXT:    bstrpick.d $a1, $a0, 31, 1
-; LA64F-NEXT:    andi $a2, $a0, 1
-; LA64F-NEXT:    or $a1, $a2, $a1
-; LA64F-NEXT:    movgr2fr.w $fa0, $a1
-; LA64F-NEXT:    ffint.s.w $fa0, $fa0
-; LA64F-NEXT:    fadd.s $fa0, $fa0, $fa0
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
 ; LA64F-NEXT:    bstrpick.d $a0, $a0, 31, 0
-; LA64F-NEXT:    slti $a1, $a0, 0
-; LA64F-NEXT:    movgr2cf $fcc0, $a1
-; LA64F-NEXT:    movgr2fr.w $fa1, $a0
-; LA64F-NEXT:    ffint.s.w $fa1, $fa1
-; LA64F-NEXT:    fsel $fa0, $fa1, $fa0, $fcc0
+; LA64F-NEXT:    bl %plt(__floatundisf)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
 ; LA64F-NEXT:    ret
 ;
 ; LA64D-LABEL: convert_u32_to_float:
 ; LA64D:       # %bb.0:
-; LA64D-NEXT:    bstrpick.d $a1, $a0, 31, 1
-; LA64D-NEXT:    andi $a2, $a0, 1
-; LA64D-NEXT:    or $a1, $a2, $a1
-; LA64D-NEXT:    movgr2fr.w $fa0, $a1
-; LA64D-NEXT:    ffint.s.w $fa0, $fa0
-; LA64D-NEXT:    fadd.s $fa0, $fa0, $fa0
 ; LA64D-NEXT:    bstrpick.d $a0, $a0, 31, 0
-; LA64D-NEXT:    slti $a1, $a0, 0
-; LA64D-NEXT:    movgr2cf $fcc0, $a1
-; LA64D-NEXT:    movgr2fr.w $fa1, $a0
-; LA64D-NEXT:    ffint.s.w $fa1, $fa1
-; LA64D-NEXT:    fsel $fa0, $fa1, $fa0, $fcc0
+; LA64D-NEXT:    movgr2fr.d $fa0, $a0
+; LA64D-NEXT:    ffint.s.l $fa0, $fa0
 ; LA64D-NEXT:    ret
   %1 = uitofp i32 %a to float
   ret float %1
@@ -568,17 +554,11 @@ define float @convert_u64_to_float(i64 %a) nounwind {
 ;
 ; LA64F-LABEL: convert_u64_to_float:
 ; LA64F:       # %bb.0:
-; LA64F-NEXT:    srli.d $a1, $a0, 1
-; LA64F-NEXT:    andi $a2, $a0, 1
-; LA64F-NEXT:    or $a1, $a2, $a1
-; LA64F-NEXT:    movgr2fr.w $fa0, $a1
-; LA64F-NEXT:    ffint.s.w $fa0, $fa0
-; LA64F-NEXT:    fadd.s $fa0, $fa0, $fa0
-; LA64F-NEXT:    slti $a1, $a0, 0
-; LA64F-NEXT:    movgr2cf $fcc0, $a1
-; LA64F-NEXT:    movgr2fr.w $fa1, $a0
-; LA64F-NEXT:    ffint.s.w $fa1, $fa1
-; LA64F-NEXT:    fsel $fa0, $fa1, $fa0, $fcc0
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    bl %plt(__floatundisf)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
 ; LA64F-NEXT:    ret
 ;
 ; LA64D-LABEL: convert_u64_to_float:
@@ -586,13 +566,13 @@ define float @convert_u64_to_float(i64 %a) nounwind {
 ; LA64D-NEXT:    srli.d $a1, $a0, 1
 ; LA64D-NEXT:    andi $a2, $a0, 1
 ; LA64D-NEXT:    or $a1, $a2, $a1
-; LA64D-NEXT:    movgr2fr.w $fa0, $a1
-; LA64D-NEXT:    ffint.s.w $fa0, $fa0
+; LA64D-NEXT:    movgr2fr.d $fa0, $a1
+; LA64D-NEXT:    ffint.s.l $fa0, $fa0
 ; LA64D-NEXT:    fadd.s $fa0, $fa0, $fa0
 ; LA64D-NEXT:    slti $a1, $a0, 0
 ; LA64D-NEXT:    movgr2cf $fcc0, $a1
-; LA64D-NEXT:    movgr2fr.w $fa1, $a0
-; LA64D-NEXT:    ffint.s.w $fa1, $fa1
+; LA64D-NEXT:    movgr2fr.d $fa1, $a0
+; LA64D-NEXT:    ffint.s.l $fa1, $fa1
 ; LA64D-NEXT:    fsel $fa0, $fa1, $fa0, $fcc0
 ; LA64D-NEXT:    ret
   %1 = uitofp i64 %a to float


        


More information about the llvm-commits mailing list