[llvm] [SandboxVec][Legality] Implement unsupported alignment check (PR #224081)

Vasileios Porpodas via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 10:58:32 PDT 2026


https://github.com/vporpo updated https://github.com/llvm/llvm-project/pull/224081

>From 5544430d961130ab0bbdfdbf4665b2248a346d6c Mon Sep 17 00:00:00 2001
From: Vasileios Porpodas <vasileios.porpodas at amd.com>
Date: Tue, 15 Sep 2026 20:30:04 +0000
Subject: [PATCH] [SandboxVec][Legality] Implement unsupported alignment check

This patch implements the legality check for unsupported alignment by the target.
---
 llvm/include/llvm/SandboxIR/Instruction.h     |  9 ++++++++
 llvm/include/llvm/SandboxIR/Module.h          |  3 +++
 llvm/include/llvm/SandboxIR/Utils.h           | 10 ++++++++
 .../Vectorize/SandboxVectorizer/Legality.h    | 14 +++++++++--
 .../Vectorize/SandboxVectorizer/Legality.cpp  | 23 +++++++++++++++++++
 .../SandboxVectorizer/Passes/BundleVec.cpp    |  4 ++--
 .../BundleVec/AMDGPU/unsupported_alignment.ll |  4 +++-
 llvm/unittests/SandboxIR/SandboxIRTest.cpp    |  4 ++++
 .../SandboxVectorizer/LegalityTest.cpp        |  9 +++++---
 9 files changed, 72 insertions(+), 8 deletions(-)

diff --git a/llvm/include/llvm/SandboxIR/Instruction.h b/llvm/include/llvm/SandboxIR/Instruction.h
index 1e07beec9b2cb..3b9e579db80da 100644
--- a/llvm/include/llvm/SandboxIR/Instruction.h
+++ b/llvm/include/llvm/SandboxIR/Instruction.h
@@ -2780,6 +2780,15 @@ inline unsigned getLoadStoreAddressSpace(const Instruction *I) {
   return cast<StoreInst>(I)->getPointerAddressSpace();
 }
 
+/// A helper function that returns the alignment of load or store instruction.
+inline Align getLoadStoreAlignment(const Value *I) {
+  assert((isa<LoadInst>(I) || isa<StoreInst>(I)) &&
+         "Expected Load or Store instruction");
+  if (auto *LI = dyn_cast<LoadInst>(I))
+    return LI->getAlign();
+  return cast<StoreInst>(I)->getAlign();
+}
+
 } // namespace llvm::sandboxir
 
 #endif // LLVM_SANDBOXIR_INSTRUCTION_H
