Skip to content

Commit 2e80e58

Browse files
committed
[IR]: Add generic_gep_type_iterator::getSequentialElementStride
This prepares a fix to GEP offset computations on vectors of overaligned elements. We have many places that analyze GEP offsets using GEP iterators with the following pattern: GTI = gep_type_begin(ElemTy, Indices), GTE = gep_type_end(ElemTy, Indices); for (; GTI != GTE; ++GTI) { if (StructType *STy = GTI.getStructTypeOrNull()) { // handle struct [..] } else { // handle sequential (outmost index, array, vector): auto Stride = DL.getTypeAllocSize(GTI.getIndexedType()); Offset += Index * Size; } } This is incorrect for vectors of types whose bit size does not equal its alloc size (e.g. overaligned types), as vectors always bit-pack their elements. This patch introduces new functions generic_gep_type_iterator::isVector() and generic_gep_type_iterator::getSequentialElementStride(const DataLayout &) to fix these patterns without having to teach all these places about the specifics of vector bit layouts. With these helpers, the pattern above can be fixed by replacing the stride computation: auto Stride = GTI.getSequentialElementStride(DL);
1 parent 2c367fb commit 2e80e58

File tree

1 file changed

+54
-3
lines changed

1 file changed

+54
-3
lines changed

llvm/include/llvm/IR/GetElementPtrTypeIterator.h

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "llvm/ADT/ArrayRef.h"
1818
#include "llvm/ADT/PointerUnion.h"
19+
#include "llvm/IR/DataLayout.h"
1920
#include "llvm/IR/DerivedTypes.h"
2021
#include "llvm/IR/Operator.h"
2122
#include "llvm/IR/User.h"
@@ -30,7 +31,39 @@ template <typename ItTy = User::const_op_iterator>
3031
class generic_gep_type_iterator {
3132

3233
ItTy OpIt;
33-
PointerUnion<StructType *, Type *> CurTy;
34+
// We use two different mechanisms to store the type a GEP index applies to.
35+
// In some cases, we need to know the outer aggregate type the index is
36+
// applied within, e.g. a struct. In such cases, we store the aggregate type
37+
// in the iterator, and derive the element type on the fly.
38+
//
39+
// However, this is not always possible, because for the outermost index there
40+
// is no containing type. In such cases, or if the containing type is not
41+
// relevant, e.g. for arrays, the element type is stored as Type* in CurTy.
42+
//
43+
// If CurTy contains a Type* value, this does not imply anything about the
44+
// type itself, because it is the element type and not the outer type.
45+
// In particular, Type* can be a struct type.
46+
//
47+
// Consider this example:
48+
//
49+
// %my.struct = type { i32, [ 4 x float ] }
50+
// [...]
51+
// %gep = getelementptr %my.struct, ptr %ptr, i32 10, i32 1, 32 3
52+
//
53+
// Iterating over the indices of this GEP, CurTy will contain the following
54+
// values:
55+
// * i32 10: The outer index always operates on the GEP value type.
56+
// CurTy contains a Type* pointing at `%my.struct`.
57+
// * i32 1: This index is within a struct.
58+
// CurTy contains a StructType* pointing at `%my.struct`.
59+
// * i32 3: This index is within an array. We reuse the "flat" indexing
60+
// for arrays which is also used in the top level GEP index.
61+
// CurTy contains a Type* pointing at `float`.
62+
//
63+
// Vectors are handled separately because the layout of vectors is different
64+
// for overaligned elements: Vectors are always bit-packed, whereas arrays
65+
// respect ABI alignment of the elements.
66+
PointerUnion<StructType *, VectorType *, Type *> CurTy;
3467

3568
generic_gep_type_iterator() = default;
3669

@@ -69,6 +102,8 @@ class generic_gep_type_iterator {
69102
Type *getIndexedType() const {
70103
if (auto *T = dyn_cast_if_present<Type *>(CurTy))
71104
return T;
105+
if (auto *VT = dyn_cast_if_present<VectorType *>(CurTy))
106+
return VT->getElementType();
72107
return cast<StructType *>(CurTy)->getTypeAtIndex(getOperand());
73108
}
74109

@@ -79,7 +114,7 @@ class generic_gep_type_iterator {
79114
if (auto *ATy = dyn_cast<ArrayType>(Ty))
80115
CurTy = ATy->getElementType();
81116
else if (auto *VTy = dyn_cast<VectorType>(Ty))
82-
CurTy = VTy->getElementType();
117+
CurTy = VTy;
83118
else
84119
CurTy = dyn_cast<StructType>(Ty);
85120
++OpIt;
@@ -108,7 +143,23 @@ class generic_gep_type_iterator {
108143
// that.
109144

110145
bool isStruct() const { return isa<StructType *>(CurTy); }
111-
bool isSequential() const { return isa<Type *>(CurTy); }
146+
bool isVector() const { return isa<VectorType *>(CurTy); }
147+
bool isSequential() const { return !isStruct(); }
148+
149+
// For sequential GEP indices (all except those into structs), the index value
150+
// can be translated into a byte offset by multiplying with an element stride.
151+
// This function returns this stride, which both depends on the element type,
152+
// and the containing aggregate type, as vectors always tightly bit-pack their
153+
// elements.
154+
TypeSize getSequentialElementStride(const DataLayout &DL) const {
155+
assert(isSequential());
156+
Type *ElemTy = getIndexedType();
157+
TypeSize ElemSizeInBits = isVector() ? DL.getTypeSizeInBits(ElemTy)
158+
: DL.getTypeAllocSizeInBits(ElemTy);
159+
// Check for invalid GEPs that are not byte-addressable.
160+
assert(ElemSizeInBits.isKnownMultipleOf(8));
161+
return ElemSizeInBits.divideCoefficientBy(8);
162+
}
112163

113164
StructType *getStructType() const { return cast<StructType *>(CurTy); }
114165

0 commit comments

Comments
 (0)