We were hitting a CIR verification error in some cases when a boolean expression was used as an index to an array because the GetElementOp verifier expected the index operand to be a fundamental integer type. To fix this, I'm updating the emitArraySubscriptExpr to cast index values to ptrDiffTy, which more closely matches what classic codegen does in the corrsponding code. The improved alignment with the classic codegen implementation caused some minor changes in generated IR that required some tests to be updated. Assisted-by: Cursor / claude-4.7-opus-high
81 lines
3.9 KiB
C++
81 lines
3.9 KiB
C++
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
|
|
// RUN: FileCheck --input-file=%t.cir %s
|
|
|
|
// Should generate basic pointer arithmetics.
|
|
void foo(int *iptr, char *cptr, unsigned ustride) {
|
|
iptr + 2;
|
|
// CHECK: %[[#STRIDE:]] = cir.const #cir.int<2> : !s32i
|
|
// CHECK: cir.ptr_stride %{{.+}}, %[[#STRIDE]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
|
|
cptr + 3;
|
|
// CHECK: %[[#STRIDE:]] = cir.const #cir.int<3> : !s32i
|
|
// CHECK: cir.ptr_stride %{{.+}}, %[[#STRIDE]] : (!cir.ptr<!s8i>, !s32i) -> !cir.ptr<!s8i>
|
|
|
|
// We need to assign to a temporary in these cases because otherwise
|
|
// constant folding of the unary minus for thenegative stride value also
|
|
// triggers erasing the unused result of the ptr_stride operation.
|
|
int* iptr2 = iptr - 2;
|
|
// CHECK: %[[#STRIDE:]] = cir.const #cir.int<-2> : !s32i
|
|
// CHECK: cir.ptr_stride %{{.+}}, %[[#STRIDE]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
|
|
char* cptr2 = cptr - 3;
|
|
|
|
// CHECK: %[[#STRIDE:]] = cir.const #cir.int<-3> : !s32i
|
|
// CHECK: cir.ptr_stride %{{.+}}, %[[#STRIDE]] : (!cir.ptr<!s8i>, !s32i) -> !cir.ptr<!s8i>
|
|
iptr + ustride;
|
|
// CHECK: %[[#STRIDE:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
|
|
// CHECK: cir.ptr_stride %{{.+}}, %[[#STRIDE]] : (!cir.ptr<!s32i>, !u32i) -> !cir.ptr<!s32i>
|
|
|
|
// Must convert unsigned stride to a signed one.
|
|
iptr - ustride;
|
|
// CHECK: %[[#STRIDE:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!u32i>, !u32i
|
|
// CHECK: %[[#SIGNSTRIDE:]] = cir.cast integral %[[#STRIDE]] : !u32i -> !s32i
|
|
// CHECK: %[[#NEGSTRIDE:]] = cir.minus %[[#SIGNSTRIDE]] : !s32i
|
|
// CHECK: cir.ptr_stride %{{.+}}, %[[#NEGSTRIDE]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
|
|
|
|
4 + iptr;
|
|
// CHECK: %[[#STRIDE:]] = cir.const #cir.int<4> : !s32i
|
|
// CHECK: cir.ptr_stride %{{.+}}, %[[#STRIDE]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
|
|
|
|
iptr++;
|
|
// CHECK: %[[#STRIDE:]] = cir.const #cir.int<1> : !s32i
|
|
// CHECK: cir.ptr_stride %{{.+}}, %[[#STRIDE]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
|
|
|
|
iptr--;
|
|
// CHECK: %[[#STRIDE:]] = cir.const #cir.int<-1> : !s32i
|
|
// CHECK: cir.ptr_stride %{{.+}}, %[[#STRIDE]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
|
|
}
|
|
|
|
void testPointerSubscriptAccess(int *ptr) {
|
|
// CHECK: testPointerSubscriptAccess
|
|
ptr[1];
|
|
// CHECK: %[[#STRIDE:]] = cir.const #cir.int<1> : !s64i
|
|
// CHECK: %[[#PTR:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
|
|
// CHECK: cir.ptr_stride %[[#PTR]], %[[#STRIDE]] : (!cir.ptr<!s32i>, !s64i) -> !cir.ptr<!s32i>
|
|
}
|
|
|
|
void testPointerMultiDimSubscriptAccess(int **ptr) {
|
|
// CHECK: testPointerMultiDimSubscriptAccess
|
|
ptr[1][2];
|
|
// CHECK: %[[#STRIDE2:]] = cir.const #cir.int<2> : !s64i
|
|
// CHECK: %[[#STRIDE1:]] = cir.const #cir.int<1> : !s64i
|
|
// CHECK: %[[#PTR1:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.ptr<!cir.ptr<!s32i>>>, !cir.ptr<!cir.ptr<!s32i>>
|
|
// CHECK: %[[#PTR2:]] = cir.ptr_stride %[[#PTR1]], %[[#STRIDE1]] : (!cir.ptr<!cir.ptr<!s32i>>, !s64i) -> !cir.ptr<!cir.ptr<!s32i>>
|
|
// CHECK: %[[#PTR3:]] = cir.load{{.*}} %[[#PTR2]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
|
|
// CHECK: cir.ptr_stride %[[#PTR3]], %[[#STRIDE2]] : (!cir.ptr<!s32i>, !s64i) -> !cir.ptr<!s32i>
|
|
}
|
|
|
|
// This test is meant to verify code that handles the 'p = nullptr + n' idiom
|
|
// used by some versions of glibc and gcc. This is undefined behavior but
|
|
// it is intended there to act like a conversion from a pointer-sized integer
|
|
// to a pointer, and we would like to tolerate that.
|
|
|
|
#define NULLPTRINT ((int*)0)
|
|
|
|
// This should get the inttoptr instruction.
|
|
int *testGnuNullPtrArithmetic(unsigned n) {
|
|
// CHECK: testGnuNullPtrArithmetic
|
|
return NULLPTRINT + n;
|
|
// CHECK: %[[NULLPTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
|
|
// CHECK: %[[N:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!u32i>, !u32i
|
|
// CHECK: %[[RESULT:.*]] = cir.ptr_stride %[[NULLPTR]], %[[N]] : (!cir.ptr<!s32i>, !u32i) -> !cir.ptr<!s32i>
|
|
}
|