[InstCombine] fold mask with not-of-sext-bool to select
authorSanjay Patel <spatel@rotateright.com>
Mon, 2 Jan 2023 18:31:01 +0000 (13:31 -0500)
committerSanjay Patel <spatel@rotateright.com>
Mon, 2 Jan 2023 18:33:28 +0000 (13:33 -0500)
~sext(A) & Op1 --> A ? 0 : Op1

With no extra uses, this pattern is already reduced,
but we would miss it in examples such as issue #59773.

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

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/binop-cast.ll

index a4b14ad..48d57e3 100644 (file)
@@ -2360,6 +2360,16 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
       A->getType()->isIntOrIntVectorTy(1))
     return SelectInst::Create(A, Op0, Constant::getNullValue(Ty));
 
+  // Similarly, a 'not' of the bool translates to a swap of the select arms:
+  // ~sext(A) & Op1 --> A ? 0 : Op1
+  // Op0 & ~sext(A) --> A ? 0 : Op0
+  if (match(Op0, m_Not(m_SExt(m_Value(A)))) &&
+      A->getType()->isIntOrIntVectorTy(1))
+    return SelectInst::Create(A, Constant::getNullValue(Ty), Op1);
+  if (match(Op1, m_Not(m_SExt(m_Value(A)))) &&
+      A->getType()->isIntOrIntVectorTy(1))
+    return SelectInst::Create(A, Constant::getNullValue(Ty), Op0);
+
   // (iN X s>> (N-1)) & Y --> (X s< 0) ? Y : 0 -- with optional sext
   if (match(&I, m_c_And(m_OneUse(m_SExtOrSelf(
                             m_AShr(m_Value(X), m_APIntAllowUndef(C)))),
index e57f77e..6bcd504 100644 (file)
@@ -76,8 +76,7 @@ define <2 x i32> @and_not_sext_to_sel(<2 x i32> %x, <2 x i1> %y) {
 ; CHECK-LABEL: @and_not_sext_to_sel(
 ; CHECK-NEXT:    [[SEXT:%.*]] = sext <2 x i1> [[Y:%.*]] to <2 x i32>
 ; CHECK-NEXT:    call void @use_vec(<2 x i32> [[SEXT]])
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i32> [[SEXT]], <i32 -1, i32 -1>
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i32> [[NOT]], [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[Y]], <2 x i32> zeroinitializer, <2 x i32> [[X:%.*]]
 ; CHECK-NEXT:    ret <2 x i32> [[R]]
 ;
   %sext = sext <2 x i1> %y to <2 x i32>
@@ -94,7 +93,7 @@ define i32 @and_not_sext_to_sel_commute(i32 %px, i1 %y) {
 ; CHECK-NEXT:    call void @use(i32 [[SEXT]])
 ; CHECK-NEXT:    [[NOT:%.*]] = xor i32 [[SEXT]], -1
 ; CHECK-NEXT:    call void @use(i32 [[NOT]])
-; CHECK-NEXT:    [[R:%.*]] = and i32 [[X]], [[NOT]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[Y]], i32 0, i32 [[X]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %x = mul i32 %px, %px ; thwart complexity-based canonicalization
@@ -106,6 +105,8 @@ define i32 @and_not_sext_to_sel_commute(i32 %px, i1 %y) {
   ret i32 %r
 }
 
+; negative test - must be 'not'
+
 define i32 @and_xor_sext_to_sel(i32 %x, i1 %y) {
 ; CHECK-LABEL: @and_xor_sext_to_sel(
 ; CHECK-NEXT:    [[SEXT:%.*]] = sext i1 [[Y:%.*]] to i32
@@ -121,6 +122,8 @@ define i32 @and_xor_sext_to_sel(i32 %x, i1 %y) {
   ret i32 %r
 }
 
+; negative test - must be 'sext'
+
 define i32 @and_not_zext_to_sel(i32 %x, i1 %y) {
 ; CHECK-LABEL: @and_not_zext_to_sel(
 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[Y:%.*]] to i32