diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index a4b14ad5eda1c9..48d57e39427d06 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -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)))), diff --git a/llvm/test/Transforms/InstCombine/binop-cast.ll b/llvm/test/Transforms/InstCombine/binop-cast.ll index e57f77ec06df17..6bcd5049f92f3a 100644 --- a/llvm/test/Transforms/InstCombine/binop-cast.ll +++ b/llvm/test/Transforms/InstCombine/binop-cast.ll @@ -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]], -; 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