blob: bafc0fc2235c57072f93031d2498b574640b27b1 [file]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
declare i8 @llvm.umax.i8(i8, i8)
; Structural X u>= Y proofs.
; X != X urem Y is true if X is an add nuw of A and Y.
define i1 @nuw_add_ne(i8 %a, i8 %y) {
; CHECK-LABEL: define i1 @nuw_add_ne(
; CHECK-SAME: i8 [[A:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: ret i1 true
;
%x = add nuw i8 %a, %y
%rem = urem i8 %x, %y
%cmp = icmp ne i8 %x, %rem
ret i1 %cmp
}
; X urem Y != X is true with commuted add and compare operands.
define i1 @nuw_add_ne_commuted(i8 %a, i8 %y) {
; CHECK-LABEL: define i1 @nuw_add_ne_commuted(
; CHECK-SAME: i8 [[A:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: ret i1 true
;
%x = add nuw i8 %y, %a
%rem = urem i8 %x, %y
%cmp = icmp ne i8 %rem, %x
ret i1 %cmp
}
; umax(X - (X urem Y), 1) is X - (X urem Y) if X is an add nuw
; of A and Y.
define i8 @nuw_add_umax(i8 %a, i8 %y) {
; CHECK-LABEL: define i8 @nuw_add_umax(
; CHECK-SAME: i8 [[A:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[X:%.*]] = add nuw i8 [[A]], [[Y]]
; CHECK-NEXT: [[REM:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i8 [[X]], [[REM]]
; CHECK-NEXT: ret i8 [[SUB]]
;
%x = add nuw i8 %a, %y
%rem = urem i8 %x, %y
%sub = sub nuw i8 %x, %rem
%max = call i8 @llvm.umax.i8(i8 %sub, i8 1)
ret i8 %max
}
; X != X urem Y is true element-wise if X is an add nuw of A and Y.
define <2 x i1> @nuw_add_ne_vector(<2 x i4> %a, <2 x i4> %y) {
; CHECK-LABEL: define <2 x i1> @nuw_add_ne_vector(
; CHECK-SAME: <2 x i4> [[A:%.*]], <2 x i4> [[Y:%.*]]) {
; CHECK-NEXT: ret <2 x i1> splat (i1 true)
;
%x = add nuw <2 x i4> %a, %y
%rem = urem <2 x i4> %x, %y
%cmp = icmp ne <2 x i4> %x, %rem
ret <2 x i1> %cmp
}
; Dominating X u>= Y proofs.
; X != X urem Y is true if X u>= Y.
define i1 @dom_ne(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @dom_ne(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp uge i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: ret i1 true
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i1 false
;
entry:
%cond = icmp uge i8 %x, %y
br i1 %cond, label %body, label %exit
body:
%rem = urem i8 %x, %y
%cmp = icmp ne i8 %x, %rem
ret i1 %cmp
exit:
ret i1 false
}
; X urem Y == X is false if X u>= Y.
define i1 @dom_eq_commuted(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @dom_eq_commuted(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp uge i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: ret i1 false
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i1 true
;
entry:
%cond = icmp uge i8 %x, %y
br i1 %cond, label %body, label %exit
body:
%rem = urem i8 %x, %y
%cmp = icmp eq i8 %rem, %x
ret i1 %cmp
exit:
ret i1 true
}
; Equivalent comparisons against one.
; (X - (X urem Y)) u>= 1 is true if X u>= Y.
define i1 @dom_uge_one(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @dom_uge_one(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp uge i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: ret i1 true
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i1 false
;
entry:
%cond = icmp uge i8 %x, %y
br i1 %cond, label %body, label %exit
body:
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%cmp = icmp uge i8 %sub, 1
ret i1 %cmp
exit:
ret i1 false
}
; (X - (X urem Y)) u< 1 is false if X u>= Y.
define i1 @dom_ult_one(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @dom_ult_one(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp uge i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: ret i1 false
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i1 true
;
entry:
%cond = icmp uge i8 %x, %y
br i1 %cond, label %body, label %exit
body:
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%cmp = icmp ult i8 %sub, 1
ret i1 %cmp
exit:
ret i1 true
}
; Equivalent unsigned comparisons against zero.
; (X - (X urem Y)) u> 0 is true on the false edge of X u< Y.
define i1 @dom_ugt_zero_false_edge(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @dom_ugt_zero_false_edge(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp ult i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[EXIT:.*]], label %[[BODY:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: ret i1 true
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i1 false
;
entry:
%cond = icmp ult i8 %x, %y
br i1 %cond, label %exit, label %body
body:
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%cmp = icmp ugt i8 %sub, 0
ret i1 %cmp
exit:
ret i1 false
}
; 0 u>= (X - (X urem Y)) is false if X u>= Y.
define i1 @dom_ule_zero_commuted(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @dom_ule_zero_commuted(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp uge i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: ret i1 false
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i1 true
;
entry:
%cond = icmp uge i8 %x, %y
br i1 %cond, label %body, label %exit
body:
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%cmp = icmp uge i8 0, %sub
ret i1 %cmp
exit:
ret i1 true
}
; Equality comparisons against zero.
; (X - (X urem Y)) != 0 is true if X u>= Y.
define i1 @dom_ne_zero(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @dom_ne_zero(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp uge i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: ret i1 true
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i1 false
;
entry:
%cond = icmp uge i8 %x, %y
br i1 %cond, label %body, label %exit
body:
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%cmp = icmp ne i8 %sub, 0
ret i1 %cmp
exit:
ret i1 false
}
; 0 == (X - (X urem Y)) is false if X u>= Y.
define i1 @dom_eq_zero_commuted(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @dom_eq_zero_commuted(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp uge i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: ret i1 false
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i1 true
;
entry:
%cond = icmp uge i8 %x, %y
br i1 %cond, label %body, label %exit
body:
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%cmp = icmp eq i8 0, %sub
ret i1 %cmp
exit:
ret i1 true
}
; Intrinsic user.
; umax(X - (X urem Y), 1) is X - (X urem Y) if X u>= Y.
define i8 @dom_umax_false_edge(i8 %x, i8 %y) {
; CHECK-LABEL: define i8 @dom_umax_false_edge(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp ult i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[EXIT:.*]], label %[[BODY:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: [[REM:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[REM]]
; CHECK-NEXT: ret i8 [[SUB]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i8 0
;
entry:
%cond = icmp ult i8 %x, %y
br i1 %cond, label %exit, label %body
body:
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%max = call i8 @llvm.umax.i8(i8 %sub, i8 1)
ret i8 %max
exit:
ret i8 0
}
; Negative tests.
; Do not simplify if the add may wrap.
define i8 @add_may_wrap(i8 %a, i8 %y) {
; CHECK-LABEL: define i8 @add_may_wrap(
; CHECK-SAME: i8 [[A:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[X:%.*]] = add i8 [[A]], [[Y]]
; CHECK-NEXT: [[REM:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[REM]]
; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[SUB]], i8 1)
; CHECK-NEXT: ret i8 [[MAX]]
;
%x = add i8 %a, %y
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%max = call i8 @llvm.umax.i8(i8 %sub, i8 1)
ret i8 %max
}
; Do not simplify (X - (X urem Y)) != 0 without proof of X u>= Y.
define i1 @no_known_relation(i8 %x, i8 %y) {
; CHECK-LABEL: define i1 @no_known_relation(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
; CHECK-NEXT: [[REM:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[REM]]
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[SUB]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%cmp = icmp ne i8 %sub, 0
ret i1 %cmp
}
; Do not simplify using X u>= Z when the remainder divisor is Y.
define i1 @dom_wrong_divisor_ne_zero(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i1 @dom_wrong_divisor_ne_zero(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp uge i8 [[X]], [[Z]]
; CHECK-NEXT: br i1 [[COND]], label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: [[REM:%.*]] = urem i8 [[X]], [[Y]]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[REM]]
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[SUB]], 0
; CHECK-NEXT: ret i1 [[CMP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i1 false
;
entry:
%cond = icmp uge i8 %x, %z
br i1 %cond, label %body, label %exit
body:
%rem = urem i8 %x, %y
%sub = sub i8 %x, %rem
%cmp = icmp ne i8 %sub, 0
ret i1 %cmp
exit:
ret i1 false
}
; Do not simplify umax using X u>= Y when the remainder divisor is Z.
define i8 @dom_wrong_divisor(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @dom_wrong_divisor(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[COND:%.*]] = icmp uge i8 [[X]], [[Y]]
; CHECK-NEXT: br i1 [[COND]], label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: [[REM:%.*]] = urem i8 [[X]], [[Z]]
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[REM]]
; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[SUB]], i8 1)
; CHECK-NEXT: ret i8 [[MAX]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i8 0
;
entry:
%cond = icmp uge i8 %x, %y
br i1 %cond, label %body, label %exit
body:
%rem = urem i8 %x, %z
%sub = sub i8 %x, %rem
%max = call i8 @llvm.umax.i8(i8 %sub, i8 1)
ret i8 %max
exit:
ret i8 0
}