Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8622,6 +8622,10 @@ llvm::isImpliedCondition(const Value *LHS, CmpInst::Predicate RHSPred,
assert(LHS->getType()->isIntOrIntVectorTy(1) &&
"Expected integer type only!");

// Match not
if (match(LHS, m_Not(m_Value(LHS))))
LHSIsTrue = !LHSIsTrue;

// Both LHS and RHS are icmps.
const ICmpInst *LHSCmp = dyn_cast<ICmpInst>(LHS);
if (LHSCmp)
Expand All @@ -8648,10 +8652,21 @@ std::optional<bool> llvm::isImpliedCondition(const Value *LHS, const Value *RHS,
if (LHS == RHS)
return LHSIsTrue;

if (const ICmpInst *RHSCmp = dyn_cast<ICmpInst>(RHS))
return isImpliedCondition(LHS, RHSCmp->getPredicate(),
RHSCmp->getOperand(0), RHSCmp->getOperand(1), DL,
LHSIsTrue, Depth);
// Match not
bool InvertRHS = false;
if (match(RHS, m_Not(m_Value(RHS)))) {
if (LHS == RHS)
return !LHSIsTrue;
InvertRHS = true;
}

if (const ICmpInst *RHSCmp = dyn_cast<ICmpInst>(RHS)) {
if (auto Implied = isImpliedCondition(
LHS, RHSCmp->getPredicate(), RHSCmp->getOperand(0),
RHSCmp->getOperand(1), DL, LHSIsTrue, Depth))
return InvertRHS ? !*Implied : *Implied;
return std::nullopt;
}

if (Depth == MaxAnalysisRecursionDepth)
return std::nullopt;
Expand All @@ -8663,21 +8678,21 @@ std::optional<bool> llvm::isImpliedCondition(const Value *LHS, const Value *RHS,
if (std::optional<bool> Imp =
isImpliedCondition(LHS, RHS1, DL, LHSIsTrue, Depth + 1))
if (*Imp == true)
return true;
return !InvertRHS;
Copy link
Member Author

@dtcxzyw dtcxzyw Mar 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it looks incorrect :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its confusing enough I think it deserves a comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NB: I don't any of your tests actually go through this control flow

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a heads up, im working on a follow up patch to this to handle more of the and/or cases + more relationships in general (LMK if you are so we can avoid duplicating work).

if (std::optional<bool> Imp =
isImpliedCondition(LHS, RHS2, DL, LHSIsTrue, Depth + 1))
if (*Imp == true)
return true;
return !InvertRHS;
}
if (match(RHS, m_LogicalAnd(m_Value(RHS1), m_Value(RHS2)))) {
if (std::optional<bool> Imp =
isImpliedCondition(LHS, RHS1, DL, LHSIsTrue, Depth + 1))
if (*Imp == false)
return false;
return InvertRHS;
if (std::optional<bool> Imp =
isImpliedCondition(LHS, RHS2, DL, LHSIsTrue, Depth + 1))
if (*Imp == false)
return false;
return InvertRHS;
}

return std::nullopt;
Expand Down
69 changes: 69 additions & 0 deletions llvm/test/Transforms/InstCombine/and-or-implied-cond-not.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt < %s -passes=instcombine -S | FileCheck %s

define i1 @test_imply_not1(i32 %depth) {
; CHECK-LABEL: define i1 @test_imply_not1(
; CHECK-SAME: i32 [[DEPTH:%.*]]) {
; CHECK-NEXT: [[CMP1_NOT1:%.*]] = icmp eq i32 [[DEPTH]], 16
; CHECK-NEXT: call void @use(i1 [[CMP1_NOT1]])
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[DEPTH]], 8
; CHECK-NEXT: call void @use(i1 [[CMP2]])
; CHECK-NEXT: br i1 [[CMP1_NOT1]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @func1()
; CHECK-NEXT: unreachable
; CHECK: if.else:
; CHECK-NEXT: call void @func2()
; CHECK-NEXT: unreachable
;
%cmp1 = icmp eq i32 %depth, 16
call void @use(i1 %cmp1)
%cmp2 = icmp slt i32 %depth, 8
call void @use(i1 %cmp2)
%cmp.not = xor i1 %cmp1, true
%brmerge = or i1 %cmp2, %cmp.not
br i1 %brmerge, label %if.then, label %if.else
if.then:
call void @func1()
unreachable

if.else:
call void @func2()
unreachable
}

define i1 @test_imply_not2(i32 %a, i1 %cmp2) {
; CHECK-LABEL: define i1 @test_imply_not2(
; CHECK-SAME: i32 [[A:%.*]], i1 [[CMP2:%.*]]) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A]], 0
; CHECK-NEXT: [[BRMERGE:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
; CHECK-NEXT: ret i1 [[BRMERGE]]
;
%cmp1 = icmp eq i32 %a, 0
%or.cond = select i1 %cmp1, i1 %cmp2, i1 false
%cmp.not = xor i1 %cmp1, true
%brmerge = or i1 %or.cond, %cmp.not
ret i1 %brmerge
}

define i1 @test_imply_not3(i32 %a, i32 %b, i1 %cond) {
; CHECK-LABEL: define i1 @test_imply_not3(
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i1 [[COND:%.*]]) {
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], [[B]]
; CHECK-NEXT: call void @use(i1 [[CMP1]])
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP2]], i1 [[COND]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%cmp1 = icmp eq i32 %a, %b
call void @use(i1 %cmp1)
%cmp2 = icmp slt i32 %a, %b
%cmp.not = xor i1 %cmp1, true
%sel = select i1 %cmp.not, i1 %cond, i1 false
%and = and i1 %cmp2, %sel
ret i1 %and
}

declare void @func1()
declare void @func2()
declare void @use(i1)
3 changes: 1 addition & 2 deletions llvm/test/Transforms/LoopVectorize/reduction-inloop.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1354,9 +1354,8 @@ define i32 @predicated_or_dominates_reduction(ptr %b) {
; CHECK: pred.load.continue6:
; CHECK-NEXT: [[TMP43:%.*]] = phi <4 x i32> [ [[TMP37]], [[PRED_LOAD_CONTINUE4]] ], [ [[TMP42]], [[PRED_LOAD_IF5]] ]
; CHECK-NEXT: [[TMP44:%.*]] = icmp ne <4 x i32> [[TMP43]], zeroinitializer
; CHECK-NEXT: [[TMP45:%.*]] = select <4 x i1> [[TMP19]], <4 x i1> [[TMP44]], <4 x i1> zeroinitializer
; CHECK-NEXT: [[TMP46:%.*]] = xor <4 x i1> [[TMP19]], <i1 true, i1 true, i1 true, i1 true>
; CHECK-NEXT: [[TMP47:%.*]] = or <4 x i1> [[TMP45]], [[TMP46]]
; CHECK-NEXT: [[TMP47:%.*]] = select <4 x i1> [[TMP46]], <4 x i1> <i1 true, i1 true, i1 true, i1 true>, <4 x i1> [[TMP44]]
; CHECK-NEXT: [[TMP48:%.*]] = bitcast <4 x i1> [[TMP47]] to i4
; CHECK-NEXT: [[TMP49:%.*]] = call i4 @llvm.ctpop.i4(i4 [[TMP48]]), !range [[RNG42:![0-9]+]]
; CHECK-NEXT: [[TMP50:%.*]] = zext nneg i4 [[TMP49]] to i32
Expand Down