[llvm] Yonah/sroa integer aggregates promotable only (PR #219418)

Yonah Goldberg via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 28 02:03:44 PDT 2026


https://github.com/YonahGoldberg created https://github.com/llvm/llvm-project/pull/219418

None

>From 28824a57bde6b30b4ac20e1a8e065a7b9f1e7c9f Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Thu, 27 Aug 2026 07:23:46 +0000
Subject: [PATCH 1/4] [SROA] Prefer legal integers for aggregate partitions

---
 llvm/lib/Transforms/Scalar/SROA.cpp | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index e4770154e2998..a449b1c9ff61e 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -4804,6 +4804,14 @@ static Type *getTypePartition(const DataLayout &DL, Type *Ty, uint64_t Offset,
   return SubTy;
 }
 
+static bool containsNonIntegralPointer(Type *Ty, const DataLayout &DL) {
+  if (auto *PtrTy = dyn_cast<PointerType>(Ty))
+    return DL.isNonIntegralPointerType(PtrTy);
+  return llvm::any_of(Ty->subtypes(), [&](Type *SubTy) {
+    return containsNonIntegralPointer(SubTy, DL);
+  });
+}
+
 /// Pre-split loads and stores to simplify rewriting.
 ///
 /// We want to break up the splittable load+store pairs as much as
@@ -5458,11 +5466,11 @@ selectPartitionType(Partition &P, const DataLayout &DL, AllocaInst &AI,
   // type?
   if (Type *TypePartitionTy = getTypePartition(DL, AI.getAllocatedType(),
                                                P.beginOffset(), P.size())) {
-    // If the partition is an integer array that can be spanned by a legal
-    // integer type, prefer to represent it as a legal integer type because
-    // it's more likely to be promotable.
-    if (TypePartitionTy->isArrayTy() &&
-        TypePartitionTy->getArrayElementType()->isIntegerTy() &&
+    // If the partition is an aggregate without non-integral pointers that can
+    // be spanned by a legal integer type, prefer to represent it as a legal
+    // integer type because it's more likely to be promotable.
+    if (TypePartitionTy->isAggregateType() &&
+        !containsNonIntegralPointer(TypePartitionTy, DL) &&
         DL.isLegalInteger(P.size() * 8))
       TypePartitionTy = Type::getIntNTy(C, P.size() * 8);
     // There was no common type used, so we prefer integer widening promotion.

>From 2e6527a6e69f366954883e2549178a7ff3a6476f Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 28 Aug 2026 03:26:32 +0000
Subject: [PATCH 2/4] [SROA] Canonicalize struct partitions to integers late

---
 llvm/lib/Transforms/Scalar/SROA.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index a449b1c9ff61e..c4a3bfccef935 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -5466,10 +5466,11 @@ selectPartitionType(Partition &P, const DataLayout &DL, AllocaInst &AI,
   // type?
   if (Type *TypePartitionTy = getTypePartition(DL, AI.getAllocatedType(),
                                                P.beginOffset(), P.size())) {
-    // If the partition is an aggregate without non-integral pointers that can
-    // be spanned by a legal integer type, prefer to represent it as a legal
-    // integer type because it's more likely to be promotable.
-    if (TypePartitionTy->isAggregateType() &&
+    // If the partition is an array, or a struct when aggregate canonicalization
+    // is requested, prefer a legal integer type because it's more likely to be
+    // promotable.
+    if ((TypePartitionTy->isArrayTy() ||
+         (AggregateToVector && TypePartitionTy->isStructTy())) &&
         !containsNonIntegralPointer(TypePartitionTy, DL) &&
         DL.isLegalInteger(P.size() * 8))
       TypePartitionTy = Type::getIntNTy(C, P.size() * 8);

>From 627c4de247a12f9ced383f475b8c86db6b85ae10 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 28 Aug 2026 08:54:13 +0000
Subject: [PATCH 3/4] [SROA] Only canonicalize aggregates when promotion is
 guaranteed

---
 llvm/lib/Transforms/Scalar/SROA.cpp | 58 ++++++++++++++++++++++++++---
 1 file changed, 53 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index c4a3bfccef935..893e78c83316c 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -4812,6 +4812,48 @@ static bool containsNonIntegralPointer(Type *Ty, const DataLayout &DL) {
   });
 }
 
+/// Return true if every non-ignorable use covers the whole partition and can
+/// be rewritten as a direct access to NewTy.
+static bool areAllUsesWholePartitionPromotable(Partition &P, Type *NewTy,
+                                                const DataLayout &DL) {
+  auto IsPromotable = [&](const Slice &S) {
+    if (S.isDead() || !S.getUse())
+      return true;
+
+    User *Usr = S.getUse()->getUser();
+    if (auto *II = dyn_cast<IntrinsicInst>(Usr);
+        II && (II->isLifetimeStartOrEnd() || II->isDroppable()))
+      return true;
+
+    if (S.beginOffset() > P.beginOffset() ||
+        S.endOffset() < P.endOffset())
+      return false;
+
+    bool IsExactPartition = S.beginOffset() == P.beginOffset() &&
+                            S.endOffset() == P.endOffset();
+    if (auto *LI = dyn_cast<LoadInst>(Usr)) {
+      if (LI->isVolatile())
+        return false;
+      return IsExactPartition ? canConvertValue(DL, NewTy, LI->getType())
+                              : S.isSplittable();
+    }
+    if (auto *SI = dyn_cast<StoreInst>(Usr)) {
+      if (SI->isVolatile())
+        return false;
+      return IsExactPartition
+                 ? canConvertValue(DL, SI->getValueOperand()->getType(), NewTy)
+                 : S.isSplittable();
+    }
+    if (auto *MI = dyn_cast<MemIntrinsic>(Usr))
+      return !MI->isVolatile() && S.isSplittable();
+    return false;
+  };
+
+  return llvm::all_of(P, IsPromotable) &&
+         llvm::all_of(P.splitSliceTails(),
+                      [&](const Slice *S) { return IsPromotable(*S); });
+}
+
 /// Pre-split loads and stores to simplify rewriting.
 ///
 /// We want to break up the splittable load+store pairs as much as
@@ -5466,14 +5508,20 @@ selectPartitionType(Partition &P, const DataLayout &DL, AllocaInst &AI,
   // type?
   if (Type *TypePartitionTy = getTypePartition(DL, AI.getAllocatedType(),
                                                P.beginOffset(), P.size())) {
-    // If the partition is an array, or a struct when aggregate canonicalization
-    // is requested, prefer a legal integer type because it's more likely to be
-    // promotable.
+    // Canonicalize arrays, or structs when requested, to a legal integer only
+    // when this is guaranteed to produce a promotable partition.
     if ((TypePartitionTy->isArrayTy() ||
          (AggregateToVector && TypePartitionTy->isStructTy())) &&
         !containsNonIntegralPointer(TypePartitionTy, DL) &&
-        DL.isLegalInteger(P.size() * 8))
-      TypePartitionTy = Type::getIntNTy(C, P.size() * 8);
+        DL.isLegalInteger(P.size() * 8)) {
+      Type *IntTy = Type::getIntNTy(C, P.size() * 8);
+      if (isIntegerWideningViable(P, IntTy, DL)) {
+        LogSelection("aggregate-int-widen", IntTy, nullptr, true);
+        return {IntTy, true, nullptr};
+      }
+      if (areAllUsesWholePartitionPromotable(P, IntTy, DL))
+        TypePartitionTy = IntTy;
+    }
     // There was no common type used, so we prefer integer widening promotion.
     if (isIntegerWideningViable(P, TypePartitionTy, DL)) {
       LogSelection("type-partition-int-widen", TypePartitionTy, nullptr, true);

>From 9d684c309c7cda73cef801177f6bf089e1778e00 Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Fri, 28 Aug 2026 09:02:14 +0000
Subject: [PATCH 4/4] [SROA] Select proven whole-partition integer immediately

---
 llvm/lib/Transforms/Scalar/SROA.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 893e78c83316c..d8282e90361b7 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -5519,8 +5519,10 @@ selectPartitionType(Partition &P, const DataLayout &DL, AllocaInst &AI,
         LogSelection("aggregate-int-widen", IntTy, nullptr, true);
         return {IntTy, true, nullptr};
       }
-      if (areAllUsesWholePartitionPromotable(P, IntTy, DL))
-        TypePartitionTy = IntTy;
+      if (areAllUsesWholePartitionPromotable(P, IntTy, DL)) {
+        LogSelection("aggregate-int-whole", IntTy, nullptr, false);
+        return {IntTy, false, nullptr};
+      }
     }
     // There was no common type used, so we prefer integer widening promotion.
     if (isIntegerWideningViable(P, TypePartitionTy, DL)) {



More information about the llvm-commits mailing list