Skip to content

Commit 84f3f46

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.6-beta.1
1 parent 305a1ce commit 84f3f46

File tree

4 files changed

+215
-35
lines changed

4 files changed

+215
-35
lines changed

llvm/docs/LangRef.rst

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -649,48 +649,95 @@ literal types are uniqued in recent versions of LLVM.
649649

650650
.. _nointptrtype:
651651

652-
Non-Integral Pointer Type
653-
-------------------------
652+
Non-Integral and Unstable Pointer Types
653+
---------------------------------------
654654

655-
Note: non-integral pointer types are a work in progress, and they should be
656-
considered experimental at this time.
655+
Note: non-integral/unstable pointer types are a work in progress, and they
656+
should be considered experimental at this time.
657657

658658
LLVM IR optionally allows the frontend to denote pointers in certain address
659-
spaces as "non-integral" via the :ref:`datalayout string<langref_datalayout>`.
660-
Non-integral pointer types represent pointers that have an *unspecified* bitwise
661-
representation; that is, the integral representation may be target dependent or
662-
unstable (not backed by a fixed integer).
659+
spaces as "non-integral" or "unstable" (or both "non-integral" and "unstable")
660+
via the :ref:`datalayout string<langref_datalayout>`.
661+
662+
These exact implications of these properties are target-specific, but the
663+
following IR semantics and restrictions to optimization passes apply:
664+
665+
Unstable pointer representation
666+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
667+
668+
Pointers in this address space have an *unspecified* bitwise representation
669+
(i.e. not backed by a fixed integer). The bitwise pattern of such pointers is
670+
allowed to change in a target-specific way. For example, this could be a pointer
671+
type used for with copying garbage collection where the garbage collector could
672+
update the pointer at any time in the collection sweep.
663673

664674
``inttoptr`` and ``ptrtoint`` instructions have the same semantics as for
665675
integral (i.e. normal) pointers in that they convert integers to and from
666-
corresponding pointer types, but there are additional implications to be
667-
aware of. Because the bit-representation of a non-integral pointer may
668-
not be stable, two identical casts of the same operand may or may not
676+
corresponding pointer types, but there are additional implications to be aware
677+
of.
678+
679+
For "unstable" pointer representations, the bit-representation of the pointer
680+
may not be stable, so two identical casts of the same operand may or may not
669681
return the same value. Said differently, the conversion to or from the
670-
non-integral type depends on environmental state in an implementation
682+
"unstable" pointer type depends on environmental state in an implementation
671683
defined manner.
672-
673684
If the frontend wishes to observe a *particular* value following a cast, the
674685
generated IR must fence with the underlying environment in an implementation
675686
defined manner. (In practice, this tends to require ``noinline`` routines for
676687
such operations.)
677688

678689
From the perspective of the optimizer, ``inttoptr`` and ``ptrtoint`` for
679-
non-integral types are analogous to ones on integral types with one
690+
"unstable" pointer types are analogous to ones on integral types with one
680691
key exception: the optimizer may not, in general, insert new dynamic
681692
occurrences of such casts. If a new cast is inserted, the optimizer would
682693
need to either ensure that a) all possible values are valid, or b)
683694
appropriate fencing is inserted. Since the appropriate fencing is
684695
implementation defined, the optimizer can't do the latter. The former is
685696
challenging as many commonly expected properties, such as
686-
``ptrtoint(v)-ptrtoint(v) == 0``, don't hold for non-integral types.
697+
``ptrtoint(v)-ptrtoint(v) == 0``, don't hold for "unstable" pointer types.
687698
Similar restrictions apply to intrinsics that might examine the pointer bits,
688699
such as :ref:`llvm.ptrmask<int_ptrmask>`.
689700

690-
The alignment information provided by the frontend for a non-integral pointer
701+
The alignment information provided by the frontend for an "unstable" pointer
691702
(typically using attributes or metadata) must be valid for every possible
692703
representation of the pointer.
693704

