Files
llvm-project/clang/test/CIR/CodeGen/pointers.cpp
Andy Kaylor 689dc6c58c [CIR] Handle boolean expression as array indexes (#193814)
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
2026-04-23 15:32:21 -07:00

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>
}