forked from OSchip/llvm-project
[LangRef] Describe memory layout for vectors types
There are a couple of caveats when it comes to how vectors are stored to memory, and thereby also how bitcast between vector and integer types work, in LLVM IR. Specially in relation to endianess. This patch is an attempt to document such things. Reviewed By: nlopes Differential Revision: https://reviews.llvm.org/D94964
This commit is contained in:
parent
5d315691c4
commit
5737010a79
|
@ -3200,6 +3200,63 @@ and a scalable property to represent vectors where the exact hardware
|
||||||
vector length is unknown at compile time. Vector types are considered
|
vector length is unknown at compile time. Vector types are considered
|
||||||
:ref:`first class <t_firstclass>`.
|
:ref:`first class <t_firstclass>`.
|
||||||
|
|
||||||
|
:Memory Layout:
|
||||||
|
|
||||||
|
In general vector elements are laid out in memory in the same way as
|
||||||
|
:ref:`array types <t_array>`. Such an anology works fine as long as the vector
|
||||||
|
elements are byte sized. However, when the elements of the vector aren't byte
|
||||||
|
sized it gets a bit more complicated. One way to describe the layout is by
|
||||||
|
describing what happens when a vector such as <N x iM> is bitcasted to an
|
||||||
|
integer type with N*M bits, and then following the rules for storing such an
|
||||||
|
integer to memory.
|
||||||
|
|
||||||
|
A bitcast from a vector type to a scalar integer type will see the elements
|
||||||
|
being packed together (without padding). The order in which elements are
|
||||||
|
inserted in the integer depends on endianess. For little endian element zero
|
||||||
|
is put in the least significant bits of the integer, and for big endian
|
||||||
|
element zero is put in the most significant bits.
|
||||||
|
|
||||||
|
Using a vector such as ``<i4 1, i4 2, i4 3, i4 5>`` as an example, together
|
||||||
|
with the analogy that we can replace a vector store by a bitcast followed by
|
||||||
|
an integer store, we ge this for big endian:
|
||||||
|
|
||||||
|
.. code-block:: llvm
|
||||||
|
|
||||||
|
%val = bitcast <4 x i4> <i4 1, i4 2, i4 3, i4 5> to i16
|
||||||
|
|
||||||
|
; Bitcasting from a vector to an integral type can be seen as
|
||||||
|
; concatenating the values:
|
||||||
|
; %val now has the hexadecimal value 0x1235.
|
||||||
|
|
||||||
|
store i16 %val, i16* %ptr
|
||||||
|
|
||||||
|
; In memory the content will be (8-bit addressing):
|
||||||
|
;
|
||||||
|
; [%ptr + 0]: 00010010 (0x12)
|
||||||
|
; [%ptr + 1]: 00110101 (0x35)
|
||||||
|
|
||||||
|
The same example for little endian:
|
||||||
|
|
||||||
|
.. code-block:: llvm
|
||||||
|
|
||||||
|
%val = bitcast <4 x i4> <i4 1, i4 2, i4 3, i4 5> to i16
|
||||||
|
|
||||||
|
; Bitcasting from a vector to an integral type can be seen as
|
||||||
|
; concatenating the values:
|
||||||
|
; %val now has the hexadecimal value 0x5321.
|
||||||
|
|
||||||
|
store i16 %val, i16* %ptr
|
||||||
|
|
||||||
|
; In memory the content will be (8-bit addressing):
|
||||||
|
;
|
||||||
|
; [%ptr + 0]: 01010011 (0x53)
|
||||||
|
; [%ptr + 1]: 00100001 (0x21)
|
||||||
|
|
||||||
|
When ``<N*M>`` isn't evenly divisible by the byte size the exact memory layout
|
||||||
|
is unspecified (just like it is for an integral type of the same size). This
|
||||||
|
is because different targets could put the padding at different positions when
|
||||||
|
the type size is smaller than the types store size.
|
||||||
|
|
||||||
:Syntax:
|
:Syntax:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -10604,14 +10661,19 @@ pointers) types with the same address space through this instruction.
|
||||||
To convert pointers to other types, use the :ref:`inttoptr <i_inttoptr>`
|
To convert pointers to other types, use the :ref:`inttoptr <i_inttoptr>`
|
||||||
or :ref:`ptrtoint <i_ptrtoint>` instructions first.
|
or :ref:`ptrtoint <i_ptrtoint>` instructions first.
|
||||||
|
|
||||||
|
There is a caveat for bitcasts involving vector types in relation to
|
||||||
|
endianess. For example ``bitcast <2 x i8> <value> to i16`` puts element zero
|
||||||
|
of the vector in the least significant bits of the i16 for little-endian while
|
||||||
|
element zero ends up in the most significant bits for big-endian.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
""""""""
|
""""""""
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
%X = bitcast i8 255 to i8 ; yields i8 :-1
|
%X = bitcast i8 255 to i8 ; yields i8 :-1
|
||||||
%Y = bitcast i32* %x to sint* ; yields sint*:%x
|
%Y = bitcast i32* %x to sint* ; yields sint*:%x
|
||||||
%Z = bitcast <2 x int> %V to i64; ; yields i64: %V
|
%Z = bitcast <2 x int> %V to i64; ; yields i64: %V (depends on endianess)
|
||||||
%Z = bitcast <2 x i32*> %V to <2 x i64*> ; yields <2 x i64*>
|
%Z = bitcast <2 x i32*> %V to <2 x i64*> ; yields <2 x i64*>
|
||||||
|
|
||||||
.. _i_addrspacecast:
|
.. _i_addrspacecast:
|
||||||
|
|
Loading…
Reference in New Issue