Skip to content

[RFC][IR] Support vector splats in ConstantPointerNull#195486

Merged
shiltian merged 1 commit intomainfrom
users/shiltian/constant-pointer-null-vector-splat
May 5, 2026
Merged

[RFC][IR] Support vector splats in ConstantPointerNull#195486
shiltian merged 1 commit intomainfrom
users/shiltian/constant-pointer-null-vector-splat

Conversation

@shiltian
Copy link
Copy Markdown
Contributor

@shiltian shiltian commented May 2, 2026

This PR allows ConstantPointerNull to represent both scalar pointer nulls and fixed or scalable vector splats of pointer nulls. This change first aligns with the native splat behavior of ConstantInt and ConstantFP, and second, makes it easier to eventually change the semantics of ConstantPointerNull to represent a semantic null pointer instead of a zero value, which is what it represents today.


This PR is with help with AI but I reviewed all the code changes.

@shiltian shiltian requested a review from nikic as a code owner May 2, 2026 22:05
@shiltian
Copy link
Copy Markdown
Contributor Author

shiltian commented May 2, 2026

This stack of pull requests is managed by sgh.

@llvmorg-github-actions llvmorg-github-actions Bot added backend:AMDGPU llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes backend:NVPTX llvm:ir llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms llvm:SandboxIR labels May 2, 2026
@shiltian shiltian requested review from arichardson and arsenm May 2, 2026 22:05
@llvmorg-github-actions
Copy link
Copy Markdown

llvmorg-github-actions Bot commented May 2, 2026

@llvm/pr-subscribers-backend-risc-v
@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-llvm-ir
@llvm/pr-subscribers-backend-amdgpu

@llvm/pr-subscribers-llvm-analysis

Author: Shilei Tian (shiltian)

Changes

This PR allows ConstantPointerNull to represent both scalar pointer nulls and
fixed or scalable vector splats of pointer nulls. This change first aligns with
the native splat behavior of ConstantInt and ConstantFP, and second, makes
it easier to eventually change the semantics of ConstantPointerNull to
represent a semantic null pointer instead of a zero value, which is what it
represents today.


Patch is 123.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/195486.diff

56 Files Affected:

  • (modified) llvm/include/llvm/IR/Constants.h (+10-7)
  • (modified) llvm/include/llvm/SandboxIR/Constant.h (+2-1)
  • (modified) llvm/lib/Analysis/BasicAliasAnalysis.cpp (+2-2)
  • (modified) llvm/lib/Analysis/GlobalsModRef.cpp (+1-1)
  • (modified) llvm/lib/Analysis/MemoryBuiltins.cpp (+1-1)
  • (modified) llvm/lib/IR/AsmWriter.cpp (+10-1)
  • (modified) llvm/lib/IR/Constants.cpp (+51-4)
  • (modified) llvm/lib/IR/LLVMContextImpl.h (+1-1)
  • (modified) llvm/lib/SandboxIR/Constant.cpp (+6-2)
  • (modified) llvm/lib/Transforms/Utils/ValueMapper.cpp (+1-1)
  • (modified) llvm/test/Assembler/ConstantExprFold.ll (+2-2)
  • (modified) llvm/test/Assembler/aggregate-constant-values.ll (+24)
  • (modified) llvm/test/Assembler/opaque-ptr.ll (+1-1)
  • (modified) llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll (+1-1)
  • (modified) llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll (+1-1)
  • (modified) llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll (+7-7)
  • (modified) llvm/test/Instrumentation/MemorySanitizer/msan_basic.ll (+6-6)
  • (modified) llvm/test/Transforms/ConstraintElimination/geps-ptrvector.ll (+1-1)
  • (modified) llvm/test/Transforms/FunctionAttrs/vector-of-pointers-getunderlyingobject-crash.ll (+1-1)
  • (modified) llvm/test/Transforms/InferAddressSpaces/AMDGPU/issue110433.ll (+2-2)
  • (modified) llvm/test/Transforms/InstCombine/call.ll (+2-2)
  • (modified) llvm/test/Transforms/InstCombine/gep-inbounds-null.ll (+3-3)
  • (modified) llvm/test/Transforms/InstCombine/icmp.ll (+1-1)
  • (modified) llvm/test/Transforms/InstCombine/or.ll (+4-4)
  • (modified) llvm/test/Transforms/InstCombine/scalar_vector_gep.ll (+1-1)
  • (modified) llvm/test/Transforms/InstCombine/vscale_cmp.ll (+1-1)
  • (modified) llvm/test/Transforms/InstSimplify/ConstProp/inttoptr-gep-nonintegral.ll (+4-4)
  • (modified) llvm/test/Transforms/InstSimplify/gep.ll (+7-7)
  • (modified) llvm/test/Transforms/InstSimplify/vscale.ll (+2-2)
  • (modified) llvm/test/Transforms/LoadStoreVectorizer/NVPTX/4x2xhalf.ll (+8-8)
  • (modified) llvm/test/Transforms/LoopIdiom/non-integral-pointers.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/cost-model.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/interleave-opaque-pointers.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/invariant-load-gather.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/masked_load_store.ll (+30-30)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/optsize.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/find-last.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/single_early_exit.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/vector-loop-backedge-elimination-outside-iv-users.ll (+8-8)
  • (modified) llvm/test/Transforms/RewriteStatepointsForGC/base-inference.ll (+18-9)
  • (modified) llvm/test/Transforms/RewriteStatepointsForGC/base-pointers.ll (+9-9)
  • (modified) llvm/test/Transforms/RewriteStatepointsForGC/base-vector.ll (+31-31)
  • (modified) llvm/test/Transforms/RewriteStatepointsForGC/insert-extract.ll (+10-10)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/catchswitch-block-in-use.ll (+3-3)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/many-uses-parent-node.ll (+1-1)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/scatter-vectorize-reorder-non-empty.ll (+1-1)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/split-vectorize-phi-user.ll (+1-1)
  • (modified) llvm/test/Transforms/SLPVectorizer/extract-vectorized-operand.ll (+3-3)
  • (modified) llvm/test/Transforms/SLPVectorizer/gep-with-extractelement-many-users.ll (+1-1)
  • (modified) llvm/test/Transforms/SLPVectorizer/revec.ll (+2-2)
  • (modified) llvm/test/Transforms/SROA/vector-promotion.ll (+2-2)
  • (modified) llvm/test/Transforms/Scalarizer/constant-extractelement.ll (+1-1)
  • (modified) llvm/test/Verifier/opaque-ptr.ll (+1-1)
  • (modified) llvm/test/Verifier/ptrmask.ll (+2-2)
  • (modified) llvm/test/tools/llvm-reduce/reduce-operands-ptr.ll (+1-1)
  • (modified) llvm/unittests/IR/ConstantsTest.cpp (+28)
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index 2b3f4119e50e2..52b1af323f3d3 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -696,12 +696,13 @@ class ConstantVector final : public ConstantAggregate {
 };
 
 //===----------------------------------------------------------------------===//
