[llvm] [IR] Only follow ptr/ptr-vector sources in stripAndAccumulateConstantOffsets bitcasts (PR #203356)
Anshil Gandhi via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 11 13:08:27 PDT 2026
https://github.com/gandhi56 updated https://github.com/llvm/llvm-project/pull/203356
>From 28dad855de63f374a918739fdbb4d5f03147878e Mon Sep 17 00:00:00 2001
From: Anshil Gandhi <Anshil.Gandhi at amd.com>
Date: Thu, 11 Jun 2026 11:59:14 -0500
Subject: [PATCH] [IR] Only follow ptr (or ptr-vector) sources in
stripAndAccumulateConstantOffsets bitcasts
stripAndAccumulateConstantOffsets used to walk through every bitcast operand.
If the operand was not a pointer (e.g. a same-sized byte type such as b64
reinterpreted as ptr), the walk could continue and violate the invariant that
the stripped value remains ptr or ptr-vector.
Align with stripPointerCastsAndOffsets: only look through bitcasts whose
source type is a pointer or pointer vector; keep addrspacecast as its own case.
Add unit tests for ptr-to-ptr bitcast (GEP offset accumulated through) and
for non-pointer-to-ptr bitcast (stop at the bitcast while still applying the
GEP offset).
This commit is needed in PR #177908.
---
llvm/lib/IR/Value.cpp | 16 +++++----
llvm/unittests/IR/InstructionsTest.cpp | 45 ++++++++++++++++++++++++++
2 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
index 6f71a5093e4a3..fa74b7cbb353d 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -783,17 +783,21 @@ const Value *Value::stripAndAccumulateConstantOffsets(
}
}
V = GEP->getPointerOperand();
- } else if (Operator::getOpcode(V) == Instruction::BitCast ||
- Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
+ } else if (Operator::getOpcode(V) == Instruction::BitCast) {
+ const Value *Src = cast<Operator>(V)->getOperand(0);
+ if (!Src->getType()->isPtrOrPtrVectorTy())
+ return V;
+ V = Src;
+ } else if (Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
V = cast<Operator>(V)->getOperand(0);
} else if (auto *GA = dyn_cast<GlobalAlias>(V)) {
if (!GA->isInterposable())
V = GA->getAliasee();
} else if (const auto *Call = dyn_cast<CallBase>(V)) {
- if (const Value *RV = Call->getReturnedArgOperand())
- V = RV;
- if (AllowInvariantGroup && Call->isLaunderOrStripInvariantGroup())
- V = Call->getArgOperand(0);
+ if (const Value *RV = Call->getReturnedArgOperand())
+ V = RV;
+ if (AllowInvariantGroup && Call->isLaunderOrStripInvariantGroup())
+ V = Call->getArgOperand(0);
} else if (auto *Int2Ptr = dyn_cast<Operator>(V)) {
// Try to accumulate across (inttoptr (add (ptrtoint p), off)).
if (!AllowNonInbounds || !LookThroughIntToPtr || !Int2Ptr ||
diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp
index a1f22bbac02a1..bb2e5cdbf9187 100644
--- a/llvm/unittests/IR/InstructionsTest.cpp
+++ b/llvm/unittests/IR/InstructionsTest.cpp
@@ -2011,4 +2011,49 @@ TEST(InstructionsTest, StripAndAccumulateConstantOffset) {
EXPECT_TRUE(Offset.isZero());
}
+TEST(InstructionsTest, StripAndAccumulateConstantOffsets_ThroughPtrBitCast) {
+ LLVMContext C;
+ DataLayout DL("e-p:64:64:64-i64:64");
+ std::unique_ptr<Module> M = parseIR(C, R"(
+ define void @foo(ptr %p) {
+ %bc = bitcast ptr %p to ptr
+ %gep = getelementptr inbounds i8, ptr %bc, i64 2
+ ret void
+ })");
+ ASSERT_TRUE(M);
+ BasicBlock &BB = M->getFunction("foo")->getEntryBlock();
+ auto It = BB.begin();
+ Value *BC = &*It++;
+ (void)BC;
+ Value *GEP = &*It++;
+ ASSERT_TRUE(isa<GetElementPtrInst>(GEP));
+ APInt Offset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
+ Value *Stripped = GEP->stripAndAccumulateConstantOffsets(
+ DL, Offset, /*AllowNonInbounds=*/true);
+ EXPECT_EQ(Stripped, M->getFunction("foo")->getArg(0));
+ EXPECT_EQ(Offset, APInt(DL.getIndexTypeSizeInBits(GEP->getType()), 2));
+}
+
+TEST(InstructionsTest,
+ StripAndAccumulateConstantOffsets_NoLookThroughNonPtrToPtrBitCast) {
+ LLVMContext C;
+ DataLayout DL("e-p:64:64:64-i64:64");
+ std::unique_ptr<Module> M = parseIR(C, R"(
+ define void @foo(b64 %x) {
+ %bc = bitcast b64 %x to ptr
+ %gep = getelementptr inbounds i8, ptr %bc, i64 1
+ ret void
+ })");
+ ASSERT_TRUE(M);
+ BasicBlock &BB = M->getFunction("foo")->getEntryBlock();
+ auto It = BB.begin();
+ Value *BC = &*It++;
+ Value *GEP = &*It++;
+ APInt Offset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
+ Value *Stripped = GEP->stripAndAccumulateConstantOffsets(
+ DL, Offset, /*AllowNonInbounds=*/true);
+ EXPECT_EQ(Stripped, BC);
+ EXPECT_EQ(Offset, APInt(DL.getIndexTypeSizeInBits(GEP->getType()), 1));
+}
+
} // end anonymous namespace
More information about the llvm-commits
mailing list