From b80f31c48d63743ece1062f30d5f747a03ee5695 Mon Sep 17 00:00:00 2001 From: Zhongyunde Date: Tue, 25 Apr 2023 21:47:41 +0800 Subject: [PATCH] [InstSimplify] with logical ops: (X | Y) ? 0 : X --> 0 Use simplifySelectWithICmpEq to handle the implied equalities from the icmp-or, then both of ICMP_NE and ICMP_EQ will be addressed (X | Y) == 0 ? X : 0 --> 0 (commuted 2 ways) (X | Y) != 0 ? 0 : X --> 0 (commuted 2 ways) Fixes https://github.com/llvm/llvm-project/issues/62263 Reviewed By: nikic, RKSimon Differential Revision: https://reviews.llvm.org/D148986 --- llvm/lib/Analysis/InstructionSimplify.cpp | 57 ++++++++++++++-------- llvm/test/Transforms/InstSimplify/select_or_and.ll | 30 +++--------- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index f45ad98..57cfef4e 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4437,6 +4437,24 @@ static Value *simplifySelectWithFakeICmpEq(Value *CmpLHS, Value *CmpRHS, } /// Try to simplify a select instruction when its condition operand is an +/// integer equality comparison. +static Value *simplifySelectWithICmpEq(Value *CmpLHS, Value *CmpRHS, + Value *TrueVal, Value *FalseVal, + const SimplifyQuery &Q, + unsigned MaxRecurse) { + if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q, + /* AllowRefinement */ false, + MaxRecurse) == TrueVal) + return FalseVal; + if (simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q, + /* AllowRefinement */ true, + MaxRecurse) == FalseVal) + return FalseVal; + + return nullptr; +} + +/// Try to simplify a select instruction when its condition operand is an /// integer comparison. static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, Value *FalseVal, @@ -4524,30 +4542,31 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, // the arms of the select. See if substituting this value into the arm and // simplifying the result yields the same value as the other arm. if (Pred == ICmpInst::ICMP_EQ) { - if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q, - /* AllowRefinement */ false, - MaxRecurse) == TrueVal || - simplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, Q, - /* AllowRefinement */ false, - MaxRecurse) == TrueVal) - return FalseVal; - if (simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q, - /* AllowRefinement */ true, - MaxRecurse) == FalseVal || - simplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, Q, - /* AllowRefinement */ true, - MaxRecurse) == FalseVal) - return FalseVal; + if (Value *V = simplifySelectWithICmpEq(CmpLHS, CmpRHS, TrueVal, FalseVal, + Q, MaxRecurse)) + return V; + if (Value *V = simplifySelectWithICmpEq(CmpRHS, CmpLHS, TrueVal, FalseVal, + Q, MaxRecurse)) + return V; + + // select(X | Y == 0 ? X : 0) --> 0 (commuted 2 ways) + Value *X; + Value *Y; + if (match(CmpLHS, m_Or(m_Value(X), m_Value(Y))) && + match(CmpRHS, m_Zero())) { + // X | Y == 0 implies X == 0 and Y == 0. + if (Value *V = simplifySelectWithICmpEq(X, CmpRHS, TrueVal, FalseVal, Q, + MaxRecurse)) + return V; + if (Value *V = simplifySelectWithICmpEq(Y, CmpRHS, TrueVal, FalseVal, Q, + MaxRecurse)) + return V; + } } if (Pred == ICmpInst::Predicate::ICMP_EQ) { Value *X; Value *Y; - // select(X | Y == 0, X or Y, X | Y) -> X | Y - if (match(CondVal, m_ICmp(Pred, m_Specific(FalseVal), m_Zero())) && - match(FalseVal, m_Or(m_Value(X), m_Value(Y))) && - (TrueVal == X || TrueVal == Y)) - return FalseVal; // select(X & Y == -1, X or Y, X & Y) -> X & Y if (match(CondVal, m_ICmp(Pred, m_Specific(FalseVal), m_AllOnes())) && match(FalseVal, m_And(m_Value(X), m_Value(Y))) && diff --git a/llvm/test/Transforms/InstSimplify/select_or_and.ll b/llvm/test/Transforms/InstSimplify/select_or_and.ll index 63476e2..fcac90b 100644 --- a/llvm/test/Transforms/InstSimplify/select_or_and.ll +++ b/llvm/test/Transforms/InstSimplify/select_or_and.ll @@ -64,10 +64,7 @@ define <4 x i32> @select_or_vec(<4 x i32> %x, <4 x i32> %y) { ; select(Y | X == 0, Y | X, Y) define i32 @select_or_not_1(i32 %x, i32 %y) { ; CHECK-LABEL: @select_or_not_1( -; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], 0 -; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[Y]] -; CHECK-NEXT: ret i32 [[RET]] +; CHECK-NEXT: ret i32 [[Y:%.*]] ; %or = or i32 %y, %x %cmp = icmp eq i32 %or, 0 @@ -77,10 +74,7 @@ define i32 @select_or_not_1(i32 %x, i32 %y) { ; select(Y | X != 0, Y, Y | X) define i32 @select_or_not_2(i32 %x, i32 %y) { ; CHECK-LABEL: @select_or_not_2( -; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[OR]], 0 -; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[OR]] -; CHECK-NEXT: ret i32 [[RET]] +; CHECK-NEXT: ret i32 [[Y:%.*]] ; %or = or i32 %y, %x %cmp = icmp ne i32 %or, 0 @@ -209,10 +203,7 @@ define i32 @select_icmp_and_eq(i32 %a, i32 %b) { ; https://alive2.llvm.org/ce/z/hSyCuR define i32 @select_icmp_or_eq(i32 %a, i32 %b) { ; CHECK-LABEL: @select_icmp_or_eq( -; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[OR]], 0 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[A]], i32 0 -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: ret i32 0 ; %or = or i32 %a, %b %tobool = icmp eq i32 %or, 0 @@ -222,10 +213,7 @@ define i32 @select_icmp_or_eq(i32 %a, i32 %b) { define i32 @select_icmp_or_eq_commuted(i32 %a, i32 %b) { ; CHECK-LABEL: @select_icmp_or_eq_commuted( -; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[OR]], 0 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[B]], i32 0 -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: ret i32 0 ; %or = or i32 %a, %b %tobool = icmp eq i32 %or, 0 @@ -236,10 +224,7 @@ define i32 @select_icmp_or_eq_commuted(i32 %a, i32 %b) { ; https://alive2.llvm.org/ce/z/S_pQek define <2 x i16> @select_icmp_or_eq_vec(<2 x i16> %a, <2 x i16> %b) { ; CHECK-LABEL: @select_icmp_or_eq_vec( -; CHECK-NEXT: [[OR:%.*]] = or <2 x i16> [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq <2 x i16> [[OR]], zeroinitializer -; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[TOBOOL]], <2 x i16> [[A]], <2 x i16> zeroinitializer -; CHECK-NEXT: ret <2 x i16> [[COND]] +; CHECK-NEXT: ret <2 x i16> zeroinitializer ; %or = or <2 x i16> %a, %b %tobool = icmp eq <2 x i16> %or, @@ -250,10 +235,7 @@ define <2 x i16> @select_icmp_or_eq_vec(<2 x i16> %a, <2 x i16> %b) { ; The ne will also be matched define i32 @select_icmp_or_ne(i32 %a, i32 %b) { ; CHECK-LABEL: @select_icmp_or_ne( -; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[OR]], 0 -; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 0, i32 [[A]] -; CHECK-NEXT: ret i32 [[COND]] +; CHECK-NEXT: ret i32 0 ; %or = or i32 %a, %b %tobool = icmp ne i32 %or, 0 -- 2.7.4