Skip to content

Commit 1fc73ca

Browse files
committed
[InstCombine] Propagate nsw flag when negating
When pushing a sub nsw 0, %x negation into an expression, try to preserve the nsw flag for the cases where this is possible. Do this by passing the flag through recursive Negator::negate() calls. Proofs: https://alive2.llvm.org/ce/z/oRPNcY Differential Revision: https://reviews.llvm.org/D158510
1 parent 0b2c88e commit 1fc73ca

File tree

7 files changed

+71
-57
lines changed

7 files changed

+71
-57
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2145,7 +2145,9 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
21452145
m_Select(m_Value(), m_Specific(Op1), m_Specific(&I))) ||
21462146
match(UI, m_Select(m_Value(), m_Specific(&I), m_Specific(Op1)));
21472147
})) {
2148-
if (Value *NegOp1 = Negator::Negate(IsNegation, Op1, *this))
2148+
if (Value *NegOp1 = Negator::Negate(IsNegation, /* IsNSW */ IsNegation &&
2149+
I.hasNoSignedWrap(),
2150+
Op1, *this))
21492151
return BinaryOperator::CreateAdd(NegOp1, Op0);
21502152
}
21512153
if (IsNegation)

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -738,13 +738,13 @@ class Negator final {
738738

739739
std::array<Value *, 2> getSortedOperandsOfBinOp(Instruction *I);
740740

741-
[[nodiscard]] Value *visitImpl(Value *V, unsigned Depth);
741+
[[nodiscard]] Value *visitImpl(Value *V, bool IsNSW, unsigned Depth);
742742

743-
[[nodiscard]] Value *negate(Value *V, unsigned Depth);
743+
[[nodiscard]] Value *negate(Value *V, bool IsNSW, unsigned Depth);
744744

745745
/// Recurse depth-first and attempt to sink the negation.
746746
/// FIXME: use worklist?
747-
[[nodiscard]] std::optional<Result> run(Value *Root);
747+
[[nodiscard]] std::optional<Result> run(Value *Root, bool IsNSW);
748748

749749
Negator(const Negator &) = delete;
750750
Negator(Negator &&) = delete;
@@ -754,7 +754,7 @@ class Negator final {
754754
public:
755755
/// Attempt to negate \p Root. Retuns nullptr if negation can't be performed,
756756
/// otherwise returns negated value.
757-
[[nodiscard]] static Value *Negate(bool LHSIsZero, Value *Root,
757+
[[nodiscard]] static Value *Negate(bool LHSIsZero, bool IsNSW, Value *Root,
758758
InstCombinerImpl &IC);
759759
};
760760

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,14 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
258258
if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) {
259259
// Interpret X * (-1<<C) as (-X) * (1<<C) and try to sink the negation.
260260
// The "* (1<<C)" thus becomes a potential shifting opportunity.
261-
if (Value *NegOp0 = Negator::Negate(/*IsNegation*/ true, Op0, *this))
262-
return BinaryOperator::CreateMul(
263-
NegOp0, ConstantExpr::getNeg(cast<Constant>(Op1)), I.getName());
261+
if (Value *NegOp0 =
262+
Negator::Negate(/*IsNegation*/ true, HasNSW, Op0, *this)) {
263+
auto *Op1C = cast<Constant>(Op1);
264+
return replaceInstUsesWith(
265+
I, Builder.CreateMul(NegOp0, ConstantExpr::getNeg(Op1C), "",
266+
/* HasNUW */ false,
267+
HasNSW && Op1C->isNotMinSignedValue()));
268+
}
264269

265270
// Try to convert multiply of extended operand to narrow negate and shift
266271
// for better analysis.

llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
128128

129129
// FIXME: can this be reworked into a worklist-based algorithm while preserving
130130
// the depth-first, early bailout traversal?
131-
[[nodiscard]] Value *Negator::visitImpl(Value *V, unsigned Depth) {
131+
[[nodiscard]] Value *Negator::visitImpl(Value *V, bool IsNSW, unsigned Depth) {
132132
// -(undef) -> undef.
133133
if (match(V, m_Undef()))
134134
return V;
@@ -237,7 +237,8 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
237237
// However, only do this either if the old `sub` doesn't stick around, or
238238
// it was subtracting from a constant. Otherwise, this isn't profitable.
239239
return Builder.CreateSub(I->getOperand(1), I->getOperand(0),
240-
I->getName() + ".neg");
240+
I->getName() + ".neg", /* HasNUW */ false,
241+
IsNSW && I->hasNoSignedWrap());
241242
}
242243

243244
// Some other cases, while still don't require recursion,
@@ -302,7 +303,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
302303
switch (I->getOpcode()) {
303304
case Instruction::Freeze: {
304305
// `freeze` is negatible if its operand is negatible.
305-
Value *NegOp = negate(I->getOperand(0), Depth + 1);
306+
Value *NegOp = negate(I->getOperand(0), IsNSW, Depth + 1);
306307
if (!NegOp) // Early return.
307308
return nullptr;
308309
return Builder.CreateFreeze(NegOp, I->getName() + ".neg");
@@ -313,7 +314,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
313314
SmallVector<Value *, 4> NegatedIncomingValues(PHI->getNumOperands());
314315
for (auto I : zip(PHI->incoming_values(), NegatedIncomingValues)) {
315316
if (!(std::get<1>(I) =
316-
negate(std::get<0>(I), Depth + 1))) // Early return.
317+
negate(std::get<0>(I), IsNSW, Depth + 1))) // Early return.
317318
return nullptr;
318319
}
319320
// All incoming values are indeed negatible. Create negated PHI node.
@@ -336,10 +337,10 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
336337
return NewSelect;
337338
}
338339
// `select` is negatible if both hands of `select` are negatible.
339-
Value *NegOp1 = negate(I->getOperand(1), Depth + 1);
340+
Value *NegOp1 = negate(I->getOperand(1), IsNSW, Depth + 1);
340341
if (!NegOp1) // Early return.
341342
return nullptr;
342-
Value *NegOp2 = negate(I->getOperand(2), Depth + 1);
343+
Value *NegOp2 = negate(I->getOperand(2), IsNSW, Depth + 1);
343344
if (!NegOp2)
344345
return nullptr;
345346
// Do preserve the metadata!
@@ -349,10 +350,10 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
349350
case Instruction::ShuffleVector: {
350351
// `shufflevector` is negatible if both operands are negatible.
351352
auto *Shuf = cast<ShuffleVectorInst>(I);
352-
Value *NegOp0 = negate(I->getOperand(0), Depth + 1);
353+
Value *NegOp0 = negate(I->getOperand(0), IsNSW, Depth + 1);
353354
if (!NegOp0) // Early return.
354355
return nullptr;
355-
Value *NegOp1 = negate(I->getOperand(1), Depth + 1);
356+
Value *NegOp1 = negate(I->getOperand(1), IsNSW, Depth + 1);
356357
if (!NegOp1)
357358
return nullptr;
358359
return Builder.CreateShuffleVector(NegOp0, NegOp1, Shuf->getShuffleMask(),
@@ -361,7 +362,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
361362
case Instruction::ExtractElement: {
362363
// `extractelement` is negatible if source operand is negatible.
363364
auto *EEI = cast<ExtractElementInst>(I);
364-
Value *NegVector = negate(EEI->getVectorOperand(), Depth + 1);
365+
Value *NegVector = negate(EEI->getVectorOperand(), IsNSW, Depth + 1);
365366
if (!NegVector) // Early return.
366367
return nullptr;
367368
return Builder.CreateExtractElement(NegVector, EEI->getIndexOperand(),
@@ -371,34 +372,36 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
371372
// `insertelement` is negatible if both the source vector and
372373
// element-to-be-inserted are negatible.
373374
auto *IEI = cast<InsertElementInst>(I);
374-
Value *NegVector = negate(IEI->getOperand(0), Depth + 1);
375+
Value *NegVector = negate(IEI->getOperand(0), IsNSW, Depth + 1);
375376
if (!NegVector) // Early return.
376377
return nullptr;
377-
Value *NegNewElt = negate(IEI->getOperand(1), Depth + 1);
378+
Value *NegNewElt = negate(IEI->getOperand(1), IsNSW, Depth + 1);
378379
if (!NegNewElt) // Early return.
379380
return nullptr;
380381
return Builder.CreateInsertElement(NegVector, NegNewElt, IEI->getOperand(2),
381382
I->getName() + ".neg");
382383
}
383384
case Instruction::Trunc: {
384385
// `trunc` is negatible if its operand is negatible.
385-
Value *NegOp = negate(I->getOperand(0), Depth + 1);
386+
Value *NegOp = negate(I->getOperand(0), /* IsNSW */ false, Depth + 1);
386387
if (!NegOp) // Early return.
387388
return nullptr;
388389
return Builder.CreateTrunc(NegOp, I->getType(), I->getName() + ".neg");
389390
}
390391
case Instruction::Shl: {
391392
// `shl` is negatible if the first operand is negatible.
392-
if (Value *NegOp0 = negate(I->getOperand(0), Depth + 1))
393-
return Builder.CreateShl(NegOp0, I->getOperand(1), I->getName() + ".neg");
393+
IsNSW &= I->hasNoSignedWrap();
394+
if (Value *NegOp0 = negate(I->getOperand(0), IsNSW, Depth + 1))
395+
return Builder.CreateShl(NegOp0, I->getOperand(1), I->getName() + ".neg",
396+
/* HasNUW */ false, IsNSW);
394397
// Otherwise, `shl %x, C` can be interpreted as `mul %x, 1<<C`.
395398
auto *Op1C = dyn_cast<Constant>(I->getOperand(1));
396399
if (!Op1C || !IsTrulyNegation)
397400
return nullptr;
398401
return Builder.CreateMul(
399402
I->getOperand(0),
400403
ConstantExpr::getShl(Constant::getAllOnesValue(Op1C->getType()), Op1C),
401-
I->getName() + ".neg");
404+
I->getName() + ".neg", /* HasNUW */ false, IsNSW);
402405
}
403406
case Instruction::Or: {
404407
if (!haveNoCommonBitsSet(I->getOperand(0), I->getOperand(1), DL, &AC, I,
@@ -417,7 +420,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
417420
SmallVector<Value *, 2> NegatedOps, NonNegatedOps;
418421
for (Value *Op : I->operands()) {
419422
// Can we sink the negation into this operand?
420-
if (Value *NegOp = negate(Op, Depth + 1)) {
423+
if (Value *NegOp = negate(Op, /* IsNSW */ false, Depth + 1)) {
421424
NegatedOps.emplace_back(NegOp); // Successfully negated operand!
422425
continue;
423426
}
@@ -458,16 +461,17 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
458461
Value *NegatedOp, *OtherOp;
459462
// First try the second operand, in case it's a constant it will be best to
460463
// just invert it instead of sinking the `neg` deeper.
461-
if (Value *NegOp1 = negate(Ops[1], Depth + 1)) {
464+
if (Value *NegOp1 = negate(Ops[1], /* IsNSW */ false, Depth + 1)) {
462465
NegatedOp = NegOp1;
463466
OtherOp = Ops[0];
464-
} else if (Value *NegOp0 = negate(Ops[0], Depth + 1)) {
467+
} else if (Value *NegOp0 = negate(Ops[0], /* IsNSW */ false, Depth + 1)) {
465468
NegatedOp = NegOp0;
466469
OtherOp = Ops[1];
467470
} else
468471
// Can't negate either of them.
469472
return nullptr;
470-
return Builder.CreateMul(NegatedOp, OtherOp, I->getName() + ".neg");
473+
return Builder.CreateMul(NegatedOp, OtherOp, I->getName() + ".neg",
474+
/* HasNUW */ false, IsNSW && I->hasNoSignedWrap());
471475
}
472476
default:
473477
return nullptr; // Don't know, likely not negatible for free.
@@ -476,7 +480,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
476480
llvm_unreachable("Can't get here. We always return from switch.");
477481
}
478482

479-
[[nodiscard]] Value *Negator::negate(Value *V, unsigned Depth) {
483+
[[nodiscard]] Value *Negator::negate(Value *V, bool IsNSW, unsigned Depth) {
480484
NegatorMaxDepthVisited.updateMax(Depth);
481485
++NegatorNumValuesVisited;
482486

@@ -506,15 +510,16 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
506510
#endif
507511

508512
// No luck. Try negating it for real.
509-
Value *NegatedV = visitImpl(V, Depth);
513+
Value *NegatedV = visitImpl(V, IsNSW, Depth);
510514
// And cache the (real) result for the future.
511515
NegationsCache[V] = NegatedV;
512516

513517
return NegatedV;
514518
}
515519

516-
[[nodiscard]] std::optional<Negator::Result> Negator::run(Value *Root) {
517-
Value *Negated = negate(Root, /*Depth=*/0);
520+
[[nodiscard]] std::optional<Negator::Result> Negator::run(Value *Root,
521+
bool IsNSW) {
522+
Value *Negated = negate(Root, IsNSW, /*Depth=*/0);
518523
if (!Negated) {
519524
// We must cleanup newly-inserted instructions, to avoid any potential
520525
// endless combine looping.
@@ -525,7 +530,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
525530
return std::make_pair(ArrayRef<Instruction *>(NewInstructions), Negated);
526531
}
527532

528-
[[nodiscard]] Value *Negator::Negate(bool LHSIsZero, Value *Root,
533+
[[nodiscard]] Value *Negator::Negate(bool LHSIsZero, bool IsNSW, Value *Root,
529534
InstCombinerImpl &IC) {
530535
++NegatorTotalNegationsAttempted;
531536
LLVM_DEBUG(dbgs() << "Negator: attempting to sink negation into " << *Root
@@ -536,7 +541,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
536541

537542
Negator N(Root->getContext(), IC.getDataLayout(), IC.getAssumptionCache(),
538543
IC.getDominatorTree(), LHSIsZero);
539-
std::optional<Result> Res = N.run(Root);
544+
std::optional<Result> Res = N.run(Root, IsNSW);
540545
if (!Res) { // Negation failed.
541546
LLVM_DEBUG(dbgs() << "Negator: failed to sink negation into " << *Root
542547
<< "\n");

llvm/test/Transforms/InstCombine/abs-intrinsic.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ define i32 @sub_abs_sgeT_swap(i32 %x, i32 %y) {
486486
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp slt i32 [[Y:%.*]], [[X:%.*]]
487487
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
488488
; CHECK: cond.true:
489-
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]]
489+
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]]
490490
; CHECK-NEXT: br label [[COND_END]]
491491
; CHECK: cond.end:
492492
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
@@ -513,7 +513,7 @@ define i32 @sub_abs_sgeT_false(i32 %x, i32 %y) {
513513
; CHECK-NEXT: [[CMP_NOT_NOT:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
514514
; CHECK-NEXT: br i1 [[CMP_NOT_NOT]], label [[COND_FALSE:%.*]], label [[COND_END:%.*]]
515515
; CHECK: cond.false:
516-
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]]
516+
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]]
517517
; CHECK-NEXT: br label [[COND_END]]
518518
; CHECK: cond.end:
519519
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_FALSE]] ], [ 0, [[ENTRY:%.*]] ]
@@ -539,7 +539,7 @@ define i32 @sub_abs_lt(i32 %x, i32 %y) {
539539
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
540540
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
541541
; CHECK: cond.true:
542-
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]]
542+
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]]
543543
; CHECK-NEXT: br label [[COND_END]]
544544
; CHECK: cond.end:
545545
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
@@ -566,7 +566,7 @@ define i32 @sub_abs_sle(i32 %x, i32 %y) {
566566
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
567567
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
568568
; CHECK: cond.true:
569-
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]]
569+
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]]
570570
; CHECK-NEXT: br label [[COND_END]]
571571
; CHECK: cond.end:
572572
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
@@ -619,7 +619,7 @@ define i8 @sub_abs_sleT(i8 %x, i8 %y) {
619619
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i8 [[X:%.*]], [[Y:%.*]]
620620
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]]
621621
; CHECK: cond.true:
622-
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i8 [[Y]], [[X]]
622+
; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i8 [[Y]], [[X]]
623623
; CHECK-NEXT: br label [[COND_END]]
624624
; CHECK: cond.end:
625625
; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]

