| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; Verify that strnlen calls with constant string arguments and offsets |
| ; and constant bounds are folded correctly. |
| ; |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| declare i64 @strnlen(ptr, i64) |
| |
| @ax = external global [0 x i8] |
| @s5 = constant [6 x i8] c"12345\00" |
| @s5_3 = constant [9 x i8] c"12345\00xyz" |
| |
| |
| ; Verify that the strnlen pointer argument is not annotated nonnull when |
| ; nothing is known about the bound. |
| |
| define i64 @no_access_strnlen_p_n(ptr %ptr, i64 %n) { |
| ; CHECK-LABEL: @no_access_strnlen_p_n( |
| ; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr [[PTR:%.*]], i64 [[N:%.*]]) |
| ; CHECK-NEXT: ret i64 [[LEN]] |
| ; |
| %len = call i64 @strnlen(ptr %ptr, i64 %n) |
| ret i64 %len |
| } |
| |
| |
| ; Verify that the strnlen pointer argument is annotated dereferenceable(1) |
| ; (and not more) when the constant bound is greater than 1. |
| |
| define i64 @access_strnlen_p_2(ptr %ptr) { |
| ; CHECK-LABEL: @access_strnlen_p_2( |
| ; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR:%.*]], i64 2) |
| ; CHECK-NEXT: ret i64 [[LEN]] |
| ; |
| %len = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) %ptr, i64 2) |
| ret i64 %len |
| } |
| |
| |
| ; Verify that the strnlen pointer argument is annotated nonnull etc., |
| ; when the bound is known to be nonzero. |
| |
| define i64 @access_strnlen_p_nz(ptr %ptr, i64 %n) { |
| ; CHECK-LABEL: @access_strnlen_p_nz( |
| ; CHECK-NEXT: [[NNZ:%.*]] = or i64 [[N:%.*]], 1 |
| ; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR:%.*]], i64 [[NNZ]]) |
| ; CHECK-NEXT: ret i64 [[LEN]] |
| ; |
| %nnz = or i64 %n, 1 |
| %len = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) %ptr, i64 %nnz) |
| ret i64 %len |
| } |
| |
| |
| ; Fold strnlen(ax, 0) to 0. |
| |
| define i64 @fold_strnlen_ax_0() { |
| ; CHECK-LABEL: @fold_strnlen_ax_0( |
| ; CHECK-NEXT: ret i64 0 |
| ; |
| %len = call i64 @strnlen(ptr @ax, i64 0) |
| ret i64 %len |
| } |
| |
| |
| ; Fold strnlen(ax, 1) to *ax ? 1 : 0. |
| |
| define i64 @fold_strnlen_ax_1() { |
| ; CHECK-LABEL: @fold_strnlen_ax_1( |
| ; CHECK-NEXT: [[STRNLEN_CHAR0:%.*]] = load i8, ptr @ax, align 1 |
| ; CHECK-NEXT: [[STRNLEN_CHAR0CMP:%.*]] = icmp ne i8 [[STRNLEN_CHAR0]], 0 |
| ; CHECK-NEXT: [[LEN:%.*]] = zext i1 [[STRNLEN_CHAR0CMP]] to i64 |
| ; CHECK-NEXT: ret i64 [[LEN]] |
| ; |
| %len = call i64 @strnlen(ptr @ax, i64 1) |
| ret i64 %len |
| } |
| |
| |
| ; Fold strnlen(s5, 0) to 0. |
| |
| define i64 @fold_strnlen_s5_0() { |
| ; CHECK-LABEL: @fold_strnlen_s5_0( |
| ; CHECK-NEXT: ret i64 0 |
| ; |
| %len = call i64 @strnlen(ptr @s5, i64 0) |
| ret i64 %len |
| } |
| |
| |
| ; Fold strnlen(s5, 4) to 4. |
| |
| define i64 @fold_strnlen_s5_4() { |
| ; CHECK-LABEL: @fold_strnlen_s5_4( |
| ; CHECK-NEXT: ret i64 4 |
| ; |
| %len = call i64 @strnlen(ptr @s5, i64 4) |
| ret i64 %len |
| } |
| |
| |
| ; Fold strnlen(s5, 5) to 5. |
| |
| define i64 @fold_strnlen_s5_5() { |
| ; CHECK-LABEL: @fold_strnlen_s5_5( |
| ; CHECK-NEXT: ret i64 5 |
| ; |
| %len = call i64 @strnlen(ptr @s5, i64 5) |
| ret i64 %len |
| } |
| |
| |
| ; Fold strnlen(s5, (size_t)-1) to 5. |
| |
| define i64 @fold_strnlen_s5_m1() { |
| ; CHECK-LABEL: @fold_strnlen_s5_m1( |
| ; CHECK-NEXT: ret i64 5 |
| ; |
| %len = call i64 @strnlen(ptr @s5, i64 -1) |
| ret i64 %len |
| } |
| |
| |
| ; Fold strnlen(s5_3 + 4, 5) to 1. |
| |
| define i64 @fold_strnlen_s5_3_p4_5() { |
| ; CHECK-LABEL: @fold_strnlen_s5_3_p4_5( |
| ; CHECK-NEXT: ret i64 1 |
| ; |
| %ptr = getelementptr [9 x i8], ptr @s5_3, i32 0, i32 4 |
| %len = call i64 @strnlen(ptr %ptr, i64 5) |
| ret i64 %len |
| } |
| |
| |
| ; Fold strnlen(s5_3 + 5, 5) to 0. |
| |
| define i64 @fold_strnlen_s5_3_p5_5() { |
| ; CHECK-LABEL: @fold_strnlen_s5_3_p5_5( |
| ; CHECK-NEXT: ret i64 0 |
| ; |
| %ptr = getelementptr [9 x i8], ptr @s5_3, i32 0, i32 5 |
| %len = call i64 @strnlen(ptr %ptr, i64 5) |
| ret i64 %len |
| } |
| |
| |
| ; Fold strnlen(s5_3 + 6, 3) to 3. |
| |
| define i64 @fold_strnlen_s5_3_p6_3() { |
| ; CHECK-LABEL: @fold_strnlen_s5_3_p6_3( |
| ; CHECK-NEXT: ret i64 3 |
| ; |
| %ptr = getelementptr [9 x i8], ptr @s5_3, i32 0, i32 6 |
| %len = call i64 @strnlen(ptr %ptr, i64 3) |
| ret i64 %len |
| } |
| |
| |
| ; Fold even the invalid strnlen(s5_3 + 6, 4) call where the bound exceeds |
| ; the number of characters in the array. This is arguably safer than |
| ; making the library call (although the low bound makes it unlikely that |
| ; the call would misbehave). |
| |
| define i64 @call_strnlen_s5_3_p6_4() { |
| ; CHECK-LABEL: @call_strnlen_s5_3_p6_4( |
| ; CHECK-NEXT: ret i64 3 |
| ; |
| %ptr = getelementptr [9 x i8], ptr @s5_3, i32 0, i32 6 |
| %len = call i64 @strnlen(ptr %ptr, i64 4) |
| ret i64 %len |
| } |