[llvm-branch-commits] [llvm] [SandboxVec][VecUtils] Use an integer element type for mixed-type bundles (PR #224996)

Anshil Gandhi via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Sep 20 22:36:05 PDT 2026


https://github.com/gandhi56 created https://github.com/llvm/llvm-project/pull/224996

Stacked on #224890, which is the base of this PR.

getCombinedVectorTypeFor() picked the narrowest element type in the bundle, which for a bundle of mixed types kept the type of whichever element happened to be narrowest, e.g. `<2 x float>` for a float and an i32. The lanes of such a vector no longer share a type, so the element type may as well be an integer of that width, which is also what `LoadStoreVectorizer::getChainElemTy()` does. Values of the original types are recovered by reinterpreting the bits of each lane, so this is a type change only.

Bundles whose element types are all the same are unaffected, and so is the element width, which keeps splitting elements into lanes unchanged.

The doc comment claimed that mixed float/integer bundles returned null, which was never the case; it now describes what the function actually does.

The unit test gains cases for both halves of the rule: element types that are all the same are kept (including float and pointer element types, and a vector mixed with a scalar of the same element type), and differing element types combine into an integer of the narrowest element's width (float/int, pointer/int, pointer/float, half/bfloat, and vectors of differing element types). Two existing mixed float/integer cases only checked the element count and width; they now check the exact type.

The visible effect on LoadStoreVec is that a mixed-type chain of constant stores is stored as integer lanes, e.g. `<2 x i32> <i32 1065353216, i32 456>` rather than `<2 x float> <float 1.0, float 6.389920e-43>`, and that pointer lanes no longer need inttoptr constant expressions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

>From 50cdc95d1eff23ad580d93402d635b964e536341 Mon Sep 17 00:00:00 2001
From: Anshil Gandhi <gandhi21299 at gmail.com>
Date: Mon, 21 Sep 2026 00:48:31 -0400
Subject: [PATCH] [SandboxVec][VecUtils] Use an integer element type for
 mixed-type bundles

This PR enhances getCombinedVectorTypeFor() to return an integer type
to fit the narrowest element in the bundle, for mixed type bundles.

NFC for homogenously-typed bundles.
---
 .../Vectorize/SandboxVectorizer/VecUtils.h    | 15 +++-
 .../load_store_vec_mixed_types.ll             | 34 ++++----
 .../SandboxVectorizer/VecUtilsTest.cpp        | 78 +++++++++++++++----
 3 files changed, 90 insertions(+), 37 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h
index f41f923a17b38..6d038c03894a4 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h
@@ -13,6 +13,7 @@
 #define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_VECUTILS_H
 
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/Analysis/ScalarEvolution.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/SandboxIR/Type.h"
@@ -119,17 +120,23 @@ class VecUtils {
     }
     return FixedVectorType::get(ElemTy, NumElts);
   }
-  /// \Returns the combined vector type for \p Bndl, even when the element types
-  /// differ. For example: i8,i8,i16 will return <4 x i8>. \Returns null if
-  /// types are of mixed float/integer types.
+  /// \returns the combined vector type for \p Bndl, even when the element
+  /// types differ. The element type is the narrowest one in \p Bndl, so
+  /// i8,i8,i16 returns <4 x i8>. When the element types are not all the same,
+  /// for example i32,float or double,ptr, the element type is an integer of
+  /// the narrowest bitwidth. Values of the original types are recovered by
+  /// reinterpreting the bits of each lane.
   static Type *getCombinedVectorTypeFor(ArrayRef<Instruction *> Bndl,
                                         const DataLayout &DL) {
     assert(!Bndl.empty() && "Expected non-empty Bndl!");
     unsigned TotalBits = 0;
     unsigned MinElmBits = std::numeric_limits<unsigned>::max();
     Type *MinElmTy = nullptr;
+    Type *FirstElmTy = getElementType(Utils::getExpectedType(Bndl[0]));
+    bool SameElmTy = true;
     for (auto [Idx, V] : enumerate(Bndl)) {
       Type *ElmTy = getElementType(Utils::getExpectedType(V));
+      SameElmTy &= ElmTy == FirstElmTy;
 
       unsigned ElmBits = Utils::getNumBits(ElmTy, DL);
       TotalBits += ElmBits * VecUtils::getNumLanes(V);
@@ -138,6 +145,8 @@ class VecUtils {
         MinElmTy = ElmTy;
       }
     }
+    if (!SameElmTy)
+      MinElmTy = IntegerType::get(Bndl[0]->getContext(), MinElmBits);
     unsigned NumElms = TotalBits / MinElmBits;
     return FixedVectorType::get(MinElmTy, NumElms);
   }
