diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1900,6 +1900,27 @@ return SelectInst::Create(Cmp, Neg, A); } + // Now that we know we have failed to fold this `sub a, b`, iff `a != 0`, + // let's see if it's worth exploding it into `add a, (sub 0, b)`. + // It is worth doing if the negation can be sunk into `b`. + if (!match(Op0, m_Zero()) && isFreeToNegate(Op1)) { + // While this does temporairly increase instruction count, we have ensured + // that this `neg` will get absorbed into Op1, so this is ok. + Instruction *NegOp1 = + BinaryOperator::CreateNeg(Op1, Op1->getName() + ".neg"); + Instruction *NewAdd = BinaryOperator::CreateAdd(NegOp1, Op0); + // Normally, the `neg` would have been added to InstCombine's WorkList + // first, and then the `add`. So we'd first revisit `add`, but we just made + // it so that one of the `add`s operands is `neg`, so it would hoist that + // `neg` and recreate subtraction, and we'll endlessly loop... + // Instead, let's manually first add the `add` and *then* `neg`, this way + // we will first visit the `neg`, and go on folding it into it's operand. + Worklist.Add(NewAdd); + Worklist.Add(NegOp1); + Builder.Insert(NegOp1); + return NewAdd; + } + if (Instruction *Ext = narrowMathIfNoOverflow(I)) return Ext; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -199,6 +199,55 @@ return true; // Can freely invert all users! } +/// Return true if the specified value is free to negate (subtract from 0). +/// This happens in cases where the 0 can be eliminated. +/// For instructions, this is limited to single-use instructions. +/// The analysis is recursive. +static inline bool isFreeToNegate(Value *V, unsigned Depth = 0) { + // -(-(X)) -> X. + if (match(V, m_Neg(m_Value()))) + return true; + + // Constants can be considered to be negated values. + if (match(V, m_AnyIntegralConstant())) + return true; + + // Rest of the checking is recursive, so time to pessimistically bailout. + if (Depth > 6) + return false; + + // If we have a non-instruction, and it's not a constant, then give up. + if (!isa(V)) + return false; + // The instruction-in-question must be one-use. + if (!V->hasOneUse()) + return false; + + auto *I = cast(V); + switch (I->getOpcode()) { + case Instruction::Select: + // `select` is negatible if both hands of select are negatible. + return isFreeToNegate(I->getOperand(1), Depth + 1) && + isFreeToNegate(I->getOperand(2), Depth + 1); + case Instruction::Shl: + case Instruction::Sub: + // `shl`, `sub` are negatible if their first operand is negatible. + return isFreeToNegate(I->getOperand(0), Depth + 1); + case Instruction::Add: + // `add` is negatible if both of it's operands are negatible. + return isFreeToNegate(I->getOperand(0), Depth + 1) && + isFreeToNegate(I->getOperand(1), Depth + 1); + case Instruction::Mul: + // `mul` is negatible one of it's operands is negatible. + return isFreeToNegate(I->getOperand(0), Depth + 1) || + isFreeToNegate(I->getOperand(1), Depth + 1); + default: + return false; // Don't know, likely not negatible for free. + } + + return false; +} + /// Some binary operators require special handling to avoid poison and undefined /// behavior. If a constant vector has undef elements, replace those undefs with /// identity constants if possible because those are always safe to execute. 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 @@ -30,8 +30,8 @@ ; Shift-left can be negated if all uses can be updated define i8 @t2(i8 %x, i8 %y) { ; CHECK-LABEL: @t2( -; CHECK-NEXT: [[T0:%.*]] = shl i8 -42, [[Y:%.*]] -; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[TMP1:%.*]] = shl i8 42, [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = add i8 [[TMP1]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[T1]] ; %t0 = shl i8 -42, %y @@ -54,8 +54,8 @@ ; CHECK-LABEL: @t3( ; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Z:%.*]] ; CHECK-NEXT: call void @use8(i8 [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = shl i8 [[T0]], [[Y:%.*]] -; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]] +; CHECK-NEXT: [[TMP1:%.*]] = shl i8 [[Z]], [[Y:%.*]] +; CHECK-NEXT: [[T2:%.*]] = add i8 [[TMP1]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[T2]] ; %t0 = sub i8 0, %z @@ -84,8 +84,8 @@ ; Select can be negated if all it's operands can be negated and all the users of select can be updated define i8 @t4(i8 %x, i1 %y) { ; CHECK-LABEL: @t4( -; CHECK-NEXT: [[T0:%.*]] = select i1 [[Y:%.*]], i8 -42, i8 44 -; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[Y:%.*]], i8 42, i8 -44 +; CHECK-NEXT: [[T1:%.*]] = add i8 [[TMP1]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[T1]] ; %t0 = select i1 %y, i8 -42, i8 44 @@ -118,8 +118,8 @@ ; CHECK-LABEL: @t6( ; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Z:%.*]] ; CHECK-NEXT: call void @use8(i8 [[T0]]) -; CHECK-NEXT: [[T1:%.*]] = select i1 [[Y:%.*]], i8 -42, i8 [[T0]] -; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[Y:%.*]], i8 42, i8 [[Z]] +; CHECK-NEXT: [[T2:%.*]] = add i8 [[TMP1]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[T2]] ; %t0 = sub i8 0, %z @@ -130,9 +130,9 @@ } define i8 @t7(i8 %x, i1 %y, i8 %z) { ; CHECK-LABEL: @t7( -; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Z:%.*]] -; CHECK-NEXT: [[T1:%.*]] = select i1 [[Y:%.*]], i8 0, i8 [[T0]] -; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]] +; CHECK-NEXT: [[T0_OP:%.*]] = shl i8 -1, [[Z:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[Y:%.*]], i8 0, i8 [[T0_OP]] +; CHECK-NEXT: [[T2:%.*]] = add i8 [[TMP1]], [[X:%.*]] ; CHECK-NEXT: ret i8 [[T2]] ; %t0 = shl i8 1, %z @@ -290,3 +290,11 @@ %t2 = sub i8 %x, %t1 ret i8 %t2 } + +; We shouldn't try to convert -b into 0+(-b) +define i32 @dont_touch_negation_itself(i32 %x, i32 %y) { + %a = mul i32 %y, 3 + %b = mul i32 %a, %x + %mul = sub i32 0, %b + ret i32 %mul +}