llvm/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=correlated-propagation < %s | FileCheck %s

declare void @use.i16(i16)
declare i16 @llvm.usub.sat.i16(i16, i16)
declare i16 @llvm.uadd.sat.i16(i16, i16)
declare i16 @llvm.umin.i16(i16, i16)
declare i16 @llvm.abs.i16(i16, i1)

define i16 @sel_true_cond(i16 noundef %x) {
; CHECK-LABEL: @sel_true_cond(
; CHECK-NEXT:    [[SUB1:%.*]] = sub nuw i16 [[X:%.*]], 10
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[X]], 10
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SUB1]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp uge i16 %x, 10
  %sel = select i1 %cmp, i16 %sub, i16 42
  ret i16 %sel
}

define i16 @sel_true_cond_insufficient(i16 %x) {
; CHECK-LABEL: @sel_true_cond_insufficient(
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[X]], 9
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SUB]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp uge i16 %x, 9
  %sel = select i1 %cmp, i16 %sub, i16 42
  ret i16 %sel
}

define i16 @sel_true_cond_wrong_swap(i16 %x) {
; CHECK-LABEL: @sel_true_cond_wrong_swap(
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[X]], 10
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 42, i16 [[SUB]]
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp uge i16 %x, 10
  %sel = select i1 %cmp, i16 42, i16 %sub
  ret i16 %sel
}

define i16 @sel_true_cond_wrong_op(i16 %x, i16 %y) {
; CHECK-LABEL: @sel_true_cond_wrong_op(
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[Y:%.*]], 10
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SUB]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp uge i16 %y, 10
  %sel = select i1 %cmp, i16 %sub, i16 42
  ret i16 %sel
}

define i16 @sel_true_cond_extra_use(i16 %x) {
; CHECK-LABEL: @sel_true_cond_extra_use(
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    call void @use.i16(i16 [[SUB]])
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[X]], 10
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SUB]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  call void @use.i16(i16 %sub)
  %cmp = icmp uge i16 %x, 10
  %sel = select i1 %cmp, i16 %sub, i16 42
  ret i16 %sel
}

define i16 @sel_true_cond_chain_speculatable(i16 noundef %x) {
; CHECK-LABEL: @sel_true_cond_chain_speculatable(
; CHECK-NEXT:    [[SUB1:%.*]] = add nuw i16 [[X:%.*]], 1
; CHECK-NEXT:    [[EXTRA:%.*]] = mul i16 [[SUB1]], 3
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i16 [[X]], -1
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[EXTRA]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.uadd.sat.i16(i16 %x, i16 1)
  %extra = mul i16 %sub, 3
  %cmp = icmp ne i16 %x, -1
  %sel = select i1 %cmp, i16 %extra, i16 42
  ret i16 %sel
}

define i16 @sel_true_cond_chain_non_speculatable(i16 %x) {
; CHECK-LABEL: @sel_true_cond_chain_non_speculatable(
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[X:%.*]], i16 1)
; CHECK-NEXT:    [[EXTRA:%.*]] = udiv i16 3, [[SUB]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i16 [[X]], -1
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[EXTRA]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.uadd.sat.i16(i16 %x, i16 1)
  %extra = udiv i16 3, %sub
  %cmp = icmp ne i16 %x, -1
  %sel = select i1 %cmp, i16 %extra, i16 42
  ret i16 %sel
}

; TODO: We could handle this case by raising the limit on the number of
; instructions we look through.
define i16 @sel_true_cond_longer_chain(i16 %x) {
; CHECK-LABEL: @sel_true_cond_longer_chain(
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[X:%.*]], i16 1)
; CHECK-NEXT:    [[EXTRA:%.*]] = mul i16 [[SUB]], 3
; CHECK-NEXT:    [[EXTRA2:%.*]] = xor i16 [[SUB]], 7
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i16 [[X]], -1
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[EXTRA2]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.uadd.sat.i16(i16 %x, i16 1)
  %extra = mul i16 %sub, 3
  %extra2 = xor i16 %sub, 7
  %cmp = icmp ne i16 %x, -1
  %sel = select i1 %cmp, i16 %extra2, i16 42
  ret i16 %sel
}

