[llvm] [VPlan] Support scalarizing vectorized structs in VPTransformState::get() (PR #194113)

Thurston Dang via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 26 11:12:26 PDT 2026


https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/194113

>From 9915f988e5ee7de2feabc03d005b3317a68e4da9 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Fri, 24 Apr 2026 06:56:20 +0000
Subject: [PATCH 1/2] [LoopVectorize] Support scalarizing vectorized structs in
 VPTransformState::get()

Currently, vectorized struct (e.g., { <4 x i64>, <4 x i1> }) inputs are handled (incorrectly) by the
"if (!VecPart->getType()->isVectorTy())" branch; thus, the vectorized struct is returned verbatim, instead of the expected struct of scalars (e.g., { i64, i1 }).

This fix is a prerequisite towards properly supporting scalarization of ExtractValue-based VPWidenRecipes (https://github.com/llvm/llvm-project/issues/193275).
---
 llvm/lib/Transforms/Vectorize/VPlan.cpp | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 197ef22dc7fc6..d2d885ab271f0 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -265,10 +265,33 @@ Value *VPTransformState::get(const VPValue *Def, const VPLane &Lane) {
 
   assert(hasVectorValue(Def));
   auto *VecPart = Data.VPV2Vector[Def];
+
+  // VPWidenRecipe converted e.g., { <i64>, <i1> } to { <4 x i64>, <4 x i1> }.
+  // Invert it here.
+  auto *StructTy = dyn_cast<StructType>(VecPart->getType());
+  if (StructTy && isVectorizedStructTy(StructTy)) {
+    Value *LaneV = Lane.getAsRuntimeExpr(Builder, VF);
+
+    Type *StructScalarTy = toScalarizedTy(StructTy);
+    Value *Extract = PoisonValue::get(StructScalarTy);
+
+    for (unsigned i = 0; i != StructTy->getNumElements(); i++) {
+      Value *FieldVectorValue = Builder.CreateExtractValue(VecPart, i);
+      Value *FieldScalarValue =
+          Builder.CreateExtractElement(FieldVectorValue, LaneV);
+      Extract = Builder.CreateInsertValue(Extract, FieldScalarValue, i);
+    }
+
+    // TODO: Cache created scalar values.
+    // set(Def, Extract, Instance);
+    return Extract;
+  }
+
   if (!VecPart->getType()->isVectorTy()) {
     assert(Lane.isFirstLane() && "cannot get lane > 0 for scalar");
     return VecPart;
   }
+
   // TODO: Cache created scalar values.
   Value *LaneV = Lane.getAsRuntimeExpr(Builder, VF);
   auto *Extract = Builder.CreateExtractElement(VecPart, LaneV);

>From eb296cae981af5ecd27241dfbba5bba2f80c5fd9 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Sun, 26 Apr 2026 18:11:54 +0000
Subject: [PATCH 2/2] They'll tell you I'm insane But I've got a blank space

---
 llvm/lib/Transforms/Vectorize/VPlan.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index d2d885ab271f0..067120b6a68fd 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -291,7 +291,6 @@ Value *VPTransformState::get(const VPValue *Def, const VPLane &Lane) {
     assert(Lane.isFirstLane() && "cannot get lane > 0 for scalar");
     return VecPart;
   }
-
   // TODO: Cache created scalar values.
   Value *LaneV = Lane.getAsRuntimeExpr(Builder, VF);
   auto *Extract = Builder.CreateExtractElement(VecPart, LaneV);



More information about the llvm-commits mailing list