Skip to content

Commit

Permalink
[InstCombine] Reduce nested logical operator if poison is implied (ll…
Browse files Browse the repository at this point in the history
…vm#86823)

Fixes llvm#76623
Alive2 proof: https://alive2.llvm.org/ce/z/gX6znJ (I'm not sure how to
write a proof for such transform, maybe there are mistakes)

In most cases, `icmp(a, C1) && (other_cond && icmp(a, C2))` will be
reduced to `icmp(a, C1) & (other_cond && icmp(a, C2))`, since latter
icmp always implies the poison of the former. After reduction, it's
easier to simplify the icmp chain.
Similarly, this patch does the same thing for `(A && B) && C --> A && (B
& C)`. Maybe we could constraint such reduction only on icmps if there
is regression in benchmarks.
  • Loading branch information
XChy authored Apr 10, 2024
1 parent 3d985a6 commit 313a33b
Show file tree
Hide file tree
Showing 3 changed files with 292 additions and 0 deletions.
14 changes: 14 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3091,6 +3091,13 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
return BinaryOperator::CreateOr(CondVal, FalseVal);
}

if (match(CondVal, m_OneUse(m_Select(m_Value(A), m_One(), m_Value(B)))) &&
impliesPoison(FalseVal, B)) {
// (A || B) || C --> A || (B | C)
return replaceInstUsesWith(
SI, Builder.CreateLogicalOr(A, Builder.CreateOr(B, FalseVal)));
}

if (auto *LHS = dyn_cast<FCmpInst>(CondVal))
if (auto *RHS = dyn_cast<FCmpInst>(FalseVal))
if (Value *V = foldLogicOfFCmps(LHS, RHS, /*IsAnd*/ false,
Expand Down Expand Up @@ -3132,6 +3139,13 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
return BinaryOperator::CreateAnd(CondVal, TrueVal);
}

if (match(CondVal, m_OneUse(m_Select(m_Value(A), m_Value(B), m_Zero()))) &&
impliesPoison(TrueVal, B)) {
// (A && B) && C --> A && (B & C)
return replaceInstUsesWith(
SI, Builder.CreateLogicalAnd(A, Builder.CreateAnd(B, TrueVal)));
}

if (auto *LHS = dyn_cast<FCmpInst>(CondVal))
if (auto *RHS = dyn_cast<FCmpInst>(TrueVal))
if (Value *V = foldLogicOfFCmps(LHS, RHS, /*IsAnd*/ true,
Expand Down
60 changes: 60 additions & 0 deletions llvm/test/Transforms/InstCombine/and-or-icmps.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3038,3 +3038,63 @@ define i32 @icmp_slt_0_or_icmp_add_1_sge_100_i32_fail(i32 %x) {
%D = or i32 %C, %B
ret i32 %D
}

define i1 @logical_and_icmps1(i32 %a, i1 %other_cond) {
; CHECK-LABEL: @logical_and_icmps1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[A:%.*]], 10086
; CHECK-NEXT: [[RET2:%.*]] = select i1 [[RET1:%.*]], i1 [[CMP3]], i1 false
; CHECK-NEXT: ret i1 [[RET2]]
;
entry:
%cmp1 = icmp sgt i32 %a, -1
%logical_and = select i1 %other_cond, i1 %cmp1, i1 false
%cmp2 = icmp slt i32 %a, 10086
%ret = select i1 %logical_and, i1 %cmp2, i1 false
ret i1 %ret
}

define i1 @logical_and_icmps2(i32 %a, i1 %other_cond) {
; CHECK-LABEL: @logical_and_icmps2(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i1 false
;
entry:
%cmp1 = icmp slt i32 %a, -1
%logical_and = select i1 %other_cond, i1 %cmp1, i1 false
%cmp2 = icmp eq i32 %a, 10086
%ret = select i1 %logical_and, i1 %cmp2, i1 false
ret i1 %ret
}

define <4 x i1> @logical_and_icmps_vec1(<4 x i32> %a, <4 x i1> %other_cond) {
; CHECK-LABEL: @logical_and_icmps_vec1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP3:%.*]] = icmp ult <4 x i32> [[A:%.*]], <i32 10086, i32 10086, i32 10086, i32 10086>
; CHECK-NEXT: [[RET2:%.*]] = select <4 x i1> [[RET1:%.*]], <4 x i1> [[CMP3]], <4 x i1> zeroinitializer
; CHECK-NEXT: ret <4 x i1> [[RET2]]
;
entry:
%cmp1 = icmp sgt <4 x i32> %a, <i32 -1, i32 -1, i32 -1, i32 -1 >
%logical_and = select <4 x i1> %other_cond, <4 x i1> %cmp1, <4 x i1> zeroinitializer
%cmp2 = icmp slt <4 x i32> %a, <i32 10086, i32 10086, i32 10086, i32 10086 >
%ret = select <4 x i1> %logical_and, <4 x i1> %cmp2, <4 x i1> zeroinitializer
ret <4 x i1> %ret
}

define i1 @logical_and_icmps_fail1(i32 %a, i32 %b, i1 %other_cond) {
; CHECK-LABEL: @logical_and_icmps_fail1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A:%.*]], -1
; CHECK-NEXT: [[LOGICAL_AND:%.*]] = select i1 [[OTHER_COND:%.*]], i1 [[CMP1]], i1 false
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B:%.*]]
; CHECK-NEXT: [[RET:%.*]] = select i1 [[LOGICAL_AND]], i1 [[CMP2]], i1 false
; CHECK-NEXT: ret i1 [[RET]]
;
entry:
%cmp1 = icmp sgt i32 %a, -1
%logical_and = select i1 %other_cond, i1 %cmp1, i1 false
%cmp2 = icmp slt i32 %a, %b
%ret = select i1 %logical_and, i1 %cmp2, i1 false
ret i1 %ret
}
218 changes: 218 additions & 0 deletions llvm/test/Transforms/InstCombine/logical-select.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1303,3 +1303,221 @@ define i1 @logical_or_and_with_common_not_op_variant5(i1 %a) {
%or = select i1 %a, i1 true, i1 %and
ret i1 %or
}

