llvm/llvm/test/Transforms/InstCombine/strnlen-2.ll

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