[llvm] 78f5014 - [Hexagon] Conversions to/from FP types, HVX and scalar

Krzysztof Parzyszek via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 4 11:04:14 PST 2022


Author: Krzysztof Parzyszek
Date: 2022-01-04T11:03:51-08:00
New Revision: 78f5014fea9d1d19bcf175d2e57f530c223794e0

URL: https://github.com/llvm/llvm-project/commit/78f5014fea9d1d19bcf175d2e57f530c223794e0
DIFF: https://github.com/llvm/llvm-project/commit/78f5014fea9d1d19bcf175d2e57f530c223794e0.diff

LOG: [Hexagon] Conversions to/from FP types, HVX and scalar

Co-authored-by: Anirudh Sundar Subramaniam <quic_sanirudh at quicinc.com>
Co-authored-by: Sumanth Gundapaneni <sgundapa at quicinc.com>

Added: 
    llvm/test/CodeGen/Hexagon/autohvx/conv-fp-fp.ll
    llvm/test/CodeGen/Hexagon/autohvx/conv-fp-int-ieee.ll
    llvm/test/CodeGen/Hexagon/fp16.ll

Modified: 
    llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
    llvm/lib/Target/Hexagon/HexagonISelLowering.h
    llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
    llvm/lib/Target/Hexagon/HexagonPatterns.td
    llvm/lib/Target/Hexagon/HexagonPatternsHVX.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
index 01fcbba7f8fba..699a818c887b4 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
@@ -1772,6 +1772,18 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
   setOperationAction(ISD::SINT_TO_FP, MVT::i8,  Promote);
   setOperationAction(ISD::SINT_TO_FP, MVT::i16, Promote);
 