define i1 @reduce_logical_and1(i1 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @reduce_logical_and1(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP1]], [[CMP]]
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, %b
%and1 = select i1 %a, i1 %cmp1, i1 false
%and2 = select i1 %and1, i1 %cmp, i1 false
ret i1 %and2
}

define i1 @reduce_logical_and2(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: @reduce_logical_and2(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[C:%.*]], true
; CHECK-NEXT: [[B:%.*]] = and i1 [[TMP0]], [[B1:%.*]]
; CHECK-NEXT: [[AND3:%.*]] = select i1 [[AND2:%.*]], i1 [[B]], i1 false
; CHECK-NEXT: ret i1 [[AND3]]
;
bb:
%or = xor i1 %c, %b
%and1 = select i1 %a, i1 %or, i1 false
%and2 = select i1 %and1, i1 %b, i1 false
ret i1 %and2
}

define i1 @reduce_logical_and3(i1 %a, i32 %b, i32 noundef %c) {
; CHECK-LABEL: @reduce_logical_and3(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP]], [[CMP1]]
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, %b
%and1 = select i1 %a, i1 %cmp, i1 false
%and2 = select i1 %and1, i1 %cmp1, i1 false
ret i1 %and2
}

define i1 @reduce_logical_or1(i1 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @reduce_logical_or1(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP1]], [[CMP]]
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, %b
%and1 = select i1 %a, i1 true, i1 %cmp1
%and2 = select i1 %and1, i1 true, i1 %cmp
ret i1 %and2
}

define i1 @reduce_logical_or2(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: @reduce_logical_or2(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[B:%.*]] = or i1 [[C:%.*]], [[B1:%.*]]
; CHECK-NEXT: [[AND3:%.*]] = select i1 [[AND2:%.*]], i1 true, i1 [[B]]
; CHECK-NEXT: ret i1 [[AND3]]
;
bb:
%or = xor i1 %c, %b
%and1 = select i1 %a, i1 true, i1 %or
%and2 = select i1 %and1, i1 true, i1 %b
ret i1 %and2
}

define i1 @reduce_logical_or3(i1 %a, i32 %b, i32 noundef %c) {
; CHECK-LABEL: @reduce_logical_or3(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP]], [[CMP1]]
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, %b
%and1 = select i1 %a, i1 true, i1 %cmp
%and2 = select i1 %and1, i1 true, i1 %cmp1
ret i1 %and2
}

define i1 @reduce_logical_and_fail1(i1 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @reduce_logical_and_fail1(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, %b
%and1 = select i1 %a, i1 %cmp, i1 false
%and2 = select i1 %and1, i1 %cmp1, i1 false
ret i1 %and2
}

define i1 @reduce_logical_and_fail2(i1 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @reduce_logical_and_fail2(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, 7
%and1 = select i1 %a, i1 %cmp, i1 false
%and2 = select i1 %and1, i1 %cmp1, i1 false
ret i1 %and2
}

define i1 @reduce_logical_or_fail1(i1 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @reduce_logical_or_fail1(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, %b
%and1 = select i1 %a, i1 true, i1 %cmp
%and2 = select i1 %and1, i1 true, i1 %cmp1
ret i1 %and2
}

define i1 @reduce_logical_or_fail2(i1 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @reduce_logical_or_fail2(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, 7
%and1 = select i1 %a, i1 true, i1 %cmp
%and2 = select i1 %and1, i1 true, i1 %cmp1
ret i1 %and2
}

define i1 @reduce_logical_and_multiuse(i1 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @reduce_logical_and_multiuse(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP1]], i1 false
; CHECK-NEXT: call void @use1(i1 [[AND1]])
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP]], i1 false
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, %b
%and1 = select i1 %a, i1 %cmp1, i1 false
call void @use1(i1 %and1)
%and2 = select i1 %and1, i1 %cmp, i1 false
ret i1 %and2
}

define i1 @reduce_bitwise_and1(i1 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @reduce_bitwise_and1(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[AND1:%.*]] = or i1 [[CMP1]], [[A:%.*]]
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[CMP]]
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, %b
%and1 = or i1 %a, %cmp1
%and2 = select i1 %and1, i1 %cmp, i1 false
ret i1 %and2
}

define i1 @reduce_bitwise_and2(i1 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @reduce_bitwise_and2(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP1]], i1 false
; CHECK-NEXT: [[AND2:%.*]] = or i1 [[AND1]], [[CMP]]
; CHECK-NEXT: ret i1 [[AND2]]
;
bb:
%cmp = icmp slt i32 %b, 6
%cmp1 = icmp sgt i32 %c, %b
%and1 = select i1 %a, i1 %cmp1, i1 false
%and2 = or i1 %and1, %cmp
ret i1 %and2
}

0 comments on commit 313a33b

Please sign in to comment.