[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