llvm/test/Transforms/InstCombine/mul.ll

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,18 +1545,20 @@ define <2 x i32> @mulsub2_vec_nonuniform_undef(<2 x i32> %a0) {
15451545

15461546
define i8 @mulsub_nsw(i8 %a1, i8 %a2) {
15471547
; CHECK-LABEL: @mulsub_nsw(
1548-
; CHECK-NEXT: [[A_NEG:%.*]] = sub i8 [[A2:%.*]], [[A1:%.*]]
1549-
; CHECK-NEXT: [[MUL:%.*]] = shl i8 [[A_NEG]], 1
1548+
; CHECK-NEXT: [[A_NEG:%.*]] = sub nsw i8 [[A2:%.*]], [[A1:%.*]]
1549+
; CHECK-NEXT: [[MUL:%.*]] = shl nsw i8 [[A_NEG]], 1
15501550
; CHECK-NEXT: ret i8 [[MUL]]
15511551
;
15521552
%a = sub nsw i8 %a1, %a2
15531553
%mul = mul nsw i8 %a, -2
15541554
ret i8 %mul
15551555
}
15561556

1557+
; It would be safe to keep the nsw on the shl here, but only because the mul
1558+
; to shl transform happens to replace undef with 0.
15571559
define <2 x i8> @mulsub_nsw_undef(<2 x i8> %a1, <2 x i8> %a2) {
15581560
; CHECK-LABEL: @mulsub_nsw_undef(
1559-
; CHECK-NEXT: [[A_NEG:%.*]] = sub <2 x i8> [[A2:%.*]], [[A1:%.*]]
1561+
; CHECK-NEXT: [[A_NEG:%.*]] = sub nsw <2 x i8> [[A2:%.*]], [[A1:%.*]]
15601562
; CHECK-NEXT: [[MUL:%.*]] = shl <2 x i8> [[A_NEG]], <i8 1, i8 0>
15611563
; CHECK-NEXT: ret <2 x i8> [[MUL]]
15621564
;

0 commit comments

Comments
 (0)