Skip to content

Commit efda127

Browse files
kasuga-fjshiltian
authored andcommitted
[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 c53caae commit efda127

File tree

8 files changed

+85
-27
lines changed

8 files changed

+85
-27
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:32:32:f-p3:32:32:32:32:f-p4:64:64"
36+
"-p5:32:32:32:32:f-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32"
37+
"-i64:64-v16:16-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

clang/test/CodeGen/target-data.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,12 @@
176176

177177
// RUN: %clang_cc1 -triple amdgcn-unknown -target-cpu hawaii -o - -emit-llvm %s \
178178
// RUN: | FileCheck %s -check-prefix=R600SI
179-
// R600SI: target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"
179+
// R600SI: target datalayout = "e-p:64:64-p1:64:64-p2:32:32:32:32:f-p3:32:32:32:32:f-p4:64:64-p5:32:32:32:32:f-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"
180180

181181
// Test default -target-cpu
182182
// RUN: %clang_cc1 -triple amdgcn-unknown -o - -emit-llvm %s \
183183
// RUN: | FileCheck %s -check-prefix=R600SIDefault
184-
// R600SIDefault: target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"
184+
// R600SIDefault: target datalayout = "e-p:64:64-p1:64:64-p2:32:32:32:32:f-p3:32:32:32:32:f-p4:64:64-p5:32:32:32:32:f-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"
185185

186186
// RUN: %clang_cc1 -triple arm64-unknown -o - -emit-llvm %s | \
187187
// RUN: FileCheck %s -check-prefix=AARCH64
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 %s -O0 -triple amdgcn -emit-llvm -o - | FileCheck %s
22
// RUN: %clang_cc1 %s -O0 -triple amdgcn---opencl -emit-llvm -o - | FileCheck %s
33

4-
// CHECK: target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"
4+
// CHECK: target datalayout = "e-p:64:64-p1:64:64-p2:32:32:32:32:f-p3:32:32:32:32:f-p4:64:64-p5:32:32:32:32:f-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"
55
void foo(void) {}

llvm/docs/LangRef.rst

+5-2
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).

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

+45-10
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ bool DataLayout::PointerSpec::operator==(const PointerSpec &Other) const {
152152
return AddrSpace == Other.AddrSpace && BitWidth == Other.BitWidth &&
153153
ABIAlign == Other.ABIAlign && PrefAlign == Other.PrefAlign &&
154154
IndexBitWidth == Other.IndexBitWidth &&
155+
SentinelValue == Other.SentinelValue &&
155156
IsNonIntegral == Other.IsNonIntegral;
156157
}
157158

@@ -206,9 +207,10 @@ constexpr DataLayout::PrimitiveSpec DefaultVectorSpecs[] = {
206207
};
207208

208209
// 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},
210+
const DataLayout::PointerSpec DefaultPointerSpecs[] = {
211+
// p0:64:64:64:64:0
212+
{0, 64, Align::Constant<8>(), Align::Constant<8>(), 64, APInt(64, 0),
213+
false},
212214
};
213215

214216
DataLayout::DataLayout()
@@ -296,6 +298,22 @@ static Error parseSize(StringRef Str, unsigned &BitWidth,
296298
return Error::success();
297299
}
298300

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

411429
Error DataLayout::parsePointerSpec(StringRef Spec) {
412-
// p[<n>]:<size>:<abi>[:<pref>[:<idx>]]
430+
// p[<n>]:<size>:<abi>[:<pref>[:<idx>[:<sentinel>]]]
413431
SmallVector<StringRef, 5> Components;
414432
assert(Spec.front() == 'p');
415433
Spec.drop_front().split(Components, ':');
416434

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

420439
// Address space. Optional, defaults to 0.
421440
unsigned AddrSpace = 0;
@@ -454,8 +473,14 @@ Error DataLayout::parsePointerSpec(StringRef Spec) {
454473
return createStringError(
455474
"index size cannot be larger than the pointer size");
456475

476+
APInt SentinelValue(BitWidth, 0);
477+
if (Components.size() > 5) {
478+
if (Error Err = parseSentinelValue(Components[5], SentinelValue))
479+
return Err;
480+
}
481+
457482
setPointerSpec(AddrSpace, BitWidth, ABIAlign, PrefAlign, IndexBitWidth,
458-
false);
483+
SentinelValue, /*IsNonIntegral=*/false);
459484
return Error::success();
460485
}
461486

@@ -631,7 +656,7 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) {
631656
// the spec for AS0, and we then update that to mark it non-integral.
632657
const PointerSpec &PS = getPointerSpec(AS);
633658
setPointerSpec(AS, PS.BitWidth, PS.ABIAlign, PS.PrefAlign, PS.IndexBitWidth,
634-
true);
659+
PS.SentinelValue, /*IsNonIntegral=*/true);
635660
}
636661

637662
return Error::success();
@@ -679,16 +704,19 @@ DataLayout::getPointerSpec(uint32_t AddrSpace) const {
679704

680705
void DataLayout::setPointerSpec(uint32_t AddrSpace, uint32_t BitWidth,
681706
Align ABIAlign, Align PrefAlign,
682-
uint32_t IndexBitWidth, bool IsNonIntegral) {
707+
uint32_t IndexBitWidth, APInt SentinelValue,
708+
bool IsNonIntegral) {
683709
auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace());
684710
if (I == PointerSpecs.end() || I->AddrSpace != AddrSpace) {
685711
PointerSpecs.insert(I, PointerSpec{AddrSpace, BitWidth, ABIAlign, PrefAlign,
686-
IndexBitWidth, IsNonIntegral});
712+
IndexBitWidth, SentinelValue,
713+
IsNonIntegral});
687714
} else {
688715
I->BitWidth = BitWidth;
689716
I->ABIAlign = ABIAlign;
690717
I->PrefAlign = PrefAlign;
691718
I->IndexBitWidth = IndexBitWidth;
719+
I->SentinelValue = SentinelValue;
692720
I->IsNonIntegral = IsNonIntegral;
693721
}
694722
}
@@ -1020,3 +1048,10 @@ Align DataLayout::getPreferredAlign(const GlobalVariable *GV) const {
10201048
}
10211049
return Alignment;
10221050
}
1051+
1052+
APInt DataLayout::getSentinelPointerValue(unsigned AS) const {
1053+
auto I = lower_bound(PointerSpecs, AS, LessPointerAddrSpace());
1054+
if (I != PointerSpecs.end() || I->AddrSpace == AS)
1055+
return I->SentinelValue;
1056+
return PointerSpecs[0].SentinelValue;
1057+
}

llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -677,11 +677,11 @@ static StringRef computeDataLayout(const Triple &TT) {
677677
// (address space 7), and 128-bit non-integral buffer resourcees (address
678678
// space 8) which cannot be non-trivilally accessed by LLVM memory operations
679679
// like getelementptr.
680-
return "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32"
681-
"-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-"
682-
"v32:32-v48:64-v96:"
683-
"128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-"
684-
"G1-ni:7:8:9";
680+
return "e-p:64:64-p1:64:64-p2:32:32:32:32:f-p3:32:32:32:32:f-p4:64:64"
681+
"-p5:32:32:32:32:f-p6:32:32-p7:160:256:256:32-p8:128:128"
682+
"-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
683+
"-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1"
684+
"-ni:7:8:9";
685685
}
686686

687687
LLVM_READNONE

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)