diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 6d5b220f0694a3..86056a4ef810b1 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3352,11 +3352,6 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { } } - // ~(X - Y) --> ~X + Y - if (match(NotVal, m_Sub(m_Value(X), m_Value(Y)))) - 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))))) { @@ -3395,9 +3390,15 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { return BinaryOperator::CreateAShr(ConstantExpr::getNot(C), Y); } - // ~(X + C) --> -(C + 1) - X - if (match(Op0, m_Add(m_Value(X), m_Constant(C)))) - return BinaryOperator::CreateSub(ConstantExpr::getNeg(AddOne(C)), X); + // ~(X + C) --> ~C - X + if (match(NotVal, m_c_Add(m_Value(X), m_ImmConstant(C)))) + return BinaryOperator::CreateSub(ConstantExpr::getNot(C), X); + + // ~(X - Y) --> ~X + Y + // FIXME: is it really beneficial to sink the `not` here? + if (match(NotVal, m_Sub(m_Value(X), m_Value(Y)))) + if (isa(X) || NotVal->hasOneUse()) + return BinaryOperator::CreateAdd(Builder.CreateNot(X), Y); // ~(~X + Y) --> X - Y if (match(NotVal, m_c_Add(m_Not(m_Value(X)), m_Value(Y)))) diff --git a/llvm/test/Transforms/InstCombine/not-add.ll b/llvm/test/Transforms/InstCombine/not-add.ll index 6891fdd5fcc54c..d372e7603724bb 100644 --- a/llvm/test/Transforms/InstCombine/not-add.ll +++ b/llvm/test/Transforms/InstCombine/not-add.ll @@ -137,3 +137,31 @@ define <4 x i32> @vector_test_undef_nsw_nuw(<4 x i32> %x, <4 x i32> %y) { %nota = xor <4 x i32> %a, ret <4 x i32> %nota } + +define i32 @pr50308(i1 %c1, i32 %v1, i32 %v2, i32 %v3) { +; CHECK-LABEL: @pr50308( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C1:%.*]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: [[ADD_NOT:%.*]] = sub i32 -2, [[V1:%.*]] +; CHECK-NEXT: [[ADD1_NEG:%.*]] = xor i32 [[ADD_NOT]], [[V2:%.*]] +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND_NEG:%.*]] = phi i32 [ [[ADD1_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[SUB:%.*]] = add i32 [[COND_NEG]], [[V3:%.*]] +; CHECK-NEXT: ret i32 [[SUB]] +; +entry: + br i1 %c1, label %cond.true, label %cond.end + +cond.true: + %add = add nsw i32 1, %v1 + %xor = xor i32 %add, %v2 + %add1 = add nsw i32 1, %xor + br label %cond.end + +cond.end: + %cond = phi i32 [ %add1, %cond.true ], [ 0, %entry ] + %sub = sub nsw i32 %v3, %cond + ret i32 %sub +}