+  // Special handling for half-precision floating point conversions.
+  // Lower half float conversions into library calls.
+  setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
+  setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand);
+  setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
+  setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand);
+
+  setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand);
+  setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand);
+  setTruncStoreAction(MVT::f32, MVT::f16, Expand);
+  setTruncStoreAction(MVT::f64, MVT::f16, Expand);
+
   // Handling of indexed loads/stores: default is "expand".
   //
   for (MVT VT : {MVT::i8, MVT::i16, MVT::i32, MVT::i64, MVT::f32, MVT::f64,
@@ -1852,6 +1864,11 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
   else
     setLibcallName(RTLIB::SQRT_F32, "__hexagon_sqrtf");
 
+  // Routines to handle fp16 storage type.
+  setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
+  setLibcallName(RTLIB::FPROUND_F64_F16, "__truncdfhf2");
+  setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
+
   // These cause problems when the shift amount is non-constant.
   setLibcallName(RTLIB::SHL_I128, nullptr);
   setLibcallName(RTLIB::SRL_I128, nullptr);

diff  --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
index a31a697b73170..f9ce7a9407aaf 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h
@@ -476,6 +476,8 @@ class HexagonTargetLowering : public TargetLowering {
   SDValue LowerHvxShift(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerHvxIntrinsic(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerHvxMaskedOp(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerHvxFpExtend(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerHvxConvertFpInt(SDValue Op, SelectionDAG &DAG) const;
 
   SDValue SplitHvxPairOp(SDValue Op, SelectionDAG &DAG) const;
   SDValue SplitHvxMemOp(SDValue Op, SelectionDAG &DAG) const;

diff  --git a/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
index a65ceccb60a17..1f2e5dc43439a 100755
--- a/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
@@ -139,6 +139,14 @@ HexagonTargetLowering::initializeHVXLowering() {
     setOperationAction(ISD::FMAXNUM, MVT::v64f32, Custom);
     setOperationAction(ISD::VSELECT, MVT::v64f32, Custom);
 
+    if (Subtarget.useHVXQFloatOps()) {
+      setOperationAction(ISD::FP_EXTEND, MVT::v64f32, Custom);
+      setOperationAction(ISD::FP_ROUND, MVT::v64f16, Legal);
+    } else if (Subtarget.useHVXIEEEFPOps()) {
+      setOperationAction(ISD::FP_EXTEND, MVT::v64f32, Legal);
+      setOperationAction(ISD::FP_ROUND, MVT::v64f16, Legal);
+    }
+
     setOperationAction(ISD::MLOAD, MVT::v32f32, Custom);
     setOperationAction(ISD::MSTORE, MVT::v32f32, Custom);
     setOperationAction(ISD::MLOAD, MVT::v64f16, Custom);
@@ -201,6 +209,18 @@ HexagonTargetLowering::initializeHVXLowering() {
       setPromoteTo(ISD::VECTOR_SHUFFLE, T, ByteV);
     }
 
+    if (Subtarget.useHVXQFloatOps()) {
+      setOperationAction(ISD::SINT_TO_FP, T, Expand);
+      setOperationAction(ISD::UINT_TO_FP, T, Expand);
+      setOperationAction(ISD::FP_TO_SINT, T, Expand);
+      setOperationAction(ISD::FP_TO_UINT, T, Expand);
+    } else if (Subtarget.useHVXIEEEFPOps()) {
+      setOperationAction(ISD::SINT_TO_FP, T, Custom);
+      setOperationAction(ISD::UINT_TO_FP, T, Custom);
+      setOperationAction(ISD::FP_TO_SINT, T, Custom);
+      setOperationAction(ISD::FP_TO_UINT, T, Custom);
+    }
+
     setCondCodeAction(ISD::SETNE,  T, Expand);
     setCondCodeAction(ISD::SETLE,  T, Expand);
     setCondCodeAction(ISD::SETGE,  T, Expand);
@@ -262,6 +282,11 @@ HexagonTargetLowering::initializeHVXLowering() {
       setOperationAction(ISD::UMIN,   T, Custom);
       setOperationAction(ISD::UMAX,   T, Custom);
     }
+
+    setOperationAction(ISD::SINT_TO_FP, T, Custom);
+    setOperationAction(ISD::UINT_TO_FP, T, Custom);
+    setOperationAction(ISD::FP_TO_SINT, T, Custom);
+    setOperationAction(ISD::FP_TO_UINT, T, Custom);
   }
 
   setCondCodeAction(ISD::SETNE,  MVT::v64f16, Expand);
@@ -1992,6 +2017,81 @@ HexagonTargetLowering::LowerHvxMaskedOp(SDValue Op, SelectionDAG &DAG) const {
   return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, {StoreLo, StoreHi});
 }
 
+SDValue HexagonTargetLowering::LowerHvxFpExtend(SDValue Op,
+                                                SelectionDAG &DAG) const {
+  // This conversion only applies to QFloat.
+  assert(Subtarget.useHVXQFloatOps());
+
+  unsigned Opc = Op->getOpcode();
+  assert(Opc == ISD::FP_EXTEND);
+
+  MVT VecTy = ty(Op);
+  MVT ArgTy = ty(Op.getOperand(0));
+  const SDLoc &dl(Op);
+  assert(VecTy == MVT::v64f32 && ArgTy == MVT::v64f16);
+
+  SDValue F16Vec = Op.getOperand(0);
+
+  APFloat FloatVal = APFloat(1.0f);
+  bool Ignored;
+  FloatVal.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven, &Ignored);
+  SDValue Fp16Ones = DAG.getConstantFP(FloatVal, dl, ArgTy);
+  SDValue VmpyVec =
+      getInstr(Hexagon::V6_vmpy_qf32_hf, dl, VecTy, {F16Vec, Fp16Ones}, DAG);
+
+  MVT HalfTy = typeSplit(VecTy).first;
+  VectorPair Pair = opSplit(VmpyVec, dl, DAG);
+  SDValue LoVec =
+      getInstr(Hexagon::V6_vconv_sf_qf32, dl, HalfTy, {Pair.first}, DAG);
+  SDValue HiVec =
+      getInstr(Hexagon::V6_vconv_sf_qf32, dl, HalfTy, {Pair.second}, DAG);
+
+  SDValue ShuffVec =
+      getInstr(Hexagon::V6_vshuffvdd, dl, VecTy,
+               {HiVec, LoVec, DAG.getConstant(-4, dl, MVT::i32)}, DAG);
+
+  return ShuffVec;
+}
+
+SDValue
+HexagonTargetLowering::LowerHvxConvertFpInt(SDValue Op, SelectionDAG &DAG)
+    const {
+  // This conversion only applies to IEEE.
+  assert(Subtarget.useHVXIEEEFPOps());
+
+  unsigned Opc = Op.getOpcode();
+  // Catch invalid conversion ops (just in case).
+  assert(Opc == ISD::FP_TO_SINT || Opc == ISD::FP_TO_UINT ||
+         Opc == ISD::SINT_TO_FP || Opc == ISD::UINT_TO_FP);
+  MVT ResTy = ty(Op);
+
+  if (Opc == ISD::FP_TO_SINT || Opc == ISD::FP_TO_UINT) {
+    MVT FpTy = ty(Op.getOperand(0)).getVectorElementType();
+    // There are only conversions of f16.
+    if (FpTy != MVT::f16)
+      return SDValue();
+
+    MVT IntTy = ResTy.getVectorElementType();
+    // Other int types aren't legal in HVX, so we shouldn't see them here.
+    assert(IntTy == MVT::i8 || IntTy == MVT::i16 || IntTy == MVT::i32);
+    // Conversions to i8 and i16 are legal.
+    if (IntTy == MVT::i8 || IntTy == MVT::i16)
+      return Op;
+  } else {
+    // Converting int -> fp.
+    if (ResTy.getVectorElementType() != MVT::f16)
+      return SDValue();
+    MVT IntTy = ty(Op.getOperand(0)).getVectorElementType();
+    // Other int types aren't legal in HVX, so we shouldn't see them here.
+    assert(IntTy == MVT::i8 || IntTy == MVT::i16 || IntTy == MVT::i32);
+    // i8, i16 -> f16 is legal.
+    if (IntTy == MVT::i8 || IntTy == MVT::i16)
+      return Op;
+  }
+
+  return SDValue();
+}
+
 SDValue
 HexagonTargetLowering::SplitHvxPairOp(SDValue Op, SelectionDAG &DAG) const {
   assert(!Op.isMachineOpcode());
@@ -2296,6 +2396,13 @@ HexagonTargetLowering::LowerHvxOperation(SDValue Op, SelectionDAG &DAG) const {
       case ISD::MLOAD:
       case ISD::MSTORE:
         return SplitHvxMemOp(Op, DAG);
+      case ISD::SINT_TO_FP:
+      case ISD::UINT_TO_FP:
+      case ISD::FP_TO_SINT:
+      case ISD::FP_TO_UINT:
+        if (ty(Op).getSizeInBits() == ty(Op.getOperand(0)).getSizeInBits())
+          return SplitHvxPairOp(Op, DAG);
+        break;
       case ISD::CTPOP:
       case ISD::CTLZ:
       case ISD::CTTZ:
@@ -2356,6 +2463,11 @@ HexagonTargetLowering::LowerHvxOperation(SDValue Op, SelectionDAG &DAG) const {
     case ISD::MSTORE:                  return LowerHvxMaskedOp(Op, DAG);
     // Unaligned loads will be handled by the default lowering.
     case ISD::LOAD:                    return SDValue();
+    case ISD::FP_EXTEND:               return LowerHvxFpExtend(Op, DAG);
+    case ISD::FP_TO_SINT:
+    case ISD::FP_TO_UINT:
+    case ISD::SINT_TO_FP:
+    case ISD::UINT_TO_FP:              return LowerHvxConvertFpInt(Op, DAG);
   }
 #ifndef NDEBUG
   Op.dumpr(&DAG);

diff  --git a/llvm/lib/Target/Hexagon/HexagonPatterns.td b/llvm/lib/Target/Hexagon/HexagonPatterns.td
index 9b21eb98e2c8a..cab59626a600c 100644
--- a/llvm/lib/Target/Hexagon/HexagonPatterns.td
+++ b/llvm/lib/Target/Hexagon/HexagonPatterns.td
@@ -369,6 +369,12 @@ def Umin: pf2<umin>;  def Umax: pf2<umax>;
 
 def Rol: pf2<rotl>;
 
+def Fptosi: pf1<fp_to_sint>;
+def Fptoui: pf1<fp_to_uint>;
+def Sitofp: pf1<sint_to_fp>;
+def Uitofp: pf1<uint_to_fp>;
+
+
 // --(1) Immediate -------------------------------------------------------
 //
 

diff  --git a/llvm/lib/Target/Hexagon/HexagonPatternsHVX.td b/llvm/lib/Target/Hexagon/HexagonPatternsHVX.td
index 33bf8ed71a9cb..2e739d6e06f85 100644
--- a/llvm/lib/Target/Hexagon/HexagonPatternsHVX.td
+++ b/llvm/lib/Target/Hexagon/HexagonPatternsHVX.td
@@ -476,11 +476,11 @@ let Predicates = [UseHVXV68, UseHVXQFloat] in {
   // since the qfloat arithmetic instructions above always generate the
   // accompanying conversions as part of their pattern
   def: Pat<(VecF16 (pf1<fpround> HWF32:$Vuu)),
-          (V6_vdealh (V6_vconv_hf_qf32
-              (VecPF32 (Combinev (V6_vadd_sf (HiVec HvxWR:$Vuu), (V6_vd0)),
-                                 (V6_vadd_sf (LoVec HvxWR:$Vuu), (V6_vd0))
-              ))))>;
-
+           (V6_vdealh (V6_vconv_hf_qf32
+             (VecPF32 (Combinev (V6_vadd_sf (HiVec HvxWR:$Vuu), (V6_vd0)),
+                                (V6_vadd_sf (LoVec HvxWR:$Vuu), (V6_vd0))
+             ))))>;
+  // fpextend for QFloat is handled manually in HexagonISelLoweringHVX.cpp.
 }
 
 // HVX IEEE arithmetic Instructions
@@ -497,6 +497,23 @@ let Predicates = [UseHVXV68, UseHVXIEEEFP] in {
            (V6_vmpy_hf_hf HVF16:$Rs, HVF16:$Rt)>;
   def: Pat<(fmul HVF32:$Rs, HVF32:$Rt),
            (V6_vmpy_sf_sf HVF32:$Rs, HVF32:$Rt)>;
+
+  def: Pat<(VecF16 (pf1<fpround> HWF32:$Vuu)),
+           (V6_vdealh (V6_vcvt_hf_sf (HiVec HvxWR:$Vuu), (LoVec HvxWR:$Vuu)))>;
+  def: Pat<(VecPF32 (pf1<fpextend> HVF16:$Vu)),
+           (V6_vcvt_sf_hf (V6_vshuffh HvxVR:$Vu))>;
+
+  def: OpR_R_pat<V6_vcvt_h_hf,  Fptosi, VecI16, HVF16>;
+  def: OpR_R_pat<V6_vcvt_uh_hf, Fptoui, VecI16, HVF16>;
+  def: OpR_R_pat<V6_vcvt_hf_h,  Sitofp, VecF16, HVI16>;
+  def: OpR_R_pat<V6_vcvt_hf_uh, Uitofp, VecF16, HVI16>;
+
+  def: Pat<(VecI8 (Fptosi HWF16:$Vu)),
+           (V6_vcvt_b_hf (HiVec $Vu), (LoVec $Vu))>;
+  def: Pat<(VecI8 (Fptoui HWF16:$Vu)),
+           (V6_vcvt_ub_hf (HiVec $Vu), (LoVec $Vu))>;
+  def: Pat<(VecPF16 (Sitofp HVI8:$Vu)), (V6_vcvt_hf_b HvxVR:$Vu)>;
+  def: Pat<(VecPF16 (Uitofp HVI8:$Vu)), (V6_vcvt_hf_ub HvxVR:$Vu)>;
 }
 
 let Predicates = [UseHVXV68, UseHVXFloatingPoint] in {

diff  --git a/llvm/test/CodeGen/Hexagon/autohvx/conv-fp-fp.ll b/llvm/test/CodeGen/Hexagon/autohvx/conv-fp-fp.ll
new file mode 100644
index 0000000000000..f5096ea9128fb
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/autohvx/conv-fp-fp.ll
@@ -0,0 +1,87 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -march=hexagon < %s | FileCheck %s
+
+define <64 x half> @f0(<64 x float> %a0) #0 {
+; CHECK-LABEL: f0:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v2 = vxor(v2,v2)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.qf32 = vadd(v0.sf,v2.sf)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v1.qf32 = vadd(v1.sf,v2.sf)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.hf = v1:0.qf32
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.h = vdeal(v0.h)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = fptrunc <64 x float> %a0 to <64 x half>
+  ret <64 x half> %v0
+}
+
+define <64 x float> @f1(<64 x half> %a0) #0 {
+; CHECK-LABEL: f1:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r0 = #15360
+; CHECK-NEXT:     r7 = #-4
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v1.h = vsplat(r0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v1:0.qf32 = vmpy(v0.hf,v1.hf)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.sf = v0.qf32
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v1.sf = v1.qf32
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v1:0 = vshuff(v1,v0,r7)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = fpext <64 x half> %a0 to <64 x float>
+  ret <64 x float> %v0
+}
+
+define <64 x half> @f2(<64 x float> %a0) #1 {
+; CHECK-LABEL: f2:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.hf = vcvt(v1.sf,v0.sf)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.h = vdeal(v0.h)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = fptrunc <64 x float> %a0 to <64 x half>
+  ret <64 x half> %v0
+}
+
+define <64 x float> @f3(<64 x half> %a0) #1 {
+; CHECK-LABEL: f3:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.h = vshuff(v0.h)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v1:0.sf = vcvt(v0.hf)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = fpext <64 x half> %a0 to <64 x float>
+  ret <64 x float> %v0
+}
+
+attributes #0 = { nounwind "target-features"="+hvxv69,+hvx-length128b,+hvx-qfloat" }
+attributes #1 = { nounwind "target-features"="+hvxv69,+hvx-length128b,+hvx-ieee-fp,-hvx-qfloat" }

diff  --git a/llvm/test/CodeGen/Hexagon/autohvx/conv-fp-int-ieee.ll b/llvm/test/CodeGen/Hexagon/autohvx/conv-fp-int-ieee.ll
new file mode 100644
index 0000000000000..889b4b3fbabf2
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/autohvx/conv-fp-int-ieee.ll
@@ -0,0 +1,100 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -march=hexagon < %s | FileCheck %s
+
+define <64 x i16> @f0(<64 x half> %a0) #0 {
+; CHECK-LABEL: f0:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.h = vcvt(v0.hf)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = fptosi <64 x half> %a0 to <64 x i16>
+  ret <64 x i16> %v0
+}
+
+define <64 x i16> @f1(<64 x half> %a0) #0 {
+; CHECK-LABEL: f1:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.uh = vcvt(v0.hf)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = fptoui <64 x half> %a0 to <64 x i16>
+  ret <64 x i16> %v0
+}
+
+define <128 x i8> @f2(<128 x half> %a0) #0 {
+; CHECK-LABEL: f2:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.b = vcvt(v1.hf,v0.hf)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = fptosi <128 x half> %a0 to <128 x i8>
+  ret <128 x i8> %v0
+}
+
+define <128 x i8> @f3(<128 x half> %a0) #0 {
+; CHECK-LABEL: f3:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.ub = vcvt(v1.hf,v0.hf)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = fptoui <128 x half> %a0 to <128 x i8>
+  ret <128 x i8> %v0
+}
+
+define <64 x half> @f4(<64 x i16> %a0) #0 {
+; CHECK-LABEL: f4:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.hf = vcvt(v0.h)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = sitofp <64 x i16> %a0 to <64 x half>
+  ret <64 x half> %v0
+}
+
+define <64 x half> @f5(<64 x i16> %a0) #0 {
+; CHECK-LABEL: f5:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0.hf = vcvt(v0.uh)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = uitofp <64 x i16> %a0 to <64 x half>
+  ret <64 x half> %v0
+}
+
+define <128 x half> @f6(<128 x i8> %a0) #0 {
+; CHECK-LABEL: f6:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v1:0.hf = vcvt(v0.b)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = sitofp <128 x i8> %a0 to <128 x half>
+  ret <128 x half> %v0
+}
+
+define <128 x half> @f7(<128 x i8> %a0) #0 {
+; CHECK-LABEL: f7:
+; CHECK:       // %bb.0: // %b0
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v1:0.hf = vcvt(v0.ub)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:    }
+b0:
+  %v0 = uitofp <128 x i8> %a0 to <128 x half>
+  ret <128 x half> %v0
+}
+
+attributes #0 = { nounwind "target-features"="+hvxv69,+hvx-length128b,+hvx-ieee-fp,-hvx-qfloat" }

