diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2224,7 +2224,7 @@ if (Value *V = simplifyLogicOfAddSub(Op0, Op1, Instruction::Or)) return V; - Value *A, *B; + Value *A, *B, *NotA; // (A & ~B) | (A ^ B) -> (A ^ B) // (~B & A) | (A ^ B) -> (A ^ B) // (A & ~B) | (B ^ A) -> (B ^ A) @@ -2236,7 +2236,7 @@ // Commute the 'or' operands. // (A ^ B) | (A & ~B) -> (A ^ B) - // (A ^ B) | (~B & A) -> (A ^ B) + // (A ^ B) | (~B & A) -> (A ^ B)D94870 // (B ^ A) | (A & ~B) -> (B ^ A) // (B ^ A) | (~B & A) -> (B ^ A) if (match(Op0, m_Xor(m_Value(A), m_Value(B))) && @@ -2253,6 +2253,7 @@ match(Op1, m_c_Xor(m_Not(m_Specific(A)), m_Specific(B))))) return Op1; + // Commute the 'or' operands. // (~A ^ B) | (A & B) -> (~A ^ B) // (~A ^ B) | (B & A) -> (~A ^ B) // (B ^ ~A) | (A & B) -> (B ^ ~A) @@ -2266,9 +2267,20 @@ // (~A & B) | ~(B | A) --> ~A // (B & ~A) | ~(A | B) --> ~A // (B & ~A) | ~(B | A) --> ~A - if (match(Op0, m_And(m_Not(m_Value(A)), m_Value(B))) && + if (match(Op0, m_c_And(m_CombineAnd(m_Value(NotA), m_Not(m_Value(A))), + m_Value(B))) && match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) - return cast(Op0)->getOperand(0); + return NotA; + + // Commute the 'or' operands. + // ~(A | B) | (~A & B) --> ~A + // ~(B | A) | (~A & B) --> ~A + // ~(A | B) | (B & ~A) --> ~A + // ~(B | A) | (B & ~A) --> ~A + if (match(Op1, m_c_And(m_CombineAnd(m_Value(NotA), m_Not(m_Value(A))), + m_Value(B))) && + match(Op0, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) + return NotA; if (Value *V = simplifyAndOrOfCmps(Q, Op0, Op1, false)) return V; diff --git a/llvm/test/Transforms/InstSimplify/or.ll b/llvm/test/Transforms/InstSimplify/or.ll --- a/llvm/test/Transforms/InstSimplify/or.ll +++ b/llvm/test/Transforms/InstSimplify/or.ll @@ -399,11 +399,7 @@ define i32 @and_or_not_or5(i32 %A, i32 %B) { ; CHECK-LABEL: @and_or_not_or5( ; CHECK-NEXT: [[I:%.*]] = xor i32 [[A:%.*]], -1 -; CHECK-NEXT: [[I2:%.*]] = and i32 [[B:%.*]], [[I]] -; CHECK-NEXT: [[I3:%.*]] = or i32 [[B]], [[A]] -; CHECK-NEXT: [[I4:%.*]] = xor i32 [[I3]], -1 -; CHECK-NEXT: [[I5:%.*]] = or i32 [[I2]], [[I4]] -; CHECK-NEXT: ret i32 [[I5]] +; CHECK-NEXT: ret i32 [[I]] ; %i = xor i32 %A, -1 %i2 = and i32 %B, %i @@ -416,11 +412,7 @@ define i32 @and_or_not_or6(i32 %A, i32 %B) { ; CHECK-LABEL: @and_or_not_or6( ; CHECK-NEXT: [[I:%.*]] = xor i32 [[A:%.*]], -1 -; CHECK-NEXT: [[I2:%.*]] = and i32 [[I]], [[B:%.*]] -; CHECK-NEXT: [[I3:%.*]] = or i32 [[B]], [[A]] -; CHECK-NEXT: [[I4:%.*]] = xor i32 [[I3]], -1 -; CHECK-NEXT: [[I5:%.*]] = or i32 [[I4]], [[I2]] -; CHECK-NEXT: ret i32 [[I5]] +; CHECK-NEXT: ret i32 [[I]] ; %i = xor i32 %A, -1 %i2 = and i32 %i, %B @@ -433,11 +425,7 @@ define i32 @and_or_not_or7(i32 %A, i32 %B) { ; CHECK-LABEL: @and_or_not_or7( ; CHECK-NEXT: [[I:%.*]] = xor i32 [[A:%.*]], -1 -; CHECK-NEXT: [[I2:%.*]] = and i32 [[B:%.*]], [[I]] -; CHECK-NEXT: [[I3:%.*]] = or i32 [[B]], [[A]] -; CHECK-NEXT: [[I4:%.*]] = xor i32 [[I3]], -1 -; CHECK-NEXT: [[I5:%.*]] = or i32 [[I4]], [[I2]] -; CHECK-NEXT: ret i32 [[I5]] +; CHECK-NEXT: ret i32 [[I]] ; %i = xor i32 %A, -1 %i2 = and i32 %B, %i @@ -450,11 +438,7 @@ define i32 @and_or_not_or8(i32 %A, i32 %B) { ; CHECK-LABEL: @and_or_not_or8( ; CHECK-NEXT: [[I:%.*]] = xor i32 [[B:%.*]], -1 -; CHECK-NEXT: [[I2:%.*]] = and i32 [[A:%.*]], [[I]] -; CHECK-NEXT: [[I3:%.*]] = or i32 [[B]], [[A]] -; CHECK-NEXT: [[I4:%.*]] = xor i32 [[I3]], -1 -; CHECK-NEXT: [[I5:%.*]] = or i32 [[I4]], [[I2]] -; CHECK-NEXT: ret i32 [[I5]] +; CHECK-NEXT: ret i32 [[I]] ; %i = xor i32 %B, -1 %i2 = and i32 %A, %i