Vitaly Buka 6dba99e14f
[InstCombine][asan] Don't speculate loads before select ptr (#100773)
Even if memory is valid from `llvm` point of view,
e.g. local alloca, sanitizers have API for user
specific memory annotations.

These annotations can be used to track size of the
local object, e.g. inline vectors may prevent
accesses beyond the current vector size.

So valid programs should not access those parts of
alloca before checking preconditions.

Fixes #100639.
2024-07-29 11:28:03 -07:00

184 lines
6.0 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; Verify that strnlen calls with conditional expressions involving constant
; string arguments and constant bounds are folded correctly.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
declare i64 @strnlen(ptr, i64)
@s3 = constant [4 x i8] c"123\00"
@s5 = constant [6 x i8] c"12345\00"
@s5_3 = constant [10 x i8] c"12345\00678\00"
@s6 = constant [7 x i8] c"123456\00"
@s7 = constant [8 x i8] c"1234567\00"
; Fold strnlen (C ? s3 : s5, 0) to 0.
define i64 @fold_strnlen_s3_s5_0(i1 %C) {
; CHECK-LABEL: @fold_strnlen_s3_s5_0(
; CHECK-NEXT: ret i64 0
;
%ptr = select i1 %C, ptr @s3, ptr @s6
%len = call i64 @strnlen(ptr %ptr, i64 0)
ret i64 %len
}
; Fold strnlen (C ? s3 : s5, 1) to 1.
define i64 @fold_strnlen_s3_s5_1(i1 %C) {
; CHECK-LABEL: @fold_strnlen_s3_s5_1(
; CHECK-NEXT: ret i64 1
;
%ptr = select i1 %C, ptr @s3, ptr @s6
%len = call i64 @strnlen(ptr %ptr, i64 1)
ret i64 %len
}
; FIXME: Constants should be allowed for this optimization.
define i64 @fold_strnlen_s3_s5_1_asan(i1 %C) sanitize_address {
; CHECK-LABEL: @fold_strnlen_s3_s5_1_asan(
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[C:%.*]], ptr @s3, ptr @s6
; CHECK-NEXT: [[STRNLEN_CHAR0:%.*]] = load i8, ptr [[PTR]], 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]]
;
%ptr = select i1 %C, ptr @s3, ptr @s6
%len = call i64 @strnlen(ptr %ptr, i64 1)
ret i64 %len
}
; Fold strnlen (C ? s3 : s5, 3) to 3.
define i64 @fold_strnlen_s3_s5_3(i1 %C) {
; CHECK-LABEL: @fold_strnlen_s3_s5_3(
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[C:%.*]], ptr @s3, ptr @s6
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 3)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = select i1 %C, ptr @s3, ptr @s6
%len = call i64 @strnlen(ptr %ptr, i64 3)
ret i64 %len
}
; Fold strnlen (C ? s3 : s5, 4) to C ? 3 : 4.
define i64 @fold_strnlen_s3_s5_4(i1 %C) {
; CHECK-LABEL: @fold_strnlen_s3_s5_4(
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[C:%.*]], ptr @s3, ptr @s6
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 4)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = select i1 %C, ptr @s3, ptr @s6
%len = call i64 @strnlen(ptr %ptr, i64 4)
ret i64 %len
}
; Fold strnlen (C ? s3 : s5, 5) to C ? 3 : 5.
define i64 @fold_strnlen_s3_s5_5(i1 %C) {
; CHECK-LABEL: @fold_strnlen_s3_s5_5(
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[C:%.*]], ptr @s3, ptr @s6
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 5)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = select i1 %C, ptr @s3, ptr @s6
%len = call i64 @strnlen(ptr %ptr, i64 5)
ret i64 %len
}
; Fold strnlen (C ? s3 : s5, 6) to C ? 3 : 5.
define i64 @fold_strnlen_s5_6(i1 %C) {
; CHECK-LABEL: @fold_strnlen_s5_6(
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[C:%.*]], ptr @s5, ptr @s6
; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[PTR]], i64 6)
; CHECK-NEXT: ret i64 [[LEN]]
;
%ptr = select i1 %C, ptr @s5, ptr @s6
%len = call i64 @strnlen(ptr %ptr, i64 6)
ret i64 %len
}
; Fold strnlen(E, N) with E being two conditional expressions:
; strlen (x == 3 ? s3 : x == 5 ? s5 : s7, 4) to x == 3 ? 3 : 4.
define i64 @fold_strnlen_s3_s5_s7_4(i32 %X) {
; CHECK-LABEL: @fold_strnlen_s3_s5_s7_4(
; CHECK-NEXT: [[X_EQ_3:%.*]] = icmp eq i32 [[X:%.*]], 3
; CHECK-NEXT: [[X_EQ_5:%.*]] = icmp eq i32 [[X]], 5
; CHECK-NEXT: [[SEL_X_EQ_5:%.*]] = select i1 [[X_EQ_5]], ptr @s5, ptr @s7
; CHECK-NEXT: [[SEL_X_EQ_3:%.*]] = select i1 [[X_EQ_3]], ptr @s3, ptr [[SEL_X_EQ_5]]
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[SEL_X_EQ_3]], i64 4)
; CHECK-NEXT: ret i64 [[LEN]]
;
%x_eq_3 = icmp eq i32 %X, 3
%x_eq_5 = icmp eq i32 %X, 5
%sel_x_eq_5 = select i1 %x_eq_5, ptr @s5, ptr @s7
%sel_x_eq_3 = select i1 %x_eq_3, ptr @s3, ptr %sel_x_eq_5
%len = tail call i64 @strnlen(ptr %sel_x_eq_3, i64 4)
ret i64 %len
}
; As above, fold strnlen(E, N) with E being two conditional expressions
; but with N == 6:
; strlen (x == 3 ? s3 : x == 5 ? s5 : s7, 6) to x == 3 ? 3 : x == 5 ? 5 : 6.
define i64 @fold_strnlen_s3_s5_s7_6(i32 %X) {
; CHECK-LABEL: @fold_strnlen_s3_s5_s7_6(
; CHECK-NEXT: [[X_EQ_3:%.*]] = icmp eq i32 [[X:%.*]], 3
; CHECK-NEXT: [[X_EQ_5:%.*]] = icmp eq i32 [[X]], 5
; CHECK-NEXT: [[SEL_X_EQ_5:%.*]] = select i1 [[X_EQ_5]], ptr @s5, ptr @s7
; CHECK-NEXT: [[SEL_X_EQ_3:%.*]] = select i1 [[X_EQ_3]], ptr @s3, ptr [[SEL_X_EQ_5]]
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[SEL_X_EQ_3]], i64 6)
; CHECK-NEXT: ret i64 [[LEN]]
;
%x_eq_3 = icmp eq i32 %X, 3
%x_eq_5 = icmp eq i32 %X, 5
%sel_x_eq_5 = select i1 %x_eq_5, ptr @s5, ptr @s7
%sel_x_eq_3 = select i1 %x_eq_3, ptr @s3, ptr %sel_x_eq_5
%len = tail call i64 @strnlen(ptr %sel_x_eq_3, i64 6)
ret i64 %len
}
; And again, fold strnlen(E, N) with E being two conditional expressions
; but with N == 8:
; strlen (x == 3 ? s3 : x == 5 ? s5 : s7, 8) to x == 3 ? 3 : x == 5 ? 5 : 7.
define i64 @fold_strnlen_s3_s5_s7_8(i32 %X) {
; CHECK-LABEL: @fold_strnlen_s3_s5_s7_8(
; CHECK-NEXT: [[X_EQ_3:%.*]] = icmp eq i32 [[X:%.*]], 3
; CHECK-NEXT: [[X_EQ_5:%.*]] = icmp eq i32 [[X]], 5
; CHECK-NEXT: [[SEL_X_EQ_5:%.*]] = select i1 [[X_EQ_5]], ptr @s5, ptr @s7
; CHECK-NEXT: [[SEL_X_EQ_3:%.*]] = select i1 [[X_EQ_3]], ptr @s3, ptr [[SEL_X_EQ_5]]
; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(ptr noundef nonnull dereferenceable(1) [[SEL_X_EQ_3]], i64 8)
; CHECK-NEXT: ret i64 [[LEN]]
;
%x_eq_3 = icmp eq i32 %X, 3
%x_eq_5 = icmp eq i32 %X, 5
%sel_x_eq_5 = select i1 %x_eq_5, ptr @s5, ptr @s7
%sel_x_eq_3 = select i1 %x_eq_3, ptr @s3, ptr %sel_x_eq_5
%len = tail call i64 @strnlen(ptr %sel_x_eq_3, i64 8)
ret i64 %len
}