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.
350 lines
9.4 KiB
LLVM
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)
|