Skip to content

Commit c966236

Browse files
committed
[DataLayout] Introduce sentinel pointer value
The value of a null pointer is not always `0`. For example, on AMDGPU, the null pointer 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`. This PR introduces the concept of a *sentinel pointer value* to `DataLayout`, representing the actual `nullptr` value for a given address space. The changes include: - A new interface function: ``` APInt getSentinelPointerValue(unsigned AS) ``` This function returns an `APInt` representing the sentinel pointer value for the given address space `AS`. An `APInt` is used instead of a literal integer to support cases where pointers are wider than 64 bits (e.g., AMDGPU’s address space 8). - An extension to the data layout string format: ``` p[n]:<size>:<abi>[:<pref>[:<idx>[:<sentinel>]]] ``` The new `<sentinel>` component specifies the sentinel value for the corresponding pointer. It currently supports two values: - `0` for an all-zero value - `f` for a full-bit set value These two values are the most common representations of `nullptr`. It is unlikely that any target would define `nullptr` as a random value. A follow-up patch series will introduce an equivalent of `ConstantPointerNull` that represents the actual `nullptr`, built on top of this PR.
1 parent 4fde8c3 commit c966236

File tree

5 files changed

+78
-21
lines changed

5 files changed

+78
-21
lines changed

clang/lib/Basic/Targets/AMDGPU.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ static const char *const DataLayoutStringR600 =
3232
"-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1";
3333

3434
static const char *const DataLayoutStringAMDGCN =
35-
"e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32"
36-
"-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:"
37-
"32-v48:64-v96:128"
35+
"e-p:64:64-p1:64:64-p2:32:32-p3:32:32:32:32:f-p4:64:64-p5:32:32:32:32:f"
36+
"-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16"
37+
"-v24:32-v32:32-v48:64-v96:128"
3838
"-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1"
3939
"-ni:7:8:9";
4040

llvm/docs/LangRef.rst

+7-4
Original file line numberDiff line numberDiff line change
@@ -3134,7 +3134,7 @@ as follows:
31343134
``A<address space>``
31353135
Specifies the address space of objects created by '``alloca``'.
31363136
Defaults to the default address space of 0.
3137-
``p[n]:<size>:<abi>[:<pref>][:<idx>]``
3137+
``p[<n>]:<size>:<abi>[:<pref>[:<idx>[:<sentinel>]]]``
31383138
This specifies the *size* of a pointer and its ``<abi>`` and
31393139
``<pref>``\erred alignments for address space ``n``. ``<pref>`` is optional
31403140
and defaults to ``<abi>``. The fourth parameter ``<idx>`` is the size of the
@@ -3143,7 +3143,10 @@ as follows:
31433143
specified, the default index size is equal to the pointer size. All sizes
31443144
are in bits. The address space, ``n``, is optional, and if not specified,
31453145
denotes the default address space 0. The value of ``n`` must be
3146-
in the range [1,2^24).
3146+
in the range [1,2^24). The fifth parameter ``<sentinel>`` specifies the
3147+
sentinel value of the pointer for the corresponding address space. It
3148+
currently accepts two values: ``0`` for an all-zero value and ``f`` for a
3149+
full-bit set value. The default sentinel pointer value is all-zero.
31473150
``i<size>:<abi>[:<pref>]``
31483151
This specifies the alignment for an integer type of a given bit
31493152
``<size>``. The value of ``<size>`` must be in the range [1,2^24).
@@ -13045,9 +13048,9 @@ This instruction requires several arguments:
1304513048
- Caller and callee both have the calling convention ``fastcc`` or ``tailcc``.
1304613049
- The call is in tail position (ret immediately follows call and ret
1304713050
uses value of call or is void).
13048-
- Option ``-tailcallopt`` is enabled, ``llvm::GuaranteedTailCallOpt`` is
13051+
- Option ``-tailcallopt`` is enabled, ``llvm::GuaranteedTailCallOpt`` is
1304913052
``true``, or the calling convention is ``tailcc``.
13050-
- `Platform-specific constraints are met.
13053+
- `Platform-specific constraints are met.
1305113054
<CodeGenerator.html#tail-call-optimization>`_
1305213055

1305313056
#. The optional ``notail`` marker indicates that the optimizers should not add