705+
Non-integral pointer representation
706+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
707+
708+
Pointers are not represented as an address, but may instead include
709+
additional metadata such as bounds information or a temporal identifier.
710+
Examples include AMDGPU buffer descriptors with a 128-bit fat pointer and a
711+
32-bit offset or CHERI capabilities that contain bounds, permissions and an
712+
out-of-band validity bit. In general, these pointers cannot be re-created
713+
from just an integer value.
714+
715+
In most cases pointers with a non-integral representation behave exactly the
716+
same as an integral pointer, the only difference is that it is not possible to
717+
create a pointer just from an address.
718+
719+
"Non-integral" pointers also impose restrictions on the optimizer, but in
720+
general these are less restrictive than for "unstable" pointers. The main
721+
difference compared to integral pointers is that ``inttoptr`` instructions
722+
should not be inserted by passes as they may not be able to create a valid
723+
pointer. This property also means that ``inttoptr(ptrtoint(x))`` cannot be
724+
folded to ``x`` as the ``ptrtoint`` operation may destroy the necessary metadata
725+
to reconstruct the pointer.
726+
Additionaly, since there could be out-of-band state, it is also not legal to
727+
convert a load/store of a non-integral pointer type to a load/store of an
728+
integer type with same bitwidth as that may not copy all the state.
729+
However, it is legal to use appropriately aligned ``llvm.memcpy`` and
730+
``llvm.memmove`` for copies of non-integral pointers as long as these are not
731+
converted into integer operations.
732+
733+
Unlike "unstable" pointers, the bit-wise representation is stable and
734+
``ptrtoint(x)`` always yields a deterministic values.
735+
This means optimizer is still permitted to insert new ``ptrtoint`` instructions.
736+
However, it is important to note that ``ptrtoint`` may not yield the same value
737+
as storing the pointer via memory and reading it back as an integer, even if the
738+
bitwidth of the two types matches (since ptrtoint could involve some form of
739+
arithmetic or strip parts of the non-integral pointer representation).
740+
694741
.. _globalvars:
695742

696743
Global Variables
@@ -3082,16 +3129,21 @@ as follows:
30823129
``A<address space>``
30833130
Specifies the address space of objects created by '``alloca``'.
30843131
Defaults to the default address space of 0.
3085-
``p[n]:<size>:<abi>[:<pref>][:<idx>]``
3132+
``p[<flags>][<address space>]:<size>:<abi>[:<pref>][:<idx>]``
30863133
This specifies the *size* of a pointer and its ``<abi>`` and
30873134
``<pref>``\erred alignments for address space ``n``. ``<pref>`` is optional
30883135
and defaults to ``<abi>``. The fourth parameter ``<idx>`` is the size of the
30893136
index that used for address calculation, which must be less than or equal
30903137
to the pointer size. If not
30913138
specified, the default index size is equal to the pointer size. All sizes
3092-
are in bits. The address space, ``n``, is optional, and if not specified,
3093-
denotes the default address space 0. The value of ``n`` must be
3094-
in the range [1,2^24).
3139+
are in bits. The ``<address space>``, is optional, and if not specified,
3140+
denotes the default address space 0. The value of ``<address space>`` must
3141+
be in the range [1,2^24).
3142+
The optional``<flags>`` are used to specify properties of pointers in this
3143+
address space: the character ``u`` marks pointers as having an unstable
3144+
representation and ``n`` marks pointers as non-integral (i.e. having
3145+
additional metadata). See :ref:`Non-Integral Pointer Types <nointptrtype>`.
3146+
30953147
``i<size>:<abi>[:<pref>]``
30963148
This specifies the alignment for an integer type of a given bit
30973149
``<size>``. The value of ``<size>`` must be in the range [1,2^24).

llvm/include/llvm/IR/DataLayout.h

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,14 @@ class DataLayout {
7979
Align PrefAlign;
8080
uint32_t IndexBitWidth;
8181
/// Pointers in this address space don't have a well-defined bitwise
82-
/// representation (e.g. may be relocated by a copying garbage collector).
83-
/// Additionally, they may also be non-integral (i.e. containing additional
84-
/// metadata such as bounds information/permissions).
85-
bool IsNonIntegral;
82+
/// representation (e.g. they may be relocated by a copying garbage
83+
/// collector and thus have different addresses at different times).
84+
bool HasUnstableRepresentation;
85+
/// Pointers in this address spacs are non-integral, i.e. don't have a
86+
/// integer representation that simply maps to the address. An example of
87+
/// this would be fat pointers with bounds information or CHERI capabilities
88+
/// that include metadata as well as one out-of-band validity bit.
89+
bool HasNonIntegralRepresentation;
8690
bool operator==(const PointerSpec &Other) const;
8791
};
8892

