https://github.com/shiltian created https://github.com/llvm/llvm-project/pull/183208
Modify `Constant::isZeroValue()` and `Constant::getNullValue()` to accept an optional `const DataLayout *DL = nullptr` parameter, and add a new `Constant::getZeroValue()` factory method. This establishes the API distinction between "null value" (semantic null pointer, which may be non-zero on some targets) and "zero value" (all-zero bits). When DataLayout is provided: - `isZeroValue()` checks `ConstantPointerNull` against the target's null pointer bit pattern via `DL->isNullPointerAllZeroes(AS)`, returning false for address spaces where null is not zero. - `getNullValue()` constructs aggregates element-by-element when they contain pointer elements in non-zero-null address spaces, preserving ConstantPointerNull instead of collapsing to ConstantAggregateZero. When DataLayout is not provided, both functions behave identically to their previous implementations, ensuring full backward compatibility. `getZeroValue()` currently delegates to `getNullValue()` and will return a distinct zero-valued pointer constant (via `inttoptr`) once constant folding is made DataLayout-aware in a follow-up patch. >From bc013697692e709258d1f0a427ae6d22cec39029 Mon Sep 17 00:00:00 2001 From: Shilei Tian <[email protected]> Date: Sat, 14 Feb 2026 15:41:29 -0500 Subject: [PATCH] [NFCI][IR] Add DataLayout-aware `isZeroValue`/`getNullValue` and `getZeroValue` APIs Modify `Constant::isZeroValue()` and `Constant::getNullValue()` to accept an optional `const DataLayout *DL = nullptr` parameter, and add a new `Constant::getZeroValue()` factory method. This establishes the API distinction between "null value" (semantic null pointer, which may be non-zero on some targets) and "zero value" (all-zero bits). When DataLayout is provided: - `isZeroValue()` checks `ConstantPointerNull` against the target's null pointer bit pattern via `DL->isNullPointerAllZeroes(AS)`, returning false for address spaces where null is not zero. - `getNullValue()` constructs aggregates element-by-element when they contain pointer elements in non-zero-null address spaces, preserving ConstantPointerNull instead of collapsing to ConstantAggregateZero. When DataLayout is not provided, both functions behave identically to their previous implementations, ensuring full backward compatibility. `getZeroValue()` currently delegates to `getNullValue()` and will return a distinct zero-valued pointer constant (via `inttoptr`) once constant folding is made DataLayout-aware in a follow-up patch. --- llvm/include/llvm/IR/Constant.h | 15 +++- llvm/lib/IR/Constants.cpp | 29 ++++++- llvm/unittests/IR/ConstantsTest.cpp | 124 ++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 3 deletions(-) diff --git a/llvm/include/llvm/IR/Constant.h b/llvm/include/llvm/IR/Constant.h index 82a570e8a1446..be0cc6b5665d4 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 @@ -69,6 +70,9 @@ class Constant : public User { /// getZeroValueForNegation. LLVM_ABI bool isNegativeZeroValue() const; + /// Return true iff this constant has an all-zero bit pattern. + LLVM_ABI bool isZeroValue(const DataLayout *DL = nullptr) const; + /// Return true if the value is not the smallest signed value, or, /// for vectors, does not contain smallest signed value elements. LLVM_ABI bool isNotMinSignedValue() const; @@ -187,7 +191,16 @@ 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. + /// Currently equivalent to getZeroValue(). Will diverge once pointer null + /// semantics change: 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. + LLVM_ABI static Constant *getZeroValue(Type *Ty); /// @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 78ac276f4f3da..5a011f50ef94b 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,6 +72,27 @@ bool Constant::isNegativeZeroValue() const { return isNullValue(); } +// Return true iff this constant has an all-zero bit pattern. +bool Constant::isZeroValue(const DataLayout *DL) const { + // When DataLayout is available, check if ConstantPointerNull actually has + // a zero bit pattern (it might not for non-zero-null address spaces). + if (DL) { + if (const auto *CPN = dyn_cast<ConstantPointerNull>(this)) + return DL->isNullPointerAllZeroes(CPN->getType()->getAddressSpace()); + + // Check for vector splats of ConstantPointerNull. + if (getType()->isVectorTy()) { + if (const auto *SplatCPN = + dyn_cast_or_null<ConstantPointerNull>(getSplatValue())) { + return DL->isNullPointerAllZeroes( + SplatCPN->getType()->getAddressSpace()); + } + } + } + + return this == getZeroValue(getType()); +} + bool Constant::isNullValue() const { // 0 is null. if (const ConstantInt *CI = dyn_cast<ConstantInt>(this)) @@ -370,8 +392,11 @@ 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) { + return getZeroValue(Ty); +} + +Constant *Constant::getZeroValue(Type *Ty) { switch (Ty->getTypeID()) { case Type::IntegerTyID: return ConstantInt::get(Ty, 0); diff --git a/llvm/unittests/IR/ConstantsTest.cpp b/llvm/unittests/IR/ConstantsTest.cpp index 34898aa467788..96730dbf16758 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,128 @@ TEST(ConstantsTest, Float128Test) { LLVMContextDispose(C); } +TEST(ConstantsTest, ZeroValueAPIs) { + LLVMContext Context; + + // Basic types. + Type *Int32Ty = Type::getInt32Ty(Context); + Type *FloatTy = Type::getFloatTy(Context); + Type *PtrTy = PointerType::get(Context, 0); + Type *Ptr1Ty = PointerType::get(Context, 1); + + // --- getZeroValue: currently returns same as getNullValue --- + 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)); + + // Aggregate types. + StructType *StructTy = StructType::get(Int32Ty, PtrTy); + ArrayType *ArrayTy = ArrayType::get(Int32Ty, 4); + EXPECT_EQ(Constant::getZeroValue(StructTy), Constant::getNullValue(StructTy)); + EXPECT_EQ(Constant::getZeroValue(ArrayTy), Constant::getNullValue(ArrayTy)); + + // --- isZeroValue(nullptr): identity check against getZeroValue --- + 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); + + 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()); + + // --- isZeroValue: FP corner cases --- + // -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()); + + // Double precision: same behavior. + Type *DoubleTy = Type::getDoubleTy(Context); + 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()); + + // --- isZeroValue(&DL) with default DataLayout (all AS have zero null) --- + DataLayout DefaultDL(""); + 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)); + + // --- isZeroValue(&DL) with all-ones-null AS 1 --- + // Format: p<flags><as>:<size>:<abi> -- flags before AS number. + DataLayout AllOnesDL("po1:64:64"); + // AS 0 still has zero null, so CPN for AS 0 is still a zero value. + EXPECT_TRUE(PtrNull0->isZeroValue(&AllOnesDL)); + // AS 1 has all-ones null, so CPN for AS 1 is NOT a zero value. + EXPECT_FALSE(PtrNull1->isZeroValue(&AllOnesDL)); + // Non-pointer constants are unaffected by DataLayout. + EXPECT_TRUE(IntZero->isZeroValue(&AllOnesDL)); + EXPECT_TRUE(FPZero->isZeroValue(&AllOnesDL)); + EXPECT_TRUE(CAZ->isZeroValue(&AllOnesDL)); + + // --- getNullValue(Ty, nullptr): same as getNullValue(Ty) --- + EXPECT_EQ(Constant::getNullValue(Int32Ty, nullptr), + Constant::getNullValue(Int32Ty)); + EXPECT_EQ(Constant::getNullValue(PtrTy, nullptr), + Constant::getNullValue(PtrTy)); + EXPECT_EQ(Constant::getNullValue(StructTy, nullptr), + Constant::getNullValue(StructTy)); + + // --- getNullValue(Ty, &DL) fast path: no non-zero-null pointers --- + EXPECT_EQ(Constant::getNullValue(Int32Ty, &DefaultDL), + Constant::getNullValue(Int32Ty)); + EXPECT_EQ(Constant::getNullValue(PtrTy, &DefaultDL), + Constant::getNullValue(PtrTy)); + EXPECT_EQ(Constant::getNullValue(StructTy, &DefaultDL), + Constant::getNullValue(StructTy)); + EXPECT_EQ(Constant::getNullValue(ArrayTy, &DefaultDL), + Constant::getNullValue(ArrayTy)); + + // With AllOnesDL, types that don't contain AS 1 pointers still take fast + // path. + EXPECT_EQ(Constant::getNullValue(Int32Ty, &AllOnesDL), + Constant::getNullValue(Int32Ty)); + EXPECT_EQ(Constant::getNullValue(PtrTy, &AllOnesDL), + Constant::getNullValue(PtrTy)); + // Struct containing AS 0 pointer -- fast path (AS 0 is zero null). + EXPECT_EQ(Constant::getNullValue(StructTy, &AllOnesDL), + Constant::getNullValue(StructTy)); + + // TODO: getNullValue slow path for aggregates with non-zero-null pointers is + // deferred to PR 3 testing (requires aggregate collapse fix). +} + } // end anonymous namespace } // end namespace llvm _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
