diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -910,6 +910,18 @@ return Builder.CreateSub( I->getOperand(1), I->getOperand(0), I->getName() + ".neg"); + // Negation is equivalent to bitwise-not + 1: + // 0 - (A ^ C) => ((A ^ C) ^ -1) + 1 => A ^ ~C + 1 + case Instruction::Xor: { + Constant *C; + if (match(I->getOperand(1), m_Constant(C))) { + Value *Xor = Builder.CreateXor(I->getOperand(0), ConstantExpr::getNot(C)); + return Builder.CreateAdd(Xor, ConstantInt::get(Xor->getType(), 1), + I->getName() + ".neg"); + } + return nullptr; + } + // 0-(A sdiv C) => A sdiv (0-C) provided the negation doesn't overflow. case Instruction::SDiv: { Constant *C = dyn_cast(I->getOperand(1)); diff --git a/llvm/test/Transforms/InstCombine/sub-of-negatible.ll b/llvm/test/Transforms/InstCombine/sub-of-negatible.ll --- a/llvm/test/Transforms/InstCombine/sub-of-negatible.ll +++ b/llvm/test/Transforms/InstCombine/sub-of-negatible.ll @@ -378,9 +378,9 @@ define i4 @negate_xor(i4 %x) { ; CHECK-LABEL: @negate_xor( -; CHECK-NEXT: [[O:%.*]] = xor i4 [[X:%.*]], 5 -; CHECK-NEXT: [[R:%.*]] = sub i4 0, [[O]] -; CHECK-NEXT: ret i4 [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i4 [[X:%.*]], -6 +; CHECK-NEXT: [[O_NEG:%.*]] = add i4 [[TMP1]], 1 +; CHECK-NEXT: ret i4 [[O_NEG]] ; %o = xor i4 %x, 5 %r = sub i4 0, %o @@ -389,9 +389,9 @@ define <2 x i4> @negate_xor_vec(<2 x i4> %x) { ; CHECK-LABEL: @negate_xor_vec( -; CHECK-NEXT: [[O:%.*]] = xor <2 x i4> [[X:%.*]], -; CHECK-NEXT: [[R:%.*]] = sub <2 x i4> zeroinitializer, [[O]] -; CHECK-NEXT: ret <2 x i4> [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i4> [[X:%.*]], +; CHECK-NEXT: [[O_NEG:%.*]] = add <2 x i4> [[TMP1]], +; CHECK-NEXT: ret <2 x i4> [[O_NEG]] ; %o = xor <2 x i4> %x, %r = sub <2 x i4> zeroinitializer, %o @@ -413,10 +413,10 @@ define i4 @negate_shl_xor(i4 %x, i4 %y) { ; CHECK-LABEL: @negate_shl_xor( -; CHECK-NEXT: [[O:%.*]] = xor i4 [[X:%.*]], 5 -; CHECK-NEXT: [[S:%.*]] = shl i4 [[O]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = sub i4 0, [[S]] -; CHECK-NEXT: ret i4 [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i4 [[X:%.*]], -6 +; CHECK-NEXT: [[O_NEG:%.*]] = add i4 [[TMP1]], 1 +; CHECK-NEXT: [[S_NEG:%.*]] = shl i4 [[O_NEG]], [[Y:%.*]] +; CHECK-NEXT: ret i4 [[S_NEG]] ; %o = xor i4 %x, 5 %s = shl i4 %o, %y