[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