Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -895,6 +895,27 @@ I->getName() + ".neg", cast(I)->isExact()); return nullptr; + // Negation is equivalent to bitwise-not + 1. + case Instruction::Xor: { + // Special case for negate of 'not' - replace with increment: + // 0 - (~A) => ((A ^ -1) ^ -1) + 1 => A + 1 + Value *A; + if (match(I, m_Not(m_Value(A)))) + return Builder.CreateAdd(A, ConstantInt::get(A->getType(), 1), + I->getName() + ".neg"); + + // General case xor (not a 'not') requires creating a new xor, so this has a + // one-use limitation: + // 0 - (A ^ C) => ((A ^ C) ^ -1) + 1 => A ^ ~C + 1 + Constant *C; + if (match(I, m_OneUse(m_Xor(m_Value(A), m_Constant(C))))) { + Value *Xor = Builder.CreateXor(A, ConstantExpr::getNot(C)); + return Builder.CreateAdd(Xor, ConstantInt::get(Xor->getType(), 1), + I->getName() + ".neg"); + } + return nullptr; + } + default: break; } @@ -910,18 +931,6 @@ 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)); Index: llvm/test/Transforms/InstCombine/sub-of-negatible.ll =================================================================== --- llvm/test/Transforms/InstCombine/sub-of-negatible.ll +++ llvm/test/Transforms/InstCombine/sub-of-negatible.ll @@ -429,9 +429,9 @@ ; CHECK-LABEL: @negate_shl_not_uses( ; CHECK-NEXT: [[O:%.*]] = xor i8 [[X:%.*]], -1 ; CHECK-NEXT: call void @use8(i8 [[O]]) -; CHECK-NEXT: [[S:%.*]] = shl i8 [[O]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = sub i8 0, [[S]] -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: [[O_NEG:%.*]] = add i8 [[X]], 1 +; CHECK-NEXT: [[S_NEG:%.*]] = shl i8 [[O_NEG]], [[Y:%.*]] +; CHECK-NEXT: ret i8 [[S_NEG]] ; %o = xor i8 %x, -1 call void @use8(i8 %o) @@ -444,9 +444,9 @@ ; CHECK-LABEL: @negate_mul_not_uses_vec( ; CHECK-NEXT: [[O:%.*]] = xor <2 x i4> [[X:%.*]], ; CHECK-NEXT: call void @use_v2i4(<2 x i4> [[O]]) -; CHECK-NEXT: [[S:%.*]] = mul <2 x i4> [[O]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = sub <2 x i4> zeroinitializer, [[S]] -; CHECK-NEXT: ret <2 x i4> [[R]] +; CHECK-NEXT: [[O_NEG:%.*]] = add <2 x i4> [[X]], +; CHECK-NEXT: [[S_NEG:%.*]] = mul <2 x i4> [[O_NEG]], [[Y:%.*]] +; CHECK-NEXT: ret <2 x i4> [[S_NEG]] ; %o = xor <2 x i4> %x, call void @use_v2i4(<2 x i4> %o)