[llvm-branch-commits] [llvm] IR: Intersect and drop the addrspacecast nonnull flag (PR #217904)
Matt Arsenault via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Aug 21 05:31:40 PDT 2026
https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/217904
Teach the flag-propagation controls about the nonnull flag
on addrspacecast.
Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
>From 915573d16ee8259ffbe7314521b596db5b5e3e2b Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 20 Aug 2026 21:58:34 +0200
Subject: [PATCH] IR: Intersect and drop the addrspacecast nonnull flag
Teach the flag-propagation controls about the nonnull flag
on addrspacecast.
Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
---
llvm/lib/IR/Instruction.cpp | 20 +++++++++
llvm/lib/IR/Operator.cpp | 4 ++
llvm/test/Transforms/EarlyCSE/flags.ll | 44 +++++++++++++++++++
llvm/test/Transforms/SimplifyCFG/HoistCode.ll | 30 +++++++++++++
llvm/unittests/IR/InstructionsTest.cpp | 21 +++++++++
5 files changed, 119 insertions(+)
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 1ac5bd6b636d1..6db2ba780ca65 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -475,6 +475,10 @@ void Instruction::dropPoisonGeneratingFlags() {
cast<ICmpInst>(this)->setSameSign(false);
break;
+ case Instruction::AddrSpaceCast:
+ cast<AddrSpaceCastInst>(this)->setNonNull(false);
+ break;
+
case Instruction::Call: {
if (auto *II = dyn_cast<IntrinsicInst>(this)) {
switch (II->getIntrinsicID()) {
@@ -766,6 +770,14 @@ void Instruction::copyIRFlags(const Value *V, bool IncludeWrapFlags) {
if (auto *SrcICmp = dyn_cast<ICmpInst>(V))
if (auto *DestICmp = dyn_cast<ICmpInst>(this))
DestICmp->setSameSign(SrcICmp->hasSameSign());
+
+ if (auto *SrcASC = dyn_cast<AddrSpaceCastInst>(V))
+ if (auto *DestASC = dyn_cast<AddrSpaceCastInst>(this)) {
+ assert(DestASC->getSrcAddressSpace() == SrcASC->getSrcAddressSpace() &&
+ "nonull flag cannot be safely preserved with different source "
+ "address spaces");
+ DestASC->setNonNull(SrcASC->hasNonNull());
+ }
}
void Instruction::andIRFlags(const Value *V) {
@@ -811,6 +823,14 @@ void Instruction::andIRFlags(const Value *V) {
if (auto *SrcICmp = dyn_cast<ICmpInst>(V))
if (auto *DestICmp = dyn_cast<ICmpInst>(this))
DestICmp->setSameSign(DestICmp->hasSameSign() && SrcICmp->hasSameSign());
+
+ if (auto *SrcASC = dyn_cast<AddrSpaceCastInst>(V))
+ if (auto *DestASC = dyn_cast<AddrSpaceCastInst>(this)) {
+ assert(DestASC->getSrcAddressSpace() == SrcASC->getSrcAddressSpace() &&
+ "nonull flag cannot be safely preserved with different source "
+ "address spaces");
+ DestASC->setNonNull(DestASC->hasNonNull() && SrcASC->hasNonNull());
+ }
}
const char *Instruction::getOpcodeName(unsigned OpCode) {
diff --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp
index 09a719b0f440f..b453b65063595 100644
--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -54,6 +54,10 @@ bool Operator::hasPoisonGeneratingFlags() const {
return false;
case Instruction::ICmp:
return cast<ICmpInst>(this)->hasSameSign();
+ case Instruction::AddrSpaceCast:
+ if (auto *ASC = dyn_cast<AddrSpaceCastInst>(this))
+ return ASC->hasNonNull();
+ return false;
case Instruction::Call:
if (auto *II = dyn_cast<IntrinsicInst>(this)) {
switch (II->getIntrinsicID()) {
diff --git a/llvm/test/Transforms/EarlyCSE/flags.ll b/llvm/test/Transforms/EarlyCSE/flags.ll
index dcaaacbac639f..ef1ba3792dce3 100644
--- a/llvm/test/Transforms/EarlyCSE/flags.ll
+++ b/llvm/test/Transforms/EarlyCSE/flags.ll
@@ -112,3 +112,47 @@ define i32 @load_undef_noundef(ptr %p) {
%v = load i32, ptr %p, !noundef !{}
ret i32 %v
}
+
+define void @addrspacecast_both_nonnull(ptr addrspace(1) %p) {
+; CHECK-LABEL: @addrspacecast_both_nonnull(
+; CHECK-NEXT: [[C1:%.*]] = addrspacecast nonnull ptr addrspace(1) [[P:%.*]] to ptr
+; CHECK-NEXT: call void @use.ptr(i32 0, ptr [[C1]])
+; CHECK-NEXT: call void @use.ptr(i32 1, ptr [[C1]])
+; CHECK-NEXT: ret void
+;
+ %c1 = addrspacecast nonnull ptr addrspace(1) %p to ptr
+ call void @use.ptr(i32 0, ptr %c1)
+ %c2 = addrspacecast nonnull ptr addrspace(1) %p to ptr
+ call void @use.ptr(i32 1, ptr %c2)
+ ret void
+}
+
+define void @addrspacecast_first_nonnull(ptr addrspace(1) %p) {
+; CHECK-LABEL: @addrspacecast_first_nonnull(
+; CHECK-NEXT: [[C1:%.*]] = addrspacecast ptr addrspace(1) [[P:%.*]] to ptr
+; CHECK-NEXT: call void @use.ptr(i32 0, ptr [[C1]])
+; CHECK-NEXT: call void @use.ptr(i32 1, ptr [[C1]])
+; CHECK-NEXT: ret void
+;
+ %c1 = addrspacecast nonnull ptr addrspace(1) %p to ptr
+ call void @use.ptr(i32 0, ptr %c1)
+ %c2 = addrspacecast ptr addrspace(1) %p to ptr
+ call void @use.ptr(i32 1, ptr %c2)
+ ret void
+}
+
+define void @addrspacecast_vector_first_nonnull(<2 x ptr addrspace(1)> %p) {
+; CHECK-LABEL: @addrspacecast_vector_first_nonnull(
+; CHECK-NEXT: [[C1:%.*]] = addrspacecast <2 x ptr addrspace(1)> [[P:%.*]] to <2 x ptr>
+; CHECK-NEXT: call void @use.vec(i32 0, <2 x ptr> [[C1]])
+; CHECK-NEXT: call void @use.vec(i32 1, <2 x ptr> [[C1]])
+; CHECK-NEXT: ret void
+;
+ %c1 = addrspacecast nonnull <2 x ptr addrspace(1)> %p to <2 x ptr>
+ call void @use.vec(i32 0, <2 x ptr> %c1)
+ %c2 = addrspacecast <2 x ptr addrspace(1)> %p to <2 x ptr>
+ call void @use.vec(i32 1, <2 x ptr> %c2)
+ ret void
+}
+
+declare void @use.vec(i32, <2 x ptr>) memory(read)
diff --git a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll
index f17652cc5e471..5d2bc55652d59 100644
--- a/llvm/test/Transforms/SimplifyCFG/HoistCode.ll
+++ b/llvm/test/Transforms/SimplifyCFG/HoistCode.ll
@@ -214,6 +214,36 @@ F:
ret i16 %z2
}
+define ptr @hoist_addrspacecast_flags_preserve(i1 %C, ptr addrspace(1) %p) {
+; CHECK-LABEL: @hoist_addrspacecast_flags_preserve(
+; CHECK-NEXT: common.ret:
+; CHECK-NEXT: [[Z1:%.*]] = addrspacecast nonnull ptr addrspace(1) [[P:%.*]] to ptr
+; CHECK-NEXT: ret ptr [[Z1]]
+;
+ br i1 %C, label %T, label %F
+T:
+ %z1 = addrspacecast nonnull ptr addrspace(1) %p to ptr
+ ret ptr %z1
+F:
+ %z2 = addrspacecast nonnull ptr addrspace(1) %p to ptr
+ ret ptr %z2
+}
+
+define ptr @hoist_addrspacecast_flags_drop(i1 %C, ptr addrspace(1) %p) {
+; CHECK-LABEL: @hoist_addrspacecast_flags_drop(
+; CHECK-NEXT: common.ret:
+; CHECK-NEXT: [[Z1:%.*]] = addrspacecast ptr addrspace(1) [[P:%.*]] to ptr
+; CHECK-NEXT: ret ptr [[Z1]]
+;
+ br i1 %C, label %T, label %F
+T:
+ %z1 = addrspacecast ptr addrspace(1) %p to ptr
+ ret ptr %z1
+F:
+ %z2 = addrspacecast nonnull ptr addrspace(1) %p to ptr
+ ret ptr %z2
+}
+
define ptr @hoist_gep_flags_both_nuw(i1 %C, ptr %p) {
; CHECK-LABEL: @hoist_gep_flags_both_nuw(
; CHECK-NEXT: common.ret:
diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp
index 6f8dc6a0b9f6f..da17c61608773 100644
--- a/llvm/unittests/IR/InstructionsTest.cpp
+++ b/llvm/unittests/IR/InstructionsTest.cpp
@@ -861,6 +861,27 @@ TEST_F(ModuleWithFunctionTest, DropPoisonGeneratingFlags) {
GI->dropPoisonGeneratingFlags();
ASSERT_FALSE(GI->isInBounds());
}
+
+ {
+ Value *Ptr = B.CreateIntToPtr(Arg0, B.getPtrTy(1));
+ auto *ASC = cast<AddrSpaceCastInst>(
+ B.CreateAddrSpaceCast(Ptr, B.getPtrTy(), "", /*IsNonNull*/ true));
+ EXPECT_TRUE(ASC->hasNonNull());
+ EXPECT_TRUE(ASC->hasPoisonGeneratingFlags());
+ ASC->dropPoisonGeneratingFlags();
+ EXPECT_FALSE(ASC->hasNonNull());
+ EXPECT_FALSE(ASC->hasPoisonGeneratingFlags());
+ }
+
+ {
+ // A ConstantExpr addrspacecast is an Operator but not an
+ // AddrSpaceCastInst; hasPoisonGeneratingFlags() must not assume the
+ // instruction subclass.
+ Constant *NullPtr = Constant::getNullValue(B.getPtrTy(1));
+ auto *CE =
+ cast<Operator>(ConstantExpr::getAddrSpaceCast(NullPtr, B.getPtrTy()));
+ EXPECT_FALSE(CE->hasPoisonGeneratingFlags());
+ }
}
TEST(InstructionsTest, GEPIndices) {
More information about the llvm-branch-commits
mailing list