define i16 @sel_false_cond(i16 noundef %x) {
; CHECK-LABEL: @sel_false_cond(
; CHECK-NEXT:    [[SUB1:%.*]] = sub nuw i16 [[X:%.*]], 10
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 10
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 42, i16 [[SUB1]]
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp ult i16 %x, 10
  %sel = select i1 %cmp, i16 42, i16 %sub
  ret i16 %sel
}

define i16 @sel_false_cond_insufficient(i16 %x) {
; CHECK-LABEL: @sel_false_cond_insufficient(
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 9
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 42, i16 [[SUB]]
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp ult i16 %x, 9
  %sel = select i1 %cmp, i16 42, i16 %sub
  ret i16 %sel
}

define i16 @phi_true_cond(i16 %x) {
; CHECK-LABEL: @phi_true_cond(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[SUB1:%.*]] = sub nuw i16 [[X:%.*]], 10
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[X]], 10
; CHECK-NEXT:    br i1 [[CMP]], label [[JOIN:%.*]], label [[SPLIT:%.*]]
; CHECK:       split:
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB1]], [[ENTRY:%.*]] ], [ 42, [[SPLIT]] ]
; CHECK-NEXT:    ret i16 [[PHI]]
;
entry:
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp uge i16 %x, 10
  br i1 %cmp, label %join, label %split

split:
  br label %join

join:
  %phi = phi i16 [ %sub, %entry ], [ 42, %split ]
  ret i16 %phi
}

define i16 @phi_true_cond_insufficient(i16 %x) {
; CHECK-LABEL: @phi_true_cond_insufficient(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[X]], 9
; CHECK-NEXT:    br i1 [[CMP]], label [[JOIN:%.*]], label [[SPLIT:%.*]]
; CHECK:       split:
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB]], [[ENTRY:%.*]] ], [ 42, [[SPLIT]] ]
; CHECK-NEXT:    ret i16 [[PHI]]
;
entry:
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp uge i16 %x, 9
  br i1 %cmp, label %join, label %split

split:
  br label %join

join:
  %phi = phi i16 [ %sub, %entry ], [ 42, %split ]
  ret i16 %phi
}

; TODO: We could handle this by using conditions that are not directly on the
; phi edge.
define i16 @phi_true_cond_non_local(i16 %x) {
; CHECK-LABEL: @phi_true_cond_non_local(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[X]], 10
; CHECK-NEXT:    br i1 [[CMP]], label [[SPLIT:%.*]], label [[JOIN:%.*]]
; CHECK:       split:
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB]], [[SPLIT]] ], [ 42, [[ENTRY:%.*]] ]
; CHECK-NEXT:    ret i16 [[PHI]]
;
entry:
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp uge i16 %x, 10
  br i1 %cmp, label %split, label %join

split:
  br label %join

join:
  %phi = phi i16 [ %sub, %split ], [ 42, %entry ]
  ret i16 %phi
}

define i16 @phi_false_cond(i16 %x) {
; CHECK-LABEL: @phi_false_cond(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[SUB1:%.*]] = sub nuw i16 [[X:%.*]], 10
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 10
; CHECK-NEXT:    br i1 [[CMP]], label [[SPLIT:%.*]], label [[JOIN:%.*]]
; CHECK:       split:
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB1]], [[ENTRY:%.*]] ], [ 42, [[SPLIT]] ]
; CHECK-NEXT:    ret i16 [[PHI]]
;
entry:
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp ult i16 %x, 10
  br i1 %cmp, label %split, label %join

split:
  br label %join

join:
  %phi = phi i16 [ %sub, %entry ], [ 42, %split ]
  ret i16 %phi
}

define i16 @phi_false_cond_insufficient(i16 %x) {
; CHECK-LABEL: @phi_false_cond_insufficient(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 9
; CHECK-NEXT:    br i1 [[CMP]], label [[SPLIT:%.*]], label [[JOIN:%.*]]
; CHECK:       split:
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB]], [[ENTRY:%.*]] ], [ 42, [[SPLIT]] ]
; CHECK-NEXT:    ret i16 [[PHI]]
;
entry:
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp ult i16 %x, 9
  br i1 %cmp, label %split, label %join

split:
  br label %join

join:
  %phi = phi i16 [ %sub, %entry ], [ 42, %split ]
  ret i16 %phi
}

; TODO: We could handle this by using conditions that are not directly on the
; phi edge.
define i16 @phi_false_cond_non_local(i16 %x) {
; CHECK-LABEL: @phi_false_cond_non_local(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 10
; CHECK-NEXT:    br i1 [[CMP]], label [[JOIN:%.*]], label [[SPLIT:%.*]]
; CHECK:       split:
; CHECK-NEXT:    br label [[JOIN]]
; CHECK:       join:
; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB]], [[SPLIT]] ], [ 42, [[ENTRY:%.*]] ]
; CHECK-NEXT:    ret i16 [[PHI]]
;
entry:
  %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
  %cmp = icmp ult i16 %x, 10
  br i1 %cmp, label %join, label %split

