[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