@@ -148,7 +152,7 @@ class DataLayout {
148152
/// Sets or updates the specification for pointer in the given address space.
149153
void setPointerSpec(uint32_t AddrSpace, uint32_t BitWidth, Align ABIAlign,
150154
Align PrefAlign, uint32_t IndexBitWidth,
151-
bool IsNonIntegral);
155+
bool HasUnstableRepr, bool HasNonIntegralRepr);
152156

153157
/// Internal helper to get alignment for integer of given bitwidth.
154158
Align getIntegerAlignment(uint32_t BitWidth, bool abi_or_pref) const;
@@ -342,14 +346,63 @@ class DataLayout {
342346
SmallVector<unsigned, 8> getNonIntegralAddressSpaces() const {
343347
SmallVector<unsigned, 8> AddrSpaces;
344348
for (const PointerSpec &PS : PointerSpecs) {
345-
if (PS.IsNonIntegral)
349+
if (PS.HasNonIntegralRepresentation || PS.HasUnstableRepresentation)
346350
AddrSpaces.push_back(PS.AddrSpace);
347351
}
348352
return AddrSpaces;
349353
}
350354

355+
/// Returns whether this address space is "non-integral" and "unstable".
356+
/// This means that passes should not introduce inttoptr or ptrtoint
357+
/// instructions operating on pointers of this address space.
358+
/// TODO: remove this function after migrating to finer-grained properties.
351359
bool isNonIntegralAddressSpace(unsigned AddrSpace) const {
352-
return getPointerSpec(AddrSpace).IsNonIntegral;
360+
const PointerSpec &PS = getPointerSpec(AddrSpace);
361+
return PS.HasNonIntegralRepresentation || PS.HasUnstableRepresentation;
362+
}
363+
364+
/// Returns whether this address space has an "unstable" pointer
365+
/// representation. The bitwise pattern of such pointers is allowed to change
366+
/// in a target-specific way. For example, this could be used for copying
367+
/// garbage collection where the garbage collector could update the pointer
368+
/// value as part of the collection sweep.
369+
bool hasUnstableRepresentation(unsigned AddrSpace) const {
370+
return getPointerSpec(AddrSpace).HasUnstableRepresentation;
371+
}
372+
373+
/// Returns whether this address space has a non-integral pointer
374+
/// representation, i.e. the pointer is not just an integer address but some
375+
/// other bitwise representation. Examples include AMDGPU buffer descriptors
376+
/// with a 128-bit fat pointer and a 32-bit offset or CHERI capabilities that
377+
/// contain bounds, permissions and an out-of-band validity bit. In general,
378+
/// these pointers cannot be re-created from just an integer value.
379+
bool hasNonIntegralRepresentation(unsigned AddrSpace) const {
380+
return getPointerSpec(AddrSpace).HasNonIntegralRepresentation;
381+
}
382+
383+
/// Returns whether passes should avoid introducing `inttoptr` instructions
384+
/// for this address space.
385+
///
386+
/// This is currently the case "non-integral" pointer representations
387+
/// (hasNonIntegralRepresentation()) since such pointers generally require
388+
/// additional metadata beyond just an address.
389+
/// New `inttoptr` instructions should also be avoided for "unstable" bitwise
390+
/// representations (hasUnstableRepresentation()) unless the pass knows it is
391+
/// within a critical section that retains the current representation.
392+
bool shouldAvoidIntToPtr(unsigned AddrSpace) const {
393+
const PointerSpec &PS = getPointerSpec(AddrSpace);
394+
return PS.HasNonIntegralRepresentation || PS.HasUnstableRepresentation;
395+
}
396+
397+
/// Returns whether passes should avoid introducing `ptrtoint` instructions
398+
/// for this address space.
399+
///
400+
/// This is currently the case for pointer address spaces that have an
401+
/// "unstable" representation (hasUnstableRepresentation()) since the
402+
/// bitwise pattern of such pointers could change unless the pass knows it is
403+
/// within a critical section that retains the current representation.
404+
bool shouldAvoidPtrToInt(unsigned AddrSpace) const {
405+
return hasUnstableRepresentation(AddrSpace);
353406
}
354407

355408
bool isNonIntegralPointerType(PointerType *PT) const {
@@ -361,6 +414,16 @@ class DataLayout {
361414
return PTy && isNonIntegralPointerType(PTy);
362415
}
363416

417+
bool shouldAvoidPtrToInt(Type *Ty) const {
418+
auto *PTy = dyn_cast<PointerType>(Ty);
419+
return PTy && shouldAvoidPtrToInt(PTy->getPointerAddressSpace());
420+
}
421+
422+
bool shouldAvoidIntToPtr(Type *Ty) const {
423+
auto *PTy = dyn_cast<PointerType>(Ty);
424+
return PTy && shouldAvoidIntToPtr(PTy->getPointerAddressSpace());
425+
}
426+
364427
/// Layout pointer size, in bits
365428
/// FIXME: The defaults need to be removed once all of
366429
/// the backends/clients are updated.

llvm/lib/IR/DataLayout.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ 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-
IsNonIntegral == Other.IsNonIntegral;
155+
HasUnstableRepresentation == Other.HasUnstableRepresentation &&
156+
HasNonIntegralRepresentation == Other.HasNonIntegralRepresentation;
156157
}
157158

158159
namespace {
@@ -419,9 +420,24 @@ Error DataLayout::parsePointerSpec(StringRef Spec) {
419420

420421
// Address space. Optional, defaults to 0.
421422
unsigned AddrSpace = 0;
422-
if (!Components[0].empty())
423-
if (Error Err = parseAddrSpace(Components[0], AddrSpace))
423+
bool UnstableRepr = false;
424+
bool NonIntegralRepr = false;
425+
StringRef AddrSpaceStr = Components[0].drop_while([&](char C) {
426+
if (C == 'n') {
427+
NonIntegralRepr = true;
428+
return true;
429+
} else if (C == 'u') {
430+
UnstableRepr = true;
431+
return true;
432+
}
433+
return false;
434+
});
435+
if (!AddrSpaceStr.empty()) {
436+
if (Error Err = parseAddrSpace(AddrSpaceStr, AddrSpace))
424437
return Err;
438+
}
439+
if (AddrSpace == 0 && (NonIntegralRepr || UnstableRepr))
440+
return createStringError("address space 0 cannot be non-integral");
425441

426442
// Size. Required, cannot be zero.
427443
unsigned BitWidth;
@@ -455,7 +471,7 @@ Error DataLayout::parsePointerSpec(StringRef Spec) {
455471
"index size cannot be larger than the pointer size");
456472

457473
setPointerSpec(AddrSpace, BitWidth, ABIAlign, PrefAlign, IndexBitWidth,
458-
false);
474+
UnstableRepr, NonIntegralRepr);
459475
return Error::success();
460476
}
461477

@@ -631,7 +647,7 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) {
631647
// the spec for AS0, and we then update that to mark it non-integral.
632648
const PointerSpec &PS = getPointerSpec(AS);
633649
setPointerSpec(AS, PS.BitWidth, PS.ABIAlign, PS.PrefAlign, PS.IndexBitWidth,
634-
true);
650+
true, true);
635651
}
636652

