Files
clang-p2996/llvm/test/Transforms/InstSimplify/and-or-implied-cond.ll
Nikita Popov de29b850f0 [InstSimplify] Fix simplifyAndOrWithICmpEq with undef refinement (#98898)
The final case in Simplify (where Res == Absorber and the predicate is
inverted) is not generally safe when the simplification is a refinement.
In particular, we may simplify assuming a specific value for undef, but
then chose a different one later.

However, it *is* safe to refine poison in this context, unlike in the
equivalent select folds. This is the reason why this fold did not use
AllowRefinement=false in the first place, and using that option would
introduce a lot of test regressions.

This patch takes the middle path of disabling undef refinements in
particular using the getWithoutUndef() SimplifyQuery option. However,
this option doesn't actually work in this case, because the problematic
fold is inside constant folding, and we currently don't propagate this
option all the way from InstSimplify over ConstantFolding to
ConstantFold. Work around this by explicitly checking for undef operands
in simplifyWithOpReplaced().

Finally, make sure that places where AllowRefinement=false also use
Q.getWithoutUndef(). I don't have a specific test case for this (the
original one does not work because we don't simplify selects with
constant condition in this mode in the first place) but this seems like
the correct thing to do to be conservative.

Fixes https://github.com/llvm/llvm-project/issues/98753.
2024-07-16 11:40:04 +02:00

