Compiler projects using llvm
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; Verify that wcslen calls with conditional expressions involving constant
; string arguments with nonconstant offsets are folded as expected.  See
; strlen-4.ll for the corresponding strlen test.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s

declare i64 @wcslen(i32*)

!0 = !{i32 1, !"wchar_size", i32 4}
!llvm.module.flags = !{!0}

@ws3 = constant [4 x i32] [i32 1, i32 2, i32 3, i32 0]
@ws5 = constant [6 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5, i32 0]
@ws5_3 = constant [10 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5, i32 0, i32 6, i32 7, i32 8, i32 0]


; Fold wcslen (x ? s3 + i: s5) to x ? 3 - i : 5.

define dso_local i64 @fold_wcslen_s3_pi_s5(i1 zeroext %0, i64 %1) {
; CHECK-LABEL: @fold_wcslen_s3_pi_s5(
; CHECK-NEXT:    [[PS3_PI:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* [[PS3_PI]], i32* getelementptr inbounds ([6 x i32], [6 x i32]* @ws5, i64 0, i64 0)
; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
; CHECK-NEXT:    ret i64 [[LEN]]
;

  %ps3_pi = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 %1
  %ps5 = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 0
  %sel = select i1 %0, i32* %ps3_pi, i32* %ps5
  %len = tail call i64 @wcslen(i32* %sel)
  ret i64 %len
}


; More complex expressions like the one below are not handled yet.
; Fold: wcslen (x ? s3 + i + 1 : s5 + j + 2) to x ? 2 - i : 3 - j.

define dso_local i64 @fold_wcslen_s3_pi_p1_s5(i1 zeroext %0, i64 %1) {
; XFAIL-CHECK-LABEL: @fold_wcslen_s3_pi_p1_s5(
; XFAIL-CHECK-NEXT:    [[DIF_I:%.*]] = sub i64 2, %1
; XFAIL-CHECK-NEXT:    [[SEL:%.*]] = select i1 %0, i64 [[DIF_I]], i64 5
; XFAIL-CHECK-NEXT:    ret i64 [[SEL]]
; CHECK-LABEL: @fold_wcslen_s3_pi_p1_s5(
; CHECK-NEXT:    [[PS3_PI:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT:    [[PS3_PI_P1:%.*]] = getelementptr inbounds i32, i32* [[PS3_PI]], i64 1
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* [[PS3_PI_P1]], i32* getelementptr inbounds ([6 x i32], [6 x i32]* @ws5, i64 0, i64 0)
; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
; CHECK-NEXT:    ret i64 [[LEN]]
;

  %ps3_pi = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 %1
  %ps3_pi_p1 = getelementptr inbounds i32, i32* %ps3_pi, i64 1
  %ps5 = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 0
  %sel = select i1 %0, i32* %ps3_pi_p1, i32* %ps5
  %len = tail call i64 @wcslen(i32* %sel)
  ret i64 %len
}


; Avoid folding calls with conditional expressions involving constant
; string arguments with embedded nuls such as:
;   wcslen (x ? s5_3 + i : s5).

define dso_local i64 @call_wcslen_s5_3_pi_s5(i1 zeroext %0, i64 %1) {
; CHECK-LABEL: @call_wcslen_s5_3_pi_s5(
; CHECK-NEXT:    [[PS5_3_PI:%.*]] = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* [[PS5_3_PI]], i32* getelementptr inbounds ([6 x i32], [6 x i32]* @ws5, i64 0, i64 0)
; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
; CHECK-NEXT:    ret i64 [[LEN]]
;

  %ps5_3_pi = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 %1
  %ps5 = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 0
  %sel = select i1 %0, i32* %ps5_3_pi, i32* %ps5
  %len = tail call i64 @wcslen(i32* %sel)
  ret i64 %len
}


; But do fold wcslen (x ? s5_3 : s5 + j) to x ? 5 : 5 - j.

define dso_local i64 @call_wcslen_s5_3_s5_pj(i1 zeroext %0, i64 %1) {
; CHECK-LABEL: @call_wcslen_s5_3_s5_pj(
; CHECK-NEXT:    [[PS5:%.*]] = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* getelementptr inbounds ([10 x i32], [10 x i32]* @ws5_3, i64 0, i64 0), i32* [[PS5]]
; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
; CHECK-NEXT:    ret i64 [[LEN]]
;

  %ps5_3_pi = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 0
  %ps5 = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 %1
  %sel = select i1 %0, i32* %ps5_3_pi, i32* %ps5
  %len = tail call i64 @wcslen(i32* %sel)
  ret i64 %len
}


; Fold wcslen (x ? s3: s5 + j) to x ? 3 : 5 - j.

define dso_local i64 @fold_wcslen_s3_s5_pj(i1 zeroext %0, i64 %1) {
; CHECK-LABEL: @fold_wcslen_s3_s5_pj(
; CHECK-NEXT:    [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* getelementptr inbounds ([4 x i32], [4 x i32]* @ws3, i64 0, i64 0), i32* [[PS5_PJ]]
; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
; CHECK-NEXT:    ret i64 [[LEN]]
;

  %ps3 = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 0
  %ps5_pj = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 %1
  %sel = select i1 %0, i32* %ps3, i32* %ps5_pj
  %len = tail call i64 @wcslen(i32* %sel)
  ret i64 %len
}


; Same as above, avoid folding calls with conditional expressions involving
; constant string arguments with embedded nuls such as:
;   wcslen (x ? s3 : s5_3 + j).

define dso_local i64 @call_wcslen_s3_s5_3_pj(i1 zeroext %0, i64 %1) {
; CHECK-LABEL: @call_wcslen_s3_s5_3_pj(
; CHECK-NEXT:    [[PS5_3_PJ:%.*]] = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* getelementptr inbounds ([4 x i32], [4 x i32]* @ws3, i64 0, i64 0), i32* [[PS5_3_PJ]]
; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @wcslen(i32* [[SEL]])
; CHECK-NEXT:    ret i64 [[LEN]]
;

  %ps3 = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 0
  %ps5_3_pj = getelementptr inbounds [10 x i32], [10 x i32]* @ws5_3, i64 0, i64 %1
  %sel = select i1 %0, i32* %ps3, i32* %ps5_3_pj
  %len = tail call i64 @wcslen(i32* %sel)
  ret i64 %len
}


; Fold wcslen (x ? s3 + i: s5 + j) to x ? 3 - i : 5 - j.

define dso_local i64 @fold_wcslen_s3_pi_s5_pj(i1 zeroext %0, i64 %1, i64 %2) {
; CHECK-LABEL: @fold_wcslen_s3_pi_s5_pj(
; CHECK-NEXT:    [[PS3_PI:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 [[TMP1:%.*]]
; CHECK-NEXT:    [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 [[TMP2:%.*]]
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], i32* [[PS3_PI]], i32* [[PS5_PJ]]
; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @wcslen(i32* nonnull [[SEL]])
; CHECK-NEXT:    ret i64 [[LEN]]
;

  %ps3_pi = getelementptr inbounds [4 x i32], [4 x i32]* @ws3, i64 0, i64 %1
  %ps5_pj = getelementptr inbounds [6 x i32], [6 x i32]* @ws5, i64 0, i64 %2
  %sel = select i1 %0, i32* %ps3_pi, i32* %ps5_pj
  %len = tail call i64 @wcslen(i32* %sel)
  ret i64 %len
}