From 412fc74140c01cc9c29245a248edeee59d8814a4 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Fri, 2 Apr 2021 11:57:34 -0400 Subject: [PATCH] [InstCombine] fold not+or+neg ~((-X) | Y) --> (X - 1) & (~Y) We generally prefer 'add' over 'sub', this reduces the dependency chain, and this looks better for codegen on x86, ARM, and AArch64 targets. https://llvm.org/PR45755 https://alive2.llvm.org/ce/z/cxZDSp --- .../InstCombine/InstCombineAndOrXor.cpp | 8 ++++++++ llvm/test/Transforms/InstCombine/not.ll | 16 ++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index b9147e978deb..5e7abebe48a7 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3204,6 +3204,14 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { if (isa(X) || NotVal->hasOneUse()) return BinaryOperator::CreateAdd(Builder.CreateNot(X), Y); + // ~((-X) | Y) --> (X - 1) & (~Y) + if (match(NotVal, + m_OneUse(m_c_Or(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))) { + Value *DecX = Builder.CreateAdd(X, ConstantInt::getAllOnesValue(Ty)); + Value *NotY = Builder.CreateNot(Y); + return BinaryOperator::CreateAnd(DecX, NotY); + } + // ~(~X >>s Y) --> (X >>s Y) if (match(NotVal, m_AShr(m_Not(m_Value(X)), m_Value(Y)))) return BinaryOperator::CreateAShr(X, Y); diff --git a/llvm/test/Transforms/InstCombine/not.ll b/llvm/test/Transforms/InstCombine/not.ll index ff9b49462bf1..146fea71cd1c 100644 --- a/llvm/test/Transforms/InstCombine/not.ll +++ b/llvm/test/Transforms/InstCombine/not.ll @@ -408,9 +408,9 @@ define i1 @not_select_cmpf_extra_use(i1 %x, i32 %z, i32 %w, i1 %cond) { define i8 @not_or_neg(i8 %x, i8 %y) { ; CHECK-LABEL: @not_or_neg( -; CHECK-NEXT: [[S:%.*]] = sub i8 0, [[Y:%.*]] -; CHECK-NEXT: [[O:%.*]] = or i8 [[S]], [[X:%.*]] -; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[O]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[Y:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[X:%.*]], -1 +; CHECK-NEXT: [[NOT:%.*]] = and i8 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i8 [[NOT]] ; %s = sub i8 0, %y @@ -422,9 +422,9 @@ define i8 @not_or_neg(i8 %x, i8 %y) { define <3 x i5> @not_or_neg_commute_vec(<3 x i5> %x, <3 x i5> %p) { ; CHECK-LABEL: @not_or_neg_commute_vec( ; CHECK-NEXT: [[Y:%.*]] = mul <3 x i5> [[P:%.*]], -; CHECK-NEXT: [[S:%.*]] = sub <3 x i5> , [[X:%.*]] -; CHECK-NEXT: [[O:%.*]] = or <3 x i5> [[Y]], [[S]] -; CHECK-NEXT: [[NOT:%.*]] = xor <3 x i5> [[O]], +; CHECK-NEXT: [[TMP1:%.*]] = add <3 x i5> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = xor <3 x i5> [[Y]], +; CHECK-NEXT: [[NOT:%.*]] = and <3 x i5> [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret <3 x i5> [[NOT]] ; %y = mul <3 x i5> %p, ; thwart complexity-based-canonicalization @@ -434,6 +434,8 @@ define <3 x i5> @not_or_neg_commute_vec(<3 x i5> %x, <3 x i5> %p) { ret <3 x i5> %not } +; negative test + define i8 @not_or_neg_use1(i8 %x, i8 %y) { ; CHECK-LABEL: @not_or_neg_use1( ; CHECK-NEXT: [[S:%.*]] = sub i8 0, [[Y:%.*]] @@ -449,6 +451,8 @@ define i8 @not_or_neg_use1(i8 %x, i8 %y) { ret i8 %not } +; negative test + define i8 @not_or_neg_use2(i8 %x, i8 %y) { ; CHECK-LABEL: @not_or_neg_use2( ; CHECK-NEXT: [[S:%.*]] = sub i8 0, [[Y:%.*]]