[InstSimplify] Add (~A & B) | ~(A | B) --> ~A
authorDávid Bolvanský <david.bolvansky@gmail.com>
Sat, 16 Jan 2021 14:43:07 +0000 (15:43 +0100)
committerDávid Bolvanský <david.bolvansky@gmail.com>
Sat, 16 Jan 2021 14:43:34 +0000 (15:43 +0100)
llvm/lib/Analysis/InstructionSimplify.cpp
llvm/test/Transforms/InstSimplify/or.ll

index 2ae4228..6266e92 100644 (file)
@@ -2262,6 +2262,12 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
        match(Op0, m_c_Xor(m_Not(m_Specific(A)), m_Specific(B)))))
     return Op0;
 
+  // (~A & B) | ~(A | B) --> ~A
+  // (~A & B) | ~(B | A) --> ~A
+  if (match(Op0, m_And(m_Not(m_Value(A)), m_Value(B))) &&
+      match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B)))))
+    return cast<BinaryOperator>(Op0)->getOperand(0);
+
   if (Value *V = simplifyAndOrOfCmps(Q, Op0, Op1, false))
     return V;
 
index e828426..7e7361d 100644 (file)
@@ -301,3 +301,97 @@ define i32 @poison(i32 %x) {
   %v = or i32 %x, poison
   ret i32 %v
 }
+
+declare void @use(i32)
+
+define i32 @and_or_not_or(i32 %A, i32 %B) {
+; CHECK-LABEL: @and_or_not_or(
+; CHECK-NEXT:    [[I:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    ret i32 [[I]]
+;
+  %i = xor i32 %B, -1
+  %i2 = and i32 %i, %A
+  %i3 = or i32 %B, %A
+  %i4 = xor i32 %i3, -1
+  %i5 = or i32 %i2, %i4
+  ret i32 %i5
+}
+
+define i32 @and_or_not_or2(i32 %A, i32 %B) {
+; CHECK-LABEL: @and_or_not_or2(
+; CHECK-NEXT:    [[I:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    ret i32 [[I]]
+;
+  %i = xor i32 %A, -1
+  %i2 = and i32 %i, %B
+  %i3 = or i32 %B, %A
+  %i4 = xor i32 %i3, -1
+  %i5 = or i32 %i2, %i4
+  ret i32 %i5
+}
+
+define <4 x i32> @and_or_not_or3_vec(<4 x i32> %A, <4 x i32> %B) {
+; CHECK-LABEL: @and_or_not_or3_vec(
+; CHECK-NEXT:    [[I:%.*]] = xor <4 x i32> [[A:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1>
+; CHECK-NEXT:    ret <4 x i32> [[I]]
+;
+  %i = xor <4 x i32> %A, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %i2 = and <4 x i32> %i, %B
+  %i3 = or <4 x i32> %B, %A
+  %i4 = xor <4 x i32> %i3, <i32 -1, i32 -1, i32 -1, i32 -1>
+  %i5 = or <4 x i32> %i2, %i4
+  ret <4 x i32> %i5
+}
+
+define i32 @and_or_not_or4_use(i32 %A, i32 %B) {
+; CHECK-LABEL: @and_or_not_or4_use(
+; CHECK-NEXT:    [[I:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[I2:%.*]] = and i32 [[I]], [[B:%.*]]
+; CHECK-NEXT:    tail call void @use(i32 [[I2]])
+; CHECK-NEXT:    ret i32 [[I]]
+;
+  %i = xor i32 %A, -1
+  %i2 = and i32 %i, %B
+  tail call void @use(i32 %i2)
+  %i3 = or i32 %B, %A
+  %i4 = xor i32 %i3, -1
+  %i5 = or i32 %i2, %i4
+  ret i32 %i5
+}
+
+define i32 @and_or_not_or4_use2(i32 %A, i32 %B) {
+; CHECK-LABEL: @and_or_not_or4_use2(
+; CHECK-NEXT:    [[I:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = xor i32 [[I]], -1
+; CHECK-NEXT:    tail call void @use(i32 [[I2]])
+; CHECK-NEXT:    [[I3:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    ret i32 [[I3]]
+;
+  %i = or i32 %B, %A
+  %i2 = xor i32 %i, -1
+  tail call void @use(i32 %i2)
+  %i3 = xor i32 %A, -1
+  %i4 = and i32 %i3, %B
+  %i5 = or i32 %i4, %i2
+  ret i32 %i5
+}
+
+define i32 @and_or_not_or4_use3(i32 %A, i32 %B) {
+; CHECK-LABEL: @and_or_not_or4_use3(
+; CHECK-NEXT:    [[I:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = xor i32 [[I]], -1
+; CHECK-NEXT:    tail call void @use(i32 [[I2]])
+; CHECK-NEXT:    [[I3:%.*]] = xor i32 [[A]], -1
+; CHECK-NEXT:    [[I4:%.*]] = and i32 [[I3]], [[B]]
+; CHECK-NEXT:    tail call void @use(i32 [[I4]])
+; CHECK-NEXT:    ret i32 [[I3]]
+;
+  %i = or i32 %B, %A
+  %i2 = xor i32 %i, -1
+  tail call void @use(i32 %i2)
+  %i3 = xor i32 %A, -1
+  %i4 = and i32 %i3, %B
+  tail call void @use(i32 %i4)
+  %i5 = or i32 %i4, %i2
+  ret i32 %i5
+}