diff options
| author | Shilei Tian <i@tianshilei.me> | 2025-11-15 23:19:05 -0500 |
|---|---|---|
| committer | Shilei Tian <i@tianshilei.me> | 2025-11-17 00:16:27 -0500 |
| commit | c52a3b6b8b1cd3fa4c7e58d4d27265482ea837d2 (patch) | |
| tree | f9a9b09e2f9a9e9f12706b6d6761dcecb99b3432 /llvm/lib/IR/DataLayout.cpp | |
| parent | 49d5bb0ad0cb31410184c462801c5049ad671517 (diff) | |
[WIP][IR][Constants] Change the semantic of `ConstantPointerNull` to represent an actual `nullptr` instead of a zero-value pointerupstream/users/shiltian/ptr-zeroinitializer-to-inttoptr
The value of a `nullptr` is not always `0`. For example, on AMDGPU, the `nullptr` in address spaces 3 and 5 is `0xffffffff`. Currently, there is no target-independent way to get this information, making it difficult and error-prone to handle null pointers in target-agnostic code.
We do have `ConstantPointerNull`, but it might be a little confusing and misleading. It represents a pointer with an all-zero value rather than necessarily a real `nullptr`. Therefore, to represent a real `nullptr` in address space `N`, we need to use `addrspacecast ptr null to ptr addrspace(N)` and it can't be folded.
In this PR, we change the semantic of `ConstantPointerNull` to represent an actual `nullptr` instead of a zero-value pointer. Here is the detailed changes.
* `ptr addrspace(N) null` will represent the actual `nullptr` in address space `N`.
* `ptr addrspace(N) zeroinitializer` will represent a zero-value pointer in address space `N`.
* `Constant::getNullValue` will return a _null_ value. It is same as the current semantics except for the `PointerType`, which will return a real `nullptr` pointer.
* `Constant::getZeroValue` will return a zero value constant. It is completely same as the current semantics. To represent a zero-value pointer, a `ConstantExpr` will be used (effectively `inttoptr i8 0 to ptr addrspace(N)`).
* Correspondingly, there will be both `Constant::isNullValue` and `Constant::isZeroValue`.
The RFC is https://discourse.llvm.org/t/rfc-introduce-sentinel-pointer-value-to-datalayout/85265. It is a little bit old and the title might look different, but everything eventually converges to this change. An early attempt can be found in https://github.com/llvm/llvm-project/pull/131557, which has many valuable discussion as well.
This PR is still WIP but any early feedback is welcome. I'll include as many necessary code changes as possible in this PR, but eventually this needs to be carefully split into multiple PRs, and I'll do it after the changes look good to every one.
Diffstat (limited to 'llvm/lib/IR/DataLayout.cpp')
| -rw-r--r-- | llvm/lib/IR/DataLayout.cpp | 41 |
1 files changed, 34 insertions, 7 deletions
diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp index 49e1f898ca59..86573c8e0942 100644 --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -193,9 +193,12 @@ constexpr DataLayout::PrimitiveSpec DefaultVectorSpecs[] = { }; // Default pointer type specifications. -constexpr DataLayout::PointerSpec DefaultPointerSpecs[] = { +const DataLayout::PointerSpec DefaultPointerSpecs[] = { // p0:64:64:64:64 - {0, 64, Align::Constant<8>(), Align::Constant<8>(), 64, false, false}, + {/*AddrSpace=*/0, /*BitWidth=*/64, /*ABIAlign=*/Align::Constant<8>(), + /*PrefAlign=*/Align::Constant<8>(), /*IndexBitWidth=*/64, + /*NullPtrValue=*/APInt(64, 0), /*HasUnstableRepr=*/false, + /*HasExternalState=*/false}, }; DataLayout::DataLayout() @@ -408,6 +411,15 @@ Error DataLayout::parsePointerSpec(StringRef Spec) { unsigned AddrSpace = 0; bool ExternalState = false; bool UnstableRepr = false; + // Default nullptr value kind is all-zeros, which is same as the previous + // behavior. + enum { + AllZeros, + AllOnes, + // The nullptr value is neither all-zeros nor all-ones. LLVM doesn't accept + // arbitrary bit patterns, so it will not be able to fold nullptr. + Custom + } NullPtrValueKind = AllZeros; StringRef AddrSpaceStr = Components[0]; while (!AddrSpaceStr.empty()) { char C = AddrSpaceStr.front(); @@ -415,6 +427,12 @@ Error DataLayout::parsePointerSpec(StringRef Spec) { ExternalState = true; } else if (C == 'u') { UnstableRepr = true; + } else if (C == 'z') { + NullPtrValueKind = AllZeros; + } else if (C == 'o') { + NullPtrValueKind = AllOnes; + } else if (C == 'c') { + NullPtrValueKind = Custom; } else if (isAlpha(C)) { return createStringError("'%c' is not a valid pointer specification flag", C); @@ -461,8 +479,14 @@ Error DataLayout::parsePointerSpec(StringRef Spec) { return createStringError( "index size cannot be larger than the pointer size"); + std::optional<APInt> NullPtrValue; + if (NullPtrValueKind == AllZeros) + NullPtrValue = APInt::getZero(BitWidth); + else if (NullPtrValueKind == AllOnes) + NullPtrValue = APInt::getAllOnes(BitWidth); + setPointerSpec(AddrSpace, BitWidth, ABIAlign, PrefAlign, IndexBitWidth, - UnstableRepr, ExternalState); + NullPtrValue, UnstableRepr, ExternalState); return Error::success(); } @@ -638,6 +662,7 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) { // the spec for AS0, and we then update that to mark it non-integral. const PointerSpec &PS = getPointerSpec(AS); setPointerSpec(AS, PS.BitWidth, PS.ABIAlign, PS.PrefAlign, PS.IndexBitWidth, + PS.NullPtrValue, /*HasUnstableRepr=*/true, /*HasExternalState=*/false); } @@ -686,18 +711,20 @@ DataLayout::getPointerSpec(uint32_t AddrSpace) const { void DataLayout::setPointerSpec(uint32_t AddrSpace, uint32_t BitWidth, Align ABIAlign, Align PrefAlign, - uint32_t IndexBitWidth, bool HasUnstableRepr, - bool HasExternalState) { + uint32_t IndexBitWidth, + std::optional<APInt> NullPtrValue, + bool HasUnstableRepr, bool HasExternalState) { auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace()); if (I == PointerSpecs.end() || I->AddrSpace != AddrSpace) { PointerSpecs.insert(I, PointerSpec{AddrSpace, BitWidth, ABIAlign, PrefAlign, - IndexBitWidth, HasUnstableRepr, - HasExternalState}); + IndexBitWidth, NullPtrValue, + HasUnstableRepr, HasExternalState}); } else { I->BitWidth = BitWidth; I->ABIAlign = ABIAlign; I->PrefAlign = PrefAlign; I->IndexBitWidth = IndexBitWidth; + I->NullPtrValue = NullPtrValue; I->HasUnstableRepresentation = HasUnstableRepr; I->HasExternalState = HasExternalState; } |
