[llvm-branch-commits] [llvm] InstSimplify: Fold nonnull addrspacecast of null to poison (PR #217905)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Aug 21 10:03:50 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Matt Arsenault (arsenm)

<details>
<summary>Changes</summary>

Perform the definitional fold if the source value is null
in the default address space.

Co-authored-by: Claude (Claude-Opus-4.8) <noreply@<!-- -->anthropic.com>

---
Full diff: https://github.com/llvm/llvm-project/pull/217905.diff


3 Files Affected:

- (modified) llvm/include/llvm/Analysis/InstructionSimplify.h (+4) 
- (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+23) 
- (added) llvm/test/Transforms/InstSimplify/addrspacecast-nonnull.ll (+69) 


``````````diff
diff --git a/llvm/include/llvm/Analysis/InstructionSimplify.h b/llvm/include/llvm/Analysis/InstructionSimplify.h
index 8f5a484ad2d57..61e1c59b59f56 100644
--- a/llvm/include/llvm/Analysis/InstructionSimplify.h
+++ b/llvm/include/llvm/Analysis/InstructionSimplify.h
@@ -194,6 +194,10 @@ LLVM_ABI Value *simplifyExtractElementInst(Value *Vec, Value *Idx,
 LLVM_ABI Value *simplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
                                  const SimplifyQuery &Q);
 
+/// Given operands for an AddrSpaceCastInst, fold the result or return null.
+LLVM_ABI Value *simplifyAddrSpaceCastInst(Value *Op, Type *Ty, bool IsNonNull,
+                                          const SimplifyQuery &Q);
+
 /// Given operands for an intrinsic, fold the result or return null. Context
 /// Function is passed as \p CxtF. \p ExBehavior and \p Rounding only apply to
 /// constrained FP intrinsics.
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index c76f4d2e9f327..22278d65d3fa1 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -5707,6 +5707,22 @@ Value *llvm::simplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
   return ::simplifyCastInst(CastOpc, Op, Ty, Q, RecursionLimit);
 }
 
+static Value *simplifyAddrSpaceCastInst(Value *Op, Type *Ty, bool IsNonNull,
+                                        const SimplifyQuery &Q,
+                                        unsigned MaxRecurse) {
+  if (IsNonNull && match(Op, m_Zero()) && Q.CxtI &&
+      !NullPointerIsDefined(Q.CxtI->getFunction(),
+                            Op->getType()->getPointerAddressSpace()))
+    return PoisonValue::get(Ty);
+
+  return ::simplifyCastInst(Instruction::AddrSpaceCast, Op, Ty, Q, MaxRecurse);
+}
+
+Value *llvm::simplifyAddrSpaceCastInst(Value *Op, Type *Ty, bool IsNonNull,
+                                       const SimplifyQuery &Q) {
+  return ::simplifyAddrSpaceCastInst(Op, Ty, IsNonNull, Q, RecursionLimit);
+}
+
 /// For the given destination element of a shuffle, peek through shuffles to
 /// match a root vector source operand that contains that element in the same
 /// vector lane (ie, the same mask index), so we can eliminate the shuffle(s).
@@ -7831,6 +7847,13 @@ static Value *simplifyInstructionWithOperands(Instruction *I,
 #define HANDLE_CAST_INST(num, opc, clas) case Instruction::opc:
 #include "llvm/IR/Instruction.def"
 #undef HANDLE_CAST_INST
+    if (I->getOpcode() == Instruction::AddrSpaceCast) {
+      return simplifyAddrSpaceCastInst(
+          NewOps[0], I->getType(),
+          Q.IIQ.UseInstrInfo && cast<AddrSpaceCastInst>(I)->hasNonNull(), Q,
+          MaxRecurse);
+    }
+
     return simplifyCastInst(I->getOpcode(), NewOps[0], I->getType(), Q,
                             MaxRecurse);
   case Instruction::Alloca:
diff --git a/llvm/test/Transforms/InstSimplify/addrspacecast-nonnull.ll b/llvm/test/Transforms/InstSimplify/addrspacecast-nonnull.ll
new file mode 100644
index 0000000000000..819577a802c4f
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/addrspacecast-nonnull.ll
@@ -0,0 +1,69 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=instsimplify < %s | FileCheck %s
+
+; A nonnull addrspacecast of the address space 0 null value is poison.
+define ptr addrspace(1) @fold_scalar() {
+; CHECK-LABEL: @fold_scalar(
+; CHECK-NEXT:    ret ptr addrspace(1) poison
+;
+  %c = addrspacecast nonnull ptr null to ptr addrspace(1)
+  ret ptr addrspace(1) %c
+}
+
+; A splat null vector of address space 0 pointers folds elementwise.
+define <2 x ptr addrspace(1)> @fold_vector() {
+; CHECK-LABEL: @fold_vector(
+; CHECK-NEXT:    ret <2 x ptr addrspace(1)> poison
+;
+  %c = addrspacecast nonnull <2 x ptr> zeroinitializer to <2 x ptr addrspace(1)>
+  ret <2 x ptr addrspace(1)> %c
+}
+
+define <2 x ptr addrspace(1)> @no_fold_splat_poison() {
+; CHECK-LABEL: @no_fold_splat_poison(
+; CHECK-NEXT:    ret <2 x ptr addrspace(1)> <ptr addrspace(1) addrspacecast (ptr null to ptr addrspace(1)), ptr addrspace(1) poison>
+;
+  %c = addrspacecast nonnull <2 x ptr> <ptr null, ptr poison> to <2 x ptr addrspace(1)>
+  ret <2 x ptr addrspace(1)> %c
+}
+
+; Without the nonnull flag the cast is not poison.
+define ptr addrspace(1) @no_fold_without_flag() {
+; CHECK-LABEL: @no_fold_without_flag(
+; CHECK-NEXT:    ret ptr addrspace(1) addrspacecast (ptr null to ptr addrspace(1))
+;
+  %c = addrspacecast ptr null to ptr addrspace(1)
+  ret ptr addrspace(1) %c
+}
+
+; A non-null source is not folded.
+define ptr addrspace(1) @no_fold_nonzero_src(ptr %p) {
+; CHECK-LABEL: @no_fold_nonzero_src(
+; CHECK-NEXT:    [[C:%.*]] = addrspacecast nonnull ptr [[P:%.*]] to ptr addrspace(1)
+; CHECK-NEXT:    ret ptr addrspace(1) [[C]]
+;
+  %c = addrspacecast nonnull ptr %p to ptr addrspace(1)
+  ret ptr addrspace(1) %c
+}
+
+; The null value of a non-zero source address space is not necessarily the zero
+; pointer, so casting it is not folded to poison.
+define ptr @no_fold_src_as1() {
+; CHECK-LABEL: @no_fold_src_as1(
+; CHECK-NEXT:    ret ptr addrspacecast (ptr addrspace(1) null to ptr)
+;
+  %c = addrspacecast nonnull ptr addrspace(1) null to ptr
+  ret ptr %c
+}
+
+; When null is a valid address for the function, the source may legitimately be
+; the null pointer, so the fold does not apply.
+define ptr addrspace(1) @no_fold_null_valid() #0 {
+; CHECK-LABEL: @no_fold_null_valid(
+; CHECK-NEXT:    ret ptr addrspace(1) addrspacecast (ptr null to ptr addrspace(1))
+;
+  %c = addrspacecast nonnull ptr null to ptr addrspace(1)
+  ret ptr addrspace(1) %c
+}
+
+attributes #0 = { null_pointer_is_valid }

``````````

</details>


https://github.com/llvm/llvm-project/pull/217905


More information about the llvm-branch-commits mailing list