[llvm] 1df96ce - [LoongArch] Add codegen support for fpround, fpextend and converting between signed integer and floating-point
Weining Lu via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 13 00:27:11 PDT 2022
Author: gonglingqin
Date: 2022-07-13T15:25:43+08:00
New Revision: 1df96ce518f44436b2801b18dd024778c669ed99
URL: https://github.com/llvm/llvm-project/commit/1df96ce518f44436b2801b18dd024778c669ed99
DIFF: https://github.com/llvm/llvm-project/commit/1df96ce518f44436b2801b18dd024778c669ed99.diff
LOG: [LoongArch] Add codegen support for fpround, fpextend and converting between signed integer and floating-point
Differential Revision: https://reviews.llvm.org/D128899
Added:
llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll
Modified:
llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp
llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h
llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
llvm/lib/Target/LoongArch/LoongArchISelLowering.h
llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
Removed:
################################################################################
diff --git a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
index 9a13b8607dca..a90313a2c70b 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
@@ -10,6 +10,22 @@
//
//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
+// LoongArch specific DAG Nodes.
+//===----------------------------------------------------------------------===//
+
+def SDT_LoongArchMOVGR2FR_W_LA64
+ : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i64>]>;
+def SDT_LoongArchMOVFR2GR_S_LA64
+ : SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, f32>]>;
+def SDT_LoongArchFTINT : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisFP<1>]>;
+
+def loongarch_movgr2fr_w_la64
+ : SDNode<"LoongArchISD::MOVGR2FR_W_LA64", SDT_LoongArchMOVGR2FR_W_LA64>;
+def loongarch_movfr2gr_s_la64
+ : SDNode<"LoongArchISD::MOVFR2GR_S_LA64", SDT_LoongArchMOVFR2GR_S_LA64>;
+def loongarch_ftint : SDNode<"LoongArchISD::FTINT", SDT_LoongArchFTINT>;
+
//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//
@@ -187,4 +203,26 @@ defm : StPat<store, FST_S, FPR32, f32>;
def : Pat<(f32 fpimm0), (MOVGR2FR_W R0)>;
def : Pat<(f32 fpimm0neg), (FNEG_S (MOVGR2FR_W R0))>;
def : Pat<(f32 fpimm1), (FFINT_S_W (MOVGR2FR_W (ADDI_W R0, 1)))>;
+
+// FP Conversion
+def : Pat<(loongarch_ftint FPR32:$src), (FTINTRZ_W_S FPR32:$src)>;
} // Predicates = [HasBasicF]
+
+let Predicates = [HasBasicF, IsLA64] in {
+// GPR -> FPR
+def : Pat<(loongarch_movgr2fr_w_la64 GPR:$src), (MOVGR2FR_W GPR:$src)>;
+// FPR -> GPR
+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))>;
+} // Predicates = [HasBasicF, IsLA64]
+
+let Predicates = [HasBasicF, IsLA32] in {
+// GPR -> FPR
+def : Pat<(bitconvert (i32 GPR:$src)), (MOVGR2FR_W GPR:$src)>;
+// FPR -> GPR
+def : Pat<(i32 (bitconvert FPR32:$src)), (MOVFR2GR_S FPR32:$src)>;
+// int -> f32
+def : Pat<(f32 (sint_to_fp (i32 GPR:$src))), (FFINT_S_W (MOVGR2FR_W GPR:$src))>;
+} // Predicates = [HasBasicF, IsLA64]
diff --git a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
index f6402606d9bf..b62e4d8c31ac 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
@@ -197,6 +197,17 @@ defm : LdPat<load, FLD_D, f64>;
/// Stores
defm : StPat<store, FST_D, FPR64, f64>;
+
+/// FP conversion operations
+
+def : Pat<(loongarch_ftint FPR64:$src), (FTINTRZ_W_D FPR64:$src)>;
+def : Pat<(f64 (loongarch_ftint FPR64:$src)), (FTINTRZ_L_D FPR64:$src)>;
+def : Pat<(loongarch_ftint FPR32:$src), (FTINTRZ_L_S FPR32:$src)>;
+
+// f64 -> f32
+def : Pat<(f32 (fpround FPR64:$src)), (FCVT_S_D FPR64:$src)>;
+// f32 -> f64
+def : Pat<(f64 (fpextend FPR32:$src)), (FCVT_D_S FPR32:$src)>;
} // Predicates = [HasBasicD]
/// Floating point constants
@@ -205,10 +216,23 @@ let Predicates = [HasBasicD, IsLA64] in {
def : Pat<(f64 fpimm0), (MOVGR2FR_D R0)>;
def : Pat<(f64 fpimm0neg), (FNEG_D (MOVGR2FR_D R0))>;
def : Pat<(f64 fpimm1), (FFINT_D_L (MOVGR2FR_D (ADDI_D R0, 1)))>;
+
+// Convert int to FP
+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<(bitconvert GPR:$src), (MOVGR2FR_D GPR:$src)>;
+
+// Convert FP to int
+def : Pat<(bitconvert FPR64:$src), (MOVFR2GR_D FPR64:$src)>;
} // Predicates = [HasBasicD, IsLA64]
let Predicates = [HasBasicD, IsLA32] in {
def : Pat<(f64 fpimm0), (MOVGR2FRH_W (MOVGR2FR_W_64 R0), R0)>;
def : Pat<(f64 fpimm0neg), (FNEG_D (MOVGR2FRH_W (MOVGR2FR_W_64 R0), R0))>;
def : Pat<(f64 fpimm1), (FCVT_D_S (FFINT_S_W (MOVGR2FR_W (ADDI_W R0, 1))))>;
+
+// Convert int to FP
+def : Pat<(f64 (sint_to_fp (i32 GPR:$src))), (FFINT_D_W (MOVGR2FR_W GPR:$src))>;
} // Predicates = [HasBasicD, IsLA32]
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp
index c58ddc293507..a9df0c9bce6c 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp
@@ -146,6 +146,21 @@ bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
return true;
}
+bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) {
+ if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
+ cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
+ Val = N.getOperand(0);
+ return true;
+ }
+ MVT VT = N.getSimpleValueType();
+ if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
+ Val = N;
+ return true;
+ }
+
+ return false;
+}
+
// This pass converts a legalized DAG into a LoongArch-specific DAG, ready
// for instruction scheduling.
FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) {
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h
index c41893f148c4..3392ec7fe929 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h
@@ -48,6 +48,8 @@ class LoongArchDAGToDAGISel : public SelectionDAGISel {
return selectShiftMask(N, 32, ShAmt);
}
+ bool selectSExti32(SDValue N, SDValue &Val);
+
// Include the pieces autogenerated from the target description.
#include "LoongArchGenDAGISel.inc"
};
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 41ccbdfdb86d..beeb072d2172 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -50,6 +50,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SHL_PARTS, GRLenVT, Custom);
setOperationAction(ISD::SRA_PARTS, GRLenVT, Custom);
setOperationAction(ISD::SRL_PARTS, GRLenVT, Custom);
+ setOperationAction(ISD::FP_TO_SINT, GRLenVT, Custom);
setOperationAction({ISD::GlobalAddress, ISD::ConstantPool}, GRLenVT, Custom);
@@ -57,6 +58,8 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SHL, MVT::i32, Custom);
setOperationAction(ISD::SRA, MVT::i32, Custom);
setOperationAction(ISD::SRL, MVT::i32, Custom);
+ setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
+ setOperationAction(ISD::BITCAST, MVT::i32, Custom);
}
static const ISD::CondCode FPCCToExpand[] = {ISD::SETOGT, ISD::SETOGE,
@@ -70,6 +73,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
+ setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
}
setOperationAction(ISD::BR_CC, GRLenVT, Expand);
@@ -117,9 +121,44 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
return SDValue();
case ISD::ConstantPool:
return lowerConstantPool(Op, DAG);
+ case ISD::FP_TO_SINT:
+ return lowerFP_TO_SINT(Op, DAG);
+ case ISD::BITCAST:
+ return lowerBITCAST(Op, DAG);
}
}
+SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
+ SelectionDAG &DAG) const {
+
+ SDLoc DL(Op);
+ SDValue Op0 = Op.getOperand(0);
+
+ if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 &&
+ Subtarget.is64Bit() && Subtarget.hasBasicF()) {
+ SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
+ return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
+ }
+ return Op;
+}
+
+SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
+ SelectionDAG &DAG) const {
+
+ SDLoc DL(Op);
+
+ if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
+ !Subtarget.hasBasicD()) {
+ SDValue Dst =
+ DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0));
+ return DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Dst);
+ }
+
+ EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
+ SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0));
+ return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
+}
+
SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
@@ -299,6 +338,27 @@ void LoongArchTargetLowering::ReplaceNodeResults(
break;
}
break;
+ case ISD::FP_TO_SINT: {
+ assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
+ "Unexpected custom legalisation");
+ SDValue Src = N->getOperand(0);
+ EVT VT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
+ SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, VT, Src);
+ Results.push_back(DAG.getNode(ISD::BITCAST, DL, N->getValueType(0), Dst));
+ break;
+ }
+ case ISD::BITCAST: {
+ EVT VT = N->getValueType(0);
+ SDValue Src = N->getOperand(0);
+ EVT SrcVT = Src.getValueType();
+ if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
+ Subtarget.hasBasicF()) {
+ SDValue Dst =
+ DAG.getNode(LoongArchISD::MOVFR2GR_S_LA64, DL, MVT::i64, Src);
+ Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
+ }
+ break;
+ }
}
}
@@ -484,6 +544,9 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(SRA_W)
NODE_NAME_CASE(SRL_W)
NODE_NAME_CASE(BSTRPICK)
+ NODE_NAME_CASE(MOVGR2FR_W_LA64)
+ NODE_NAME_CASE(MOVFR2GR_S_LA64)
+ NODE_NAME_CASE(FTINT)
}
#undef NODE_NAME_CASE
return nullptr;
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 6e4747a5f940..186348460521 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -35,6 +35,12 @@ enum NodeType : unsigned {
SRA_W,
SRL_W,
+ // FPR<->GPR transfer operations
+ MOVGR2FR_W_LA64,
+ MOVFR2GR_S_LA64,
+
+ FTINT,
+
BSTRPICK,
};
@@ -97,6 +103,8 @@ class LoongArchTargetLowering : public TargetLowering {
EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const override;
SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
+ SDValue lowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const;
+ SDValue lowerBITCAST(SDValue Op, SelectionDAG &DAG) const;
bool isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const override;
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index db5e0b59f83c..fd1fa13147e1 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -590,6 +590,8 @@ def shiftMaskGRLen
: ComplexPattern<GRLenVT, 1, "selectShiftMaskGRLen", [], [], 0>;
def shiftMask32 : ComplexPattern<i64, 1, "selectShiftMask32", [], [], 0>;
+def sexti32 : ComplexPattern<i64, 1, "selectSExti32">;
+
class shiftop<SDPatternOperator operator>
: PatFrag<(ops node:$val, node:$count),
(operator node:$val, (GRLenVT (shiftMaskGRLen node:$count)))>;
diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
new file mode 100644
index 000000000000..0f8abab2b1be
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll
@@ -0,0 +1,173 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch32 --mattr=+d < %s | FileCheck %s --check-prefix=LA32
+; RUN: llc --mtriple=loongarch64 --mattr=+d < %s | FileCheck %s --check-prefix=LA64
+
+define float @convert_double_to_float(double %a) nounwind {
+; LA32-LABEL: convert_double_to_float:
+; LA32: # %bb.0:
+; LA32-NEXT: fcvt.s.d $fa0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_double_to_float:
+; LA64: # %bb.0:
+; LA64-NEXT: fcvt.s.d $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = fptrunc double %a to float
+ ret float %1
+}
+
+define double @convert_float_to_double(float %a) nounwind {
+; LA32-LABEL: convert_float_to_double:
+; LA32: # %bb.0:
+; LA32-NEXT: fcvt.d.s $fa0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_float_to_double:
+; LA64: # %bb.0:
+; LA64-NEXT: fcvt.d.s $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = fpext float %a to double
+ ret double %1
+}
+
+define double @convert_i8_to_double(i8 signext %a) nounwind {
+; LA32-LABEL: convert_i8_to_double:
+; LA32: # %bb.0:
+; LA32-NEXT: movgr2fr.w $fa0, $a0
+; LA32-NEXT: ffint.d.w $fa0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_i8_to_double:
+; LA64: # %bb.0:
+; LA64-NEXT: movgr2fr.w $fa0, $a0
+; LA64-NEXT: ffint.d.w $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = sitofp i8 %a to double
+ ret double %1
+}
+
+define double @convert_i16_to_double(i16 signext %a) nounwind {
+; LA32-LABEL: convert_i16_to_double:
+; LA32: # %bb.0:
+; LA32-NEXT: movgr2fr.w $fa0, $a0
+; LA32-NEXT: ffint.d.w $fa0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_i16_to_double:
+; LA64: # %bb.0:
+; LA64-NEXT: movgr2fr.w $fa0, $a0
+; LA64-NEXT: ffint.d.w $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = sitofp i16 %a to double
+ ret double %1
+}
+
+define double @convert_i32_to_double(i32 %a) nounwind {
+; LA32-LABEL: convert_i32_to_double:
+; LA32: # %bb.0:
+; LA32-NEXT: movgr2fr.w $fa0, $a0
+; LA32-NEXT: ffint.d.w $fa0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_i32_to_double:
+; LA64: # %bb.0:
+; LA64-NEXT: movgr2fr.w $fa0, $a0
+; LA64-NEXT: ffint.d.w $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = sitofp i32 %a to double
+ ret double %1
+}
+
+define double @convert_i64_to_double(i64 %a) nounwind {
+; LA32-LABEL: convert_i64_to_double:
+; LA32: # %bb.0:
+; LA32-NEXT: addi.w $sp, $sp, -16
+; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32-NEXT: bl __floatdidf
+; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32-NEXT: addi.w $sp, $sp, 16
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_i64_to_double:
+; LA64: # %bb.0:
+; LA64-NEXT: movgr2fr.d $fa0, $a0
+; LA64-NEXT: ffint.d.l $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = sitofp i64 %a to double
+ ret double %1
+}
+
+define i32 @convert_double_to_i32(double %a) nounwind {
+; LA32-LABEL: convert_double_to_i32:
+; LA32: # %bb.0:
+; LA32-NEXT: ftintrz.w.d $fa0, $fa0
+; LA32-NEXT: movfr2gr.s $a0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_double_to_i32:
+; LA64: # %bb.0:
+; LA64-NEXT: ftintrz.w.d $fa0, $fa0
+; LA64-NEXT: movfr2gr.s $a0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = fptosi double %a to i32
+ ret i32 %1
+}
+
+define i64 @convert_double_to_i64(double %a) nounwind {
+; LA32-LABEL: convert_double_to_i64:
+; LA32: # %bb.0:
+; LA32-NEXT: addi.w $sp, $sp, -16
+; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32-NEXT: bl __fixdfdi
+; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32-NEXT: addi.w $sp, $sp, 16
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_double_to_i64:
+; LA64: # %bb.0:
+; LA64-NEXT: ftintrz.l.d $fa0, $fa0
+; LA64-NEXT: movfr2gr.d $a0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = fptosi double %a to i64
+ ret i64 %1
+}
+
+define i64 @bitcast_double_to_i64(double %a) nounwind {
+; LA32-LABEL: bitcast_double_to_i64:
+; LA32: # %bb.0:
+; LA32-NEXT: addi.w $sp, $sp, -16
+; LA32-NEXT: fst.d $fa0, $sp, 8
+; LA32-NEXT: addi.w $a0, $sp, 8
+; LA32-NEXT: ori $a0, $a0, 4
+; LA32-NEXT: ld.w $a1, $a0, 0
+; LA32-NEXT: ld.w $a0, $sp, 8
+; LA32-NEXT: addi.w $sp, $sp, 16
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: bitcast_double_to_i64:
+; LA64: # %bb.0:
+; LA64-NEXT: movfr2gr.d $a0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = bitcast double %a to i64
+ ret i64 %1
+}
+
+define double @bitcast_i64_to_double(i64 %a) nounwind {
+; LA32-LABEL: bitcast_i64_to_double:
+; LA32: # %bb.0:
+; LA32-NEXT: addi.w $sp, $sp, -16
+; LA32-NEXT: addi.w $a2, $sp, 8
+; LA32-NEXT: ori $a2, $a2, 4
+; LA32-NEXT: st.w $a1, $a2, 0
+; LA32-NEXT: st.w $a0, $sp, 8
+; LA32-NEXT: fld.d $fa0, $sp, 8
+; LA32-NEXT: addi.w $sp, $sp, 16
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: bitcast_i64_to_double:
+; LA64: # %bb.0:
+; LA64-NEXT: movgr2fr.d $fa0, $a0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = bitcast i64 %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
new file mode 100644
index 000000000000..32a0c369cc40
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll
@@ -0,0 +1,166 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch32 --mattr=+f,-d < %s | FileCheck %s --check-prefix=LA32
+; RUN: llc --mtriple=loongarch64 --mattr=+f,-d < %s | FileCheck %s --check-prefix=LA64
+
+define signext i8 @convert_float_to_i8(float %a) nounwind {
+; LA32-LABEL: convert_float_to_i8:
+; LA32: # %bb.0:
+; LA32-NEXT: ftintrz.w.s $fa0, $fa0
+; LA32-NEXT: movfr2gr.s $a0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_float_to_i8:
+; LA64: # %bb.0:
+; LA64-NEXT: ftintrz.w.s $fa0, $fa0
+; LA64-NEXT: movfr2gr.s $a0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = fptosi float %a to i8
+ ret i8 %1
+}
+
+define signext i16 @convert_float_to_i16(float %a) nounwind {
+; LA32-LABEL: convert_float_to_i16:
+; LA32: # %bb.0:
+; LA32-NEXT: ftintrz.w.s $fa0, $fa0
+; LA32-NEXT: movfr2gr.s $a0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_float_to_i16:
+; LA64: # %bb.0:
+; LA64-NEXT: ftintrz.w.s $fa0, $fa0
+; LA64-NEXT: movfr2gr.s $a0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = fptosi float %a to i16
+ ret i16 %1
+}
+
+define i32 @convert_float_to_i32(float %a) nounwind {
+; LA32-LABEL: convert_float_to_i32:
+; LA32: # %bb.0:
+; LA32-NEXT: ftintrz.w.s $fa0, $fa0
+; LA32-NEXT: movfr2gr.s $a0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_float_to_i32:
+; LA64: # %bb.0:
+; LA64-NEXT: ftintrz.w.s $fa0, $fa0
+; LA64-NEXT: movfr2gr.s $a0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = fptosi float %a to i32
+ ret i32 %1
+}
+
+define i64 @convert_float_to_i64(float %a) nounwind {
+; LA32-LABEL: convert_float_to_i64:
+; LA32: # %bb.0:
+; LA32-NEXT: addi.w $sp, $sp, -16
+; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32-NEXT: bl __fixsfdi
+; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32-NEXT: addi.w $sp, $sp, 16
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_float_to_i64:
+; LA64: # %bb.0:
+; LA64-NEXT: ftintrz.w.s $fa0, $fa0
+; LA64-NEXT: movfr2gr.s $a0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = fptosi float %a to i64
+ ret i64 %1
+}
+
+define float @convert_i8_to_float(i8 signext %a) nounwind {
+; LA32-LABEL: convert_i8_to_float:
+; LA32: # %bb.0:
+; LA32-NEXT: movgr2fr.w $fa0, $a0
+; LA32-NEXT: ffint.s.w $fa0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_i8_to_float:
+; LA64: # %bb.0:
+; LA64-NEXT: movgr2fr.w $fa0, $a0
+; LA64-NEXT: ffint.s.w $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = sitofp i8 %a to float
+ ret float %1
+}
+
+define float @convert_i16_to_float(i16 signext %a) nounwind {
+; LA32-LABEL: convert_i16_to_float:
+; LA32: # %bb.0:
+; LA32-NEXT: movgr2fr.w $fa0, $a0
+; LA32-NEXT: ffint.s.w $fa0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_i16_to_float:
+; LA64: # %bb.0:
+; LA64-NEXT: movgr2fr.w $fa0, $a0
+; LA64-NEXT: ffint.s.w $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = sitofp i16 %a to float
+ ret float %1
+}
+
+define float @convert_i32_to_float(i32 %a) nounwind {
+; LA32-LABEL: convert_i32_to_float:
+; LA32: # %bb.0:
+; LA32-NEXT: movgr2fr.w $fa0, $a0
+; LA32-NEXT: ffint.s.w $fa0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_i32_to_float:
+; LA64: # %bb.0:
+; LA64-NEXT: addi.w $a0, $a0, 0
+; LA64-NEXT: movgr2fr.w $fa0, $a0
+; LA64-NEXT: ffint.s.w $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = sitofp i32 %a to float
+ ret float %1
+}
+
+define float @convert_i64_to_float(i64 %a) nounwind {
+; LA32-LABEL: convert_i64_to_float:
+; LA32: # %bb.0:
+; LA32-NEXT: addi.w $sp, $sp, -16
+; LA32-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32-NEXT: bl __floatdisf
+; LA32-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32-NEXT: addi.w $sp, $sp, 16
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: convert_i64_to_float:
+; LA64: # %bb.0:
+; LA64-NEXT: movgr2fr.w $fa0, $a0
+; LA64-NEXT: ffint.s.w $fa0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = sitofp i64 %a to float
+ ret float %1
+}
+
+define i32 @bitcast_float_to_i32(float %a) nounwind {
+; LA32-LABEL: bitcast_float_to_i32:
+; LA32: # %bb.0:
+; LA32-NEXT: movfr2gr.s $a0, $fa0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: bitcast_float_to_i32:
+; LA64: # %bb.0:
+; LA64-NEXT: movfr2gr.s $a0, $fa0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = bitcast float %a to i32
+ ret i32 %1
+}
+
+define float @bitcast_i32_to_float(i32 %a) nounwind {
+; LA32-LABEL: bitcast_i32_to_float:
+; LA32: # %bb.0:
+; LA32-NEXT: movgr2fr.w $fa0, $a0
+; LA32-NEXT: jirl $zero, $ra, 0
+;
+; LA64-LABEL: bitcast_i32_to_float:
+; LA64: # %bb.0:
+; LA64-NEXT: movgr2fr.w $fa0, $a0
+; LA64-NEXT: jirl $zero, $ra, 0
+ %1 = bitcast i32 %a to float
+ ret float %1
+}
More information about the llvm-commits
mailing list