[llvm] [Hexagon]Handle bitcast of i32/v2i16/v4i8 -> v32i1 when Hvx is enabled (PR #147466)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 8 07:30:39 PDT 2025


https://github.com/pkarveti updated https://github.com/llvm/llvm-project/pull/147466

>From 8152d6fba1240e1b631f007f425e17552d21248d Mon Sep 17 00:00:00 2001
From: pavani karveti <quic_pkarveti at quicinc.com>
Date: Mon, 7 Jul 2025 23:09:59 -0700
Subject: [PATCH] [Hexagon]Handle bitcast of i32/v2i16/v4i8 -> v32i1 when Hvx
 is enabled

Change-Id: I1f3c4783424a2c068f207a7680f85ef95c70f573
---
 .../Target/Hexagon/HexagonISelLoweringHVX.cpp | 24 +++++++
 .../CodeGen/Hexagon/bitcast-i32-to-v32i1.ll   | 69 +++++++++++++++++++
 .../CodeGen/Hexagon/bitcast-v2i16-to-v32i1.ll | 47 +++++++++++++
 .../CodeGen/Hexagon/bitcast-v4i8-to-v32i1.ll  | 47 +++++++++++++
 4 files changed, 187 insertions(+)
 create mode 100644 llvm/test/CodeGen/Hexagon/bitcast-i32-to-v32i1.ll
 create mode 100644 llvm/test/CodeGen/Hexagon/bitcast-v2i16-to-v32i1.ll
 create mode 100644 llvm/test/CodeGen/Hexagon/bitcast-v4i8-to-v32i1.ll

diff --git a/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
index 0e13dd3214da6..9b69c892308cb 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp
@@ -117,6 +117,8 @@ HexagonTargetLowering::initializeHVXLowering() {
   setOperationAction(ISD::VECTOR_SHUFFLE,          ByteW, Legal);
   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
 
+  if (Subtarget.useHVX128BOps())
+    setOperationAction(ISD::BITCAST, MVT::v32i1, Custom);
   if (Subtarget.useHVX128BOps() && Subtarget.useHVXV68Ops() &&
       Subtarget.useHVXFloatingPoint()) {
 
@@ -2001,6 +2003,28 @@ HexagonTargetLowering::LowerHvxBitcast(SDValue Op, SelectionDAG &DAG) const {
 
     return DAG.getNode(ISD::BUILD_PAIR, dl, ResTy, Combines);
   }
+
+  // Handle bitcast from i32, v2i16, and v4i8 to v32i1.
+  // Splat the input into a 32-element i32 vector, then AND each element
+  //  with a unique bitmask to isolate individual bits.
+  if (ResTy == MVT::v32i1 &&
+      (ValTy == MVT::i32 || ValTy == MVT::v2i16 || ValTy == MVT::v4i8) &&
+      Subtarget.useHVX128BOps()) {
+    SDValue Val32 = Val;
+    if (ValTy == MVT::v2i16 || ValTy == MVT::v4i8)
+      Val32 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Val);
+
+    MVT VecTy = MVT::getVectorVT(MVT::i32, 32);
+    SDValue Splat = DAG.getNode(ISD::SPLAT_VECTOR, dl, VecTy, Val32);
+    SmallVector<SDValue, 32> Mask;
+    for (unsigned i = 0; i < 32; ++i)
+      Mask.push_back(DAG.getConstant(1u << i, dl, MVT::i32));
+
+    SDValue MaskVec = DAG.getBuildVector(VecTy, dl, Mask);
+    SDValue Anded = DAG.getNode(ISD::AND, dl, VecTy, Splat, MaskVec);
+    return DAG.getNode(HexagonISD::V2Q, dl, ResTy, Anded);
+  }
+
   if (isHvxBoolTy(ResTy) && ValTy.isScalarInteger()) {
     // Handle bitcast from i128 -> v128i1 and i64 -> v64i1.
     unsigned BitWidth = ValTy.getSizeInBits();
diff --git a/llvm/test/CodeGen/Hexagon/bitcast-i32-to-v32i1.ll b/llvm/test/CodeGen/Hexagon/bitcast-i32-to-v32i1.ll
new file mode 100644
index 0000000000000..fe6379066b941
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/bitcast-i32-to-v32i1.ll
@@ -0,0 +1,69 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=hexagon -mattr=+hvxv79,+hvx-length128b < %s | FileCheck %s
+
+define void @bitcast_i32_to_v32i1(ptr %in, ptr %out) {
+; CHECK-LABEL: bitcast_i32_to_v32i1:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  // %bb.0: // %entry
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r3:2 = combine(#-1,##.LCPI0_0)
+; CHECK-NEXT:     allocframe(r29,#128):raw
+; CHECK-NEXT:    }
+; CHECK-NEXT:    .cfi_def_cfa r30, 8
+; CHECK-NEXT:    .cfi_offset r31, -4
+; CHECK-NEXT:    .cfi_offset r30, -8
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r29 = and(r29,#-128)
+; CHECK-NEXT:     r0 = memw(r0+#0)
+; CHECK-NEXT:     v1 = vmem(r2+#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vsplat(r0)
+; CHECK-NEXT:     r5 = add(r29,#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vand(v0,v1)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     q0 = vand(v0,r3)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vand(q0,r3)
+; CHECK-NEXT:     vmem(r5+#0) = v0.new
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r4 = memw(r5+#0)
+; CHECK-NEXT:     r0 = memw(r5+#4)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r2 = and(r4,#255)
+; CHECK-NEXT:     r0 = and(r0,#255)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     p1 = cmp.gtu(r2,#0)
+; CHECK-NEXT:     p0 = cmp.gtu(r0,#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r0 = mux(p1,#1,#0)
+; CHECK-NEXT:     r2 = mux(p0,#1,#0)
+; CHECK-NEXT:     memb(r1+#0) = r0.new
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     memb(r1+#1) = r2
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r31:30 = dealloc_return(r30):raw
+; CHECK-NEXT:    }
+entry:
+  %load = load i32, ptr %in, align 4
+  %bitcast = bitcast i32 %load to <32 x i1>
+  %e0 = extractelement <32 x i1> %bitcast, i32 0
+  %e1 = extractelement <32 x i1> %bitcast, i32 1
+  %z0 = zext i1 %e0 to i8
+  %z1 = zext i1 %e1 to i8
+  %ptr0 = getelementptr i8, ptr %out, i32 0
+  %ptr1 = getelementptr i8, ptr %out, i32 1
+  store i8 %z0, ptr %ptr0, align 1
+  store i8 %z1, ptr %ptr1, align 1
+  ret void
+}
diff --git a/llvm/test/CodeGen/Hexagon/bitcast-v2i16-to-v32i1.ll b/llvm/test/CodeGen/Hexagon/bitcast-v2i16-to-v32i1.ll
new file mode 100644
index 0000000000000..a51becc98c1fa
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/bitcast-v2i16-to-v32i1.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=hexagon -mattr=+hvxv79,+hvx-length128b < %s | FileCheck %s
+
+define void @bitcast_v2i16_to_v32i1(ptr %in, ptr %out) {
+; CHECK-LABEL: bitcast_v2i16_to_v32i1:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  // %bb.0: // %entry
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r3:2 = combine(#-1,##.LCPI0_0)
+; CHECK-NEXT:     r0 = memw(r0+#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vsplat(r0)
+; CHECK-NEXT:     r2 = #0
+; CHECK-NEXT:     v1 = vmem(r2+#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vand(v0,v1)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     q0 = vand(v0,r3)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vand(q0,r3)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r0 = vextract(v0,r2)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r0 = and(r0,#255)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     p0 = cmp.gtu(r0,#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r0 = mux(p0,#1,#0)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:     memb(r1+#0) = r0.new
+; CHECK-NEXT:    }
+entry:
+  %load = load <2 x i16>, ptr %in, align 4
+  %bitcast = bitcast <2 x i16> %load to <32 x i1>
+  %extract = extractelement <32 x i1> %bitcast, i32 0
+  %zext = zext i1 %extract to i8
+  store i8 %zext, ptr %out, align 1
+  ret void
+}
diff --git a/llvm/test/CodeGen/Hexagon/bitcast-v4i8-to-v32i1.ll b/llvm/test/CodeGen/Hexagon/bitcast-v4i8-to-v32i1.ll
new file mode 100644
index 0000000000000..59324e8cbdbf1
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/bitcast-v4i8-to-v32i1.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=hexagon -mattr=+hvxv79,+hvx-length128b < %s | FileCheck %s
+
+define void @bitcast_v4i8_to_v32i1(ptr %in, ptr %out) {
+; CHECK-LABEL: bitcast_v4i8_to_v32i1:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  // %bb.0: // %entry
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r3:2 = combine(#-1,##.LCPI0_0)
+; CHECK-NEXT:     r0 = memw(r0+#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vsplat(r0)
+; CHECK-NEXT:     r2 = #0
+; CHECK-NEXT:     v1 = vmem(r2+#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vand(v0,v1)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     q0 = vand(v0,r3)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vand(q0,r3)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r0 = vextract(v0,r2)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r0 = and(r0,#255)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     p0 = cmp.gtu(r0,#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r0 = mux(p0,#1,#0)
+; CHECK-NEXT:     jumpr r31
+; CHECK-NEXT:     memb(r1+#0) = r0.new
+; CHECK-NEXT:    }
+entry:
+  %load = load <4 x i8>, ptr %in, align 4
+  %bitcast = bitcast <4 x i8> %load to <32 x i1>
+  %extract = extractelement <32 x i1> %bitcast, i32 0
+  %zext = zext i1 %extract to i8
+  store i8 %zext, ptr %out, align 1
+  ret void
+}



More information about the llvm-commits mailing list