[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:
Bjorn Pettersson 2021-03-16 12:47:16 +01:00
parent 5d315691c4
commit 5737010a79
1 changed files with 65 additions and 3 deletions

View File

@ -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
: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:
::
@ -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>`
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:
""""""""
.. code-block:: text
%X = bitcast i8 255 to i8 ; yields i8 :-1
%Y = bitcast i32* %x to sint* ; yields sint*:%x
%Z = bitcast <2 x int> %V to i64; ; yields i64: %V
%X = bitcast i8 255 to i8 ; yields i8 :-1
%Y = bitcast i32* %x to sint* ; yields sint*:%x
%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*>
.. _i_addrspacecast: