; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Verify that strnlen calls that aren't folded into constants are annotated ; with noundef, nonnull, and dereferenceable only when maxlen is known to ; to be nonzero. ; ; RUN: opt < %s -passes=instcombine -S | FileCheck %s declare i64 @strnlen(i8*, i64) @ecp = external global i8*, align 8 ; Annotate strnlen(ecp, 3) call with noundef, nonnull, and dereferenceable ; based on the access to *ecp. define i64 @deref_strnlen_ecp_3() { ; CHECK-LABEL: @deref_strnlen_ecp_3( ; CHECK-NEXT: [[PTR:%.*]] = load i8*, i8** @ecp, align 8 ; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* noundef nonnull dereferenceable(1) [[PTR]], i64 3) ; CHECK-NEXT: ret i64 [[LEN]] ; %ptr = load i8*, i8** @ecp %len = call i64 @strnlen(i8* %ptr, i64 3) ret i64 %len } ; Annotate strnlen(ecp, %n) call with nonzero %n with noundef, nonnull, and ; dereferenceable based on the access to *ecp. define i64 @deref_strnlen_ecp_nz(i64 %n) { ; CHECK-LABEL: @deref_strnlen_ecp_nz( ; CHECK-NEXT: [[NONZERO:%.*]] = or i64 [[N:%.*]], 1 ; CHECK-NEXT: [[PTR:%.*]] = load i8*, i8** @ecp, align 8 ; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* noundef nonnull dereferenceable(1) [[PTR]], i64 [[NONZERO]]) ; CHECK-NEXT: ret i64 [[LEN]] ; %nonzero = or i64 %n, 1 %ptr = load i8*, i8** @ecp %len = call i64 @strnlen(i8* %ptr, i64 %nonzero) ret i64 %len } ; Do not annotate strnlen(ecp, %n) call with nonnull etc. because it need ; not access *ecp. (Strictly, every pointer function argument must be ; noundef, so this is overly conservative.) define i64 @noderef_strnlen_ecp_n(i64 %n) { ; CHECK-LABEL: @noderef_strnlen_ecp_n( ; CHECK-NEXT: [[PTR:%.*]] = load i8*, i8** @ecp, align 8 ; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 [[N:%.*]]) ; CHECK-NEXT: ret i64 [[LEN]] ; %ptr = load i8*, i8** @ecp %len = call i64 @strnlen(i8* %ptr, i64 %n) ret i64 %len }