llvm/include/llvm/IR/DataLayout.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class DataLayout {
7878
Align ABIAlign;
7979
Align PrefAlign;
8080
uint32_t IndexBitWidth;
81+
APInt SentinelValue;
8182
/// Pointers in this address space don't have a well-defined bitwise
8283
/// representation (e.g. may be relocated by a copying garbage collector).
8384
/// Additionally, they may also be non-integral (i.e. containing additional
@@ -148,7 +149,7 @@ class DataLayout {
148149
/// Sets or updates the specification for pointer in the given address space.
149150
void setPointerSpec(uint32_t AddrSpace, uint32_t BitWidth, Align ABIAlign,
150151
Align PrefAlign, uint32_t IndexBitWidth,
151-
bool IsNonIntegral);
152+
APInt SentinelValue, bool IsNonIntegral);
152153

153154
/// Internal helper to get alignment for integer of given bitwidth.
154155
Align getIntegerAlignment(uint32_t BitWidth, bool abi_or_pref) const;
@@ -552,6 +553,11 @@ class DataLayout {
552553
///
553554
/// This includes an explicitly requested alignment (if the global has one).
554555
Align getPreferredAlign(const GlobalVariable *GV) const;
556+
557+
/// Returns the sentinel pointer value for a given address space. If the
558+
/// address space is invalid, it defaults to the sentinel pointer value of
559+
/// address space 0, aligning with the behavior of \p getPointerSpec.
560+
APInt getSentinelPointerValue(unsigned AS) const;
555561
};
556562

557563
inline DataLayout *unwrap(LLVMTargetDataRef P) {

llvm/lib/IR/DataLayout.cpp

+44-10
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,10 @@ constexpr DataLayout::PrimitiveSpec DefaultVectorSpecs[] = {
206206
};
207207

208208
// Default pointer type specifications.
209-
constexpr DataLayout::PointerSpec DefaultPointerSpecs[] = {
210-
// p0:64:64:64:64
211-
{0, 64, Align::Constant<8>(), Align::Constant<8>(), 64, false},
209+
const DataLayout::PointerSpec DefaultPointerSpecs[] = {
210+
// p0:64:64:64:64:0
211+
{0, 64, Align::Constant<8>(), Align::Constant<8>(), 64, APInt(64, 0),
212+
false},
212213
};
213214

214215
DataLayout::DataLayout()
@@ -296,6 +297,22 @@ static Error parseSize(StringRef Str, unsigned &BitWidth,
296297
return Error::success();
297298
}
298299

300+
static Error parseSentinelValue(StringRef Str, APInt &V) {
301+
if (Str.empty())
302+
return createStringError("sentinel value component cannot be empty");
303+
if (Str.size() != 1)
304+
return createStringError("sentinel value component must be a '0' or 'f'");
305+
if (Str[0] == '0') {
306+
V.clearAllBits();
307+
return Error::success();
308+
}
309+
if (Str[0] == 'f') {
310+
V.setAllBits();
311+
return Error::success();
312+
}
313+
return createStringError("sentinel value component must be a '0' or 'f'");
314+
}
315+
299316
/// Attempts to parse an alignment component of a specification.
300317
///
301318
/// On success, returns the value converted to byte amount in \p Alignment.
@@ -409,13 +426,14 @@ Error DataLayout::parseAggregateSpec(StringRef Spec) {
409426
}
410427

411428
Error DataLayout::parsePointerSpec(StringRef Spec) {
412-
// p[<n>]:<size>:<abi>[:<pref>[:<idx>]]
429+
// p[<n>]:<size>:<abi>[:<pref>[:<idx>[:<sentinel>]]]
413430
SmallVector<StringRef, 5> Components;
414431
assert(Spec.front() == 'p');
415432
Spec.drop_front().split(Components, ':');
416433

417-
if (Components.size() < 3 || Components.size() > 5)
418-
return createSpecFormatError("p[<n>]:<size>:<abi>[:<pref>[:<idx>]]");
434+
if (Components.size() < 3 || Components.size() > 6)
435+
return createSpecFormatError(
436+
"p[<n>]:<size>:<abi>[:<pref>[:<idx>[:<sentinel>]]]");
419437

420438
// Address space. Optional, defaults to 0.
421439
unsigned AddrSpace = 0;
@@ -454,8 +472,14 @@ Error DataLayout::parsePointerSpec(StringRef Spec) {
454472
return createStringError(
455473
"index size cannot be larger than the pointer size");
456474

475+
APInt SentinelValue(BitWidth, 0);
476+
if (Components.size() > 5) {
477+
if (Error Err = parseSentinelValue(Components[5], SentinelValue))
478+
return Err;
479+
}
480+
457481
setPointerSpec(AddrSpace, BitWidth, ABIAlign, PrefAlign, IndexBitWidth,
458-
false);
482+
SentinelValue, /*IsNonIntegral=*/false);
459483
return Error::success();
460484
}
461485

@@ -631,7 +655,7 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) {
631655
// the spec for AS0, and we then update that to mark it non-integral.
632656
const PointerSpec &PS = getPointerSpec(AS);
633657
setPointerSpec(AS, PS.BitWidth, PS.ABIAlign, PS.PrefAlign, PS.IndexBitWidth,
634-
true);
658+
PS.SentinelValue, /*IsNonIntegral=*/true);
635659
}
636660

637661
return Error::success();
@@ -679,16 +703,19 @@ DataLayout::getPointerSpec(uint32_t AddrSpace) const {
679703

680704
void DataLayout::setPointerSpec(uint32_t AddrSpace, uint32_t BitWidth,
681705
Align ABIAlign, Align PrefAlign,
682-
uint32_t IndexBitWidth, bool IsNonIntegral) {
706+
uint32_t IndexBitWidth, APInt SentinelValue,
707+
bool IsNonIntegral) {
683708
auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace());
684709
if (I == PointerSpecs.end() || I->AddrSpace != AddrSpace) {
685710
PointerSpecs.insert(I, PointerSpec{AddrSpace, BitWidth, ABIAlign, PrefAlign,
686-
IndexBitWidth, IsNonIntegral});
711+
IndexBitWidth, SentinelValue,
712+
IsNonIntegral});
687713
} else {
688714
I->BitWidth = BitWidth;
689715
I->ABIAlign = ABIAlign;
690716
I->PrefAlign = PrefAlign;
691717
I->IndexBitWidth = IndexBitWidth;
718+
I->SentinelValue = SentinelValue;
692719
I->IsNonIntegral = IsNonIntegral;
693720
}
694721
}
@@ -1020,3 +1047,10 @@ Align DataLayout::getPreferredAlign(const GlobalVariable *GV) const {
10201047
}
10211048
return Alignment;
10221049
}
1050+
1051+
APInt DataLayout::getSentinelPointerValue(unsigned AS) const {
1052+
auto I = lower_bound(PointerSpecs, AS, LessPointerAddrSpace());
1053+
if (I != PointerSpecs.end() || I->AddrSpace == AS)
1054+
return I->SentinelValue;
1055+
return PointerSpecs[0].SentinelValue;
1056+
}

