-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[DataLayout][LangRef] Split non-integral and unstable pointer properties #105735
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: users/arichardson/spr/main.datalayoutlangref-split-non-integral-and-unstable-pointer-properties
Are you sure you want to change the base?
Changes from 5 commits
90068f1
e4bd118
35afb97
db97145
94ecfa3
278ce21
df9bdfe
7615db9
142a3ff
bdb6acc
de449dd
2c49735
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -649,48 +649,99 @@ literal types are uniqued in recent versions of LLVM. | |
|
||
.. _nointptrtype: | ||
|
||
Non-Integral Pointer Type | ||
------------------------- | ||
Non-Integral and Unstable Pointer Types | ||
--------------------------------------- | ||
|
||
Note: non-integral pointer types are a work in progress, and they should be | ||
considered experimental at this time. | ||
Note: non-integral/unstable pointer types are a work in progress, and they | ||
should be considered experimental at this time. | ||
|
||
LLVM IR optionally allows the frontend to denote pointers in certain address | ||
spaces as "non-integral" via the :ref:`datalayout string<langref_datalayout>`. | ||
Non-integral pointer types represent pointers that have an *unspecified* bitwise | ||
representation; that is, the integral representation may be target dependent or | ||
unstable (not backed by a fixed integer). | ||
spaces as "non-integral" or "unstable" (or both "non-integral" and "unstable") | ||
via the :ref:`datalayout string<langref_datalayout>`. | ||
|
||
The exact implications of these properties are target-specific, but the | ||
following IR semantics and restrictions to optimization passes apply: | ||
|
||
Unstable pointer representation | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Pointers in this address space have an *unspecified* bitwise representation | ||
(i.e. not backed by a fixed integer). The bitwise pattern of such pointers is | ||
allowed to change in a target-specific way. For example, this could be a pointer | ||
type used with copying garbage collection where the garbage collector could | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
update the pointer at any time in the collection sweep. | ||
|
||
``inttoptr`` and ``ptrtoint`` instructions have the same semantics as for | ||
integral (i.e. normal) pointers in that they convert integers to and from | ||
corresponding pointer types, but there are additional implications to be | ||
aware of. Because the bit-representation of a non-integral pointer may | ||
not be stable, two identical casts of the same operand may or may not | ||
corresponding pointer types, but there are additional implications to be aware | ||
of. | ||
|
||
For "unstable" pointer representations, the bit-representation of the pointer | ||
may not be stable, so two identical casts of the same operand may or may not | ||
return the same value. Said differently, the conversion to or from the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this applies to only an SSA value of an unstable pointer type? What about an in-memory value with the unstable pointer type? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not familiar with how GC pointers are used in LLVM, I just tried to split out the existing "copying GC" non-integral pointers properties into a separate property to allow for "fat pointers", CHERI capabilities, etc to use non-integral pointers without incurring all the restrictions imposed by GC pointers. Not sure who is best to comment on this, probably someone from azul who has worked on it recently. |
||
non-integral type depends on environmental state in an implementation | ||
"unstable" pointer type depends on environmental state in an implementation | ||
defined manner. | ||
|
||
If the frontend wishes to observe a *particular* value following a cast, the | ||
generated IR must fence with the underlying environment in an implementation | ||
defined manner. (In practice, this tends to require ``noinline`` routines for | ||
such operations.) | ||
|
||
From the perspective of the optimizer, ``inttoptr`` and ``ptrtoint`` for | ||
non-integral types are analogous to ones on integral types with one | ||
"unstable" pointer types are analogous to ones on integral types with one | ||
key exception: the optimizer may not, in general, insert new dynamic | ||
occurrences of such casts. If a new cast is inserted, the optimizer would | ||
need to either ensure that a) all possible values are valid, or b) | ||
appropriate fencing is inserted. Since the appropriate fencing is | ||
implementation defined, the optimizer can't do the latter. The former is | ||
challenging as many commonly expected properties, such as | ||
``ptrtoint(v)-ptrtoint(v) == 0``, don't hold for non-integral types. | ||
``ptrtoint(v)-ptrtoint(v) == 0``, don't hold for "unstable" pointer types. | ||
Similar restrictions apply to intrinsics that might examine the pointer bits, | ||
such as :ref:`llvm.ptrmask<int_ptrmask>`. | ||
|
||
The alignment information provided by the frontend for a non-integral pointer | ||
The alignment information provided by the frontend for an "unstable" pointer | ||
(typically using attributes or metadata) must be valid for every possible | ||
representation of the pointer. | ||
|
||
Non-integral pointer representation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is non-integral the right term for something that is more than just an integer? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Naming is hard - I kept this pre-existing name since it can also be interpreted as not just an integer, i.e. it can be anything else (such as integer+metadata). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, just to toss out a drive-by name suggestion (though I'm fine with keeping non-integral): how about "annotated" pointers? That is, the pointer does (without unstable) have a fixed representation and point to some address, but there are bits in that representation that "annotate" the address, and so |
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Pointers are not represented as just an address, but may instead include | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
additional metadata such as bounds information or a temporal identifier. | ||
Examples include AMDGPU buffer descriptors with a 128-bit fat pointer and a | ||
32-bit offset, or CHERI capabilities that contain bounds, permissions and an | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
out-of-band validity bit. In general, valid non-integral pointers cannot be | ||
created from just an integer value: while ``inttoptr`` yields a deterministic | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
bitwise pattern, the resulting value is not guaranteed to be a valid | ||
dereferenceable pointer. | ||
|
||
In most cases pointers with a non-integral representation behave exactly the | ||
same as an integral pointer, the only difference is that it is not possible to | ||
create a pointer just from an address. | ||
|
||
"Non-integral" pointers also impose restrictions on transformation passes, but | ||
in general these are less restrictive than for "unstable" pointers. The main | ||
difference compared to integral pointers is that ``inttoptr`` instructions | ||
should not be inserted by passes as they may not be able to create a valid | ||
pointer. This property also means that ``inttoptr(ptrtoint(x))`` cannot be | ||
folded to ``x`` as the ``ptrtoint`` operation may destroy the necessary metadata | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
to reconstruct the pointer. | ||
Additionally, since there could be out-of-band state, it is also not legal to | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
convert a load/store of a non-integral pointer type to a load/store of an | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
integer type with same bitwidth, as that may not copy all the state. | ||
However, it is legal to use appropriately-aligned ``llvm.memcpy`` and | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``llvm.memmove`` for copies of non-integral pointers. | ||
NOTE: Lowering of ``llvm.memcpy`` containing non-integral pointer types must use | ||
appropriately-aligned and sized types instead of smaller integer types. | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... Wait, hold on, I thought one of the firmer outcomes of the big ptrtoint semantics thread is that That is
is exactly
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, apologies for the delay here - I need to get around to rebasing my changes on top of the outcome of the discussion. I hope to have something next week. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No problem, just wanted to flag that (Also, re that discussion - it might be good to get your thoughts on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated, hopefully all issues resolved in the new wording. |
||
|
||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Unlike "unstable" pointers, the bit-wise representation is stable and | ||
``ptrtoint(x)`` always yields a deterministic value. | ||
This means transformation passes are still permitted to insert new ``ptrtoint`` | ||
instructions. | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
However, it is important to note that ``ptrtoint`` may not yield the same value | ||
as storing the pointer via memory and reading it back as an integer, even if the | ||
bitwidth of the two types matches (since ptrtoint could involve some form of | ||
arithmetic or strip parts of the non-integral pointer representation). | ||
|
||
.. _globalvars: | ||
|
||
Global Variables | ||
|
@@ -3082,16 +3133,21 @@ as follows: | |
``A<address space>`` | ||
Specifies the address space of objects created by '``alloca``'. | ||
Defaults to the default address space of 0. | ||
``p[n]:<size>:<abi>[:<pref>][:<idx>]`` | ||
``p[<flags>][<address space>]:<size>:<abi>[:<pref>][:<idx>]`` | ||
This specifies the *size* of a pointer and its ``<abi>`` and | ||
``<pref>``\erred alignments for address space ``n``. ``<pref>`` is optional | ||
and defaults to ``<abi>``. The fourth parameter ``<idx>`` is the size of the | ||
index that used for address calculation, which must be less than or equal | ||
to the pointer size. If not | ||
specified, the default index size is equal to the pointer size. All sizes | ||
arichardson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
are in bits. The address space, ``n``, is optional, and if not specified, | ||
denotes the default address space 0. The value of ``n`` must be | ||
in the range [1,2^24). | ||
are in bits. The ``<address space>``, is optional, and if not specified, | ||
denotes the default address space 0. The value of ``<address space>`` must | ||
be in the range [1,2^24). | ||
The optional``<flags>`` are used to specify properties of pointers in this | ||
address space: the character ``u`` marks pointers as having an unstable | ||
representation and ``n`` marks pointers as non-integral (i.e. having | ||
additional metadata). See :ref:`Non-Integral Pointer Types <nointptrtype>`. | ||
|
||
``i<size>:<abi>[:<pref>]`` | ||
This specifies the alignment for an integer type of a given bit | ||
``<size>``. The value of ``<size>`` must be in the range [1,2^24). | ||
|
@@ -3146,9 +3202,11 @@ as follows: | |
this set are considered to support most general arithmetic operations | ||
efficiently. | ||
``ni:<address space0>:<address space1>:<address space2>...`` | ||
This specifies pointer types with the specified address spaces | ||
as :ref:`Non-Integral Pointer Type <nointptrtype>` s. The ``0`` | ||
address space cannot be specified as non-integral. | ||
This marks pointer types with the specified address spaces | ||
as :ref:`non-integral and unstable <nointptrtype>`. | ||
The ``0`` address space cannot be specified as non-integral. | ||
It is only supported for backwards compatibility, the flags of the ``p`` | ||
specifier should be used instead for new code. | ||
|
||
On every specification that takes a ``<abi>:<pref>``, specifying the | ||
``<pref>`` alignment is optional. If omitted, the preceding ``:`` | ||
|
@@ -12135,6 +12193,8 @@ If ``value`` is smaller than ``ty2`` then a zero extension is done. If | |
``value`` is larger than ``ty2`` then a truncation is done. If they are | ||
the same size, then nothing is done (*no-op cast*) other than a type | ||
change. | ||
For :ref:`non-integral pointers <nointptrtype>` the ``ptrtoint`` instruction | ||
may involve additional transformations beyond truncations or extension. | ||
|
||
Example: | ||
"""""""" | ||
|
Uh oh!
There was an error while loading. Please reload this page.