[llvm] 8591640 - [InstCombine] add DeMorgan folds for logical ops in select form

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 14 09:55:49 PDT 2021


Author: Sanjay Patel
Date: 2021-06-14T12:54:35-04:00
New Revision: 8591640379ac9175a8a8493126ecf0b44e3bb4af

URL: https://github.com/llvm/llvm-project/commit/8591640379ac9175a8a8493126ecf0b44e3bb4af
DIFF: https://github.com/llvm/llvm-project/commit/8591640379ac9175a8a8493126ecf0b44e3bb4af.diff

LOG: [InstCombine] add DeMorgan folds for logical ops in select form

We canonicalized to these select patterns (poison-safe logic)
with D101191, so we need to reduce 'not' ops when possible
as we would with 'and'/'or' instructions.

This is shown in a secondary example in:
https://llvm.org/PR50389

https://alive2.llvm.org/ce/z/BvsESh

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/test/Transforms/InstCombine/select-and-or.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index f48cc901b7428..2308cdfe0e111 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2705,6 +2705,19 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
       return SelectInst::Create(FalseVal, One, TrueVal);
 
     Value *A, *B;
+
+    // DeMorgan in select form: !a && !b --> !(a || b)
+    // select !a, !b, false --> not (select a, true, b)
+    if (match(&SI, m_LogicalAnd(m_Not(m_Value(A)), m_Not(m_Value(B)))) &&
+        (CondVal->hasOneUse() || TrueVal->hasOneUse()))
+      return BinaryOperator::CreateNot(Builder.CreateSelect(A, One, B));
+
+    // DeMorgan in select form: !a || !b --> !(a && b)
+    // select !a, true, !b --> not (select a, b, false)
+    if (match(&SI, m_LogicalOr(m_Not(m_Value(A)), m_Not(m_Value(B)))) &&
+        (CondVal->hasOneUse() || FalseVal->hasOneUse()))
+      return BinaryOperator::CreateNot(Builder.CreateSelect(A, B, Zero));
+
     // select (select a, true, b), true, b -> select a, true, b
     if (match(CondVal, m_Select(m_Value(A), m_One(), m_Value(B))) &&
         match(TrueVal, m_One()) && match(FalseVal, m_Specific(B)))

diff  --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll
index 9146f12f51cad..5d6352e3484cb 100644
--- a/llvm/test/Transforms/InstCombine/select-and-or.ll
+++ b/llvm/test/Transforms/InstCombine/select-and-or.ll
@@ -179,6 +179,8 @@ define i1 @logical_and_noundef_b(i1 %a, i1 noundef %b) {
   ret i1 %res
 }
 
+; (!x && !y) || x --> x || !y
+
 define i1 @not_not_true(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_not_true(
 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
@@ -191,11 +193,12 @@ define i1 @not_not_true(i1 %x, i1 %y) {
   ret i1 %r
 }
 
+; (!x && !y) --> !(x || y)
+
 define i1 @not_not_false(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_not_false(
-; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
-; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOTX]], i1 [[NOTY]], i1 false
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notx = xor i1 %x, true
@@ -204,11 +207,12 @@ define i1 @not_not_false(i1 %x, i1 %y) {
   ret i1 %r
 }
 
+; (!x || !y) --> !(x && y)
+
 define i1 @not_true_not(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_true_not(
-; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
-; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOTX]], i1 true, i1 [[NOTY]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notx = xor i1 %x, true
@@ -217,6 +221,8 @@ define i1 @not_true_not(i1 %x, i1 %y) {
   ret i1 %r
 }
 
+; (!!x && !y) --> x && !y
+
 define i1 @not_false_not(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_false_not(
 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
@@ -248,8 +254,8 @@ define i1 @not_not_false_use1(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_not_false_use1(
 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
-; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOTX]], i1 [[NOTY]], i1 false
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X]], i1 true, i1 [[Y:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notx = xor i1 %x, true
@@ -263,8 +269,8 @@ define i1 @not_true_not_use1(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_true_not_use1(
 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
 ; CHECK-NEXT:    call void @use(i1 [[NOTX]])
-; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOTX]], i1 true, i1 [[NOTY]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X]], i1 [[Y:%.*]], i1 false
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notx = xor i1 %x, true
@@ -305,10 +311,10 @@ define i1 @not_not_true_use2(i1 %x, i1 %y) {
 
 define i1 @not_not_false_use2(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_not_false_use2(
-; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOTX]], i1 [[NOTY]], i1 false
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notx = xor i1 %x, true
@@ -320,10 +326,10 @@ define i1 @not_not_false_use2(i1 %x, i1 %y) {
 
 define i1 @not_true_not_use2(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_true_not_use2(
-; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
 ; CHECK-NEXT:    [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
 ; CHECK-NEXT:    call void @use(i1 [[NOTY]])
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[NOTX]], i1 true, i1 [[NOTY]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 [[Y]], i1 false
+; CHECK-NEXT:    [[R:%.*]] = xor i1 [[TMP1]], true
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notx = xor i1 %x, true


        


More information about the llvm-commits mailing list