[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