================
@@ -15454,33 +15471,43 @@ 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
+``basetype``, and the next index 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
-  inbounds.
-
-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.
+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.
+
+If the indexed type is a struct with N fields, the index must be an
+integer constant in the range ``[0, N[``.
+
+If the constraints implied by a flag bit are violated, the result is 
``poison``.
 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.
 
+Defined flag bits:
+""""""""""""""""""
+
+``inbounds``
+  Bit 0 (``1 << 0``) - specifies that this index is within the bounds of the 
type
+  being indexed at that level. In particular, when indexing an array or vector
+  ``[ N x T ]``, implies that the index is in the range ``[0, N[``. As an 
exception,
+  if ``N`` is 0, the bound is treated as an unknown, dynamic value, but the 
flag
+  still implies that the index is inside that runtime bound.
+  Structure accesses are always ``inbounds`` and must be marked as
+  such. A structured GEP is said to be inbounds if all of its indices are 
inbounds.
+
+``nneg``
+  Bit 1 (``1 << 1``) - specifies that the value of this index is non-negative.
+  This is not necessarily implied by ``inbounds``, as an object may have more
+  fields than the maximal signed value for the index type.
----------------
Flakebi wrote:

> the "beginning of type" requirement

Would it make sense to make this a flag on the instruction? So you could have
```llvm
; %src guaranteed to point to the start of the array
%ptr = sgep fromstart [128 x [2 x i32]], ptr %src, i32 3
; %ptr guaranteed to point to the start of the [2 x i32]
%use = sgep fromstart [2 x i32], ptr %ptr, i32 %n

; %ptr might point somewhere inside the array
; %m is an arbitrary, potentially signed integer
%arbitrary = sgep [4 x i32], ptr %ptr, i32 %m

; %ptr might point somewhere inside the array
; %m is a potentially signed integer, guaranteeing that %inbounds points to 
somewhere inside the logical [4 x i32] array
%inbounds = sgep inbounds [4 x i32], ptr %ptr, i32 %m
```

> If so, this might mean we cannot do SROA anymore:
> 
> ```
> %ptr = sgep [128 x [2 x i32]], ptr %src, i32 3
> %use = sgep [2 x i32], ptr %ptr, i32 %n
> ```
> 
> Here, with the current behavior, we know `%n` cannot reach back to any other 
> index in the 128-elements base array, meaning it is valid to say only one 
> index is used, and we could maybe simplify the array allocation to only 
> allocate a single `[2 x i32]`.

I think with fromstart and inbounds, we can (a) combine the two sgeps into one 
(independent of the target), and (b) guarantee that `0 ≤ %n < 2`.
And if `%src` is an `alloca` that has no other uses, reducing the allocation to 
a `[2 x i32]` sounds correct.

```llvm
%ptr = sgep inbounds [128 x [2 x i32]], ptr %src, i32 3
%use = sgep fromstart inbounds [2 x i32], ptr %ptr, i32 %n
; is equal to
%newUse = sgep inbounds [128 x [2 x i32]], ptr %src, i32 3, i32 %n
; if the sgep creating %ptr had a fromstart, %newUse would have it too
```

> I think it's OK to accept having pointers not starting at the base of an 
> object/allocation, but if you want to drop the "subobject provenance" bit, 
> I'd like to make sure we can still implement something like SROA

There is no mention of provenance in the current documentation of sgep, so any 
assumption there is venturing into new land :)
Given sgep defines nothing regarding provenance, I believe the only correct 
conclusion is that it currently does not do anything with provenance. I.e. the 
provenance of the returned pointer is the same as that of the base pointer.
This also means, the following is completely correct IR:
```llvm
%ptr = sgep inbounds [128 x [2 x i32]], ptr %src, i32 3
%use = sgep fromstart inbounds [5 x f64], ptr %ptr, i32 %n
%val = load i16, ptr %use
```
SROA needs to be able to handle such code and e.g. bail out of optimizations.

Modifying provenance as part of sgep sounds like an interesting idea. I guess 
it could be a separate flag on the instruction? (And replace something like 
`fromstart`?)

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

Reply via email to