[llvm] [Hexagon] Add an option to use fast FP to int convert for some HVX cases (PR #169562)

Fateme Hosseini via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 25 12:06:58 PST 2025


https://github.com/fhossein-quic created https://github.com/llvm/llvm-project/pull/169562

Lowering several flavors of fptosi for HVX can be done faster, but violates c/c++ convention on some arch tags. Nevertheless customers are using direct intrinsics with "incorrect" rounding mode and want compiler to do the same.

Default behavior is not changed.

Patch By: Fateme Hosseini

>From d505c490c366fb5f1e45bfb8e9b506c21e2e97d4 Mon Sep 17 00:00:00 2001
From: Sergei Larin <slarin at codeaurora.org>
Date: Thu, 10 Jul 2025 15:34:18 -0700
Subject: [PATCH] [Hexagon] Add an option to use fast FP to int convert for
 some HVX cases

Lowering several flavors of fptosi for HVX can be done faster, but violates
c/c++ convention on some arch tags. Nevertheless customers are using direct
intrinsics with "incorrect" rounding mode and want compiler to do the same.

Default behavior is not changed.

Patch By: Fateme Hosseini

Co-authored-by: Sergei Larin <slarin at qti.qualcomm.com>
---
 .../Target/Hexagon/HexagonISelLoweringHVX.cpp | 30 ++++++++++++++++++
 .../CodeGen/Hexagon/autohvx/fp-to-int_2.ll    | 31 +++++++++++++++++++
 2 files changed, 61 insertions(+)
 create mode 100644 llvm/test/CodeGen/Hexagon/autohvx/fp-to-int_2.ll

diff --git a/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
index 212a57bc7cde5..fc1f30f895f15 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
@@ -31,6 +31,10 @@ static cl::opt<unsigned> HvxWidenThreshold("hexagon-hvx-widen",
   cl::Hidden, cl::init(16),
   cl::desc("Lower threshold (in bytes) for widening to HVX vectors"));
 
+static cl::opt<bool>
+    EnableFpFastConvert("hexagon-fp-fast-convert", cl::Hidden, cl::init(false),
+                         cl::desc("Enable FP fast conversion routine."));
+
 static const MVT LegalV64[] =  { MVT::v64i8,  MVT::v32i16,  MVT::v16i32 };
 static const MVT LegalW64[] =  { MVT::v128i8, MVT::v64i16,  MVT::v32i32 };
 static const MVT LegalV128[] = { MVT::v128i8, MVT::v64i16,  MVT::v32i32 };
@@ -2970,6 +2974,32 @@ HexagonTargetLowering::ExpandHvxFpToInt(SDValue Op, SelectionDAG &DAG) const {
   MVT ResTy = ty(Op);
   assert(InpTy.changeTypeToInteger() == ResTy);
 
+  // At this point this is an experiment under a flag.
+  // In arch before V81 the rounding mode is towards nearest value.
+  // The C/C++ standard requires rounding towards zero:
+  // C (C99 and later): ISO/IEC 9899:2018 (C18), section 6.3.1.4 — "When a
+  // finite value of real floating type is converted to an integer type, the
+  // fractional part is discarded (i.e., the value is truncated toward zero)."
+  // C++: ISO/IEC 14882:2020 (C++20), section 7.3.7 — "A prvalue of a
+  // floating-point type can be converted to a prvalue of an integer type. The
+  // conversion truncates; that is, the fractional part is discarded."
+  if (InpTy == MVT::v64f16) {
+    if (Subtarget.useHVXV81Ops()) {
+      // This is c/c++ compliant
+      SDValue ConvVec =
+          getInstr(Hexagon::V6_vconv_h_hf_rnd, dl, ResTy, {Op0}, DAG);
+      return ConvVec;
+    } else if (EnableFpFastConvert) {
+      // Vd32.h=Vu32.hf same as Q6_Vh_equals_Vhf
+      SDValue ConvVec = getInstr(Hexagon::V6_vconv_h_hf, dl, ResTy, {Op0}, DAG);
+      return ConvVec;
+    }
+  } else if (EnableFpFastConvert && InpTy == MVT::v32f32) {
+    // Vd32.w=Vu32.sf same as Q6_Vw_equals_Vsf
+    SDValue ConvVec = getInstr(Hexagon::V6_vconv_w_sf, dl, ResTy, {Op0}, DAG);
+    return ConvVec;
+  }
+
   // int32_t conv_f32_to_i32(uint32_t inp) {
   //   // s | exp8 | frac23
   //
diff --git a/llvm/test/CodeGen/Hexagon/autohvx/fp-to-int_2.ll b/llvm/test/CodeGen/Hexagon/autohvx/fp-to-int_2.ll
new file mode 100644
index 0000000000000..2cd1c4939bc06
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/autohvx/fp-to-int_2.ll
@@ -0,0 +1,31 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=hexagon -mv73 -mhvx -mattr=+hvx-length128b  -hexagon-hvx-widen=32 -hexagon-fp-fast-convert=true < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"
+target triple = "hexagon"
+
+; f16 -> s16
+; No widening
+define void @f16s16_0(ptr %a0, ptr %a1) {
+; CHECK-LABEL: f16s16_0:
+; CHECK:         {
+; CHECK-NEXT:     v1.h = v0.hf
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:     v0.cur = vmem(r0+#0)
+; CHECK-NEXT:     vmem(r1+#0) = v1.new
+; CHECK-NEXT:    }
+  %v0 = load <64 x half>, ptr %a0, align 128
+  %v1 = fptosi <64 x half> %v0 to <64 x i16>
+  store <64 x i16> %v1, ptr %a1, align 128
+  ret void
+}
+
+; Widen result #2
+define void @f32s8_2(ptr %a0, ptr %a1) #0 {
+; CHECK-LABEL: f32s8_2:
+; CHECK:         v{{.*}}.w = v{{.*}}.sf
+  %v0 = load <32 x float>, ptr %a0, align 128
+  %v1 = fptosi <32 x float> %v0 to <32 x i8>
+  store <32 x i8> %v1, ptr %a1, align 128
+  ret void
+}



More information about the llvm-commits mailing list