split:
  br label %join

join:
  %phi = phi i16 [ %sub, %split ], [ 42, %entry ]
  ret i16 %phi
}

define i16 @loop_cond() {
; CHECK-LABEL: @loop_cond(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 1000, [[ENTRY:%.*]] ], [ [[IV_NEXT1:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[COUNT:%.*]] = phi i16 [ 0, [[ENTRY]] ], [ [[COUNT_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[IV]], 0
; CHECK-NEXT:    [[IV_NEXT1]] = sub nuw i16 [[IV]], 1
; CHECK-NEXT:    [[COUNT_NEXT]] = add i16 [[COUNT]], 1
; CHECK-NEXT:    br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]]
; CHECK:       exit:
; CHECK-NEXT:    ret i16 [[COUNT]]
;
entry:
  br label %loop

loop:
  %iv = phi i16 [ 1000, %entry ], [ %iv.next, %loop ]
  %count = phi i16 [ 0, %entry ], [ %count.next, %loop ]
  %cmp = icmp eq i16 %iv, 0
  %iv.next = call i16 @llvm.usub.sat.i16(i16 %iv, i16 1)
  %count.next = add i16 %count, 1
  br i1 %cmp, label %exit, label %loop

exit:
  ret i16 %count
}

define i16 @urem_elide(i16 noundef %x) {
; CHECK-LABEL: @urem_elide(
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X:%.*]], 42
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[X]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %urem = urem i16 %x, 42
  %cmp = icmp ult i16 %x, 42
  %sel = select i1 %cmp, i16 %urem, i16 24
  ret i16 %sel
}

define i16 @urem_expand(i16 noundef %x) {
; CHECK-LABEL: @urem_expand(
; CHECK-NEXT:    [[UREM_UREM:%.*]] = sub nuw i16 [[X:%.*]], 42
; CHECK-NEXT:    [[UREM_CMP:%.*]] = icmp ult i16 [[X]], 42
; CHECK-NEXT:    [[UREM:%.*]] = select i1 [[UREM_CMP]], i16 [[X]], i16 [[UREM_UREM]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 84
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[UREM]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %urem = urem i16 %x, 42
  %cmp = icmp ult i16 %x, 84
  %sel = select i1 %cmp, i16 %urem, i16 24
  ret i16 %sel
}

define i16 @urem_narrow(i16 noundef %x) {
; CHECK-LABEL: @urem_narrow(
; CHECK-NEXT:    [[UREM_LHS_TRUNC:%.*]] = trunc i16 [[X:%.*]] to i8
; CHECK-NEXT:    [[UREM1:%.*]] = urem i8 [[UREM_LHS_TRUNC]], 42
; CHECK-NEXT:    [[UREM_ZEXT:%.*]] = zext i8 [[UREM1]] to i16
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 85
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[UREM_ZEXT]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %urem = urem i16 %x, 42
  %cmp = icmp ult i16 %x, 85
  %sel = select i1 %cmp, i16 %urem, i16 24
  ret i16 %sel
}

define i16 @urem_insufficient(i16 %x) {
; CHECK-LABEL: @urem_insufficient(
; CHECK-NEXT:    [[UREM:%.*]] = urem i16 [[X:%.*]], 42
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 257
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[UREM]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %urem = urem i16 %x, 42
  %cmp = icmp ult i16 %x, 257
  %sel = select i1 %cmp, i16 %urem, i16 24
  ret i16 %sel
}

define i16 @srem_elide(i16 noundef %x) {
; CHECK-LABEL: @srem_elide(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i16 [[X:%.*]], 42
; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i16 [[X]], -42
; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[AND]], i16 [[X]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %srem = srem i16 %x, 42
  %cmp1 = icmp slt i16 %x, 42
  %cmp2 = icmp sgt i16 %x, -42
  %and = and i1 %cmp1, %cmp2
  %sel = select i1 %and, i16 %srem, i16 24
  ret i16 %sel
}

define i16 @srem_narrow(i16 noundef %x) {
; CHECK-LABEL: @srem_narrow(
; CHECK-NEXT:    [[SREM_LHS_TRUNC:%.*]] = trunc i16 [[X:%.*]] to i8
; CHECK-NEXT:    [[SREM1:%.*]] = srem i8 [[SREM_LHS_TRUNC]], 42
; CHECK-NEXT:    [[SREM_SEXT:%.*]] = sext i8 [[SREM1]] to i16
; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i16 [[X]], 43
; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i16 [[X]], -43
; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[AND]], i16 [[SREM_SEXT]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %srem = srem i16 %x, 42
  %cmp1 = icmp slt i16 %x, 43
  %cmp2 = icmp sgt i16 %x, -43
  %and = and i1 %cmp1, %cmp2
  %sel = select i1 %and, i16 %srem, i16 24
  ret i16 %sel
}

define i16 @srem_convert(i16 noundef %x) {
; CHECK-LABEL: @srem_convert(
; CHECK-NEXT:    [[X_NONNEG:%.*]] = sub i16 0, [[X:%.*]]
; CHECK-NEXT:    [[SREM1:%.*]] = urem i16 [[X_NONNEG]], 42
; CHECK-NEXT:    [[SREM1_NEG:%.*]] = sub i16 0, [[SREM1]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[X]], 0
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SREM1_NEG]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %srem = srem i16 %x, 42
  %cmp = icmp slt i16 %x, 0
  %sel = select i1 %cmp, i16 %srem, i16 24
  ret i16 %sel
}

define i16 @sdiv_convert(i16 noundef %x) {
; CHECK-LABEL: @sdiv_convert(
; CHECK-NEXT:    [[X_NONNEG:%.*]] = sub i16 0, [[X:%.*]]
; CHECK-NEXT:    [[SREM1:%.*]] = udiv i16 [[X_NONNEG]], 42
; CHECK-NEXT:    [[SREM1_NEG:%.*]] = sub i16 0, [[SREM1]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[X]], 0
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SREM1_NEG]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %srem = sdiv i16 %x, 42
  %cmp = icmp slt i16 %x, 0
  %sel = select i1 %cmp, i16 %srem, i16 24
  ret i16 %sel
}

define i16 @abs_elide(i16 %x) {
; CHECK-LABEL: @abs_elide(
; CHECK-NEXT:    [[ABS:%.*]] = call i16 @llvm.abs.i16(i16 [[X:%.*]], i1 false)
; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i16 [[X]], -32768
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[ABS]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %abs = call i16 @llvm.abs.i16(i16 %x, i1 false)
  %cmp = icmp ule i16 %x, 32768
  %sel = select i1 %cmp, i16 %abs, i16 42
  ret i16 %sel
}

define i16 @abs_elide2(i16 %x) {
; CHECK-LABEL: @abs_elide2(
; CHECK-NEXT:    [[ABS:%.*]] = call i16 @llvm.abs.i16(i16 [[X:%.*]], i1 false)
; CHECK-NEXT:    [[CMP:%.*]] = icmp sle i16 [[X]], 0
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[ABS]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %abs = call i16 @llvm.abs.i16(i16 %x, i1 false)
  %cmp = icmp sle i16 %x, 0
  %sel = select i1 %cmp, i16 %abs, i16 42
  ret i16 %sel
}

define i16 @abs_not_int_min(i16 %x) {
; CHECK-LABEL: @abs_not_int_min(
; CHECK-NEXT:    [[ABS:%.*]] = call i16 @llvm.abs.i16(i16 [[X:%.*]], i1 false)
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i16 [[X]], -32768
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[ABS]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %abs = call i16 @llvm.abs.i16(i16 %x, i1 false)
  %cmp = icmp ne i16 %x, 32768
  %sel = select i1 %cmp, i16 %abs, i16 42
  ret i16 %sel
}

define i16 @umin_elide(i16 %x) {
; CHECK-LABEL: @umin_elide(
; CHECK-NEXT:    [[MIN:%.*]] = call i16 @llvm.umin.i16(i16 [[X:%.*]], i16 10)
; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i16 [[X]], 10
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[MIN]], i16 42
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %min = call i16 @llvm.umin.i16(i16 %x, i16 10)
  %cmp = icmp ule i16 %x, 10
  %sel = select i1 %cmp, i16 %min, i16 42
  ret i16 %sel
}

define i16 @ashr_convert(i16 noundef %x, i16 %y) {
; CHECK-LABEL: @ashr_convert(
; CHECK-NEXT:    [[ASHR:%.*]] = lshr i16 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i16 [[X]], 0
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[ASHR]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %ashr = ashr i16 %x, %y
  %cmp = icmp sge i16 %x, 0
  %sel = select i1 %cmp, i16 %ashr, i16 24
  ret i16 %sel
}

define i32 @sext_convert(i16 noundef %x) {
; CHECK-LABEL: @sext_convert(
; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i16 [[X:%.*]] to i32
; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i16 [[X]], 0
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[EXT]], i32 24
; CHECK-NEXT:    ret i32 [[SEL]]
;
  %ext = sext i16 %x to i32
  %cmp = icmp sge i16 %x, 0
  %sel = select i1 %cmp, i32 %ext, i32 24
  ret i32 %sel
}

define i16 @infer_flags(i16 %x) {
; CHECK-LABEL: @infer_flags(
; CHECK-NEXT:    [[ADD:%.*]] = add i16 [[X:%.*]], 42
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 100
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[ADD]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %add = add i16 %x, 42
  %cmp = icmp ult i16 %x, 100
  %sel = select i1 %cmp, i16 %add, i16 24
  ret i16 %sel
}

define i16 @and_elide(i16 noundef %x) {
; CHECK-LABEL: @and_elide(
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X:%.*]], 8
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[X]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %and = and i16 %x, 7
  %cmp = icmp ult i16 %x, 8
  %sel = select i1 %cmp, i16 %and, i16 24
  ret i16 %sel
}

define i16 @cond_value_may_not_well_defined(i16 %x) {
; CHECK-LABEL: @cond_value_may_not_well_defined(
; CHECK-NEXT:    [[AND:%.*]] = and i16 [[X:%.*]], 7
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 8
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[AND]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %and = and i16 %x, 7
  %cmp = icmp ult i16 %x, 8
  %sel = select i1 %cmp, i16 %and, i16 24
  ret i16 %sel
}

define i16 @and_elide_poison_flags(i16 noundef %a) {
; CHECK-LABEL: @and_elide_poison_flags(
; CHECK-NEXT:    [[X:%.*]] = add nuw i16 [[A:%.*]], 1
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 8
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[X]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %x = add nuw i16 %a, 1
  %and = and i16 %x, 7
  %cmp = icmp ult i16 %x, 8
  %sel = select i1 %cmp, i16 %and, i16 24
  ret i16 %sel
}

define i16 @and_elide_poison_flags_missing_noundef(i16 %a) {
; CHECK-LABEL: @and_elide_poison_flags_missing_noundef(
; CHECK-NEXT:    [[X:%.*]] = add nuw i16 [[A:%.*]], 1
; CHECK-NEXT:    [[AND:%.*]] = and i16 [[X]], 7
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 8
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[AND]], i16 24
; CHECK-NEXT:    ret i16 [[SEL]]
;
  %x = add nuw i16 %a, 1
  %and = and i16 %x, 7
  %cmp = icmp ult i16 %x, 8
  %sel = select i1 %cmp, i16 %and, i16 24
  ret i16 %sel
}

define i32 @pr87854(i32 noundef %x.1, i32 noundef %i) {
; CHECK-LABEL: @pr87854(
; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i32 [[X_1:%.*]], -1
; CHECK-NEXT:    tail call void @llvm.assume(i1 [[COND]])
; CHECK-NEXT:    [[INBOUNDS:%.*]] = icmp ult i32 [[I:%.*]], [[X_1]]
; CHECK-NEXT:    [[NEXT:%.*]] = add nuw i32 [[I]], 1
; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[INBOUNDS]], i32 [[NEXT]], i32 -1
; CHECK-NEXT:    ret i32 [[SPEC_SELECT]]
;
  %cond = icmp sgt i32 %x.1, -1
  tail call void @llvm.assume(i1 %cond)
  %inbounds = icmp ult i32 %i, %x.1
  %next = add i32 %i, 1
  %spec.select = select i1 %inbounds, i32 %next, i32 -1
  ret i32 %spec.select
}

define i64 @test_shl_nsw_at_use(i64 noundef %x) {
; CHECK-LABEL: @test_shl_nsw_at_use(
; CHECK-NEXT:    [[ADD:%.*]] = add i64 [[X:%.*]], 2147483648
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[ADD]], 4294967296
; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i64 [[X]], 32
; CHECK-NEXT:    [[SHR:%.*]] = ashr exact i64 [[SHL]], 32
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[CMP]], i64 [[SHR]], i64 0
; CHECK-NEXT:    ret i64 [[RES]]
;
  %add = add i64 %x, 2147483648
  %cmp = icmp ult i64 %add, 4294967296
  %shl = shl i64 %x, 32
  %shr = ashr exact i64 %shl, 32
  %res = select i1 %cmp, i64 %shr, i64 0
  ret i64 %res
}