diff --git a/llvm/include/llvm/SandboxIR/Module.h b/llvm/include/llvm/SandboxIR/Module.h
index 275960392211d..fc79bf514df09 100644
--- a/llvm/include/llvm/SandboxIR/Module.h
+++ b/llvm/include/llvm/SandboxIR/Module.h
@@ -43,6 +43,9 @@ class Module {
 
   const DataLayout &getDataLayout() const { return LLVMM.getDataLayout(); }
 
+  /// Get the target triple which is a string describing the target host.
+  const Triple &getTargetTriple() const { return LLVMM.getTargetTriple(); }
+
   const std::string &getSourceFileName() const {
     return LLVMM.getSourceFileName();
   }
diff --git a/llvm/include/llvm/SandboxIR/Utils.h b/llvm/include/llvm/SandboxIR/Utils.h
index 8bc62169738e6..c22b7de3b9594 100644
--- a/llvm/include/llvm/SandboxIR/Utils.h
+++ b/llvm/include/llvm/SandboxIR/Utils.h
@@ -16,6 +16,7 @@
 #include "llvm/Analysis/LoopAccessAnalysis.h"
 #include "llvm/Analysis/MemoryLocation.h"
 #include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/SandboxIR/Function.h"
@@ -132,6 +133,15 @@ class Utils {
     const auto &LLVMF = *cast<llvm::Function>(F->Val);
     return llvm::verifyFunction(LLVMF, &OS);
   }
+
+  static bool TTIAllowsMisalignedMemoryAccesses(TargetTransformInfo &TTI,
+                                                Context &Ctx, unsigned BitWidth,
+                                                unsigned AddressSpace = 0,
+                                                Align Alignment = Align(1),
+                                                unsigned *Fast = nullptr) {
+    return TTI.allowsMisalignedMemoryAccesses(Ctx.LLVMCtx, BitWidth,
+                                              AddressSpace, Alignment, Fast);
+  }
 };
 
 } // namespace llvm::sandboxir
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h
index e4519fb7e1ec7..f773e26f0086e 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h
@@ -14,6 +14,7 @@
 
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Compiler.h"
@@ -95,6 +96,7 @@ enum class ResultReason {
   DiffBBs,
   RepeatedInstrs,
   NotConsecutive,
+  AlignmentNotSupported,
   CantSchedule,
   Unimplemented,
   Infeasible,
@@ -137,6 +139,8 @@ struct ToStr {
       return "RepeatedInstrs";
     case ResultReason::NotConsecutive:
       return "NotConsecutive";
+    case ResultReason::AlignmentNotSupported:
+      return "AlignmentNotSupported";
     case ResultReason::CantSchedule:
       return "CantSchedule";
     case ResultReason::Unimplemented:
@@ -326,6 +330,7 @@ class LegalityAnalysis {
 
   ScalarEvolution &SE;
   const DataLayout &DL;
+  TargetTransformInfo &TTI;
   InstrMaps &IMaps;
 
   /// Finds how we can collect the values in \p Bndl from the vectorized or
@@ -335,8 +340,9 @@ class LegalityAnalysis {
 
 public:
   LegalityAnalysis(AAResults &AA, ScalarEvolution &SE, const DataLayout &DL,
-                   Context &Ctx, InstrMaps &IMaps, SchedDirection Dir)
-      : Sched(AA, Ctx, Dir), SE(SE), DL(DL), IMaps(IMaps) {}
+                   TargetTransformInfo &TTI, Context &Ctx, InstrMaps &IMaps,
+                   SchedDirection Dir)
+      : Sched(AA, Ctx, Dir), SE(SE), DL(DL), TTI(TTI), IMaps(IMaps) {}
   /// A LegalityResult factory.
   template <typename ResultT, typename... ArgsT>
   ResultT &createLegalityResult(ArgsT &&...Args) {
@@ -360,6 +366,10 @@ class LegalityAnalysis {
     return Unique.size() == Values.size();
   }
 
+  /// \returns true if the alignment of the vector composed of \p Values has
+  /// alignment that is supported by the target.
+  bool isAlignmentSupported(ArrayRef<Value *> Values) const;
+
   /// Checks if it's legal to vectorize the instructions in \p Bndl.
   /// \Returns a LegalityResult object owned by LegalityAnalysis.
   /// \p SkipScheduling skips the scheduler check and is only meant for testing.
diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Legality.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Legality.cpp
index 05201ff502997..d41a151f721d6 100644
--- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Legality.cpp
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Legality.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h"
 #include "llvm/SandboxIR/Instruction.h"
+#include "llvm/SandboxIR/Module.h"
 #include "llvm/SandboxIR/Operator.h"
 #include "llvm/SandboxIR/Utils.h"
 #include "llvm/SandboxIR/Value.h"
@@ -213,6 +214,25 @@ LegalityAnalysis::getHowToCollectValues(BndlRef<Value *> Bndl) const {
   return CollectDescr(std::move(Vec));
 }
 
+bool LegalityAnalysis::isAlignmentSupported(ArrayRef<Value *> Values) const {
+  Value *V0 = Values[0];
+  if (!isa<LoadInst>(V0) && !isa<StoreInst>(V0))
+    return true;
+  Instruction *I0 = cast<Instruction>(V0);
+  // If the target is not set, just return true. This helps simplify
+  // target-independent lit tests.
+  if (I0->getParent()->getParent()->getParent()->getTargetTriple().empty())
+    return true;
+  Align Alignment = getLoadStoreAlignment(I0);
+  unsigned VecSizeBits =
+      Utils::getNumBits(Utils::getExpectedType(I0), DL) * Values.size();
+  unsigned AS = getLoadStoreAddressSpace(I0);
+  unsigned Fast = 0;
+  bool Supported = Utils::TTIAllowsMisalignedMemoryAccesses(
+      TTI, I0->getContext(), VecSizeBits, AS, Alignment, &Fast);
+  return Supported;
+}
+
 const LegalityResult &LegalityAnalysis::canVectorize(BndlRef<Value *> Bndl,
                                                      bool SkipScheduling) {
   // If Bndl contains values other than instructions, we need to Pack.
@@ -224,6 +244,9 @@ const LegalityResult &LegalityAnalysis::canVectorize(BndlRef<Value *> Bndl,
   // Pack if instructions repeat, i.e., require some sort of broadcast.
   if (!LegalityAnalysis::areUnique(Bndl))
     return createLegalityResult<Pack>(ResultReason::RepeatedInstrs);
+  // Check if the target supports the alignment of the generated vector.
+  if (!isAlignmentSupported(Bndl))
+    return createLegalityResult<Pack>(ResultReason::AlignmentNotSupported);
 
   auto CollectDescrs = getHowToCollectValues(Bndl);
   if (CollectDescrs.hasVectorInputs()) {
diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.cpp
index 80dd30896b00b..bcfd36ce0fbd0 100644
--- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.cpp
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.cpp
@@ -535,8 +535,8 @@ bool BundleVec::runOnRegion(Region &Rgn, const Analyses &A) {
   Function &F = *SeedSlice[0]->getParent()->getParent();
   IMaps = std::make_unique<InstrMaps>();
   LegalityAnalysis Legality(A.getAA(), A.getScalarEvolution(),
-                            F.getParent()->getDataLayout(), F.getContext(),
-                            *IMaps, Dir);
+                            F.getParent()->getDataLayout(), A.getTTI(),
+                            F.getContext(), *IMaps, Dir);
 
   // TODO: Refactor to remove the unnecessary copy to SeedSliceVals.
   SmallVector<Value *> SeedSliceVals(SeedSlice.begin(), SeedSlice.end());
diff --git a/llvm/test/Transforms/SandboxVectorizer/Passes/BundleVec/AMDGPU/unsupported_alignment.ll b/llvm/test/Transforms/SandboxVectorizer/Passes/BundleVec/AMDGPU/unsupported_alignment.ll
index 85ded44d7c154..4d546befc9db4 100644
--- a/llvm/test/Transforms/SandboxVectorizer/Passes/BundleVec/AMDGPU/unsupported_alignment.ll
+++ b/llvm/test/Transforms/SandboxVectorizer/Passes/BundleVec/AMDGPU/unsupported_alignment.ll
@@ -6,7 +6,9 @@
 define void @unsupported_alignment(ptr %ptr0, i32 %offset) {
 ; CHECK-LABEL: define void @unsupported_alignment(
 ; CHECK-SAME: ptr [[PTR0:%.*]], i32 [[OFFSET:%.*]]) #[[ATTR0:[0-9]+]] {
-; CHECK-NEXT:    store <2 x i8> <i8 0, i8 1>, ptr [[PTR0]], align 1, !sandboxvec [[META0:![0-9]+]]
+; CHECK-NEXT:    [[PTR1:%.*]] = getelementptr i8, ptr [[PTR0]], i32 1
+; CHECK-NEXT:    store i8 0, ptr [[PTR0]], align 1, !sandboxvec [[META0:![0-9]+]]
+; CHECK-NEXT:    store i8 1, ptr [[PTR1]], align 1, !sandboxvec [[META0]]
 ; CHECK-NEXT:    ret void
 ;
   %ptr1 = getelementptr i8, ptr %ptr0, i32 1
diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
index 9cada23da4404..58ee78c6bcbc5 100644
--- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp
+++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
@@ -1927,6 +1927,8 @@ define void @bar() {
   EXPECT_EQ(FBar, Ctx.getValue(LLVMFBar));
   // Check getDataLayout().
   EXPECT_EQ(&M->getDataLayout(), &LLVMM->getDataLayout());
+  // Check getTargetTriple().
+  EXPECT_EQ(&M->getTargetTriple(), &LLVMM->getTargetTriple());
   // Check getSourceFileName().
   EXPECT_EQ(M->getSourceFileName(), LLVMM->getSourceFileName());
   // Check getGlobalVariable().
@@ -3267,6 +3269,8 @@ define void @foo(ptr %arg0, ptr %arg1) {
   EXPECT_EQ(getLoadStoreAddressSpace(NewLd), NewLd->getPointerAddressSpace());
   EXPECT_EQ(NewLd->getAlign(), 8);
   EXPECT_EQ(NewLd->getName(), "NewLd");
+  // Check helper function getLoadStoreAlignment()
+  EXPECT_EQ(getLoadStoreAlignment(NewLd), NewLd->getAlign());
   // Check create(InsertBefore, IsVolatile=true)
   sandboxir::LoadInst *NewVLd = sandboxir::LoadInst::create(
       VLd->getType(), Arg1, Align(8), Ret->getIterator(),
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp
index e5ddf53b598c1..4c88ad87b9209 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp
@@ -12,6 +12,7 @@
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/ScalarEvolution.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/Dominators.h"
@@ -35,6 +36,7 @@ struct LegalityTest : public testing::Test {
   std::unique_ptr<ScalarEvolution> SE;
   std::unique_ptr<BasicAAResult> BAA;
   std::unique_ptr<AAResults> AA;
+  std::unique_ptr<TargetTransformInfo> TTI;
 
   void getAnalyses(llvm::Function &LLVMF) {
     DT = std::make_unique<DominatorTree>(LLVMF);
@@ -50,6 +52,7 @@ struct LegalityTest : public testing::Test {
   void parseIR(LLVMContext &C, const char *IR) {
     SMDiagnostic Err;
     M = parseAssemblyString(IR, Err, C);
+    TTI = std::make_unique<TargetTransformInfo>(M->getDataLayout());
     if (!M) {
       Err.print("LegalityTest", errs());
       return;
@@ -137,7 +140,7 @@ define void @foo(ptr %ptr, <2 x float> %vec2, <3 x float> %vec3, i8 %arg, float
   auto *Sel1 = cast<sandboxir::SelectInst>(&*It++);
 
   llvm::sandboxir::InstrMaps IMaps;
-  sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, Ctx, IMaps,
+  sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, *TTI, Ctx, IMaps,
                                        sandboxir::SchedDirection::BottomUp);
   const auto &Result =
       Legality.canVectorize({St0, St1}, /*SkipScheduling=*/true);
@@ -290,7 +293,7 @@ define void @foo(ptr %ptr) {
   auto *St1 = cast<sandboxir::StoreInst>(&*It++);
 
   llvm::sandboxir::InstrMaps IMaps;
-  sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, Ctx, IMaps,
+  sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, *TTI, Ctx, IMaps,
                                        sandboxir::SchedDirection::BottomUp);
   {
     // Can vectorize St0,St1.
@@ -327,7 +330,7 @@ define void @foo() {
 
   sandboxir::Context Ctx(C);
   llvm::sandboxir::InstrMaps IMaps;
-  sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, Ctx, IMaps,
+  sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, *TTI, Ctx, IMaps,
                                        sandboxir::SchedDirection::BottomUp);
   EXPECT_TRUE(
       Matches(Legality.createLegalityResult<sandboxir::Widen>(), "Widen"));



More information about the llvm-commits mailing list