350 lines
9.4 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=instsimplify < %s | FileCheck %s
define i1 @or_implied(i8 %x, i1 %c) {
; CHECK-LABEL: @or_implied(
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp eq i8 %x, 0
%cmp2 = icmp ne i8 %x, 1
%and = and i1 %cmp, %c
%or = or i1 %and, %cmp2
ret i1 %or
}
define i1 @or_implied_comm1(i8 %x, i1 %c) {
; CHECK-LABEL: @or_implied_comm1(
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp eq i8 %x, 0
%cmp2 = icmp ne i8 %x, 1
%and = and i1 %cmp, %c
%or = or i1 %cmp2, %and
ret i1 %or
}
define i1 @or_implied_comm2(i8 %x, i1 %c) {
; CHECK-LABEL: @or_implied_comm2(
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp eq i8 %x, 0
%cmp2 = icmp ne i8 %x, 1
%and = and i1 %c, %cmp
%or = or i1 %and, %cmp2
ret i1 %or
}
define i1 @or_implied_comm3(i8 %x, i1 %c) {
; CHECK-LABEL: @or_implied_comm3(
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp eq i8 %x, 0
%cmp2 = icmp ne i8 %x, 1
%and = and i1 %c, %cmp
%or = or i1 %cmp2, %and
ret i1 %or
}
define i1 @or_not_implied(i8 %x, i1 %c) {
; CHECK-LABEL: @or_not_implied(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X]], 0
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], [[C:%.*]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[AND]], [[CMP2]]
; CHECK-NEXT: ret i1 [[OR]]
;
%cmp = icmp eq i8 %x, 0
%cmp2 = icmp ne i8 %x, 0
%and = and i1 %cmp, %c
%or = or i1 %and, %cmp2
ret i1 %or
}
define i1 @and_implied(i8 %x, i1 %c) {
; CHECK-LABEL: @and_implied(
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp ne i8 %x, 0
%cmp2 = icmp eq i8 %x, 1
%or = or i1 %cmp, %c
%and = and i1 %or, %cmp2
ret i1 %and
}
define i1 @and_implied_comm1(i8 %x, i1 %c) {
; CHECK-LABEL: @and_implied_comm1(
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp ne i8 %x, 0
%cmp2 = icmp eq i8 %x, 1
%or = or i1 %cmp, %c
%and = and i1 %cmp2, %or
ret i1 %and
}
define i1 @and_implied_comm2(i8 %x, i1 %c) {
; CHECK-LABEL: @and_implied_comm2(
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp ne i8 %x, 0
%cmp2 = icmp eq i8 %x, 1
%or = or i1 %c, %cmp
%and = and i1 %or, %cmp2
ret i1 %and
}
define i1 @and_implied_comm3(i8 %x, i1 %c) {
; CHECK-LABEL: @and_implied_comm3(
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp ne i8 %x, 0
%cmp2 = icmp eq i8 %x, 1
%or = or i1 %c, %cmp
%and = and i1 %cmp2, %or
ret i1 %and
}
define i1 @and_not_implied(i8 %x, i1 %c) {
; CHECK-LABEL: @and_not_implied(
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[X:%.*]], 0
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[X]], 0
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP]], [[C:%.*]]
; CHECK-NEXT: [[AND:%.*]] = and i1 [[OR]], [[CMP2]]
; CHECK-NEXT: ret i1 [[AND]]
;
%cmp = icmp ne i8 %x, 0
%cmp2 = icmp eq i8 %x, 0
%or = or i1 %cmp, %c
%and = and i1 %or, %cmp2
ret i1 %and
}
define i1 @uaddo_and(i64 %a, i64 %b){
; CHECK-LABEL: @uaddo_and(
; CHECK-NEXT: [[S:%.*]] = add i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[COND_A:%.*]] = icmp uge i64 [[S]], [[A]]
; CHECK-NEXT: ret i1 [[COND_A]]
;
%s = add i64 %a, %b
%cond_a = icmp uge i64 %s, %a
%cond_b = icmp uge i64 %s, %b
%cond = and i1 %cond_a, %cond_b
ret i1 %cond
}
define i1 @uaddo_and_commuted1(i64 %a, i64 %b){
; CHECK-LABEL: @uaddo_and_commuted1(
; CHECK-NEXT: [[S:%.*]] = add i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[COND_A:%.*]] = icmp ule i64 [[A]], [[S]]
; CHECK-NEXT: ret i1 [[COND_A]]
;
%s = add i64 %a, %b
%cond_a = icmp ule i64 %a, %s
%cond_b = icmp uge i64 %s, %b
%cond = and i1 %cond_a, %cond_b
ret i1 %cond
}
define i1 @uaddo_and_commuted2(i64 %a, i64 %b){
; CHECK-LABEL: @uaddo_and_commuted2(
; CHECK-NEXT: [[S:%.*]] = add i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[COND_A:%.*]] = icmp uge i64 [[S]], [[A]]
; CHECK-NEXT: ret i1 [[COND_A]]
;
%s = add i64 %a, %b
%cond_a = icmp uge i64 %s, %a
%cond_b = icmp ule i64 %b, %s
%cond = and i1 %cond_a, %cond_b
ret i1 %cond
}
define i1 @uaddo_and_commuted3(i64 %a, i64 %b){
; CHECK-LABEL: @uaddo_and_commuted3(
; CHECK-NEXT: [[S:%.*]] = add i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[COND_A:%.*]] = icmp ule i64 [[A]], [[S]]
; CHECK-NEXT: ret i1 [[COND_A]]
;
%s = add i64 %a, %b
%cond_a = icmp ule i64 %a, %s
%cond_b = icmp ule i64 %b, %s
%cond = and i1 %cond_a, %cond_b
ret i1 %cond
}
define i1 @uaddo_or(i64 %a, i64 %b){
; CHECK-LABEL: @uaddo_or(
; CHECK-NEXT: [[S:%.*]] = add i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[COND_A:%.*]] = icmp ult i64 [[S]], [[A]]
; CHECK-NEXT: ret i1 [[COND_A]]
;
%s = add i64 %a, %b
%cond_a = icmp ult i64 %s, %a
%cond_b = icmp ult i64 %s, %b
%cond = or i1 %cond_a, %cond_b
ret i1 %cond
}
define i1 @uaddo_or_commuted1(i64 %a, i64 %b){
; CHECK-LABEL: @uaddo_or_commuted1(
; CHECK-NEXT: [[S:%.*]] = add i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[COND_A:%.*]] = icmp ugt i64 [[A]], [[S]]
; CHECK-NEXT: ret i1 [[COND_A]]
;
%s = add i64 %a, %b
%cond_a = icmp ugt i64 %a, %s
%cond_b = icmp ult i64 %s, %b
%cond = or i1 %cond_a, %cond_b
ret i1 %cond
}
define i1 @uaddo_or_commuted2(i64 %a, i64 %b){
; CHECK-LABEL: @uaddo_or_commuted2(
; CHECK-NEXT: [[S:%.*]] = add i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[COND_A:%.*]] = icmp ult i64 [[S]], [[A]]
; CHECK-NEXT: ret i1 [[COND_A]]
;
%s = add i64 %a, %b
%cond_a = icmp ult i64 %s, %a
%cond_b = icmp ugt i64 %b, %s
%cond = or i1 %cond_a, %cond_b
ret i1 %cond
}
define i1 @uaddo_or_commuted3(i64 %a, i64 %b){
; CHECK-LABEL: @uaddo_or_commuted3(
; CHECK-NEXT: [[S:%.*]] = add i64 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[COND_A:%.*]] = icmp ugt i64 [[A]], [[S]]
; CHECK-NEXT: ret i1 [[COND_A]]
;
%s = add i64 %a, %b
%cond_a = icmp ugt i64 %a, %s
%cond_b = icmp ugt i64 %b, %s
%cond = or i1 %cond_a, %cond_b
ret i1 %cond
}
define i1 @pr69050(i32 %arg, i32 %arg1) {
; CHECK-LABEL: @pr69050(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[ARG:%.*]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[XOR]], [[ARG1:%.*]]
; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[AND]], 0
; CHECK-NEXT: ret i1 [[ICMP]]
;
%xor = xor i32 %arg, -1
%and = and i32 %xor, %arg1
%icmp = icmp ne i32 %and, 0
%icmp2 = icmp ne i32 %arg, -1
%and3 = and i1 %icmp2, %icmp
ret i1 %and3
}
define i1 @pr69091(i32 %arg, i32 %arg1) {
; CHECK-LABEL: @pr69091(
; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[ARG:%.*]], -1
; CHECK-NEXT: ret i1 [[ICMP]]
;
%icmp = icmp ne i32 %arg, -1
%add = add i32 %arg, 1
%mul = mul i32 %add, %arg1
%icmp2 = icmp ne i32 %mul, 0
%or = or i1 %icmp, %icmp2
ret i1 %or
}
declare void @barrier()
define i1 @or_icmp_implies_ub(i32 %x) {
; CHECK-LABEL: @or_icmp_implies_ub(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: call void @barrier()
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp1 = icmp ne i32 %x, 0
call void @barrier()
%div = udiv i32 2147483647, %x
%cmp2 = icmp ugt i32 %x, %div
%or = or i1 %cmp1, %cmp2
ret i1 %or
}
define i1 @and_icmp_implies_ub(i32 %x) {
; CHECK-LABEL: @and_icmp_implies_ub(
; CHECK-NEXT: call void @barrier()
; CHECK-NEXT: ret i1 false
;
%cmp1 = icmp eq i32 %x, 0
call void @barrier()
%div = udiv i32 2147483647, %x
%cmp2 = icmp ugt i32 %x, %div
%and = and i1 %cmp1, %cmp2
ret i1 %and
}
define i1 @or_icmp_implies_poison(i32 %x) {
; CHECK-LABEL: @or_icmp_implies_poison(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X:%.*]], 32
; CHECK-NEXT: [[SHL:%.*]] = shl i32 1, [[X]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[X]], [[SHL]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: ret i1 [[OR]]
;
%cmp1 = icmp ne i32 %x, 32
%shl = shl i32 1, %x
%cmp2 = icmp ugt i32 %x, %shl
%or = or i1 %cmp1, %cmp2
ret i1 %or
}
define i1 @and_icmp_implies_poison(i32 %x) {
; CHECK-LABEL: @and_icmp_implies_poison(
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[X:%.*]], 32
; CHECK-NEXT: [[SHL:%.*]] = shl i32 1, [[X]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[X]], [[SHL]]
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: ret i1 [[AND]]
;
%cmp1 = icmp eq i32 %x, 32
%shl = shl i32 1, %x
%cmp2 = icmp ugt i32 %x, %shl
%and = and i1 %cmp1, %cmp2
ret i1 %and
}
define i1 @and_is_constant(ptr %arg, ptr %arg2) {
; CHECK-LABEL: @and_is_constant(
; CHECK-NEXT: [[ICMP:%.*]] = icmp eq ptr [[ARG:%.*]], [[ARG2:%.*]]
; CHECK-NEXT: [[CALL:%.*]] = call i1 @llvm.is.constant.i1(i1 [[ICMP]])
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CALL]], [[ICMP]]
; CHECK-NEXT: ret i1 [[AND]]
;
%icmp = icmp eq ptr %arg, %arg2
%call = call i1 @llvm.is.constant.i1(i1 %icmp)
%and = and i1 %call, %icmp
ret i1 %and
}
define i1 @pr98753(i32 noundef %x, i32 %y) {
; CHECK-LABEL: @pr98753(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i32 [[Y:%.*]], i32 undef
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[SEL]], 0
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: ret i1 [[AND]]
;
%cmp1 = icmp ne i32 %x, 0
%sel = select i1 %cmp1, i32 %y, i32 undef
%cmp2 = icmp sgt i32 %sel, 0
%and = and i1 %cmp1, %cmp2
ret i1 %and
}
declare i1 @llvm.is.constant.i1(i1)