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