Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>,
Nathan =?utf-8?q?Gauër?= <[email protected]>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/[email protected]>


================
@@ -14991,6 +14991,180 @@ Semantics:
 
 See the description for :ref:`llvm.stacksave <int_stacksave>`.
 
+.. _i_structured_gep:
+
+'``llvm.structured.gep``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+      declare <ret_type>
+      @llvm.structured.gep(ptr elementtype(<basetype>) <source>
+                           {, [i32/i64] <index> }*)
+
+Overview:
+"""""""""
+
+The '``llvm.structured.gep``' intrinsic (structured **G**\ et\ **E**\ lement\ 
**P**\ tr) computes a new pointer address
+resulting of a logical indexing into the ``<source>`` pointer. The returned
+address depends on the indices and may depend on the layout of ``<basetype>``
+at runtime.
+
+Arguments:
+""""""""""
+
+``ptr elementtype(<basetype>) <source>``:
+A pointer to the memory location used as base for the address computation.
+
+The ``source`` argument must be annotated with an :ref:`elementtype
+<attr_elementtype>` attribute at the call-site. This attribute specifies the
+type of the element pointed to by the pointer source. This type will be
+used along with the provided indices and source operand to compute a new
+pointer representing the result of a logical indexing into the basetype
+pointed by source.
+
+The ``basetype`` is only associated with ``<source>`` for this particular
+call. A frontend could possibly emit multiple structured
+GEP with the same source pointer but a different ``basetype``.
+
+``[i32/i64] index, ...``:
+Indices used to traverse into the ``basetype`` and compute a pointer to the
+target element. Indices can be 32-bit or 64-bit unsigned integers. Indices 
being
+handled one by one, both sizes can be mixed in the same instruction. The
+precision used to compute the resulting pointer is target-dependent.
+When used to index into a struct, only integer constants are allowed.
+
+Semantics:
+""""""""""
+
+The ``llvm.structured.gep`` performs a logical traversal of the type
+``basetype`` using the list of provided indices, computing the pointer
+addressing the targeted element/field assuming ``source`` points to a
+physically laid out ``basetype``.
+
+The first index determines which element/field of ``basetype`` is selected,
+computes the pointer to access this element/field assuming ``source`` points
+to the start of ``basetype``.
+This pointer becomes the new ``source``, the current type the new
+``basetype``, and the next indices is consumed until a scalar type is
+reached or all indices are consumed.
+
+All indices must be consumed, and it is illegal to index into a scalar type.
+Meaning the maximum number of indices depends on the depth of the basetype.
+
+Because this instruction performs a logical addressing, all indices are
+assumed to be inbounds. This means it is not possible to access the next
+element in the logical layout by overflowing:
+
+- If the indexed type is a struct with N fields, the index must be an
+  immediate/constant value in the range ``[0; N[``.
+- If indexing into an array or vector, the index can be a variable, but
+  is assumed to be inbounds with regards to the current basetype logical 
layout.
+- If the traversed type is an array or vector of N elements with ``N > 0``,
+  the index is assumed to belong to ``[0; N[``.
+- If the traversed type is an array of size ``0``, the array size is assumed
+  to be known at runtime, and the instruction assumes the index is always
+  inbound.
+
+In all cases **except** when the accessed type is a 0-sized array**, indexing
+out of bounds yields `poison`. When the index value is unknown, optimizations
+can use the type bounds to determine the range of values the index can have.
+If the source pointer is poison, the instruction returns poison.
+The resulting pointer belongs to the same address space as ``source``.
+This instruction does not dereference the pointer.
+
+Example:
+""""""""
+
+**Simple case: logical access of a struct field**
+
+.. code-block:: cpp
+
+    struct A { int a, int b, int c, int d };
+    int val = my_struct->b;
+
+Could be translated to:
+
+.. code-block:: llvm
+
+    %A = type { i32, i32, i32, i32 }
+    %src = call ptr @llvm.structured.gep(ptr elementtype(%A) %my_struct, i32 1)
+    %val = load i32, ptr %src
+
+**A more complex case**
+
+This instruction can also be used on the same pointer with different
+basetypes, as long as codegen knows how those are physically laid out.
+Let’s consider the following code:
+
+.. code-block:: cpp
+
+   struct S {
+       uint3 array[5];
+       float my_float;
+   }
+
+   my_struct->array[2].y = 12;
+   int val = my_struct->array[index].y;
+
+
+The frontend knows this struct has a particular physical layout:
+    - an array of 5 vectors of 3 integers, aligned on 16 bytes.
+    - one float at the end, with no alignment requirement, so packed right
+      after the last ``uint3``, which is a ``<3 x uint>``.
+
+.. code-block:: llvm
+
+    %S = type { [4 x { <3 x i32>, i32 }], <3 x i32>, float }
+    ;                               `-> explicit padding
+    ; -> 4 byte padding between each array element, except
+    ;    between the last vector and the float.
+
+The store is simple:
+
+.. code-block:: llvm
+
+    %dst = call ptr @llvm.structured.gep(ptr elementtype(%S) %my_struct, i32 
0, i32 2, i32 0, i32 1)
+    store i32 12, ptr %dst
+
+But the load depends on a dynamic index. This means accessing logically the
+first 4 elements is different than accessing the last:
+
+.. code-block:: llvm
+
+    %firsts = call ptr @llvm.structured.gep(ptr elementtype(%S) %my_struct, 
i32 0, i32 %index, i32 0)
+    %last = call ptr @llvm.structured.gep(ptr elementtype(%S) %my_struct, i32 
1)
+
+And because :ref:`i_structured_gep` always assumes indexing inbounds, we
+cannot reach the last element by doing:
+
+.. code-block:: llvm
+
+    ; BAD
+    call ptr @llvm.structured.gep(ptr elementtype(%S) %my_struct, i32 0, i32 
5, i32 0)
+
+If codegen knew nothing about the physical layout of ``%S``, a condition
+would be required to select between ``%firsts`` and ``%last`` depending on
+the value of ``%index``.
+But if the codegen knows that some logical layouts are lowered to the same
+physical layout, it can interchangeably use them.
+In this example, the codegen knows `%S` and `%T` have the same physical
+layout (even if layout itself is unknown). Hence, the codegen can access
+every element in the array with a single structured.gep:
+
+.. code-block:: llvm
+
+    %T = type [ 5 x { <3 x i32>, i32 } ]
+    %ptr = call ptr @llvm.structured.gep(ptr elementtype(%T) %my_struct, i32 
%index, i32 0, i32 1)
+    store i32 12, ptr %ptr
+
+This is, however, dependent on context that codegen has an insight on. The
+fact that `%T` and `%S` are equivalent depends on the target & frontend.
----------------
s-perron wrote:

This should only depend on the target. What `llvm-opt` and the backends do 
should not depend on which FE the code came from.

https://github.com/llvm/llvm-project/pull/176145
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to