637653
return Error::success();
@@ -679,17 +695,20 @@ DataLayout::getPointerSpec(uint32_t AddrSpace) const {
679695

680696
void DataLayout::setPointerSpec(uint32_t AddrSpace, uint32_t BitWidth,
681697
Align ABIAlign, Align PrefAlign,
682-
uint32_t IndexBitWidth, bool IsNonIntegral) {
698+
uint32_t IndexBitWidth, bool HasUnstableRepr,
699+
bool HasNonIntegralRepr) {
683700
auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace());
684701
if (I == PointerSpecs.end() || I->AddrSpace != AddrSpace) {
685702
PointerSpecs.insert(I, PointerSpec{AddrSpace, BitWidth, ABIAlign, PrefAlign,
686-
IndexBitWidth, IsNonIntegral});
703+
IndexBitWidth, HasUnstableRepr,
704+
HasNonIntegralRepr});
687705
} else {
688706
I->BitWidth = BitWidth;
689707
I->ABIAlign = ABIAlign;
690708
I->PrefAlign = PrefAlign;
691709
I->IndexBitWidth = IndexBitWidth;
692-
I->IsNonIntegral = IsNonIntegral;
710+
I->HasUnstableRepresentation = HasUnstableRepr;
711+
I->HasNonIntegralRepresentation = HasNonIntegralRepr;
693712
}
694713
}
695714

llvm/unittests/IR/DataLayoutTest.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,12 @@ TEST(DataLayout, ParsePointerSpec) {
319319
FailedWithMessage("malformed specification, must be of the form "
320320
"\"p[<n>]:<size>:<abi>[:<pref>[:<idx>]]\""));
321321