diff --git a/llvm/test/Transforms/SandboxVectorizer/Passes/LoadStoreVec/load_store_vec_mixed_types.ll b/llvm/test/Transforms/SandboxVectorizer/Passes/LoadStoreVec/load_store_vec_mixed_types.ll
index 1cb43f93a7ffb..1daf0a5bc2146 100644
--- a/llvm/test/Transforms/SandboxVectorizer/Passes/LoadStoreVec/load_store_vec_mixed_types.ll
+++ b/llvm/test/Transforms/SandboxVectorizer/Passes/LoadStoreVec/load_store_vec_mixed_types.ll
@@ -30,8 +30,8 @@ define void @mixed_int_float(ptr %ptr0) {
 define void @mixed_int_vector_float(ptr %ptr) {
 ; CHECK-LABEL: define void @mixed_int_vector_float(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    [[VECIINITL:%.*]] = load <4 x half>, ptr [[PTR]], align 1, !sandboxvec [[META1:![0-9]+]]
-; CHECK-NEXT:    store <4 x half> [[VECIINITL]], ptr [[PTR]], align 1, !sandboxvec [[META1]]
+; CHECK-NEXT:    [[VECIINITL:%.*]] = load <4 x i16>, ptr [[PTR]], align 1, !sandboxvec [[META1:![0-9]+]]
+; CHECK-NEXT:    store <4 x i16> [[VECIINITL]], ptr [[PTR]], align 1, !sandboxvec [[META1]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr_4 = getelementptr inbounds i8, ptr %ptr, i64 4
@@ -66,8 +66,8 @@ define void @mixed_int_pointer(ptr %ptr) {
 define void @mixed_dboule_pointer(ptr %ptr) {
 ; CHECK-LABEL: define void @mixed_dboule_pointer(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    [[VECIINITL:%.*]] = load <2 x double>, ptr [[PTR]], align 1, !sandboxvec [[META3:![0-9]+]]
-; CHECK-NEXT:    store <2 x double> [[VECIINITL]], ptr [[PTR]], align 1, !sandboxvec [[META3]]
+; CHECK-NEXT:    [[VECIINITL:%.*]] = load <2 x i64>, ptr [[PTR]], align 1, !sandboxvec [[META3:![0-9]+]]
+; CHECK-NEXT:    store <2 x i64> [[VECIINITL]], ptr [[PTR]], align 1, !sandboxvec [[META3]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr_8 = getelementptr inbounds i8, ptr %ptr, i64 8
@@ -413,7 +413,7 @@ define amdgpu_kernel void @merge_global_store_2_constants_i32_f32(ptr addrspace(
 define void @const_int_reinterpreted_as_float_lane(ptr %ptr) {
 ; CHECK-LABEL: define void @const_int_reinterpreted_as_float_lane(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <2 x float> <float 1.000000e+00, float 6.389920e-43>, ptr [[PTR]], align 1, !sandboxvec [[META19:![0-9]+]]
+; CHECK-NEXT:    store <2 x i32> <i32 1065353216, i32 456>, ptr [[PTR]], align 1, !sandboxvec [[META19:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.4 = getelementptr i8, ptr %ptr, i64 4
@@ -441,7 +441,7 @@ define void @const_global_ptr_in_int_lane(ptr %ptr) {
 define void @const_global_ptr_in_double_lane(ptr %ptr) {
 ; CHECK-LABEL: define void @const_global_ptr_in_double_lane(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <2 x double> <double 1.000000e+00, double bitcast (i64 ptrtoint (ptr @g to i64) to double)>, ptr [[PTR]], align 1, !sandboxvec [[META21:![0-9]+]]
+; CHECK-NEXT:    store <2 x i64> <i64 4607182418800017408, i64 ptrtoint (ptr @g to i64)>, ptr [[PTR]], align 1, !sandboxvec [[META21:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.8 = getelementptr i8, ptr %ptr, i64 8
@@ -454,7 +454,7 @@ define void @const_global_ptr_in_double_lane(ptr %ptr) {
 define void @const_double_in_ptr_lane(ptr %ptr) {
 ; CHECK-LABEL: define void @const_double_in_ptr_lane(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <2 x ptr> <ptr null, ptr inttoptr (i64 4607182418800017408 to ptr)>, ptr [[PTR]], align 1, !sandboxvec [[META22:![0-9]+]]
+; CHECK-NEXT:    store <2 x i64> <i64 0, i64 4607182418800017408>, ptr [[PTR]], align 1, !sandboxvec [[META22:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.8 = getelementptr i8, ptr %ptr, i64 8
@@ -467,7 +467,7 @@ define void @const_double_in_ptr_lane(ptr %ptr) {
 define void @const_ptrtoint_constexpr(ptr %ptr) {
 ; CHECK-LABEL: define void @const_ptrtoint_constexpr(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <2 x double> <double 1.000000e+00, double bitcast (i64 ptrtoint (ptr @g to i64) to double)>, ptr [[PTR]], align 1, !sandboxvec [[META23:![0-9]+]]
+; CHECK-NEXT:    store <2 x i64> <i64 4607182418800017408, i64 ptrtoint (ptr @g to i64)>, ptr [[PTR]], align 1, !sandboxvec [[META23:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.8 = getelementptr i8, ptr %ptr, i64 8
@@ -480,7 +480,7 @@ define void @const_ptrtoint_constexpr(ptr %ptr) {
 define void @const_gep_constexpr(ptr %ptr) {
 ; CHECK-LABEL: define void @const_gep_constexpr(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <2 x double> <double 1.000000e+00, double bitcast (i64 ptrtoint (ptr getelementptr (i32, ptr @arr, i64 2) to i64) to double)>, ptr [[PTR]], align 1, !sandboxvec [[META24:![0-9]+]]
+; CHECK-NEXT:    store <2 x i64> <i64 4607182418800017408, i64 ptrtoint (ptr getelementptr (i32, ptr @arr, i64 2) to i64)>, ptr [[PTR]], align 1, !sandboxvec [[META24:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.8 = getelementptr i8, ptr %ptr, i64 8
@@ -492,7 +492,7 @@ define void @const_gep_constexpr(ptr %ptr) {
 define void @const_scalar_poison(ptr %ptr) {
 ; CHECK-LABEL: define void @const_scalar_poison(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <2 x float> <float 1.000000e+00, float poison>, ptr [[PTR]], align 1, !sandboxvec [[META25:![0-9]+]]
+; CHECK-NEXT:    store <2 x i32> <i32 1065353216, i32 poison>, ptr [[PTR]], align 1, !sandboxvec [[META25:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.4 = getelementptr i8, ptr %ptr, i64 4
@@ -555,7 +555,7 @@ define void @const_null_ptr_split_into_i32_lanes(ptr %ptr) {
 define void @const_i128_split_into_ptr_lanes(ptr %ptr) {
 ; CHECK-LABEL: define void @const_i128_split_into_ptr_lanes(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <4 x ptr> <ptr null, ptr null, ptr inttoptr (i64 5 to ptr), ptr null>, ptr [[PTR]], align 1, !sandboxvec [[META29:![0-9]+]]
+; CHECK-NEXT:    store <4 x i64> <i64 0, i64 0, i64 5, i64 0>, ptr [[PTR]], align 1, !sandboxvec [[META29:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.8 = getelementptr i8, ptr %ptr, i64 8
@@ -570,7 +570,7 @@ define void @const_i128_split_into_ptr_lanes(ptr %ptr) {
 define void @const_i32_split_into_half_lanes(ptr %ptr) {
 ; CHECK-LABEL: define void @const_i32_split_into_half_lanes(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <4 x half> <half 1.000000e+00, half 2.000000e+00, half 4.172330e-07, half 0.000000e+00>, ptr [[PTR]], align 1, !sandboxvec [[META30:![0-9]+]]
+; CHECK-NEXT:    store <4 x i16> <i16 15360, i16 16384, i16 7, i16 0>, ptr [[PTR]], align 1, !sandboxvec [[META30:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.2 = getelementptr i8, ptr %ptr, i64 2
@@ -585,7 +585,7 @@ define void @const_i32_split_into_half_lanes(ptr %ptr) {
 define void @const_float_split_into_bfloat_lanes(ptr %ptr) {
 ; CHECK-LABEL: define void @const_float_split_into_bfloat_lanes(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <4 x bfloat> <bfloat 1.000000e+00, bfloat 2.000000e+00, bfloat 0.000000e+00, bfloat 3.000000e+00>, ptr [[PTR]], align 1, !sandboxvec [[META31:![0-9]+]]
+; CHECK-NEXT:    store <4 x i16> <i16 16256, i16 16384, i16 0, i16 16448>, ptr [[PTR]], align 1, !sandboxvec [[META31:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.2 = getelementptr i8, ptr %ptr, i64 2
@@ -613,7 +613,7 @@ define void @const_i16_split_into_i8_lanes(ptr %ptr) {
 define void @const_mixed_widths_in_float_lanes(ptr %ptr) {
 ; CHECK-LABEL: define void @const_mixed_widths_in_float_lanes(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <8 x float> <float 1.401300e-45, float 0.000000e+00, float 0.000000e+00, float 2.000000e+00, float 0.000000e+00, float 0.000000e+00, float 3.000000e+00, float 4.000000e+00>, ptr [[PTR]], align 1, !sandboxvec [[META33:![0-9]+]]
+; CHECK-NEXT:    store <8 x i32> <i32 1, i32 0, i32 0, i32 1073741824, i32 0, i32 0, i32 1077936128, i32 1082130432>, ptr [[PTR]], align 1, !sandboxvec [[META33:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.8 = getelementptr i8, ptr %ptr, i64 8
@@ -647,7 +647,7 @@ define void @const_data_vectors(ptr %ptr) {
 define void @const_aggregate_zero(ptr %ptr) {
 ; CHECK-LABEL: define void @const_aggregate_zero(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <4 x float> <float 0.000000e+00, float 0.000000e+00, float 7.006490e-45, float 8.407790e-45>, ptr [[PTR]], align 1, !sandboxvec [[META35:![0-9]+]]
+; CHECK-NEXT:    store <4 x i32> <i32 0, i32 0, i32 5, i32 6>, ptr [[PTR]], align 1, !sandboxvec [[META35:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.8 = getelementptr i8, ptr %ptr, i64 8
@@ -685,7 +685,7 @@ define void @const_splat_int_vector(ptr %ptr) {
 define void @const_splat_fp_vector(ptr %ptr) {
 ; CHECK-LABEL: define void @const_splat_fp_vector(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <4 x float> <float 2.000000e+00, float 2.000000e+00, float 1.261170e-44, float 1.401300e-44>, ptr [[PTR]], align 1, !sandboxvec [[META38:![0-9]+]]
+; CHECK-NEXT:    store <4 x i32> <i32 1073741824, i32 1073741824, i32 9, i32 10>, ptr [[PTR]], align 1, !sandboxvec [[META38:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.8 = getelementptr i8, ptr %ptr, i64 8
@@ -698,7 +698,7 @@ define void @const_splat_fp_vector(ptr %ptr) {
 define void @const_vector_of_ptrs(ptr %ptr) {
 ; CHECK-LABEL: define void @const_vector_of_ptrs(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
-; CHECK-NEXT:    store <4 x ptr> <ptr @g, ptr null, ptr inttoptr (i64 3 to ptr), ptr inttoptr (i64 4 to ptr)>, ptr [[PTR]], align 1, !sandboxvec [[META39:![0-9]+]]
+; CHECK-NEXT:    store <4 x i64> <i64 ptrtoint (ptr @g to i64), i64 0, i64 3, i64 4>, ptr [[PTR]], align 1, !sandboxvec [[META39:![0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr.16 = getelementptr i8, ptr %ptr, i64 16
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/VecUtilsTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/VecUtilsTest.cpp
index 16fd5d168bdde..79c47cd9aee95 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/VecUtilsTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/VecUtilsTest.cpp
@@ -429,7 +429,7 @@ TEST_F(VecUtilsTest, GetWideType) {
 
 TEST_F(VecUtilsTest, GetCombinedVectorTypeFor) {
   parseIR(R"IR(
-define void @foo(ptr %ptr, i8 %i8, i16 %i16, i32 %i32, float %f32, double %f64, <2 x i8> %v2xi8, <2 x i16> %v2xi16) {
+define void @foo(ptr %ptr, i8 %i8, i16 %i16, i32 %i32, i64 %i64, float %f32, double %f64, <2 x i8> %v2xi8, <2 x i16> %v2xi16, half %f16, bfloat %bf16, <2 x float> %v2xf32, <2 x i32> %v2xi32) {
   store i8 %i8, ptr %ptr
   store i16 %i16, ptr %ptr
   store i32 %i32, ptr %ptr
@@ -437,6 +437,12 @@ define void @foo(ptr %ptr, i8 %i8, i16 %i16, i32 %i32, float %f32, double %f64,
   store double %f64, ptr %ptr
   store <2 x i8> %v2xi8, ptr %ptr
   store <2 x i16> %v2xi16, ptr %ptr
+  store i64 %i64, ptr %ptr
+  store ptr %ptr, ptr %ptr
+  store half %f16, ptr %ptr
+  store bfloat %bf16, ptr %ptr
+  store <2 x float> %v2xf32, ptr %ptr
+  store <2 x i32> %v2xi32, ptr %ptr
   ret void
 }
 )IR");
@@ -454,10 +460,19 @@ define void @foo(ptr %ptr, i8 %i8, i16 %i16, i32 %i32, float %f32, double %f64,
   auto *Store_f64 = &*It++;
   auto *Store_2xi8 = &*It++;
   auto *Store_2xi16 = &*It++;
+  auto *Store_i64 = &*It++;
+  auto *Store_ptr = &*It++;
+  auto *Store_f16 = &*It++;
+  auto *Store_bf16 = &*It++;
+  auto *Store_2xf32 = &*It++;
+  auto *Store_2xi32 = &*It++;
 
   auto *I8Ty = sandboxir::IntegerType::get(Ctx, 8);
   auto *I16Ty = sandboxir::IntegerType::get(Ctx, 16);
-  auto *F32Ty = sandboxir::Type::getFloatTy(Ctx);
+  auto *I32Ty = sandboxir::IntegerType::get(Ctx, 32);
+  auto *I64Ty = sandboxir::IntegerType::get(Ctx, 64);
+  auto *F32Ty = sandboxir::Utils::getExpectedType(Store_f32);
+  auto *PtrTy = sandboxir::Utils::getExpectedType(Store_ptr);
 
   // Check same type.
   EXPECT_EQ(
@@ -466,6 +481,20 @@ define void @foo(ptr %ptr, i8 %i8, i16 %i16, i32 %i32, float %f32, double %f64,
   EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
                 {Store_2xi8, Store_2xi8}, DL),
             sandboxir::FixedVectorType::get(I8Ty, 4));
+  // Non-integer element types are kept as long as they are all the same.
+  EXPECT_EQ(
+      sandboxir::VecUtils::getCombinedVectorTypeFor({Store_f32, Store_f32}, DL),
+      sandboxir::FixedVectorType::get(F32Ty, 2));
+  EXPECT_EQ(
+      sandboxir::VecUtils::getCombinedVectorTypeFor({Store_ptr, Store_ptr}, DL),
+      sandboxir::FixedVectorType::get(PtrTy, 2));
+  // Only the element type has to match, not the type itself.
+  EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
+                {Store_2xf32, Store_f32}, DL),
+            sandboxir::FixedVectorType::get(F32Ty, 3));
+  EXPECT_EQ(
+      sandboxir::VecUtils::getCombinedVectorTypeFor({Store_2xi8, Store_i8}, DL),
+      sandboxir::FixedVectorType::get(I8Ty, 3));
 
   // Check different types, power-of-two.
   EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
@@ -478,10 +507,11 @@ define void @foo(ptr %ptr, i8 %i8, i16 %i16, i32 %i32, float %f32, double %f64,
                 {Store_2xi8, Store_2xi8, Store_2xi16}, DL),
             sandboxir::FixedVectorType::get(I8Ty, 8));
 
-  // Check different types non-power-of-two.
+  // Check different types non-power-of-two. Element types that are not all
+  // the same combine into an integer element type.
   EXPECT_EQ(
       sandboxir::VecUtils::getCombinedVectorTypeFor({Store_f32, Store_f64}, DL),
-      sandboxir::FixedVectorType::get(F32Ty, 3));
+      sandboxir::FixedVectorType::get(I32Ty, 3));
   EXPECT_EQ(
       sandboxir::VecUtils::getCombinedVectorTypeFor({Store_i32, Store_i16}, DL),
       sandboxir::FixedVectorType::get(I16Ty, 3));
@@ -492,19 +522,33 @@ define void @foo(ptr %ptr, i8 %i8, i16 %i16, i32 %i32, float %f32, double %f64,
                 {Store_i8, Store_i16, Store_2xi8}, DL),
             sandboxir::FixedVectorType::get(I8Ty, 5));
 
-  // Mix float and integer.
-  {
-    auto *CVTy = sandboxir::VecUtils::getCombinedVectorTypeFor(
-        {Store_i32, Store_f32}, DL);
-    EXPECT_EQ(cast<sandboxir::FixedVectorType>(CVTy)->getNumElements(), 2u);
-    EXPECT_EQ(CVTy->getScalarSizeInBits(), 32u);
-  }
-  {
-    auto *CVTy = sandboxir::VecUtils::getCombinedVectorTypeFor(
-        {Store_f32, Store_2xi8}, DL);
-    EXPECT_EQ(cast<sandboxir::FixedVectorType>(CVTy)->getNumElements(), 6u);
-    EXPECT_EQ(CVTy->getScalarSizeInBits(), 8u);
-  }
+  // Mix float and integer: the element type is an integer of the narrowest
+  // element's width.
+  EXPECT_EQ(
+      sandboxir::VecUtils::getCombinedVectorTypeFor({Store_i32, Store_f32}, DL),
+      sandboxir::FixedVectorType::get(I32Ty, 2));
+  EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
+                {Store_f32, Store_2xi8}, DL),
+            sandboxir::FixedVectorType::get(I8Ty, 6));
+  EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
+                {Store_2xf32, Store_2xi32}, DL),
+            sandboxir::FixedVectorType::get(I32Ty, 4));
+  // Same width but different types, so still an integer element type.
+  EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
+                {Store_f16, Store_bf16}, DL),
+            sandboxir::FixedVectorType::get(I16Ty, 2));
+
+  // Mix pointer and integer, and pointer and float.
+  EXPECT_EQ(
+      sandboxir::VecUtils::getCombinedVectorTypeFor({Store_ptr, Store_i64}, DL),
+      sandboxir::FixedVectorType::get(I64Ty, 2));
+  EXPECT_EQ(
+      sandboxir::VecUtils::getCombinedVectorTypeFor({Store_f64, Store_ptr}, DL),
+      sandboxir::FixedVectorType::get(I64Ty, 2));
+  // The narrowest element sets the element width, here the i32 of the vector.
+  EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
+                {Store_ptr, Store_ptr, Store_2xi32}, DL),
+            sandboxir::FixedVectorType::get(I32Ty, 6));
 }
 
 TEST_F(VecUtilsTest, GetLowest) {



More information about the llvm-branch-commits mailing list