[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