From e48a70ea4d633a84748ea57b287b092d1d7fa7a0 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 21 Nov 2024 14:08:42 +0800 Subject: [PATCH 1/6] [ConstraintElim] Add pre-commit tests. NFC. --- .../ConstraintElimination/unreachable-bb.ll | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll diff --git a/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll b/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll new file mode 100644 index 0000000000000..4e65f5ad385b8 --- /dev/null +++ b/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll @@ -0,0 +1,36 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p constraint-elimination -S %s | FileCheck %s + +define void @f(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) { +; CHECK-LABEL: define void @f( +; CHECK-SAME: i32 noundef [[V0:%.*]], i32 noundef [[V1:%.*]], i32 noundef [[V2:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[V0]], [[V1]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[V1]], [[V2]] +; CHECK-NEXT: [[AND1:%.*]] = and i1 [[CMP0]], [[CMP1]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V0]], [[V2]] +; CHECK-NEXT: [[AND2:%.*]] = and i1 [[CMP2]], [[AND1]] +; CHECK-NEXT: br i1 [[AND2]], label %[[IF_THEN:.*]], label %[[RETURN:.*]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: call void @side_effect() +; CHECK-NEXT: br label %[[RETURN]] +; CHECK: [[RETURN]]: +; CHECK-NEXT: ret void +; +entry: + %cmp0 = icmp sge i32 %v0, %v1 + %cmp1 = icmp sge i32 %v1, %v2 + %and1 = and i1 %cmp0, %cmp1 + %cmp2 = icmp slt i32 %v0, %v2 + %and2 = and i1 %cmp2, %and1 + br i1 %and2, label %if.then, label %return + +if.then: + call void @side_effect() + br label %return + +return: + ret void +} + +declare void @side_effect() From d5a87434037fb898cebe34f24acee3708036768b Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 21 Nov 2024 15:25:56 +0800 Subject: [PATCH 2/6] [ConstraintElim] Extend `checkOrAndOpImpliedByOther` to handle and/or expr trees --- .../Scalar/ConstraintElimination.cpp | 31 +++++++++++++------ .../Transforms/ConstraintElimination/or.ll | 2 +- .../ConstraintElimination/unreachable-bb.ll | 2 +- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index d03e3a0570cd3..45cb38ce042f0 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1511,18 +1511,29 @@ static bool checkOrAndOpImpliedByOther( if (OtherOpIdx != 0 && isa(JoinOp)) return false; - if (!match(JoinOp->getOperand(OtherOpIdx), - m_ICmp(Pred, m_Value(A), m_Value(B)))) - return false; - - // For OR, check if the negated condition implies CmpToCheck. - bool IsOr = match(JoinOp, m_LogicalOr()); - if (IsOr) - Pred = CmpInst::getInversePredicate(Pred); - // Optimistically add fact from first condition. unsigned OldSize = DFSInStack.size(); - Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); + // For OR, check if the negated condition implies CmpToCheck. + bool IsOr = match(JoinOp, m_LogicalOr()); + SmallVector Worklist({JoinOp->getOperand(OtherOpIdx)}); + while (!Worklist.empty()) { + Value *Val = Worklist.pop_back_val(); + Value *LHS, *RHS; + ICmpInst::Predicate Pred; + if (match(Val, m_ICmp(Pred, m_Value(LHS), m_Value(RHS)))) { + if (IsOr) + Pred = CmpInst::getInversePredicate(Pred); + Info.addFact(Pred, LHS, RHS, CB.NumIn, CB.NumOut, DFSInStack); + continue; + } + if (IsOr ? match(Val, m_LogicalOr(m_Value(LHS), m_Value(RHS))) + : match(Val, m_LogicalAnd(m_Value(LHS), m_Value(RHS)))) { + Worklist.push_back(LHS); + Worklist.push_back(RHS); + continue; + } + return false; + } if (OldSize == DFSInStack.size()) return false; diff --git a/llvm/test/Transforms/ConstraintElimination/or.ll b/llvm/test/Transforms/ConstraintElimination/or.ll index 01b8ca973efa5..b401d6f181369 100644 --- a/llvm/test/Transforms/ConstraintElimination/or.ll +++ b/llvm/test/Transforms/ConstraintElimination/or.ll @@ -124,7 +124,7 @@ define i1 @test_or_chain_ule_1(i4 %x, i4 %y, i4 %z, i4 %a, i4 %b) { ; CHECK-NEXT: [[C_3:%.*]] = icmp ule i4 2, [[X]] ; CHECK-NEXT: [[C_4:%.*]] = icmp ule i4 2, [[A:%.*]] ; CHECK-NEXT: [[OR_1:%.*]] = or i1 [[C_1]], [[C_2]] -; CHECK-NEXT: [[OR_2:%.*]] = or i1 [[OR_1]], [[C_3]] +; CHECK-NEXT: [[OR_2:%.*]] = or i1 [[OR_1]], true ; CHECK-NEXT: [[OR_3:%.*]] = or i1 [[C_4]], [[OR_2]] ; CHECK-NEXT: br i1 [[OR_3]], label [[BB1:%.*]], label [[EXIT:%.*]] ; CHECK: bb1: diff --git a/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll b/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll index 4e65f5ad385b8..a3cea2e3b7889 100644 --- a/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll +++ b/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll @@ -9,7 +9,7 @@ define void @f(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) { ; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[V1]], [[V2]] ; CHECK-NEXT: [[AND1:%.*]] = and i1 [[CMP0]], [[CMP1]] ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V0]], [[V2]] -; CHECK-NEXT: [[AND2:%.*]] = and i1 [[CMP2]], [[AND1]] +; CHECK-NEXT: [[AND2:%.*]] = and i1 false, [[AND1]] ; CHECK-NEXT: br i1 [[AND2]], label %[[IF_THEN:.*]], label %[[RETURN:.*]] ; CHECK: [[IF_THEN]]: ; CHECK-NEXT: call void @side_effect() From a90be3ac98e38415894bea1f2e68c475954b6ec3 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 21 Nov 2024 16:34:47 +0800 Subject: [PATCH 3/6] [ConstraintElim] Fix miscompilation --- .../Scalar/ConstraintElimination.cpp | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 45cb38ce042f0..31e9691ecde4c 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1498,9 +1498,6 @@ static bool checkOrAndOpImpliedByOther( FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule, SmallVectorImpl &ReproducerCondStack, SmallVectorImpl &DFSInStack) { - - CmpInst::Predicate Pred; - Value *A, *B; Instruction *JoinOp = CB.getContextInst(); CmpInst *CmpToCheck = cast(CB.getInstructionToSimplify()); unsigned OtherOpIdx = JoinOp->getOperand(0) == CmpToCheck ? 1 : 0; @@ -1513,6 +1510,14 @@ static bool checkOrAndOpImpliedByOther( // Optimistically add fact from first condition. unsigned OldSize = DFSInStack.size(); + auto InfoRestorer = make_scope_exit([&]() { + // Remove entries again. + while (OldSize < DFSInStack.size()) { + StackEntry E = DFSInStack.back(); + removeEntryFromStack(E, Info, ReproducerModule, ReproducerCondStack, + DFSInStack); + } + }); // For OR, check if the negated condition implies CmpToCheck. bool IsOr = match(JoinOp, m_LogicalOr()); SmallVector Worklist({JoinOp->getOperand(OtherOpIdx)}); @@ -1537,7 +1542,6 @@ static bool checkOrAndOpImpliedByOther( if (OldSize == DFSInStack.size()) return false; - bool Changed = false; // Check if the second condition can be simplified now. if (auto ImpliedCondition = checkCondition(CmpToCheck->getPredicate(), CmpToCheck->getOperand(0), @@ -1551,16 +1555,10 @@ static bool checkOrAndOpImpliedByOther( 1 - OtherOpIdx, ConstantInt::getBool(JoinOp->getType(), *ImpliedCondition)); - Changed = true; + return true; } - // Remove entries again. - while (OldSize < DFSInStack.size()) { - StackEntry E = DFSInStack.back(); - removeEntryFromStack(E, Info, ReproducerModule, ReproducerCondStack, - DFSInStack); - } - return Changed; + return false; } void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B, From cddc2c37f364e0568c425410c376d7d2d29e33b5 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 21 Nov 2024 21:13:04 +0800 Subject: [PATCH 4/6] [ConstraintElim] Address review comments. NFC. --- .../Scalar/ConstraintElimination.cpp | 5 +- .../and-implied-by-operands.ll | 188 ++++++++++++++++++ .../ConstraintElimination/unreachable-bb.ll | 36 ---- 3 files changed, 191 insertions(+), 38 deletions(-) delete mode 100644 llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 31e9691ecde4c..64c0d3fe6a8dc 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1508,7 +1508,6 @@ static bool checkOrAndOpImpliedByOther( if (OtherOpIdx != 0 && isa(JoinOp)) return false; - // Optimistically add fact from first condition. unsigned OldSize = DFSInStack.size(); auto InfoRestorer = make_scope_exit([&]() { // Remove entries again. @@ -1518,16 +1517,18 @@ static bool checkOrAndOpImpliedByOther( DFSInStack); } }); - // For OR, check if the negated condition implies CmpToCheck. bool IsOr = match(JoinOp, m_LogicalOr()); SmallVector Worklist({JoinOp->getOperand(OtherOpIdx)}); + // Do a traversal of the AND/OR tree to add facts from leaf compares. while (!Worklist.empty()) { Value *Val = Worklist.pop_back_val(); Value *LHS, *RHS; ICmpInst::Predicate Pred; if (match(Val, m_ICmp(Pred, m_Value(LHS), m_Value(RHS)))) { + // For OR, check if the negated condition implies CmpToCheck. if (IsOr) Pred = CmpInst::getInversePredicate(Pred); + // Optimistically add fact from the other compares in the AND/OR. Info.addFact(Pred, LHS, RHS, CB.NumIn, CB.NumOut, DFSInStack); continue; } diff --git a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll index 6bbc73c9c996c..9b798ea255c0e 100644 --- a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll +++ b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll @@ -497,4 +497,192 @@ entry: ret i1 %and } +define void @and_tree_second_implies_first(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) { +; CHECK-LABEL: @and_tree_second_implies_first( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[V0:%.*]], [[V1:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[V1]], [[V2:%.*]] +; CHECK-NEXT: [[AND1:%.*]] = and i1 [[CMP0]], [[CMP1]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V0]], [[V2]] +; CHECK-NEXT: [[AND2:%.*]] = and i1 false, [[AND1]] +; CHECK-NEXT: br i1 [[AND2]], label [[IF_THEN:%.*]], label [[RETURN:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @side_effect() +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: ret void +; +entry: + %cmp0 = icmp sge i32 %v0, %v1 + %cmp1 = icmp sge i32 %v1, %v2 + %and1 = and i1 %cmp0, %cmp1 + %cmp2 = icmp slt i32 %v0, %v2 + %and2 = and i1 %cmp2, %and1 + br i1 %and2, label %if.then, label %return + +if.then: + call void @side_effect() + br label %return + +return: + ret void +} + +define void @and_tree_second_implies_first_perm1(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) { +; CHECK-LABEL: @and_tree_second_implies_first_perm1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[V0:%.*]], [[V1:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[V1]], [[V2:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V0]], [[V2]] +; CHECK-NEXT: [[AND1:%.*]] = and i1 [[CMP2]], [[CMP1]] +; CHECK-NEXT: [[AND2:%.*]] = and i1 false, [[AND1]] +; CHECK-NEXT: br i1 [[AND2]], label [[IF_THEN:%.*]], label [[RETURN:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @side_effect() +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: ret void +; +entry: + %cmp0 = icmp sge i32 %v0, %v1 + %cmp1 = icmp sge i32 %v1, %v2 + %cmp2 = icmp slt i32 %v0, %v2 + %and1 = and i1 %cmp2, %cmp1 + %and2 = and i1 %cmp0, %and1 + br i1 %and2, label %if.then, label %return + +if.then: + call void @side_effect() + br label %return + +return: + ret void +} + + +define void @and_tree_second_implies_first_perm2(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) { +; CHECK-LABEL: @and_tree_second_implies_first_perm2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[V0:%.*]], [[V1:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[V1]], [[V2:%.*]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V0]], [[V2]] +; CHECK-NEXT: [[AND1:%.*]] = and i1 [[CMP0]], [[CMP2]] +; CHECK-NEXT: [[AND2:%.*]] = and i1 false, [[AND1]] +; CHECK-NEXT: br i1 [[AND2]], label [[IF_THEN:%.*]], label [[RETURN:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @side_effect() +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: ret void +; +entry: + %cmp0 = icmp sge i32 %v0, %v1 + %cmp1 = icmp sge i32 %v1, %v2 + %cmp2 = icmp slt i32 %v0, %v2 + %and1 = and i1 %cmp0, %cmp2 + %and2 = and i1 %cmp1, %and1 + br i1 %and2, label %if.then, label %return + +if.then: + call void @side_effect() + br label %return + +return: + ret void +} + +define void @logical_and_tree_second_implies_first(i32 %v0, i32 %v1, i32 %v2) { +; CHECK-LABEL: @logical_and_tree_second_implies_first( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[V0:%.*]], [[V1:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[V1]], [[V2:%.*]] +; CHECK-NEXT: [[AND1:%.*]] = select i1 [[CMP0]], i1 [[CMP1]], i1 false +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V0]], [[V2]] +; CHECK-NEXT: [[AND2:%.*]] = select i1 [[CMP2]], i1 [[AND1]], i1 false +; CHECK-NEXT: br i1 [[AND2]], label [[IF_THEN:%.*]], label [[RETURN:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @side_effect() +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: ret void +; +entry: + %cmp0 = icmp sge i32 %v0, %v1 + %cmp1 = icmp sge i32 %v1, %v2 + %and1 = select i1 %cmp0, i1 %cmp1, i1 false + %cmp2 = icmp slt i32 %v0, %v2 + %and2 = select i1 %cmp2, i1 %and1, i1 false + br i1 %and2, label %if.then, label %return + +if.then: + call void @side_effect() + br label %return + +return: + ret void +} + +define void @or_tree_second_implies_first(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) { +; CHECK-LABEL: @or_tree_second_implies_first( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[V0:%.*]], [[V1:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[V1]], [[V2:%.*]] +; CHECK-NEXT: [[AND1:%.*]] = or i1 [[CMP0]], [[CMP1]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V0]], [[V2]] +; CHECK-NEXT: [[AND2:%.*]] = or i1 true, [[AND1]] +; CHECK-NEXT: br i1 [[AND2]], label [[IF_THEN:%.*]], label [[RETURN:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @side_effect() +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: ret void +; +entry: + %cmp0 = icmp sge i32 %v0, %v1 + %cmp1 = icmp sge i32 %v1, %v2 + %and1 = or i1 %cmp0, %cmp1 + %cmp2 = icmp slt i32 %v0, %v2 + %and2 = or i1 %cmp2, %and1 + br i1 %and2, label %if.then, label %return + +if.then: + call void @side_effect() + br label %return + +return: + ret void +} + +define void @negative_and_or_tree_second_implies_first(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) { +; CHECK-LABEL: @negative_and_or_tree_second_implies_first( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[V0:%.*]], [[V1:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[V1]], [[V2:%.*]] +; CHECK-NEXT: [[AND1:%.*]] = or i1 [[CMP0]], [[CMP1]] +; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V0]], [[V2]] +; CHECK-NEXT: [[AND2:%.*]] = and i1 [[CMP2]], [[AND1]] +; CHECK-NEXT: br i1 [[AND2]], label [[IF_THEN:%.*]], label [[RETURN:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @side_effect() +; CHECK-NEXT: br label [[RETURN]] +; CHECK: return: +; CHECK-NEXT: ret void +; +entry: + %cmp0 = icmp sge i32 %v0, %v1 + %cmp1 = icmp sge i32 %v1, %v2 + %and1 = or i1 %cmp0, %cmp1 + %cmp2 = icmp slt i32 %v0, %v2 + %and2 = and i1 %cmp2, %and1 + br i1 %and2, label %if.then, label %return + +if.then: + call void @side_effect() + br label %return + +return: + ret void +} + +declare void @side_effect() declare void @no_noundef(i1 noundef) diff --git a/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll b/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll deleted file mode 100644 index a3cea2e3b7889..0000000000000 --- a/llvm/test/Transforms/ConstraintElimination/unreachable-bb.ll +++ /dev/null @@ -1,36 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 -; RUN: opt -p constraint-elimination -S %s | FileCheck %s - -define void @f(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) { -; CHECK-LABEL: define void @f( -; CHECK-SAME: i32 noundef [[V0:%.*]], i32 noundef [[V1:%.*]], i32 noundef [[V2:%.*]]) { -; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[V0]], [[V1]] -; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[V1]], [[V2]] -; CHECK-NEXT: [[AND1:%.*]] = and i1 [[CMP0]], [[CMP1]] -; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[V0]], [[V2]] -; CHECK-NEXT: [[AND2:%.*]] = and i1 false, [[AND1]] -; CHECK-NEXT: br i1 [[AND2]], label %[[IF_THEN:.*]], label %[[RETURN:.*]] -; CHECK: [[IF_THEN]]: -; CHECK-NEXT: call void @side_effect() -; CHECK-NEXT: br label %[[RETURN]] -; CHECK: [[RETURN]]: -; CHECK-NEXT: ret void -; -entry: - %cmp0 = icmp sge i32 %v0, %v1 - %cmp1 = icmp sge i32 %v1, %v2 - %and1 = and i1 %cmp0, %cmp1 - %cmp2 = icmp slt i32 %v0, %v2 - %and2 = and i1 %cmp2, %and1 - br i1 %and2, label %if.then, label %return - -if.then: - call void @side_effect() - br label %return - -return: - ret void -} - -declare void @side_effect() From c140c313d059e45369963fdbdaf2f8c0cb443f4a Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Tue, 26 Nov 2024 22:29:40 +0800 Subject: [PATCH 5/6] [ConstraintElim] Add a test case from clamav --- .../and-implied-by-operands.ll | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll index 9b798ea255c0e..891dcbabc52b8 100644 --- a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll +++ b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll @@ -653,6 +653,35 @@ return: ret void } +define void @or_tree_second_implies_first_with_unknown_cond(i64 %x, i1 %cond) { +; CHECK-LABEL: @or_tree_second_implies_first_with_unknown_cond( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[X:%.*]], 1 +; CHECK-NEXT: [[OR1:%.*]] = select i1 [[CMP1]], i1 [[COND:%.*]], i1 false +; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[X]], 2 +; CHECK-NEXT: [[OR2:%.*]] = select i1 [[OR1]], i1 [[CMP2]], i1 false +; CHECK-NEXT: br i1 [[OR2]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @side_effect() +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret void +; +entry: + %cmp1 = icmp ugt i64 %x, 1 + %or1 = select i1 %cmp1, i1 %cond, i1 false + %cmp2 = icmp ult i64 %x, 2 + %or2 = select i1 %or1, i1 %cmp2, i1 false + br i1 %or2, label %if.then, label %if.end + +if.then: + call void @side_effect() + br label %if.end + +if.end: + ret void +} + define void @negative_and_or_tree_second_implies_first(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) { ; CHECK-LABEL: @negative_and_or_tree_second_implies_first( ; CHECK-NEXT: entry: From 919416d2c4c71e3b9fe533af2c168a36c7893be5 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Tue, 26 Nov 2024 22:42:03 +0800 Subject: [PATCH 6/6] [ConstraintElim] Ignore unknown conditions --- llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 2 -- .../Transforms/ConstraintElimination/and-implied-by-operands.ll | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 64c0d3fe6a8dc..4884c23f16e12 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1536,9 +1536,7 @@ static bool checkOrAndOpImpliedByOther( : match(Val, m_LogicalAnd(m_Value(LHS), m_Value(RHS)))) { Worklist.push_back(LHS); Worklist.push_back(RHS); - continue; } - return false; } if (OldSize == DFSInStack.size()) return false; diff --git a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll index 891dcbabc52b8..8bd0b4100cff9 100644 --- a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll +++ b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll @@ -659,7 +659,7 @@ define void @or_tree_second_implies_first_with_unknown_cond(i64 %x, i1 %cond) { ; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[X:%.*]], 1 ; CHECK-NEXT: [[OR1:%.*]] = select i1 [[CMP1]], i1 [[COND:%.*]], i1 false ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[X]], 2 -; CHECK-NEXT: [[OR2:%.*]] = select i1 [[OR1]], i1 [[CMP2]], i1 false +; CHECK-NEXT: [[OR2:%.*]] = select i1 [[OR1]], i1 false, i1 false ; CHECK-NEXT: br i1 [[OR2]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] ; CHECK: if.then: ; CHECK-NEXT: call void @side_effect()