322+
// Only 'u' and 'n' flags are valid.
323+
for (StringRef Str : {"pa:32:32", "px:32:32"})
324+
EXPECT_THAT_EXPECTED(
325+
DataLayout::parse(Str),
326+
FailedWithMessage("address space must be a 24-bit integer"));
327+
322328
// address space
323329
for (StringRef Str : {"p0x0:32:32", "px:32:32:32", "p16777216:32:32:32:32"})
324330
EXPECT_THAT_EXPECTED(
@@ -401,6 +407,12 @@ TEST(DataLayout, ParsePointerSpec) {
401407
EXPECT_THAT_EXPECTED(
402408
DataLayout::parse(Str),
403409
FailedWithMessage("index size cannot be larger than the pointer size"));
410+
411+
for (StringRef Str : {"pn:64:64", "pu:64:64", "pun:64:64", "pnu:64:64",
412+
"pn0:64:64", "pu0:64:64", "pun0:64:64", "pnu0:64:64"})
413+
EXPECT_THAT_EXPECTED(
414+
DataLayout::parse(Str),
415+
FailedWithMessage("address space 0 cannot be non-integral"));
404416
}
405417

406418
TEST(DataLayoutTest, ParseNativeIntegersSpec) {
@@ -568,6 +580,40 @@ TEST(DataLayout, IsNonIntegralAddressSpace) {
568580
EXPECT_FALSE(Custom.isNonIntegralAddressSpace(1));
569581
EXPECT_TRUE(Custom.isNonIntegralAddressSpace(2));
570582
EXPECT_TRUE(Custom.isNonIntegralAddressSpace(16777215));
583+
584+
// Pointers can be marked as non-integral using 'pn'
585+
DataLayout NonIntegral = cantFail(DataLayout::parse("pn2:64:64:64:32"));
586+
EXPECT_TRUE(NonIntegral.isNonIntegralAddressSpace(2));
587+
EXPECT_TRUE(NonIntegral.hasNonIntegralRepresentation(2));
588+
EXPECT_FALSE(NonIntegral.hasUnstableRepresentation(2));
589+
EXPECT_TRUE(NonIntegral.shouldAvoidIntToPtr(2));
590+
EXPECT_FALSE(NonIntegral.shouldAvoidPtrToInt(2));
591+
592+
// Pointers can be marked as unstable using 'pu'
593+
DataLayout Unstable = cantFail(DataLayout::parse("pu2:64:64:64:32"));
594+
EXPECT_TRUE(Unstable.isNonIntegralAddressSpace(2));
595+
EXPECT_TRUE(Unstable.hasUnstableRepresentation(2));
596+
EXPECT_FALSE(Unstable.hasNonIntegralRepresentation(2));
597+
EXPECT_TRUE(Unstable.shouldAvoidPtrToInt(2));
598+
EXPECT_TRUE(Unstable.shouldAvoidIntToPtr(2));
599+
600+
// Both properties can also be set using 'pnu'/'pun'
601+
for (auto Layout : {"pnu2:64:64:64:32", "pun2:64:64:64:32"}) {
602+
DataLayout DL = cantFail(DataLayout::parse(Layout));
603+
EXPECT_TRUE(DL.isNonIntegralAddressSpace(2));
604+
EXPECT_TRUE(DL.hasNonIntegralRepresentation(2));
605+
EXPECT_TRUE(DL.hasUnstableRepresentation(2));
606+
}
607+
608+
// For backwards compatibility, the ni DataLayout part overrides any p[n][u].
609+
for (auto Layout : {"ni:2-pn2:64:64:64:32", "ni:2-pnu2:64:64:64:32",
610+
"ni:2-pu2:64:64:64:32", "pn2:64:64:64:32-ni:2",
611+
"pnu2:64:64:64:32-ni:2", "pu2:64:64:64:32-ni:2"}) {
612+
DataLayout DL = cantFail(DataLayout::parse(Layout));
613+
EXPECT_TRUE(DL.isNonIntegralAddressSpace(2));
614+
EXPECT_TRUE(DL.hasNonIntegralRepresentation(2));
615+
EXPECT_TRUE(DL.hasUnstableRepresentation(2));
616+
}
571617
}
572618

573619
TEST(DataLayoutTest, CopyAssignmentInvalidatesStructLayout) {

0 commit comments

Comments
 (0)