[llvm] [NFCI][IR] Add DataLayout-aware `isZeroValue`/`getNullValue` and `getZeroValue` APIs (PR #183208)

Shilei Tian via llvm-commits llvm-commits at lists.llvm.org
Sat May 2 08:18:47 PDT 2026


https://github.com/shiltian updated https://github.com/llvm/llvm-project/pull/183208

>From 2ce499bac234348d538b7dba13458fa1d475f867 Mon Sep 17 00:00:00 2001
From: Shilei Tian <i at tianshilei.me>
Date: Sat, 2 May 2026 10:58:40 -0400
Subject: [PATCH] [NFCI][IR] Add DataLayout pointer to zero and null value
 related APIs

When the semantics of `ConstantPointerNull` change to represent a semantic null
pointer in the future, a null value won't necessarily be a zero value anymore.
Because of that, the entire LLVM constant infrastructure will need to change. As
a first step, this PR adds an optional data layout pointer to `isNullValue`,
`isZeroValue`, `getNullValue`, and `getZeroValue`. It isn't used yet, since a
null value is still a zero value right now.
---
 llvm/include/llvm/IR/Constant.h     |  27 +++++-
 llvm/lib/IR/Constants.cpp           |  18 +++-
 llvm/unittests/IR/ConstantsTest.cpp | 144 ++++++++++++++++++++++++++++
 3 files changed, 184 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/IR/Constant.h b/llvm/include/llvm/IR/Constant.h
index 82a570e8a1446..f0a106f9f7ad9 100644
--- a/llvm/include/llvm/IR/Constant.h
+++ b/llvm/include/llvm/IR/Constant.h
@@ -22,6 +22,7 @@ namespace llvm {
 
 class ConstantRange;
 class APInt;
+class DataLayout;
 
 /// This is an important base class in LLVM. It provides the common facilities
 /// of all constant values in an LLVM program. A constant is a value that is
@@ -52,7 +53,15 @@ class Constant : public User {
   Constant(const Constant &) = delete;
 
   /// Return true if this is the value that would be returned by getNullValue.
-  LLVM_ABI bool isNullValue() const;
+  /// TODO: Currently equivalent to isZeroValue(). Will diverge once the
+  /// semantics of ConstantPointerNull changes.
+  LLVM_ABI bool isNullValue(const DataLayout *DL = nullptr) const;
+
+  /// Return true iff this constant has an all-zero bit pattern.
+  /// TODO: For pointer types, it currently returns true if it is
+  /// ConstantPointerNull, but this will change once the semantics of
+  /// ConstantPointerNull changes to represent the semantic null pointer.
+  LLVM_ABI bool isZeroValue(const DataLayout *DL = nullptr) const;
 
   /// Returns true if the value is one.
   LLVM_ABI bool isOneValue() const;
@@ -187,7 +196,21 @@ class Constant : public User {
   ///
   LLVM_ABI void handleOperandChange(Value *, Value *);
 
-  LLVM_ABI static Constant *getNullValue(Type *Ty);
+  /// Constructor to create a null constant of arbitrary type.
+  /// TODO: Currently equivalent to getZeroValue(). Will diverge once the
+  /// semantics of ConstantPointerNull changes: for pointer types in address
+  /// spaces with non-zero null, getNullValue() will return the semantic null
+  /// pointer (ConstantPointerNull) while getZeroValue() will continue to return
+  /// the all-zero-bits value.
+  LLVM_ABI static Constant *getNullValue(Type *Ty,
+                                         const DataLayout *DL = nullptr);
+
+  /// Return the all-zero-bits constant for the given type.
+  /// TODO: For pointer types, it returns ConstantPointerNull but this will
+  /// change once the semantics of ConstantPointerNull changes to represent the
+  /// semantic null pointer.
+  LLVM_ABI static Constant *getZeroValue(Type *Ty,
+                                         const DataLayout *DL = nullptr);
 
   /// @returns the value for an integer or vector of integer constant of the
   /// given type that has all its bits set to true.
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index f07ce527c1240..e55534d8dbb38 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -17,6 +17,7 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/ConstantFold.h"
+#include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/GetElementPtrTypeIterator.h"
@@ -71,7 +72,13 @@ bool Constant::isNegativeZeroValue() const {
   return isNullValue();
 }
 
-bool Constant::isNullValue() const {
+bool Constant::isNullValue(const DataLayout *DL) const {
+  // TODO: when the semantics of ConstantPointerNull changes, a null value is
+  // not necessarily a zero value.
+  return isZeroValue(DL);
+}
+
+bool Constant::isZeroValue(const DataLayout *DL) const {
   // 0 is null.
   if (const ConstantInt *CI = dyn_cast<ConstantInt>(this))
     return CI->isZero();
@@ -386,8 +393,13 @@ bool Constant::containsConstantExpression() const {
   return false;
 }
 
-/// Constructor to create a '0' constant of arbitrary type.
-Constant *Constant::getNullValue(Type *Ty) {
+Constant *Constant::getNullValue(Type *Ty, const DataLayout *DL) {
+  // TODO: when the semantics of ConstantPointerNull changes, a null value is
+  // not necessarily a zero value.
+  return getZeroValue(Ty, DL);
+}
+
+Constant *Constant::getZeroValue(Type *Ty, const DataLayout *DL) {
   switch (Ty->getTypeID()) {
   case Type::ByteTyID:
     return ConstantByte::get(Ty, 0);
diff --git a/llvm/unittests/IR/ConstantsTest.cpp b/llvm/unittests/IR/ConstantsTest.cpp
index 34898aa467788..5d4a9cd3e5f95 100644
--- a/llvm/unittests/IR/ConstantsTest.cpp
+++ b/llvm/unittests/IR/ConstantsTest.cpp
@@ -10,6 +10,7 @@
 #include "llvm-c/Core.h"
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/IR/ConstantFold.h"
+#include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
@@ -868,5 +869,148 @@ TEST(ConstantsTest, Float128Test) {
   LLVMContextDispose(C);
 }
 
+TEST(ConstantsTest, ZeroValueAPIs) {
+  LLVMContext Context;
+
+  Type *Int32Ty = Type::getInt32Ty(Context);
+  Type *FloatTy = Type::getFloatTy(Context);
+  Type *DoubleTy = Type::getDoubleTy(Context);
+  Type *PtrTy = PointerType::get(Context, /*AddressSpace=*/0);
+  Type *Ptr1Ty = PointerType::get(Context, /*AddressSpace=*/1);
+  StructType *StructTy = StructType::get(Int32Ty, PtrTy);
+  StructType *StructWithAS1PtrTy = StructType::get(Int32Ty, Ptr1Ty);
+  ArrayType *ArrayTy = ArrayType::get(Int32Ty, /*NumElements=*/4);
+
+  Constant *IntZero = ConstantInt::get(Int32Ty, 0);
+  Constant *IntOne = ConstantInt::get(Int32Ty, 1);
+  Constant *FPZero = ConstantFP::get(FloatTy, 0.0);
+  Constant *FPNegZero = ConstantFP::get(FloatTy, -0.0);
+  Constant *FPOne = ConstantFP::get(FloatTy, 1.0);
+  Constant *PtrNull0 = ConstantPointerNull::get(cast<PointerType>(PtrTy));
+  Constant *PtrNull1 = ConstantPointerNull::get(cast<PointerType>(Ptr1Ty));
+  Constant *CAZ = ConstantAggregateZero::get(StructTy);
+
+  // TODO: Null and zero are still the same value. The DataLayout argument is
+  // accepted by the API but is not used yet.
+  EXPECT_EQ(Constant::getZeroValue(Int32Ty), Constant::getNullValue(Int32Ty));
+  EXPECT_EQ(Constant::getZeroValue(FloatTy), Constant::getNullValue(FloatTy));
+  EXPECT_EQ(Constant::getZeroValue(PtrTy), Constant::getNullValue(PtrTy));
+  EXPECT_EQ(Constant::getZeroValue(Ptr1Ty), Constant::getNullValue(Ptr1Ty));
+  EXPECT_EQ(Constant::getZeroValue(StructTy), Constant::getNullValue(StructTy));
+  EXPECT_EQ(Constant::getZeroValue(StructWithAS1PtrTy),
+            Constant::getNullValue(StructWithAS1PtrTy));
+  EXPECT_EQ(Constant::getZeroValue(ArrayTy), Constant::getNullValue(ArrayTy));
+
+  EXPECT_TRUE(IntZero->isZeroValue());
+  EXPECT_FALSE(IntOne->isZeroValue());
+  EXPECT_TRUE(FPZero->isZeroValue());
+  // -0.0 has a non-zero bit pattern (sign bit set), so it is NOT a zero value.
+  EXPECT_FALSE(FPNegZero->isZeroValue());
+  EXPECT_FALSE(FPOne->isZeroValue());
+  EXPECT_TRUE(PtrNull0->isZeroValue());
+  EXPECT_TRUE(PtrNull1->isZeroValue());
+  EXPECT_TRUE(CAZ->isZeroValue());
+
+  // -0.0 is NOT zero (sign bit set = non-zero bit pattern).
+  // Verify consistency with isNullValue: both agree +0.0 is zero, -0.0 is not.
+  EXPECT_TRUE(FPZero->isNullValue());
+  EXPECT_FALSE(FPNegZero->isNullValue());
+  EXPECT_TRUE(FPZero->isZeroValue());
+  EXPECT_FALSE(FPNegZero->isZeroValue());
+
+  Constant *DblZero = ConstantFP::get(DoubleTy, 0.0);
+  Constant *DblNegZero = ConstantFP::get(DoubleTy, -0.0);
+  EXPECT_TRUE(DblZero->isZeroValue());
+  EXPECT_FALSE(DblNegZero->isZeroValue());
+
+  // Vector splats of FP zeros.
+  Constant *VecPosZero =
+      ConstantVector::getSplat(ElementCount::getFixed(2), FPZero);
+  Constant *VecNegZero =
+      ConstantVector::getSplat(ElementCount::getFixed(2), FPNegZero);
+  // Splat of +0.0 collapses to CAZ, which is zero.
+  EXPECT_TRUE(isa<ConstantAggregateZero>(VecPosZero));
+  EXPECT_TRUE(VecPosZero->isZeroValue());
+  // Splat of -0.0 does NOT collapse to CAZ and is NOT zero.
+  EXPECT_FALSE(isa<ConstantAggregateZero>(VecNegZero));
+  EXPECT_FALSE(VecNegZero->isZeroValue());
+
+  DataLayout DefaultDL("");
+  DataLayout AllOnesDL("po1:64:64");
+
+  EXPECT_TRUE(IntZero->isZeroValue(&DefaultDL));
+  EXPECT_FALSE(IntOne->isZeroValue(&DefaultDL));
+  EXPECT_TRUE(FPZero->isZeroValue(&DefaultDL));
+  EXPECT_FALSE(FPNegZero->isZeroValue(&DefaultDL));
+  EXPECT_FALSE(FPOne->isZeroValue(&DefaultDL));
+  EXPECT_TRUE(PtrNull0->isZeroValue(&DefaultDL));
+  EXPECT_TRUE(PtrNull1->isZeroValue(&DefaultDL));
+  EXPECT_TRUE(CAZ->isZeroValue(&DefaultDL));
+
+  // TODO: Even though AS 1 has an all-ones null pointer representation in this
+  // layout, ConstantPointerNull is still treated as both null and zero.
+  EXPECT_TRUE(PtrNull0->isZeroValue(&AllOnesDL));
+  EXPECT_TRUE(PtrNull1->isZeroValue(&AllOnesDL));
+  EXPECT_TRUE(PtrNull0->isNullValue(&AllOnesDL));
+  EXPECT_TRUE(PtrNull1->isNullValue(&AllOnesDL));
+  EXPECT_TRUE(IntZero->isZeroValue(&AllOnesDL));
+  EXPECT_TRUE(FPZero->isZeroValue(&AllOnesDL));
+  EXPECT_TRUE(CAZ->isZeroValue(&AllOnesDL));
+
+  EXPECT_EQ(Constant::getNullValue(Int32Ty, /*DL=*/nullptr),
+            Constant::getNullValue(Int32Ty));
+  EXPECT_EQ(Constant::getZeroValue(Int32Ty, /*DL=*/nullptr),
+            Constant::getZeroValue(Int32Ty));
+  EXPECT_EQ(Constant::getNullValue(PtrTy, /*DL=*/nullptr),
+            Constant::getNullValue(PtrTy));
+  EXPECT_EQ(Constant::getZeroValue(PtrTy, /*DL=*/nullptr),
+            Constant::getZeroValue(PtrTy));
+  EXPECT_EQ(Constant::getNullValue(StructTy, /*DL=*/nullptr),
+            Constant::getNullValue(StructTy));
+  EXPECT_EQ(Constant::getZeroValue(StructTy, /*DL=*/nullptr),
+            Constant::getZeroValue(StructTy));
+
+  EXPECT_EQ(Constant::getNullValue(Int32Ty, &DefaultDL),
+            Constant::getNullValue(Int32Ty));
+  EXPECT_EQ(Constant::getZeroValue(Int32Ty, &DefaultDL),
+            Constant::getZeroValue(Int32Ty));
+  EXPECT_EQ(Constant::getNullValue(PtrTy, &DefaultDL),
+            Constant::getNullValue(PtrTy));
+  EXPECT_EQ(Constant::getZeroValue(PtrTy, &DefaultDL),
+            Constant::getZeroValue(PtrTy));
+  EXPECT_EQ(Constant::getNullValue(StructTy, &DefaultDL),
+            Constant::getNullValue(StructTy));
+  EXPECT_EQ(Constant::getZeroValue(StructTy, &DefaultDL),
+            Constant::getZeroValue(StructTy));
+  EXPECT_EQ(Constant::getNullValue(ArrayTy, &DefaultDL),
+            Constant::getNullValue(ArrayTy));
+  EXPECT_EQ(Constant::getZeroValue(ArrayTy, &DefaultDL),
+            Constant::getZeroValue(ArrayTy));
+
+  // TODO: The DataLayout argument does not affect getNullValue() or
+  // getZeroValue() yet, even for pointer-containing types in an address space
+  // with a non-zero null pointer value.
+  EXPECT_EQ(Constant::getNullValue(Int32Ty, &AllOnesDL),
+            Constant::getNullValue(Int32Ty));
+  EXPECT_EQ(Constant::getZeroValue(Int32Ty, &AllOnesDL),
+            Constant::getZeroValue(Int32Ty));
+  EXPECT_EQ(Constant::getNullValue(PtrTy, &AllOnesDL),
+            Constant::getNullValue(PtrTy));
+  EXPECT_EQ(Constant::getZeroValue(PtrTy, &AllOnesDL),
+            Constant::getZeroValue(PtrTy));
+  EXPECT_EQ(Constant::getNullValue(Ptr1Ty, &AllOnesDL),
+            Constant::getNullValue(Ptr1Ty));
+  EXPECT_EQ(Constant::getZeroValue(Ptr1Ty, &AllOnesDL),
+            Constant::getZeroValue(Ptr1Ty));
+  EXPECT_EQ(Constant::getNullValue(StructTy, &AllOnesDL),
+            Constant::getNullValue(StructTy));
+  EXPECT_EQ(Constant::getZeroValue(StructTy, &AllOnesDL),
+            Constant::getZeroValue(StructTy));
+  EXPECT_EQ(Constant::getNullValue(StructWithAS1PtrTy, &AllOnesDL),
+            Constant::getNullValue(StructWithAS1PtrTy));
+  EXPECT_EQ(Constant::getZeroValue(StructWithAS1PtrTy, &AllOnesDL),
+            Constant::getZeroValue(StructWithAS1PtrTy));
+}
+
 } // end anonymous namespace
 } // end namespace llvm



More information about the llvm-commits mailing list