llvm.org GIT mirror llvm / de0e587
Canonicalize indices in a constantexpr GEP. If Indices exceed the static extents of the static array type, it causes GlobalOpt and other passes to be more conservative. This canonicalization also allows the constant folder to add "inbounds" to GEPs. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79440 91177308-0d34-0410-b5e6-96231b3b80d8 Dan Gohman 10 years ago
2 changed file(s) with 98 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
130130 return 0;
131131
132132 uint64_t BasePtr = 0;
133 bool BaseIsInt = true;
133134 if (!Ptr->isNullValue()) {
134135 // If this is a inttoptr from a constant int, we can fold this as the base,
135136 // otherwise we can't.
139140 BasePtr = Base->getZExtValue();
140141
141142 if (BasePtr == 0)
142 return 0;
143 BaseIsInt = false;
143144 }
144145
145146 // If this is a constant expr gep that is effectively computing an
146147 // "offsetof", fold it into 'cast int Size to T*' instead of 'gep 0, 0, 12'
147148 for (unsigned i = 1; i != NumOps; ++i)
148149 if (!isa(Ops[i]))
149 return false;
150 return 0;
150151
151152 uint64_t Offset = TD->getIndexedOffset(Ptr->getType(),
152153 (Value**)Ops+1, NumOps-1);
153 Constant *C = ConstantInt::get(TD->getIntPtrType(Context), Offset+BasePtr);
154 return ConstantExpr::getIntToPtr(C, ResultTy);
154 // If the base value for this address is a literal integer value, fold the
155 // getelementptr to the resulting integer value casted to the pointer type.
156 if (BaseIsInt) {
157 Constant *C = ConstantInt::get(TD->getIntPtrType(Context), Offset+BasePtr);
158 return ConstantExpr::getIntToPtr(C, ResultTy);
159 }
160
161 // Otherwise form a regular getelementptr. Recompute the indices so that
162 // we eliminate over-indexing of the notional static type array bounds.
163 // This makes it easy to determine if the getelementptr is "inbounds".
164 // Also, this helps GlobalOpt do SROA on GlobalVariables.
165 const Type *Ty = Ptr->getType();
166 SmallVector NewIdxs;
167 for (unsigned Index = 1; Index != NumOps; ++Index) {
168 if (const SequentialType *ATy = dyn_cast(Ty)) {
169 // Determine which element of the array the offset points into.
170 uint64_t ElemSize = TD->getTypeAllocSize(ATy->getElementType());
171 if (ElemSize == 0)
172 return 0;
173 uint64_t NewIdx = Offset / ElemSize;
174 Offset -= NewIdx * ElemSize;
175 NewIdxs.push_back(ConstantInt::get(TD->getIntPtrType(Context), NewIdx));
176 Ty = ATy->getElementType();
177 } else if (const StructType *STy = dyn_cast(Ty)) {
178 // Determine which field of the struct the offset points into.
179 const StructLayout &SL = *TD->getStructLayout(STy);
180 unsigned ElIdx = SL.getElementContainingOffset(Offset);
181 NewIdxs.push_back(ConstantInt::get(Type::getInt32Ty(Context), ElIdx));
182 Offset -= SL.getElementOffset(ElIdx);
183 Ty = STy->getTypeAtIndex(ElIdx);
184 } else {
185 return 0;
186 }
187 }
188
189 // If the base is the start of a GlobalVariable and all the array indices
190 // remain in their static bounds, the GEP is inbounds. We can check that
191 // all indices are in bounds by just checking the first index only
192 // because we've just normalized all the indices.
193 if (isa(Ptr) && NewIdxs[0]->isNullValue())
194 return ConstantExpr::getInBoundsGetElementPtr(Ptr,
195 &NewIdxs[0], NewIdxs.size());
196
197 // Otherwise it may not be inbounds.
198 return ConstantExpr::getGetElementPtr(Ptr, &NewIdxs[0], NewIdxs.size());
155199 }
156200
157201 /// FoldBitCast - Constant fold bitcast, symbolically evaluating it with
0 ; RUN: llvm-as < %s | opt -instcombine | llvm-dis | FileCheck %s
1
2 ; Constant folding should fix notionally out-of-bounds indices
3 ; and add inbounds keywords.
4
5 %struct.X = type { [3 x i32], [3 x i32] }
6
7 @Y = internal global [3 x %struct.X] zeroinitializer
8
9 define void @frob() {
10 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 0), align 8
11 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 0), align 4
12 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 1), align 4
13 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 1), align 4
14 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 2), align 8
15 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 2), align 4
16 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 0), align 4
17 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 3), align 4
18 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 1), align 4
19 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 4), align 4
20 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 0, i32 1, i64 2), align 4
21 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 5), align 4
22 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 0), align 8
23 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 6), align 4
24 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 1), align 4
25 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 7), align 4
26 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 0, i64 2), align 8
27 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 8), align 4
28 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 0), align 4
29 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 9), align 4
30 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 1), align 4
31 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 10), align 4
32 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 1, i32 1, i64 2), align 4
33 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 11), align 4
34 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 0), align 8
35 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 12), align 4
36 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 1), align 4
37 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 13), align 4
38 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 0, i64 2), align 8
39 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 14), align 8
40 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 0), align 8
41 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 15), align 8
42 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 1), align 8
43 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 16), align 8
44 ; CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.X]* @Y, i64 0, i64 2, i32 1, i64 2), align 8
45 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 17), align 8
46 ; CHECK: store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 1, i64 0, i32 0, i64 0), align 8
47 store i32 1, i32* getelementptr ([3 x %struct.X]* @Y, i64 0, i64 0, i32 0, i64 18), align 8
48 ret void
49 }