diff  --git a/llvm/test/CodeGen/Hexagon/fp16.ll b/llvm/test/CodeGen/Hexagon/fp16.ll
new file mode 100644
index 0000000000000..c1fd501fd51a4
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/fp16.ll
@@ -0,0 +1,76 @@
+; RUN: llc -march=hexagon < %s | FileCheck %s
+
+; This test validates the following facts for half-precision floating point
+; conversions.
+; Generate correct libcall names for conversion from fp16 to fp32.
+; (__extendhfsf2).
+;  The extension from fp16 to fp64 is implicitly handled by __extendhfsf2 and convert_sf2d.
+; (fp16->fp32->fp64).
+; Generate correcct libcall names for conversion from fp32/fp64 to fp16
+; (__truncsfhf2 and __truncdfhf2)
+; Verify that we generate loads and stores of halfword.
+
+; Validate that we generate correct lib calls to convert fp16
+
+;CHECK-LABEL: @test1
+;CHECK: call __extendhfsf2
+;CHECK: r0 = memuh
+define dso_local float @test1(i16* nocapture readonly %a) local_unnamed_addr #0 {
+entry:
+  %0 = load i16, i16* %a, align 2
+  %1 = tail call float @llvm.convert.from.fp16.f32(i16 %0)
+  ret float %1
+}
+
+;CHECK-LABEL: @test2
+;CHECK: call __extendhfsf2
+;CHECK: r0 = memuh
+;CHECK: convert_sf2d
+define dso_local double @test2(i16* nocapture readonly %a) local_unnamed_addr #0 {
+entry:
+  %0 = load i16, i16* %a, align 2
+  %1 = tail call double @llvm.convert.from.fp16.f64(i16 %0)
+  ret double %1
+}
+
+;CHECK-LABEL: @test3
+;CHECK: call __truncsfhf2
+;CHECK: memh{{.*}}= r0
+define dso_local void @test3(float %src, i16* nocapture %dst) local_unnamed_addr #0 {
+entry:
+  %0 = tail call i16 @llvm.convert.to.fp16.f32(float %src)
+  store i16 %0, i16* %dst, align 2
+  ret void
+}
+
+;CHECK-LABEL: @test4
+;CHECK: call __truncdfhf2
+;CHECK: memh{{.*}}= r0
+define dso_local void @test4(double %src, i16* nocapture %dst) local_unnamed_addr #0 {
+entry:
+  %0 = tail call i16 @llvm.convert.to.fp16.f64(double %src)
+  store i16 %0, i16* %dst, align 2
+  ret void
+}
+
+;CHECK-LABEL: @test5
+;CHECK: call __extendhfsf2
+;CHECK: call __extendhfsf2
+;CHECK: sfadd
+define dso_local float @test5(i16* nocapture readonly %a, i16* nocapture readonly %b) local_unnamed_addr #0 {
+entry:
+  %0 = load i16, i16* %a, align 2
+  %1 = tail call float @llvm.convert.from.fp16.f32(i16 %0)
+  %2 = load i16, i16* %b, align 2
+  %3 = tail call float @llvm.convert.from.fp16.f32(i16 %2)
+  %add = fadd float %1, %3
+  ret float %add
+}
+
+declare float @llvm.convert.from.fp16.f32(i16) #1
+declare double @llvm.convert.from.fp16.f64(i16) #1
+declare i16 @llvm.convert.to.fp16.f32(float) #1
+declare i16 @llvm.convert.to.fp16.f64(double) #1
+
+attributes #0 = { nounwind readonly }
+attributes #1 = { nounwind readnone }


        


More information about the llvm-commits mailing list