; CHECK: getelementptr [32 x [32 x float]]* @float_2d_array
; CHECK-NOT: getelementptr
-; if zext(a + b) <= max signed value of typeof(a + b), then we can prove
-; a + b >= 0 and zext(a + b) == sext(a + b). If we can prove further a or b is
-; non-negative, we have zext(a + b) == sext(a) + sext(b).
-define float* @inbounds_zext_add(i32 %i, i4 %j) {
+; The code that rebuilds an OR expression used to be buggy, and failed on this
+; test.
+define float* @shl_add_or(i64 %a, float* %ptr) {
+; CHECK-LABEL: @shl_add_or(
entry:
- %0 = add i32 %i, 1
- %1 = zext i32 %0 to i64
- ; Because zext(i + 1) is an index of an in bounds GEP based on
- ; float_2d_array, zext(i + 1) <= sizeof(float_2d_array) = 4096.
- ; Furthermore, since typeof(i + 1) is i32 and 4096 < 2^31, we are sure the
- ; sign bit of i + 1 is 0. This implies zext(i + 1) = sext(i + 1).
- %2 = add i4 %j, 2
- %3 = zext i4 %2 to i64
- ; In this case, typeof(j + 2) is i4, so zext(j + 2) <= 4096 does not imply
- ; the sign bit of j + 2 is 0.
- %p = getelementptr inbounds [32 x [32 x float]]* @float_2d_array, i64 0, i64 %1, i64 %3
+ %shl = shl i64 %a, 2
+ %add = add i64 %shl, 12
+ %or = or i64 %add, 1
+; CHECK: [[OR:%or[0-9]*]] = add i64 %shl, 1
+ ; ((a << 2) + 12) and 1 have no common bits. Therefore,
+ ; SeparateConstOffsetFromGEP is able to extract the 12.
+ ; TODO(jingyue): We could reassociate the expression to combine 12 and 1.
+ %p = getelementptr float* %ptr, i64 %or
+; CHECK: [[PTR:%[a-zA-Z0-9]+]] = getelementptr float* %ptr, i64 [[OR]]
+; CHECK: getelementptr float* [[PTR]], i64 12
ret float* %p
+; CHECK-NEXT: ret
}
-; CHECK-LABEL: @inbounds_zext_add(
+
+; The source code used to be buggy in checking
+; (AccumulativeByteOffset % ElementTypeSizeOfGEP == 0)
+; where AccumulativeByteOffset is signed but ElementTypeSizeOfGEP is unsigned.
+; The compiler would promote AccumulativeByteOffset to unsigned, causing
+; unexpected results. For example, while -64 % (int64_t)24 != 0,
+; -64 % (uint64_t)24 == 0.
+%struct3 = type { i64, i32 }
+%struct2 = type { %struct3, i32 }
+%struct1 = type { i64, %struct2 }
+%struct0 = type { i32, i32, i64*, [100 x %struct1] }
+define %struct2* @sign_mod_unsign(%struct0* %ptr, i64 %idx) {
+; CHECK-LABEL: @sign_mod_unsign(
+entry:
+ %arrayidx = add nsw i64 %idx, -2
; CHECK-NOT: add
-; CHECK: add i4 %j, 2
-; CHECK: sext
-; CHECK: getelementptr [32 x [32 x float]]* @float_2d_array, i64 0, i64 %{{[a-zA-Z0-9]+}}, i64 %{{[a-zA-Z0-9]+}}
-; CHECK: getelementptr float* %{{[a-zA-Z0-9]+}}, i64 32
+ %ptr2 = getelementptr inbounds %struct0* %ptr, i64 0, i32 3, i64 %arrayidx, i32 1
+; CHECK: [[PTR:%[a-zA-Z0-9]+]] = getelementptr %struct0* %ptr, i64 0, i32 3, i64 %idx, i32 1
+; CHECK: [[PTR1:%[a-zA-Z0-9]+]] = bitcast %struct2* [[PTR]] to i8*
+; CHECK: getelementptr i8* [[PTR1]], i64 -64
+; CHECK: bitcast
+ ret %struct2* %ptr2
+; CHECK-NEXT: ret
+}