llvm/unittests/IR/DataLayoutTest.cpp

+17-3
Original file line numberDiff line numberDiff line change
@@ -313,11 +313,12 @@ TEST(DataLayout, ParsePointerSpec) {
313313
EXPECT_THAT_EXPECTED(DataLayout::parse(Str), Succeeded());
314314

315315
for (StringRef Str :
316-
{"p", "p0", "p:32", "p0:32", "p:32:32:32:32:32", "p0:32:32:32:32:32"})
316+
{"p", "p0", "p:32", "p0:32", "p:32:32:32:32:32:0", "p0:32:32:32:32:32:0"})
317317
EXPECT_THAT_EXPECTED(
318318
DataLayout::parse(Str),
319-
FailedWithMessage("malformed specification, must be of the form "
320-
"\"p[<n>]:<size>:<abi>[:<pref>[:<idx>]]\""));
319+
FailedWithMessage(
320+
"malformed specification, must be of the form "
321+
"\"p[<n>]:<size>:<abi>[:<pref>[:<idx>[:<sentinel>]]]\""));
321322

322323
// address space
323324
for (StringRef Str : {"p0x0:32:32", "px:32:32:32", "p16777216:32:32:32:32"})
@@ -401,6 +402,19 @@ TEST(DataLayout, ParsePointerSpec) {
401402
EXPECT_THAT_EXPECTED(
402403
DataLayout::parse(Str),
403404
FailedWithMessage("index size cannot be larger than the pointer size"));
405+
406+
// sentinel value
407+
for (StringRef Str :
408+
{"p:32:32:32:32:a", "p0:32:32:32:32:ab", "p42:32:32:32:32:123"})
409+
EXPECT_THAT_EXPECTED(
410+
DataLayout::parse(Str),
411+
FailedWithMessage("sentinel value component must be a '0' or 'f'"));
412+
413+
for (StringRef Str :
414+
{"p:32:32:32:32:", "p0:32:32:32:32:", "p42:32:32:32:32:"})
415+
EXPECT_THAT_EXPECTED(
416+
DataLayout::parse(Str),
417+
FailedWithMessage("sentinel value component cannot be empty"));
404418
}
405419

406420
TEST(DataLayoutTest, ParseNativeIntegersSpec) {

0 commit comments

Comments
 (0)