blob: 27c0ff485c5e10dced8c6421362367b3422ef3cd [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
; Test that foldICmpDivConstant can treat sdiv as udiv when the dividend
; is known non-negative (e.g. via a dominating condition), allowing the
; fold to proceed despite a signed div / unsigned icmp mismatch.
; Non-power-of-two divisors are used to prevent sdiv->lshr conversion.
; The sdiv is placed in the entry block where x's sign is unknown, and
; the icmp is in a block dominated by a condition that proves x >= 0.
declare void @use(i32)
; Positive test: x > 255 dominates the icmp, proving x non-negative.
; sdiv(x, 65) = udiv(x, 65) when x >= 0, and udiv(x, 65) > 2 when x >= 195.
; Since x > 255 >= 195, the result folds to true.
define i1 @icmp_sdiv_domcond(i32 %x) {
; CHECK-LABEL: @icmp_sdiv_domcond(
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65
; CHECK-NEXT: call void @use(i32 [[DIV]])
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 255
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: ret i1 true
; CHECK: if.false:
; CHECK-NEXT: ret i1 false
;
%div = sdiv i32 %x, 65
call void @use(i32 %div)
%cond = icmp sgt i32 %x, 255
br i1 %cond, label %if.true, label %if.false
if.true:
%cmp = icmp samesign ugt i32 %div, 2
ret i1 %cmp
if.false:
ret i1 false
}
; Positive test: add+sdiv pattern (mirrors real-world kernel case).
; x+63 > 255 dominates the icmp, proving x+63 non-negative.
define i1 @icmp_add_sdiv_domcond(i32 %x) {
; CHECK-LABEL: @icmp_add_sdiv_domcond(
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 63
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[ADD]], 65
; CHECK-NEXT: call void @use(i32 [[DIV]])
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[ADD]], 255
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: ret i1 true
; CHECK: if.false:
; CHECK-NEXT: ret i1 false
;
%add = add i32 %x, 63
%div = sdiv i32 %add, 65
call void @use(i32 %div)
%cond = icmp sgt i32 %add, 255
br i1 %cond, label %if.true, label %if.false
if.true:
%cmp = icmp samesign ugt i32 %div, 2
ret i1 %cmp
if.false:
ret i1 false
}
; Positive test: udiv case (no signedness mismatch, baseline behavior).
define i1 @icmp_udiv_domcond(i32 %x) {
; CHECK-LABEL: @icmp_udiv_domcond(
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[X:%.*]], 65
; CHECK-NEXT: call void @use(i32 [[DIV]])
; CHECK-NEXT: [[COND:%.*]] = icmp ugt i32 [[X]], 255
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: ret i1 true
; CHECK: if.false:
; CHECK-NEXT: ret i1 false
;
%div = udiv i32 %x, 65
call void @use(i32 %div)
%cond = icmp ugt i32 %x, 255
br i1 %cond, label %if.true, label %if.false
if.true:
%cmp = icmp ugt i32 %div, 2
ret i1 %cmp
if.false:
ret i1 false
}
; Negative test: dominating condition is too weak.
; x > 127 does NOT prove sdiv(x, 65) > 2 (e.g. x=128, sdiv(128,65)=1).
define i1 @icmp_sdiv_domcond_too_weak(i32 %x) {
; CHECK-LABEL: @icmp_sdiv_domcond_too_weak(
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65
; CHECK-NEXT: call void @use(i32 [[DIV]])
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 127
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 194
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK: if.false:
; CHECK-NEXT: ret i1 false
;
%div = sdiv i32 %x, 65
call void @use(i32 %div)
%cond = icmp sgt i32 %x, 127
br i1 %cond, label %if.true, label %if.false
if.true:
%cmp = icmp samesign ugt i32 %div, 2
ret i1 %cmp
if.false:
ret i1 false
}
; Negative test: no dominating condition, x's sign is unknown.
define i1 @icmp_sdiv_no_domcond(i32 %x) {
; CHECK-LABEL: @icmp_sdiv_no_domcond(
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[DIV]], 2
; CHECK-NEXT: ret i1 [[CMP]]
;
%div = sdiv i32 %x, 65
%cmp = icmp samesign ugt i32 %div, 2
ret i1 %cmp
}
; Negative test: comparison is on the boundary.
; x > 194 means x >= 195, sdiv(195, 65) = 3, but 3 > 3 is false.
define i1 @icmp_sdiv_domcond_boundary(i32 %x) {
; CHECK-LABEL: @icmp_sdiv_domcond_boundary(
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65
; CHECK-NEXT: call void @use(i32 [[DIV]])
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 194
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 259
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK: if.false:
; CHECK-NEXT: ret i1 false
;
%div = sdiv i32 %x, 65
call void @use(i32 %div)
%cond = icmp sgt i32 %x, 194
br i1 %cond, label %if.true, label %if.false
if.true:
%cmp = icmp samesign ugt i32 %div, 3
ret i1 %cmp
if.false:
ret i1 false
}
; Negative test: dividend is known negative, sdiv != udiv.
define i1 @icmp_sdiv_negative_dividend(i32 %x) {
; CHECK-LABEL: @icmp_sdiv_negative_dividend(
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65
; CHECK-NEXT: call void @use(i32 [[DIV]])
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[X]], -100
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[DIV]], 2
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK: if.false:
; CHECK-NEXT: ret i1 false
;
%div = sdiv i32 %x, 65
call void @use(i32 %div)
%cond = icmp slt i32 %x, -100
br i1 %cond, label %if.true, label %if.false
if.true:
%cmp = icmp samesign ugt i32 %div, 2
ret i1 %cmp
if.false:
ret i1 false
}
; Negative test: divisor is negative, sdiv(x, -65) != udiv(x, -65).
define i1 @icmp_sdiv_negative_divisor(i32 %x) {
; CHECK-LABEL: @icmp_sdiv_negative_divisor(
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], -65
; CHECK-NEXT: call void @use(i32 [[DIV]])
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 255
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[DIV]], 2
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK: if.false:
; CHECK-NEXT: ret i1 false
;
%div = sdiv i32 %x, -65
call void @use(i32 %div)
%cond = icmp sgt i32 %x, 255
br i1 %cond, label %if.true, label %if.false
if.true:
%cmp = icmp samesign ugt i32 %div, 2
ret i1 %cmp
if.false:
ret i1 false
}