[llvm] [LSROA] Add logical SROA pass (PR #192058)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 30 03:37:28 PDT 2026


Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/192058 at github.com>


================
@@ -0,0 +1,266 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This transformation implements the well known scalar replacement of
+/// aggregates transformation but for logical pointers.
+/// It tries to identify promotable elements of an aggregate alloca, and
+/// promote them to multiple allocas of scalar type.
+///
+/// FIXME: nested aggregates are not fully optimized (#192619).
+/// FIXME: array are not optimized (#192620).
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/LogicalSROA.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/DomTreeUpdater.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Transforms/Scalar.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "logical-sroa"
+
+// Return all lifetime intrinsics with the instruction I as operand.
+static SmallVector<LifetimeIntrinsic *>
+collectLifetimeIntrinsicsUsing(Instruction &I) {
+  SmallVector<LifetimeIntrinsic *> Output;
+
+  for (User *U : I.users()) {
+    if (auto *LI = dyn_cast<LifetimeIntrinsic>(U))
+      Output.push_back(LI);
+  }
+
+  return Output;
+}
+
+// Returns true if all direct and indirect users of the alloca
+// allow the split.
+static bool isAllocaSplittable(StructuredAllocaInst &SAI) {
+  SmallVector<Value *> WorkList(SAI.users());
+  DenseSet<Value *> Visited;
+
+  // Helper function to enqueue all non-visited users of `I`.
+  auto enqueueAllUsers = [&](Instruction *I) {
+    for (auto *U : I->users()) {
+      if (Visited.contains(U))
+        continue;
+      WorkList.push_back(U);
+    }
+  };
+
+  while (!WorkList.empty()) {
+    Instruction *I = dyn_cast<Instruction>(WorkList.back());
+    WorkList.pop_back();
+
+    // User is not an instruction. Not sure what it it, in
+    // doubt, don't split.
+    if (!I)
+      return false;
+
+    Visited.insert(I);
+
+    // Those allow the alloca split.
+    if (isa<LifetimeIntrinsic>(I))
+      continue;
+
+    // If we load the whole alloca, we cannot split,
+    // otherwise, we can stop looking into derived users.
+    if (auto *LI = dyn_cast<LoadInst>(I)) {
+      if (LI->getPointerOperand() == &SAI)
+        return false;
----------------
nikic wrote:

This would still allow something like this:
```
%a = structured.alloca {i32, i32}
%gep = structured.gep {i32, i32}, ptr %a, 0
%v = load i64, ptr %gep
```

In which case the split is also invalid under the current rules.

TBH I think this is not the right direction to go for structured gep semantics. I think we do want to specify that you can only access the "subobject" returned by structured.gep. Otherwise, we'll also get issues with alias analysis support. It's easiest if we can just say that structured.gep T, 0 and structured.gep T, 1 can never alias, otherwise we need to reason about sizes of accesses and then we'll run into problems because we have access sizes in bytes on one side and a type with unknown layout on the other, so it's unclear how we'd handle that in non-trivial cases.

https://github.com/llvm/llvm-project/pull/192058


More information about the llvm-commits mailing list