-/// A constant pointer value that points to null
+/// A constant pointer value that points to null. This represents both scalar
+/// pointer nulls and vector splats of pointer nulls.
 ///
 class ConstantPointerNull final : public ConstantData {
   friend class Constant;
 
-  explicit ConstantPointerNull(PointerType *T)
+  explicit ConstantPointerNull(Type *T)
       : ConstantData(T, Value::ConstantPointerNullVal) {}
 
   void destroyConstantImpl();
@@ -709,13 +710,15 @@ class ConstantPointerNull final : public ConstantData {
 public:
   ConstantPointerNull(const ConstantPointerNull &) = delete;
 
-  /// Static factory methods - Return objects of the specified value
+  /// Static factory methods - Return objects of the specified value. If Ty is a
+  /// vector type, return a ConstantPointerNull with a splat of null pointer
+  /// values. Otherwise return a ConstantPointerNull for the given pointer type.
   LLVM_ABI static ConstantPointerNull *get(PointerType *T);
+  LLVM_ABI static ConstantPointerNull *get(Type *T);
 
-  /// Specialize the getType() method to always return an PointerType,
-  /// which reduces the amount of casting needed in parts of the compiler.
-  inline PointerType *getType() const {
-    return cast<PointerType>(Value::getType());
+  /// Return the scalar pointer type for this null value.
+  inline PointerType *getPointerType() const {
+    return cast<PointerType>(Value::getType()->getScalarType());
   }
 
   /// Methods for support type inquiry through isa, cast, and dyn_cast:
diff --git a/llvm/include/llvm/SandboxIR/Constant.h b/llvm/include/llvm/SandboxIR/Constant.h
index 669cc79aed957..99543c03de82a 100644
--- a/llvm/include/llvm/SandboxIR/Constant.h
+++ b/llvm/include/llvm/SandboxIR/Constant.h
@@ -773,7 +773,8 @@ class ConstantPointerNull final : public Constant {
 public:
   LLVM_ABI static ConstantPointerNull *get(PointerType *Ty);
 
-  LLVM_ABI PointerType *getType() const;
+  LLVM_ABI Type *getType() const;
+  LLVM_ABI PointerType *getPointerType() const;
 
   /// For isa/dyn_cast.
   static bool classof(const sandboxir::Value *From) {
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index bb8a17c37c881..8172cf29d890b 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -1640,10 +1640,10 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, LocationSize V1Size,
   // Null values in the default address space don't point to any object, so they
   // don't alias any other pointer.
   if (const ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(O1))
-    if (!NullPointerIsDefined(&F, CPN->getType()->getAddressSpace()))
+    if (!NullPointerIsDefined(&F, CPN->getPointerType()->getAddressSpace()))
       return AliasResult::NoAlias;
   if (const ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(O2))
-    if (!NullPointerIsDefined(&F, CPN->getType()->getAddressSpace()))
+    if (!NullPointerIsDefined(&F, CPN->getPointerType()->getAddressSpace()))
       return AliasResult::NoAlias;
 
   if (O1 != O2) {
diff --git a/llvm/lib/Analysis/GlobalsModRef.cpp b/llvm/lib/Analysis/GlobalsModRef.cpp
index 295e267848b23..a0d75334f0f2b 100644
--- a/llvm/lib/Analysis/GlobalsModRef.cpp
+++ b/llvm/lib/Analysis/GlobalsModRef.cpp
@@ -773,7 +773,7 @@ bool GlobalsAAResult::isNonEscapingGlobalNoAlias(const GlobalValue *GV,
       if (auto *CPN = dyn_cast<ConstantPointerNull>(Input)) {
         // Null pointer cannot alias with a non-addr-taken global.
         const Function *F = CtxI->getFunction();
-        if (!NullPointerIsDefined(F, CPN->getType()->getAddressSpace()))
+        if (!NullPointerIsDefined(F, CPN->getPointerType()->getAddressSpace()))
           continue;
       }
 
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index 0be03eb7af558..a02949548add8 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -1016,7 +1016,7 @@ ObjectSizeOffsetVisitor::visitConstantPointerNull(ConstantPointerNull &CPN) {
   // TODO: How should this work with address space casts? We currently just drop
   // them on the floor, but it's unclear what we should do when a NULL from
   // addrspace(1) gets casted to addrspace(0) (or vice-versa).
-  if (Options.NullIsUnknownSize || CPN.getType()->getAddressSpace())
+  if (Options.NullIsUnknownSize || CPN.getPointerType()->getAddressSpace())
     return ObjectSizeOffsetVisitor::unknown();
   return OffsetSpan(Zero, Zero);
 }
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 29e253e7c5f97..e4bae3ae26011 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -1813,7 +1813,16 @@ static void writeConstantInternal(raw_ostream &Out, const Constant *CV,
     return;
   }
 
-  if (isa<ConstantPointerNull>(CV)) {
+  if (const auto *CPN = dyn_cast<ConstantPointerNull>(CV)) {
+    if (CPN->getType()->isVectorTy()) {
+      Out << "splat (";
+      writeAsOperandInternal(Out,
+                             ConstantPointerNull::get(CPN->getPointerType()),
+                             WriterCtx, /*PrintType=*/true);
+      Out << ')';
+      return;
+    }
+
     Out << "null";
     return;
   }
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index f07ce527c1240..795c55e9858cc 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -48,6 +48,22 @@ static cl::opt<bool> UseConstantIntForScalableSplat(
 static cl::opt<bool> UseConstantFPForScalableSplat(
     "use-constant-fp-for-scalable-splat", cl::init(true), cl::Hidden,
     cl::desc("Use ConstantFP's native scalable vector splat support."));
+static cl::opt<bool> UseConstantPtrNullForFixedLengthSplat(
+    "use-constant-ptrnull-for-fixed-length-splat", cl::init(true), cl::Hidden,
+    cl::desc("Use ConstantPointerNull's native fixed-length vector splat "
+             "support."));
+static cl::opt<bool> UseConstantPtrNullForScalableSplat(
+    "use-constant-ptrnull-for-scalable-splat", cl::init(true), cl::Hidden,
+    cl::desc(
+        "Use ConstantPointerNull's native scalable vector splat support."));
+
+static bool shouldUseConstantPointerNullForVector(VectorType *VTy) {
+  if (!VTy->getElementType()->isPointerTy())
+    return false;
+  return VTy->getElementCount().isScalable()
+             ? UseConstantPtrNullForScalableSplat
+             : UseConstantPtrNullForFixedLengthSplat;
+}
 
 //===----------------------------------------------------------------------===//
 //                              Constant Class
@@ -404,10 +420,13 @@ Constant *Constant::getNullValue(Type *Ty) {
                            APFloat::getZero(Ty->getFltSemantics()));
   case Type::PointerTyID:
     return ConstantPointerNull::get(cast<PointerType>(Ty));
-  case Type::StructTyID:
-  case Type::ArrayTyID:
   case Type::FixedVectorTyID:
   case Type::ScalableVectorTyID:
+    if (shouldUseConstantPointerNullForVector(cast<VectorType>(Ty)))
+      return ConstantPointerNull::get(Ty);
+    return ConstantAggregateZero::get(Ty);
+  case Type::StructTyID:
+  case Type::ArrayTyID:
     return ConstantAggregateZero::get(Ty);
   case Type::TokenTyID:
     return ConstantTokenNone::get(Ty->getContext());
@@ -492,6 +511,13 @@ Constant *Constant::getAggregateElement(unsigned Elt) const {
                ? ConstantFP::get(getContext(), CFP->getValue())
                : nullptr;
 
+  if (const auto *CPN = dyn_cast<ConstantPointerNull>(this))
+    return Elt < cast<VectorType>(getType())
+                       ->getElementCount()
+                       .getKnownMinValue()
+               ? ConstantPointerNull::get(CPN->getPointerType())
+               : nullptr;
+
   // FIXME: getNumElements() will fail for non-fixed vector types.
   if (isa<ScalableVectorType>(getType()))
     return nullptr;
@@ -1591,16 +1617,21 @@ Constant *ConstantVector::getImpl(ArrayRef<Constant*> V) {
   bool isSplatFP = UseConstantFPForFixedLengthSplat && isa<ConstantFP>(C);
   bool isSplatInt = UseConstantIntForFixedLengthSplat && isa<ConstantInt>(C);
   bool isSplatByte = isa<ConstantByte>(C);
+  bool isSplatPtrNull =
+      UseConstantPtrNullForFixedLengthSplat && isa<ConstantPointerNull>(C);
 
-  if (isZero || isUndef || isSplatFP || isSplatInt || isSplatByte) {
+  if (isZero || isUndef || isSplatFP || isSplatInt || isSplatByte ||
+      isSplatPtrNull) {
     for (unsigned i = 1, e = V.size(); i != e; ++i)
       if (V[i] != C) {
         isZero = isUndef = isPoison = isSplatFP = isSplatInt = isSplatByte =
-            false;
+            isSplatPtrNull = false;
         break;
       }
   }
 
+  if (isSplatPtrNull)
+    return ConstantPointerNull::get(T);
   if (isZero)
     return ConstantAggregateZero::get(T);
   if (isPoison)
@@ -1628,6 +1659,12 @@ Constant *ConstantVector::getImpl(ArrayRef<Constant*> V) {
 }
 
 Constant *ConstantVector::getSplat(ElementCount EC, Constant *V) {
+  if (isa<ConstantPointerNull>(V)) {
+    VectorType *VTy = VectorType::get(V->getType(), EC);
+    if (shouldUseConstantPointerNullForVector(VTy))
+      return ConstantPointerNull::get(VTy);
+  }
+
   if (!EC.isScalable()) {
     // Maintain special handling of zero.
     if (!V->isNullValue()) {
@@ -1884,6 +1921,8 @@ Constant *Constant::getSplatValue(bool AllowPoison) const {
     return ConstantByte::get(getContext(), CB->getValue());
   if (auto *CFP = dyn_cast<ConstantFP>(this))
     return ConstantFP::get(getContext(), CFP->getValue());
+  if (auto *CPN = dyn_cast<ConstantPointerNull>(this))
+    return ConstantPointerNull::get(CPN->getPointerType());
   if (const ConstantDataVector *CV = dyn_cast<ConstantDataVector>(this))
     return CV->getSplatValue();
   if (const ConstantVector *CV = dyn_cast<ConstantVector>(this))
@@ -2001,11 +2040,19 @@ ConstantRange Constant::toConstantRange() const {
 //
 
 ConstantPointerNull *ConstantPointerNull::get(PointerType *Ty) {
+  return get(static_cast<Type *>(Ty));
+}
+
+ConstantPointerNull *ConstantPointerNull::get(Type *Ty) {
+  assert((Ty->isPointerTy() ||
+          (Ty->isVectorTy() && Ty->getScalarType()->isPointerTy())) &&
+         "invalid type for null pointer constant");
   std::unique_ptr<ConstantPointerNull> &Entry =
       Ty->getContext().pImpl->CPNConstants[Ty];
   if (!Entry)
     Entry.reset(new ConstantPointerNull(Ty));
 
+  assert(Entry->getType() == Ty);
   return Entry.get();
 }
 
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index ee331f39c4b75..b7645a25989e8 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -1697,7 +1697,7 @@ class LLVMContextImpl {
   using VectorConstantsTy = ConstantUniqueMap<ConstantVector>;
   VectorConstantsTy VectorConstants;
 
-  DenseMap<PointerType *, std::unique_ptr<ConstantPointerNull>> CPNConstants;
+  DenseMap<Type *, std::unique_ptr<ConstantPointerNull>> CPNConstants;
 
   DenseMap<TargetExtType *, std::unique_ptr<ConstantTargetNone>> CTNConstants;
 
diff --git a/llvm/lib/SandboxIR/Constant.cpp b/llvm/lib/SandboxIR/Constant.cpp
index 5c50d79d50c8b..4fa01646203ec 100644
--- a/llvm/lib/SandboxIR/Constant.cpp
+++ b/llvm/lib/SandboxIR/Constant.cpp
@@ -225,9 +225,13 @@ ConstantPointerNull *ConstantPointerNull::get(PointerType *Ty) {
   return cast<ConstantPointerNull>(Ty->getContext().getOrCreateConstant(LLVMC));
 }
 
-PointerType *ConstantPointerNull::getType() const {
+Type *ConstantPointerNull::getType() const {
+  return Ctx.getType(cast<llvm::ConstantPointerNull>(Val)->getType());
+}
+
+PointerType *ConstantPointerNull::getPointerType() const {
   return cast<PointerType>(
-      Ctx.getType(cast<llvm::ConstantPointerNull>(Val)->getType()));
+      Ctx.getType(cast<llvm::ConstantPointerNull>(Val)->getPointerType()));
 }
 
 UndefValue *UndefValue::get(Type *T) {
diff --git a/llvm/lib/Transforms/Utils/ValueMapper.cpp b/llvm/lib/Transforms/Utils/ValueMapper.cpp
index 73ba1e6a128b0..22230c352bf01 100644
--- a/llvm/lib/Transforms/Utils/ValueMapper.cpp
+++ b/llvm/lib/Transforms/Utils/ValueMapper.cpp
@@ -539,7 +539,7 @@ Value *Mapper::mapValue(const Value *V) {
   if (isa<ConstantTargetNone>(C))
     return getVM()[V] = Constant::getNullValue(NewTy);
   assert(isa<ConstantPointerNull>(C));
-  return getVM()[V] = ConstantPointerNull::get(cast<PointerType>(NewTy));
+  return getVM()[V] = ConstantPointerNull::get(NewTy);
 }
 
 void Mapper::remapDbgRecord(DbgRecord &DR) {
diff --git a/llvm/test/Assembler/ConstantExprFold.ll b/llvm/test/Assembler/ConstantExprFold.ll
index 33ee49296de0a..6945b469889ab 100644
--- a/llvm/test/Assembler/ConstantExprFold.ll
+++ b/llvm/test/Assembler/ConstantExprFold.ll
@@ -37,8 +37,8 @@
 ; CHECK: @cons = weak global i32 0, align 8
 ; CHECK: @gep1 = global <2 x ptr> undef
 ; CHECK: @gep2 = global <2 x ptr> undef
-; CHECK: @gep3 = global <2 x ptr> zeroinitializer
-; CHECK: @gep4 = global <2 x ptr> zeroinitializer
+; CHECK: @gep3 = global <2 x ptr> splat (ptr null)
+; CHECK: @gep4 = global <2 x ptr> splat (ptr null)
 ; CHECK: @bitcast1 = global <2 x i32> splat (i32 -1)
 ; CHECK: @bitcast2 = global <4 x i16> splat (i16 -1)
 ;.
diff --git a/llvm/test/Assembler/aggregate-constant-values.ll b/llvm/test/Assembler/aggregate-constant-values.ll
index b208b582a4657..69a10319083f7 100644
--- a/llvm/test/Assembler/aggregate-constant-values.ll
+++ b/llvm/test/Assembler/aggregate-constant-values.ll
@@ -1,4 +1,5 @@
 ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
+; RUN: llvm-as -use-constant-ptrnull-for-fixed-length-splat=false -use-constant-ptrnull-for-scalable-splat=false < %s | llvm-dis -use-constant-ptrnull-for-fixed-length-splat=false -use-constant-ptrnull-for-scalable-splat=false | FileCheck %s --check-prefix=DISABLED
 ; RUN: verify-uselistorder %s
 
 ; CHECK: @foo
@@ -49,3 +50,26 @@ define void @qux_empty(ptr %x) nounwind {
   ret void
 }
 
+; CHECK: @fixed_ptr_null_splat
+; CHECK: ret <2 x ptr> splat (ptr null)
+; DISABLED: @fixed_ptr_null_splat
+; DISABLED: ret <2 x ptr> zeroinitializer
+define <2 x ptr> @fixed_ptr_null_splat() {
+  ret <2 x ptr> zeroinitializer
+}
+
+; CHECK: @scalable_ptr_null_splat
+; CHECK: ret <vscale x 2 x ptr> splat (ptr null)
+; DISABLED: @scalable_ptr_null_splat
+; DISABLED: ret <vscale x 2 x ptr> zeroinitializer
+define <vscale x 2 x ptr> @scalable_ptr_null_splat() {
+  ret <vscale x 2 x ptr> zeroinitializer
+}
+
+; CHECK: @explicit_fixed_ptr_null_splat
+; CHECK: ret <2 x ptr> splat (ptr null)
+; DISABLED: @explicit_fixed_ptr_null_splat
+; DISABLED: ret <2 x ptr> zeroinitializer
+define <2 x ptr> @explicit_fixed_ptr_null_splat() {
+  ret <2 x ptr> splat (ptr null)
+}
diff --git a/llvm/test/Assembler/opaque-ptr.ll b/llvm/test/Assembler/opaque-ptr.ll
index 287b81d2d1c2f..c516f4d11d6ae 100644
--- a/llvm/test/Assembler/opaque-ptr.ll
+++ b/llvm/test/Assembler/opaque-ptr.ll
@@ -92,7 +92,7 @@ define <2 x ptr> @gep_constexpr_vec1(ptr %a) {
 }
 
 ; CHECK: define <2 x ptr> @gep_constexpr_vec2(<2 x ptr> %a)
-; CHECK:     ret <2 x ptr> getelementptr (i16, <2 x ptr> zeroinitializer, <2 x i32> splat (i32 3))
+; CHECK:     ret <2 x ptr> getelementptr (i16, <2 x ptr> splat (ptr null), <2 x i32> splat (i32 3))
 define <2 x ptr> @gep_constexpr_vec2(<2 x ptr> %a) {
   ret <2 x ptr> getelementptr (i16, <2 x ptr> zeroinitializer, i32 3)
 }
diff --git a/llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll b/llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll
index 94c571a29f991..d18e1a3004445 100644
--- a/llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll
+++ b/llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll
@@ -5,7 +5,7 @@
 
 define <4 x ptr> @vec_of_local_to_flat_nonnull_arg() {
 ; OPT-LABEL: define <4 x ptr> @vec_of_local_to_flat_nonnull_arg() {
-; OPT-NEXT:    [[X:%.*]] = addrspacecast <4 x ptr addrspace(3)> zeroinitializer to <4 x ptr>
+; OPT-NEXT:    [[X:%.*]] = addrspacecast <4 x ptr addrspace(3)> splat (ptr addrspace(3) null) to <4 x ptr>
 ; OPT-NEXT:    ret <4 x ptr> [[X]]
 ;
   %x = addrspacecast <4 x ptr addrspace(3)> zeroinitializer to <4 x ptr>
diff --git a/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll
index a09e392b89e63..06064db0d0646 100644
--- a/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll
+++ b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll
@@ -209,7 +209,7 @@ define ptr addrspace(7) @inttoptr() {
 define <2 x ptr addrspace(7)> @inttoptr_vec() {
 ; CHECK-LABEL: define { <2 x ptr addrspace(8)>, <2 x i32> } @inttoptr_vec
 ; CHECK-SAME: () #[[ATTR0]] {
-; CHECK-NEXT:    ret { <2 x ptr addrspace(8)>, <2 x i32> } { <2 x ptr addrspace(8)> zeroinitializer, <2 x i32> <i32 1, i32 2> }
+; CHECK-NEXT:    ret { <2 x ptr addrspace(8)>, <2 x i32> } { <2 x ptr addrspace(8)> splat (ptr addrspace(8) null), <2 x i32> <i32 1, i32 2> }
 ;
   ret <2 x ptr addrspace(7)> inttoptr (<2 x i160> <i160 1, i160 2> to <2 x ptr addrspace(7)>)
 }
diff --git a/llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll b/llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll
index fdcbe74dc7ebf..4e9c28071c5af 100644
--- a/llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll
+++ b/llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll
@@ -91,7 +91,7 @@ define amdgpu_kernel void @scalar_alloca_ptr_with_vector_gep_offset_select_nullp
 ; CHECK-NEXT:    [[TMP13:%.*]] = add i32 [[TMP12]], [[TMP8]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds [1024 x [4 x i32]], ptr addrspace(3) @scalar_alloca_ptr_with_vector_gep_offset_select_nullptr0.alloca, i32 0, i32 [[TMP13]]
 ; CHECK-NEXT:    [[GETELEMENTPTR0:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[TMP14]], <4 x i64> <i64 0, i64 1, i64 2, i64 3>
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> zeroinitializer, <4 x ptr addrspace(3)> [[GETELEMENTPTR0]]
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> splat (ptr addrspace(3) null), <4 x ptr addrspace(3)> [[GETELEMENTPTR0]]
 ; CHECK-NEXT:    [[EXTRACTELEMENT:%.*]] = extractelement <4 x ptr addrspace(3)> [[SELECT]], i64 1
 ; CHECK-NEXT:    store i32 0, ptr addrspace(3) [[EXTRACTELEMENT]], align 4
 ; CHECK-NEXT:    ret void
@@ -125,7 +125,7 @@ define amdgpu_kernel void @scalar_alloca_ptr_with_vector_gep_offset_select_nullp
 ; CHECK-NEXT:    [[TMP13:%.*]] = add i32 [[TMP12]], [[TMP8]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds [1024 x [4 x i32]], ptr addrspace(3) @scalar_alloca_ptr_with_vector_gep_offset_select_nullptr1.alloca, i32 0, i32 [[TMP13]]
 ; CHECK-NEXT:    [[GETELEMENTPTR0:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[TMP14]], <4 x i64> <i64 0, i64 1, i64 2, i64 3>
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> [[GETELEMENTPTR0]], <4 x ptr addrspace(3)> zeroinitializer
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> [[GETELEMENTPTR0]], <4 x ptr addrspace(3)> splat (ptr addrspace(3) null)
 ; CHECK-NEXT:    [[EXTRACTELEMENT:%.*]] = extractelement <4 x ptr addrspace(3)> [[SELECT]], i64 1
 ; CHECK-NEXT:    store i32 0, ptr addrspace(3) [[EXTRACTELEMENT]], align 4
 ; CHECK-NEXT:    ret void
@@ -159,8 +159,8 @@ define amdgpu_kernel void @scalar_alloca_ptr_with_vector_gep_offset_icmp_nullptr
 ; CHECK-NEXT:    [[TMP13:%.*]] = add i32 [[TMP12]], [[TMP8]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds [1024 x [4 x i32]], ptr addrspace(3) @scalar_alloca_ptr_with_vector_gep_offset_icmp_nullptr0.alloca, i32 0, i32 [[TMP13]]
 ; CHECK-NEXT:    [[GETELEMENTPTR0:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[TMP14]], <4 x i64> <i64 0, i64 1, i64 2, i64 3>
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> zeroinitializer, <4 x ptr addrspace(3)> [[GETELEMENTPTR0]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq <4 x ptr addrspace(3)> [[SELECT]], zeroinitializer
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> splat (ptr addrspace(3) null), <4 x ptr addrspace(3)> [[GE...
[truncated]

@llvmorg-github-actions
Copy link
Copy Markdown

@llvm/pr-subscribers-backend-nvptx

Author: Shilei Tian (shiltian)

Changes

This PR allows ConstantPointerNull to represent both scalar pointer nulls and
fixed or scalable vector splats of pointer nulls. This change first aligns with
the native splat behavior of ConstantInt and ConstantFP, and second, makes
it easier to eventually change the semantics of ConstantPointerNull to
represent a semantic null pointer instead of a zero value, which is what it
represents today.


Patch is 123.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/195486.diff

56 Files Affected:

  • (modified) llvm/include/llvm/IR/Constants.h (+10-7)
  • (modified) llvm/include/llvm/SandboxIR/Constant.h (+2-1)
  • (modified) llvm/lib/Analysis/BasicAliasAnalysis.cpp (+2-2)
  • (modified) llvm/lib/Analysis/GlobalsModRef.cpp (+1-1)
  • (modified) llvm/lib/Analysis/MemoryBuiltins.cpp (+1-1)
  • (modified) llvm/lib/IR/AsmWriter.cpp (+10-1)
  • (modified) llvm/lib/IR/Constants.cpp (+51-4)
  • (modified) llvm/lib/IR/LLVMContextImpl.h (+1-1)
  • (modified) llvm/lib/SandboxIR/Constant.cpp (+6-2)
  • (modified) llvm/lib/Transforms/Utils/ValueMapper.cpp (+1-1)
  • (modified) llvm/test/Assembler/ConstantExprFold.ll (+2-2)
  • (modified) llvm/test/Assembler/aggregate-constant-values.ll (+24)
  • (modified) llvm/test/Assembler/opaque-ptr.ll (+1-1)
  • (modified) llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll (+1-1)
  • (modified) llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll (+1-1)
  • (modified) llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll (+7-7)
  • (modified) llvm/test/Instrumentation/MemorySanitizer/msan_basic.ll (+6-6)
  • (modified) llvm/test/Transforms/ConstraintElimination/geps-ptrvector.ll (+1-1)
  • (modified) llvm/test/Transforms/FunctionAttrs/vector-of-pointers-getunderlyingobject-crash.ll (+1-1)
  • (modified) llvm/test/Transforms/InferAddressSpaces/AMDGPU/issue110433.ll (+2-2)
  • (modified) llvm/test/Transforms/InstCombine/call.ll (+2-2)
  • (modified) llvm/test/Transforms/InstCombine/gep-inbounds-null.ll (+3-3)
  • (modified) llvm/test/Transforms/InstCombine/icmp.ll (+1-1)
  • (modified) llvm/test/Transforms/InstCombine/or.ll (+4-4)
  • (modified) llvm/test/Transforms/InstCombine/scalar_vector_gep.ll (+1-1)
  • (modified) llvm/test/Transforms/InstCombine/vscale_cmp.ll (+1-1)
  • (modified) llvm/test/Transforms/InstSimplify/ConstProp/inttoptr-gep-nonintegral.ll (+4-4)
  • (modified) llvm/test/Transforms/InstSimplify/gep.ll (+7-7)
  • (modified) llvm/test/Transforms/InstSimplify/vscale.ll (+2-2)
  • (modified) llvm/test/Transforms/LoadStoreVectorizer/NVPTX/4x2xhalf.ll (+8-8)
  • (modified) llvm/test/Transforms/LoopIdiom/non-integral-pointers.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/cost-model.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/interleave-opaque-pointers.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/invariant-load-gather.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/masked_load_store.ll (+30-30)
  • (modified) llvm/test/Transforms/LoopVectorize/X86/optsize.ll (+2-2)
  • (modified) llvm/test/Transforms/LoopVectorize/find-last.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/single_early_exit.ll (+1-1)
  • (modified) llvm/test/Transforms/LoopVectorize/vector-loop-backedge-elimination-outside-iv-users.ll (+8-8)
  • (modified) llvm/test/Transforms/RewriteStatepointsForGC/base-inference.ll (+18-9)
  • (modified) llvm/test/Transforms/RewriteStatepointsForGC/base-pointers.ll (+9-9)
  • (modified) llvm/test/Transforms/RewriteStatepointsForGC/base-vector.ll (+31-31)
  • (modified) llvm/test/Transforms/RewriteStatepointsForGC/insert-extract.ll (+10-10)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/catchswitch-block-in-use.ll (+3-3)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/many-uses-parent-node.ll (+1-1)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/scatter-vectorize-reorder-non-empty.ll (+1-1)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/split-vectorize-phi-user.ll (+1-1)
  • (modified) llvm/test/Transforms/SLPVectorizer/extract-vectorized-operand.ll (+3-3)
  • (modified) llvm/test/Transforms/SLPVectorizer/gep-with-extractelement-many-users.ll (+1-1)
  • (modified) llvm/test/Transforms/SLPVectorizer/revec.ll (+2-2)
  • (modified) llvm/test/Transforms/SROA/vector-promotion.ll (+2-2)
  • (modified) llvm/test/Transforms/Scalarizer/constant-extractelement.ll (+1-1)
  • (modified) llvm/test/Verifier/opaque-ptr.ll (+1-1)
  • (modified) llvm/test/Verifier/ptrmask.ll (+2-2)
  • (modified) llvm/test/tools/llvm-reduce/reduce-operands-ptr.ll (+1-1)
  • (modified) llvm/unittests/IR/ConstantsTest.cpp (+28)
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index 2b3f4119e50e2..52b1af323f3d3 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -696,12 +696,13 @@ class ConstantVector final : public ConstantAggregate {
 };
 
 //===----------------------------------------------------------------------===//
-/// A constant pointer value that points to null
+/// A constant pointer value that points to null. This represents both scalar
+/// pointer nulls and vector splats of pointer nulls.
 ///
 class ConstantPointerNull final : public ConstantData {
   friend class Constant;
 
-  explicit ConstantPointerNull(PointerType *T)
+  explicit ConstantPointerNull(Type *T)
       : ConstantData(T, Value::ConstantPointerNullVal) {}
 
   void destroyConstantImpl();
@@ -709,13 +710,15 @@ class ConstantPointerNull final : public ConstantData {
 public:
   ConstantPointerNull(const ConstantPointerNull &) = delete;
 
-  /// Static factory methods - Return objects of the specified value
+  /// Static factory methods - Return objects of the specified value. If Ty is a
+  /// vector type, return a ConstantPointerNull with a splat of null pointer
+  /// values. Otherwise return a ConstantPointerNull for the given pointer type.
   LLVM_ABI static ConstantPointerNull *get(PointerType *T);
+  LLVM_ABI static ConstantPointerNull *get(Type *T);
 
-  /// Specialize the getType() method to always return an PointerType,
-  /// which reduces the amount of casting needed in parts of the compiler.
-  inline PointerType *getType() const {
-    return cast<PointerType>(Value::getType());
+  /// Return the scalar pointer type for this null value.
+  inline PointerType *getPointerType() const {
+    return cast<PointerType>(Value::getType()->getScalarType());
   }
 
   /// Methods for support type inquiry through isa, cast, and dyn_cast:
diff --git a/llvm/include/llvm/SandboxIR/Constant.h b/llvm/include/llvm/SandboxIR/Constant.h
index 669cc79aed957..99543c03de82a 100644
--- a/llvm/include/llvm/SandboxIR/Constant.h
+++ b/llvm/include/llvm/SandboxIR/Constant.h
@@ -773,7 +773,8 @@ class ConstantPointerNull final : public Constant {
 public:
   LLVM_ABI static ConstantPointerNull *get(PointerType *Ty);
 
-  LLVM_ABI PointerType *getType() const;
+  LLVM_ABI Type *getType() const;
+  LLVM_ABI PointerType *getPointerType() const;
 
   /// For isa/dyn_cast.
   static bool classof(const sandboxir::Value *From) {
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index bb8a17c37c881..8172cf29d890b 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -1640,10 +1640,10 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, LocationSize V1Size,
   // Null values in the default address space don't point to any object, so they
   // don't alias any other pointer.
   if (const ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(O1))
-    if (!NullPointerIsDefined(&F, CPN->getType()->getAddressSpace()))
+    if (!NullPointerIsDefined(&F, CPN->getPointerType()->getAddressSpace()))
       return AliasResult::NoAlias;
   if (const ConstantPointerNull *CPN = dyn_cast<ConstantPointerNull>(O2))
-    if (!NullPointerIsDefined(&F, CPN->getType()->getAddressSpace()))
+    if (!NullPointerIsDefined(&F, CPN->getPointerType()->getAddressSpace()))
       return AliasResult::NoAlias;
 
   if (O1 != O2) {
diff --git a/llvm/lib/Analysis/GlobalsModRef.cpp b/llvm/lib/Analysis/GlobalsModRef.cpp
index 295e267848b23..a0d75334f0f2b 100644
--- a/llvm/lib/Analysis/GlobalsModRef.cpp
+++ b/llvm/lib/Analysis/GlobalsModRef.cpp
@@ -773,7 +773,7 @@ bool GlobalsAAResult::isNonEscapingGlobalNoAlias(const GlobalValue *GV,
       if (auto *CPN = dyn_cast<ConstantPointerNull>(Input)) {
         // Null pointer cannot alias with a non-addr-taken global.
         const Function *F = CtxI->getFunction();
-        if (!NullPointerIsDefined(F, CPN->getType()->getAddressSpace()))
+        if (!NullPointerIsDefined(F, CPN->getPointerType()->getAddressSpace()))
           continue;
       }
 
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index 0be03eb7af558..a02949548add8 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -1016,7 +1016,7 @@ ObjectSizeOffsetVisitor::visitConstantPointerNull(ConstantPointerNull &CPN) {
   // TODO: How should this work with address space casts? We currently just drop
   // them on the floor, but it's unclear what we should do when a NULL from
   // addrspace(1) gets casted to addrspace(0) (or vice-versa).
-  if (Options.NullIsUnknownSize || CPN.getType()->getAddressSpace())
+  if (Options.NullIsUnknownSize || CPN.getPointerType()->getAddressSpace())
     return ObjectSizeOffsetVisitor::unknown();
   return OffsetSpan(Zero, Zero);
 }
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 29e253e7c5f97..e4bae3ae26011 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -1813,7 +1813,16 @@ static void writeConstantInternal(raw_ostream &Out, const Constant *CV,
     return;
   }
 
-  if (isa<ConstantPointerNull>(CV)) {
+  if (const auto *CPN = dyn_cast<ConstantPointerNull>(CV)) {
+    if (CPN->getType()->isVectorTy()) {
+      Out << "splat (";
+      writeAsOperandInternal(Out,
+                             ConstantPointerNull::get(CPN->getPointerType()),
+                             WriterCtx, /*PrintType=*/true);
+      Out << ')';
+      return;
+    }
+
     Out << "null";
     return;
   }
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index f07ce527c1240..795c55e9858cc 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -48,6 +48,22 @@ static cl::opt<bool> UseConstantIntForScalableSplat(
 static cl::opt<bool> UseConstantFPForScalableSplat(
     "use-constant-fp-for-scalable-splat", cl::init(true), cl::Hidden,
     cl::desc("Use ConstantFP's native scalable vector splat support."));
+static cl::opt<bool> UseConstantPtrNullForFixedLengthSplat(
+    "use-constant-ptrnull-for-fixed-length-splat", cl::init(true), cl::Hidden,
+    cl::desc("Use ConstantPointerNull's native fixed-length vector splat "
+             "support."));
+static cl::opt<bool> UseConstantPtrNullForScalableSplat(
+    "use-constant-ptrnull-for-scalable-splat", cl::init(true), cl::Hidden,
+    cl::desc(
+        "Use ConstantPointerNull's native scalable vector splat support."));
+
+static bool shouldUseConstantPointerNullForVector(VectorType *VTy) {
+  if (!VTy->getElementType()->isPointerTy())
+    return false;
+  return VTy->getElementCount().isScalable()
+             ? UseConstantPtrNullForScalableSplat
+             : UseConstantPtrNullForFixedLengthSplat;
+}
 
 //===----------------------------------------------------------------------===//
 //                              Constant Class
@@ -404,10 +420,13 @@ Constant *Constant::getNullValue(Type *Ty) {
                            APFloat::getZero(Ty->getFltSemantics()));
   case Type::PointerTyID:
     return ConstantPointerNull::get(cast<PointerType>(Ty));
-  case Type::StructTyID:
-  case Type::ArrayTyID:
   case Type::FixedVectorTyID:
   case Type::ScalableVectorTyID:
+    if (shouldUseConstantPointerNullForVector(cast<VectorType>(Ty)))
+      return ConstantPointerNull::get(Ty);
+    return ConstantAggregateZero::get(Ty);
+  case Type::StructTyID:
+  case Type::ArrayTyID:
     return ConstantAggregateZero::get(Ty);
   case Type::TokenTyID:
     return ConstantTokenNone::get(Ty->getContext());
@@ -492,6 +511,13 @@ Constant *Constant::getAggregateElement(unsigned Elt) const {
                ? ConstantFP::get(getContext(), CFP->getValue())
                : nullptr;
 
+  if (const auto *CPN = dyn_cast<ConstantPointerNull>(this))
+    return Elt < cast<VectorType>(getType())
+                       ->getElementCount()
+                       .getKnownMinValue()
+               ? ConstantPointerNull::get(CPN->getPointerType())
+               : nullptr;
+
   // FIXME: getNumElements() will fail for non-fixed vector types.
   if (isa<ScalableVectorType>(getType()))
     return nullptr;
@@ -1591,16 +1617,21 @@ Constant *ConstantVector::getImpl(ArrayRef<Constant*> V) {
   bool isSplatFP = UseConstantFPForFixedLengthSplat && isa<ConstantFP>(C);
   bool isSplatInt = UseConstantIntForFixedLengthSplat && isa<ConstantInt>(C);
   bool isSplatByte = isa<ConstantByte>(C);
+  bool isSplatPtrNull =
+      UseConstantPtrNullForFixedLengthSplat && isa<ConstantPointerNull>(C);
 
-  if (isZero || isUndef || isSplatFP || isSplatInt || isSplatByte) {
+  if (isZero || isUndef || isSplatFP || isSplatInt || isSplatByte ||
+      isSplatPtrNull) {
     for (unsigned i = 1, e = V.size(); i != e; ++i)
       if (V[i] != C) {
         isZero = isUndef = isPoison = isSplatFP = isSplatInt = isSplatByte =
-            false;
+            isSplatPtrNull = false;
         break;
       }
   }
 
+  if (isSplatPtrNull)
+    return ConstantPointerNull::get(T);
   if (isZero)
     return ConstantAggregateZero::get(T);
   if (isPoison)
@@ -1628,6 +1659,12 @@ Constant *ConstantVector::getImpl(ArrayRef<Constant*> V) {
 }
 
 Constant *ConstantVector::getSplat(ElementCount EC, Constant *V) {
+  if (isa<ConstantPointerNull>(V)) {
+    VectorType *VTy = VectorType::get(V->getType(), EC);
+    if (shouldUseConstantPointerNullForVector(VTy))
+      return ConstantPointerNull::get(VTy);
+  }
+
   if (!EC.isScalable()) {
     // Maintain special handling of zero.
     if (!V->isNullValue()) {
@@ -1884,6 +1921,8 @@ Constant *Constant::getSplatValue(bool AllowPoison) const {
     return ConstantByte::get(getContext(), CB->getValue());
   if (auto *CFP = dyn_cast<ConstantFP>(this))
     return ConstantFP::get(getContext(), CFP->getValue());
+  if (auto *CPN = dyn_cast<ConstantPointerNull>(this))
+    return ConstantPointerNull::get(CPN->getPointerType());
   if (const ConstantDataVector *CV = dyn_cast<ConstantDataVector>(this))
     return CV->getSplatValue();
   if (const ConstantVector *CV = dyn_cast<ConstantVector>(this))
@@ -2001,11 +2040,19 @@ ConstantRange Constant::toConstantRange() const {
 //
 
 ConstantPointerNull *ConstantPointerNull::get(PointerType *Ty) {
+  return get(static_cast<Type *>(Ty));
+}
+
+ConstantPointerNull *ConstantPointerNull::get(Type *Ty) {
+  assert((Ty->isPointerTy() ||
+          (Ty->isVectorTy() && Ty->getScalarType()->isPointerTy())) &&
+         "invalid type for null pointer constant");
   std::unique_ptr<ConstantPointerNull> &Entry =
       Ty->getContext().pImpl->CPNConstants[Ty];
   if (!Entry)
     Entry.reset(new ConstantPointerNull(Ty));
 
+  assert(Entry->getType() == Ty);
   return Entry.get();
 }
 
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index ee331f39c4b75..b7645a25989e8 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -1697,7 +1697,7 @@ class LLVMContextImpl {
   using VectorConstantsTy = ConstantUniqueMap<ConstantVector>;
   VectorConstantsTy VectorConstants;
 
-  DenseMap<PointerType *, std::unique_ptr<ConstantPointerNull>> CPNConstants;
+  DenseMap<Type *, std::unique_ptr<ConstantPointerNull>> CPNConstants;
 
   DenseMap<TargetExtType *, std::unique_ptr<ConstantTargetNone>> CTNConstants;
 
diff --git a/llvm/lib/SandboxIR/Constant.cpp b/llvm/lib/SandboxIR/Constant.cpp
index 5c50d79d50c8b..4fa01646203ec 100644
--- a/llvm/lib/SandboxIR/Constant.cpp
+++ b/llvm/lib/SandboxIR/Constant.cpp
@@ -225,9 +225,13 @@ ConstantPointerNull *ConstantPointerNull::get(PointerType *Ty) {
   return cast<ConstantPointerNull>(Ty->getContext().getOrCreateConstant(LLVMC));
 }
 
-PointerType *ConstantPointerNull::getType() const {
+Type *ConstantPointerNull::getType() const {
+  return Ctx.getType(cast<llvm::ConstantPointerNull>(Val)->getType());
+}
+
+PointerType *ConstantPointerNull::getPointerType() const {
   return cast<PointerType>(
-      Ctx.getType(cast<llvm::ConstantPointerNull>(Val)->getType()));
+      Ctx.getType(cast<llvm::ConstantPointerNull>(Val)->getPointerType()));
 }
 
 UndefValue *UndefValue::get(Type *T) {
diff --git a/llvm/lib/Transforms/Utils/ValueMapper.cpp b/llvm/lib/Transforms/Utils/ValueMapper.cpp
index 73ba1e6a128b0..22230c352bf01 100644
--- a/llvm/lib/Transforms/Utils/ValueMapper.cpp
+++ b/llvm/lib/Transforms/Utils/ValueMapper.cpp
@@ -539,7 +539,7 @@ Value *Mapper::mapValue(const Value *V) {
   if (isa<ConstantTargetNone>(C))
     return getVM()[V] = Constant::getNullValue(NewTy);
   assert(isa<ConstantPointerNull>(C));
-  return getVM()[V] = ConstantPointerNull::get(cast<PointerType>(NewTy));
+  return getVM()[V] = ConstantPointerNull::get(NewTy);
 }
 
 void Mapper::remapDbgRecord(DbgRecord &DR) {
diff --git a/llvm/test/Assembler/ConstantExprFold.ll b/llvm/test/Assembler/ConstantExprFold.ll
index 33ee49296de0a..6945b469889ab 100644
--- a/llvm/test/Assembler/ConstantExprFold.ll
+++ b/llvm/test/Assembler/ConstantExprFold.ll
@@ -37,8 +37,8 @@
 ; CHECK: @cons = weak global i32 0, align 8
 ; CHECK: @gep1 = global <2 x ptr> undef
 ; CHECK: @gep2 = global <2 x ptr> undef
-; CHECK: @gep3 = global <2 x ptr> zeroinitializer
-; CHECK: @gep4 = global <2 x ptr> zeroinitializer
+; CHECK: @gep3 = global <2 x ptr> splat (ptr null)
+; CHECK: @gep4 = global <2 x ptr> splat (ptr null)
 ; CHECK: @bitcast1 = global <2 x i32> splat (i32 -1)
 ; CHECK: @bitcast2 = global <4 x i16> splat (i16 -1)
 ;.
diff --git a/llvm/test/Assembler/aggregate-constant-values.ll b/llvm/test/Assembler/aggregate-constant-values.ll
index b208b582a4657..69a10319083f7 100644
--- a/llvm/test/Assembler/aggregate-constant-values.ll
+++ b/llvm/test/Assembler/aggregate-constant-values.ll
@@ -1,4 +1,5 @@
 ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
+; RUN: llvm-as -use-constant-ptrnull-for-fixed-length-splat=false -use-constant-ptrnull-for-scalable-splat=false < %s | llvm-dis -use-constant-ptrnull-for-fixed-length-splat=false -use-constant-ptrnull-for-scalable-splat=false | FileCheck %s --check-prefix=DISABLED
 ; RUN: verify-uselistorder %s
 
 ; CHECK: @foo
@@ -49,3 +50,26 @@ define void @qux_empty(ptr %x) nounwind {
   ret void
 }
 
+; CHECK: @fixed_ptr_null_splat
+; CHECK: ret <2 x ptr> splat (ptr null)
+; DISABLED: @fixed_ptr_null_splat
+; DISABLED: ret <2 x ptr> zeroinitializer
+define <2 x ptr> @fixed_ptr_null_splat() {
+  ret <2 x ptr> zeroinitializer
+}
+
+; CHECK: @scalable_ptr_null_splat
+; CHECK: ret <vscale x 2 x ptr> splat (ptr null)
+; DISABLED: @scalable_ptr_null_splat
+; DISABLED: ret <vscale x 2 x ptr> zeroinitializer
+define <vscale x 2 x ptr> @scalable_ptr_null_splat() {
+  ret <vscale x 2 x ptr> zeroinitializer
+}
+
+; CHECK: @explicit_fixed_ptr_null_splat
+; CHECK: ret <2 x ptr> splat (ptr null)
+; DISABLED: @explicit_fixed_ptr_null_splat
+; DISABLED: ret <2 x ptr> zeroinitializer
+define <2 x ptr> @explicit_fixed_ptr_null_splat() {
+  ret <2 x ptr> splat (ptr null)
+}
diff --git a/llvm/test/Assembler/opaque-ptr.ll b/llvm/test/Assembler/opaque-ptr.ll
index 287b81d2d1c2f..c516f4d11d6ae 100644
--- a/llvm/test/Assembler/opaque-ptr.ll
+++ b/llvm/test/Assembler/opaque-ptr.ll
@@ -92,7 +92,7 @@ define <2 x ptr> @gep_constexpr_vec1(ptr %a) {
 }
 
 ; CHECK: define <2 x ptr> @gep_constexpr_vec2(<2 x ptr> %a)
-; CHECK:     ret <2 x ptr> getelementptr (i16, <2 x ptr> zeroinitializer, <2 x i32> splat (i32 3))
+; CHECK:     ret <2 x ptr> getelementptr (i16, <2 x ptr> splat (ptr null), <2 x i32> splat (i32 3))
 define <2 x ptr> @gep_constexpr_vec2(<2 x ptr> %a) {
   ret <2 x ptr> getelementptr (i16, <2 x ptr> zeroinitializer, i32 3)
 }
diff --git a/llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll b/llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll
index 94c571a29f991..d18e1a3004445 100644
--- a/llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll
+++ b/llvm/test/CodeGen/AMDGPU/codegen-prepare-addrspacecast-non-null-vector.ll
@@ -5,7 +5,7 @@
 
 define <4 x ptr> @vec_of_local_to_flat_nonnull_arg() {
 ; OPT-LABEL: define <4 x ptr> @vec_of_local_to_flat_nonnull_arg() {
-; OPT-NEXT:    [[X:%.*]] = addrspacecast <4 x ptr addrspace(3)> zeroinitializer to <4 x ptr>
+; OPT-NEXT:    [[X:%.*]] = addrspacecast <4 x ptr addrspace(3)> splat (ptr addrspace(3) null) to <4 x ptr>
 ; OPT-NEXT:    ret <4 x ptr> [[X]]
 ;
   %x = addrspacecast <4 x ptr addrspace(3)> zeroinitializer to <4 x ptr>
diff --git a/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll
index a09e392b89e63..06064db0d0646 100644
--- a/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll
+++ b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll
@@ -209,7 +209,7 @@ define ptr addrspace(7) @inttoptr() {
 define <2 x ptr addrspace(7)> @inttoptr_vec() {
 ; CHECK-LABEL: define { <2 x ptr addrspace(8)>, <2 x i32> } @inttoptr_vec
 ; CHECK-SAME: () #[[ATTR0]] {
-; CHECK-NEXT:    ret { <2 x ptr addrspace(8)>, <2 x i32> } { <2 x ptr addrspace(8)> zeroinitializer, <2 x i32> <i32 1, i32 2> }
+; CHECK-NEXT:    ret { <2 x ptr addrspace(8)>, <2 x i32> } { <2 x ptr addrspace(8)> splat (ptr addrspace(8) null), <2 x i32> <i32 1, i32 2> }
 ;
   ret <2 x ptr addrspace(7)> inttoptr (<2 x i160> <i160 1, i160 2> to <2 x ptr addrspace(7)>)
 }
diff --git a/llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll b/llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll
index fdcbe74dc7ebf..4e9c28071c5af 100644
--- a/llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll
+++ b/llvm/test/CodeGen/AMDGPU/promote-alloca-vector-gep.ll
@@ -91,7 +91,7 @@ define amdgpu_kernel void @scalar_alloca_ptr_with_vector_gep_offset_select_nullp
 ; CHECK-NEXT:    [[TMP13:%.*]] = add i32 [[TMP12]], [[TMP8]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds [1024 x [4 x i32]], ptr addrspace(3) @scalar_alloca_ptr_with_vector_gep_offset_select_nullptr0.alloca, i32 0, i32 [[TMP13]]
 ; CHECK-NEXT:    [[GETELEMENTPTR0:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[TMP14]], <4 x i64> <i64 0, i64 1, i64 2, i64 3>
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> zeroinitializer, <4 x ptr addrspace(3)> [[GETELEMENTPTR0]]
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> splat (ptr addrspace(3) null), <4 x ptr addrspace(3)> [[GETELEMENTPTR0]]
 ; CHECK-NEXT:    [[EXTRACTELEMENT:%.*]] = extractelement <4 x ptr addrspace(3)> [[SELECT]], i64 1
 ; CHECK-NEXT:    store i32 0, ptr addrspace(3) [[EXTRACTELEMENT]], align 4
 ; CHECK-NEXT:    ret void
@@ -125,7 +125,7 @@ define amdgpu_kernel void @scalar_alloca_ptr_with_vector_gep_offset_select_nullp
 ; CHECK-NEXT:    [[TMP13:%.*]] = add i32 [[TMP12]], [[TMP8]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds [1024 x [4 x i32]], ptr addrspace(3) @scalar_alloca_ptr_with_vector_gep_offset_select_nullptr1.alloca, i32 0, i32 [[TMP13]]
 ; CHECK-NEXT:    [[GETELEMENTPTR0:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[TMP14]], <4 x i64> <i64 0, i64 1, i64 2, i64 3>
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> [[GETELEMENTPTR0]], <4 x ptr addrspace(3)> zeroinitializer
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> [[GETELEMENTPTR0]], <4 x ptr addrspace(3)> splat (ptr addrspace(3) null)
 ; CHECK-NEXT:    [[EXTRACTELEMENT:%.*]] = extractelement <4 x ptr addrspace(3)> [[SELECT]], i64 1
 ; CHECK-NEXT:    store i32 0, ptr addrspace(3) [[EXTRACTELEMENT]], align 4
 ; CHECK-NEXT:    ret void
@@ -159,8 +159,8 @@ define amdgpu_kernel void @scalar_alloca_ptr_with_vector_gep_offset_icmp_nullptr
 ; CHECK-NEXT:    [[TMP13:%.*]] = add i32 [[TMP12]], [[TMP8]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds [1024 x [4 x i32]], ptr addrspace(3) @scalar_alloca_ptr_with_vector_gep_offset_icmp_nullptr0.alloca, i32 0, i32 [[TMP13]]
 ; CHECK-NEXT:    [[GETELEMENTPTR0:%.*]] = getelementptr inbounds i8, ptr addrspace(3) [[TMP14]], <4 x i64> <i64 0, i64 1, i64 2, i64 3>
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> zeroinitializer, <4 x ptr addrspace(3)> [[GETELEMENTPTR0]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq <4 x ptr addrspace(3)> [[SELECT]], zeroinitializer
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], <4 x ptr addrspace(3)> splat (ptr addrspace(3) null), <4 x ptr addrspace(3)> [[GE...
[truncated]

@shiltian shiltian force-pushed the users/shiltian/constant-pointer-null-vector-splat branch 2 times, most recently from 444848f to d6ffa06 Compare May 2, 2026 22:21
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 2, 2026

🐧 Linux x64 Test Results

  • 194665 tests passed
  • 5167 tests skipped

✅ The build succeeded and all tests passed.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 2, 2026

🪟 Windows x64 Test Results

  • 134162 tests passed
  • 3222 tests skipped

✅ The build succeeded and all tests passed.

Copy link
Copy Markdown
Member

@arichardson arichardson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good to me just one comment

Comment thread llvm/lib/IR/Constants.cpp
static cl::opt<bool> UseConstantFPForScalableSplat(
"use-constant-fp-for-scalable-splat", cl::init(true), cl::Hidden,
cl::desc("Use ConstantFP's native scalable vector splat support."));
static cl::opt<bool> UseConstantPtrNullForFixedLengthSplat(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these options used anywhere? Is this for downstream migration purposes? If so there should be a comment, and if not maybe best to not add any not options that aren't strictly needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just made it align with the migration of ConstantInt and ConstantFP, where they are guarded by an option. @nikic said they were turned on by default just recently. This is a completely new thing so I don't think there would be any downstream uses at all, but I'm not sure if it is helpful to provide an option to turn it off.

@shiltian shiltian force-pushed the users/shiltian/constant-pointer-null-vector-splat branch from d6ffa06 to 8f81288 Compare May 3, 2026 03:49
Comment thread llvm/include/llvm/IR/Constants.h Outdated
Comment thread llvm/lib/IR/Constants.cpp Outdated
Comment thread llvm/lib/IR/Constants.cpp Outdated
@shiltian shiltian force-pushed the users/shiltian/constant-pointer-null-vector-splat branch from 8f81288 to b07d2a9 Compare May 4, 2026 14:06
Comment thread llvm/lib/IR/AsmWriter.cpp Outdated
Comment thread llvm/lib/IR/Constants.cpp
static cl::opt<bool> UseConstantFPForScalableSplat(
"use-constant-fp-for-scalable-splat", cl::init(true), cl::Hidden,
cl::desc("Use ConstantFP's native scalable vector splat support."));
static cl::opt<bool> UseConstantPtrNullForFixedLengthSplat(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is really necessary, but I guess it's good to be consistent with ConstantInt for now

This PR allows `ConstantPointerNull` to represent both scalar pointer nulls and
fixed or scalable vector splats of pointer nulls. This change first aligns with
the native splat behavior of `ConstantInt` and `ConstantFP`, and second, makes
it easier to eventually change the semantics of `ConstantPointerNull` to
represent a semantic null pointer instead of a zero value, which is what it
represents today.
@shiltian shiltian force-pushed the users/shiltian/constant-pointer-null-vector-splat branch from b07d2a9 to 8c6ee8d Compare May 4, 2026 23:38
@shiltian shiltian enabled auto-merge (squash) May 4, 2026 23:39
@shiltian shiltian merged commit f846769 into main May 5, 2026
10 of 11 checks passed
@shiltian shiltian deleted the users/shiltian/constant-pointer-null-vector-splat branch May 5, 2026 00:12
@llvm-ci
Copy link
Copy Markdown

llvm-ci commented May 5, 2026

LLVM Buildbot has detected a new failure on builder openmp-offload-amdgpu-runtime-2 running on rocm-worker-hw-02 while building llvm at step 6 "test-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/10/builds/27896

Here is the relevant piece of the build log for the reference
Step 6 (test-openmp) failure: test (failure)
******************** TEST 'libarcher :: races/parallel-simple.c' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 13
/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/./bin/clang -fopenmp  -gdwarf-4 -O1 -fsanitize=thread  -I /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests -I /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/runtime/src   /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests/races/parallel-simple.c -o /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/parallel-simple.c.tmp -latomic && env TSAN_OPTIONS='ignore_noninstrumented_modules=0:ignore_noninstrumented_modules=1' /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests/deflake.bash /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/parallel-simple.c.tmp 2>&1 | tee /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/parallel-simple.c.tmp.log | /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/./bin/FileCheck /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests/races/parallel-simple.c
# executed command: /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/./bin/clang -fopenmp -gdwarf-4 -O1 -fsanitize=thread -I /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests -I /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -L /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/runtime/src /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests/races/parallel-simple.c -o /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/parallel-simple.c.tmp -latomic
# note: command had no output on stdout or stderr
# executed command: env TSAN_OPTIONS=ignore_noninstrumented_modules=0:ignore_noninstrumented_modules=1 /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests/deflake.bash /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/parallel-simple.c.tmp
# note: command had no output on stdout or stderr
# executed command: tee /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/parallel-simple.c.tmp.log
# note: command had no output on stdout or stderr
# executed command: /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.build/./bin/FileCheck /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests/races/parallel-simple.c
# .---command stderr------------
# | /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests/races/parallel-simple.c:36:11: error: CHECK: expected string not found in input
# | // CHECK: ThreadSanitizer: reported {{[1-7]}} warnings
# |           ^
# | <stdin>:23:5: note: scanning from here
# | DONE
# |     ^
# | <stdin>:24:1: note: possible intended match here
# | ThreadSanitizer: thread T4 finished with ignores enabled, created at:
# | ^
# | 
# | Input file: <stdin>
# | Check file: /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests/races/parallel-simple.c
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |             .
# |             .
# |             .
# |            18:  #0 pthread_create /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:1082:3 (parallel-simple.c.tmp+0xa545a) 
# |            19:  #1 __kmp_create_worker z_Linux_util.cpp (libomp.so+0xcbed2) 
# |            20:  
# |            21: SUMMARY: ThreadSanitizer: data race /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/openmp/tools/archer/tests/races/parallel-simple.c:23:8 in main.omp_outlined_debug__ 
# |            22: ================== 
# |            23: DONE 
# | check:36'0         X error: no match found
# |            24: ThreadSanitizer: thread T4 finished with ignores enabled, created at: 
# | check:36'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | check:36'1     ?                                                                      possible intended match
# |            25:  #0 pthread_create /home/botworker/builds/openmp-offload-amdgpu-runtime-2/llvm.src/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:1082:3 (parallel-simple.c.tmp+0xa545a) 
# | check:36'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            26:  #1 __kmp_create_worker z_Linux_util.cpp (libomp.so+0xcbed2) 
# | check:36'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            27:  
...

@llvm-ci
Copy link
Copy Markdown

llvm-ci commented May 5, 2026

LLVM Buildbot has detected a new failure on builder openmp-s390x-linux running on systemz-1 while building llvm at step 6 "test-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/88/builds/23061

Here is the relevant piece of the build log for the reference
Step 6 (test-openmp) failure: test (failure)
******************** TEST 'libomp :: tasking/issue-94260-2.c' FAILED ********************
Exit Code: -11

Command Output (stdout):
--
# RUN: at line 1
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp   -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src  -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic && /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic
# executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -11

--

********************


@DKLoehr
Copy link
Copy Markdown
Contributor

DKLoehr commented May 5, 2026

We've started seeing crashes when building chromium that bisect to this commit. I used cvise to but together a minimized reproducer

After this commit, running clang++ -cc1 -triple aarch64-unknown-linux-android29 -O2 -emit-obj -std=c++23 -fwrapv-pointer -Wno-everything -vectorize-slp repro.cpp results in a crash:

clang++: llvm/lib/IR/Value.cpp:523: void llvm::Value::doRAUW(Value *, ReplaceMetadataUses): Assertion `New->getType() == getType() && "replaceAllUses of value with new value of different type!"' failed.
Stack dump:
0.      Program arguments: clang++ -cc1 -triple aarch64-unknown-linux-android29 -O2 -emit-obj -std=c++23 -fwrapv-pointer -Wno-everything -vectorize-slp repro.cpp
1.      <eof> parser at end of file
2.      Optimizer
3.      Running pass "function<eager-inv>(drop-unnecessary-assumes,float2int,lower-constant-intrinsics,loop(loop-rotate<header-duplication;no-prepare-for-lto;check-exit-count>,loop-deletion),loop-distribute,inject-tli-mappings,loop-vectorize<no-interleave-forced-only;vectorize-forced-only;>,drop-unnecessary-assumes,infer-alignment,loop-load-elim,instcombine<max-iterations=1;no-verify-fixpoint>,simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-arithmetic;switch-to-lookup;no-keep-loops;hoist-common-insts;no-hoist-loads-stores-with-cond-faulting;sink-common-insts;speculate-blocks;simplify-cond-branch;no-speculate-unpredictables>,slp-vectorizer,vector-combine,instcombine<max-iterations=1;no-verify-fixpoint>,loop-unroll<O2>,transform-warning,sroa<preserve-cfg>,infer-alignment,instcombine<max-iterations=1;no-verify-fixpoint>,loop-mssa(licm<allowspeculation>),alignment-from-assumptions,loop-sink,instsimplify,div-rem-pairs,mergeicmps,expand-memcmp,tailcallelim,simplifycfg<bonus-inst-threshold=1;no-forward-switch-cond;switch-range-to-icmp;switch-to-arithmetic;no-switch-to-lookup;keep-loops;no-hoist-common-insts;hoist-loads-stores-with-cond-faulting;no-sink-common-insts;speculate-blocks;simplify-cond-branch;speculate-unpredictables>)" on module "repro.cpp"
4.      Running pass "instcombine<max-iterations=1;no-verify-fixpoint>" on function "_Z45FilteredIterableTest_Vector_None_TestTestBodyv"
#0 0x000055dea3a24f18 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (clang+++0x55d6f18)
Aborted                    (core dumped)

@maurer
Copy link
Copy Markdown
Contributor

maurer commented May 5, 2026

This PR caused rustc to segfault when it passed in a null pointer with a type other than <N x i32> as the argument to shufflevector when trying to implement splat. It might be possible that LLVM has a similar error somewhere.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:AArch64 backend:AMDGPU backend:NVPTX backend:RISC-V llvm:analysis Includes value tracking, cost tables and constant folding llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:ir llvm:SandboxIR llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants