Files
Nikita Popov 89905ff214 [FunctionAttrs] Add support for nofree argument inference (#201591)
Unlike Attributor, FunctionAttrs currently only supports inferring
nofree on functions. This PR adds support for inferring it on arguments
as well.

I've chosen to integrate this with the inference for
readnone/readonly/writeonly attributes, as the core logic for these is
the same.

There is a lot of test fallout. The only significant changes are in
llvm/lib/Transforms/IPO/FunctionAttrs.cpp and
llvm/test/Transforms/FunctionAttrs/nofree.ll.
2026-06-05 12:36:55 +02:00

84 lines
3.4 KiB
C

// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// RUN: %clang_cc1 -O1 -triple=x86_64-unknown-linux %s -emit-llvm -o - | FileCheck %s
typedef unsigned char uint8_t;
typedef unsigned long long uint64_t;
struct a {
uint64_t b;
uint8_t block[16];
};
// CHECK-LABEL: define dso_local void @ptradd_0(
// CHECK-SAME: ptr nofree noundef writeonly captures(none) initializes((8, 9)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[BLOCK:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 8
// CHECK-NEXT: store i8 0, ptr [[BLOCK]], align 8, !tbaa [[TBAA5:![0-9]+]]
// CHECK-NEXT: ret void
//
void ptradd_0(struct a *ctx) {
*(ctx->block + 0) = 0;
}
// CHECK-LABEL: define dso_local void @ptradd_4(
// CHECK-SAME: ptr nofree noundef writeonly captures(none) initializes((12, 13)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 12
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 4, !tbaa [[TBAA5]]
// CHECK-NEXT: ret void
//
void ptradd_4(struct a *ctx) {
*(ctx->block + 4) = 0;
}
// CHECK-LABEL: define dso_local void @ptradd_8(
// CHECK-SAME: ptr nofree noundef writeonly captures(none) initializes((16, 17)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 16
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA5]]
// CHECK-NEXT: ret void
//
void ptradd_8(struct a *ctx) {
*(ctx->block + 8) = 0;
}
// CHECK-LABEL: define dso_local void @ptradd_8_commuted(
// CHECK-SAME: ptr nofree noundef writeonly captures(none) initializes((16, 17)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 16
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 8, !tbaa [[TBAA5]]
// CHECK-NEXT: ret void
//
void ptradd_8_commuted(struct a *ctx) {
*(8 + ctx->block) = 0;
}
// CHECK-LABEL: define dso_local void @ptrsub_4(
// CHECK-SAME: ptr nofree noundef writeonly captures(none) initializes((8, 9)) [[CTX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 8
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 4, !tbaa [[TBAA5]]
// CHECK-NEXT: ret void
//
void ptrsub_4(struct a *ctx) {
*(&ctx->block[4] - 4) = 0;
}
// CHECK-LABEL: define dso_local void @neg_ptradd_var_index(
// CHECK-SAME: ptr nofree noundef writeonly captures(none) [[CTX:%.*]], i8 noundef zeroext [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[BLOCK:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 8
// CHECK-NEXT: [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i64
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[BLOCK]], i64 [[IDX_EXT]]
// CHECK-NEXT: store i8 0, ptr [[ADD_PTR]], align 1, !tbaa [[TBAA5]]
// CHECK-NEXT: ret void
//
void neg_ptradd_var_index(struct a *ctx, uint8_t idx) {
*(ctx->block + idx) = 0;
}
//.
// CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
// CHECK: [[META4]] = !{!"Simple C/C++ TBAA"}
// CHECK: [[TBAA5]] = !{[[META3]], [[META3]], i64 0}
//.