Skip to content

Commit

Permalink
[Reassociate] Keep flags for more unchanged operations
Browse files Browse the repository at this point in the history
Reassociation destroys nsw/nuw flags from BinOps that are changed. But if the
expression at the end of a tree that was altered, but didn't change itself,
the flags do not need to be removed. For example, if %a, %b and %c are
reassociated in
  %x = add nsw i32 %a, %c
  %y = add nsw i32 %x, %b
  %z = add nsw i32 %y, %d
The value of %y and so add %y %d remains the same, and %z needn't drop the nsw
flags.
https://alive2.llvm.org/ce/z/_juAiV

Differential Revision: https://reviews.llvm.org/D154289
  • Loading branch information
davemgreen committed Jul 3, 2023
1 parent 273600c commit db32d11
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 27 deletions.
61 changes: 39 additions & 22 deletions llvm/lib/Transforms/Scalar/Reassociate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,10 +689,12 @@ void ReassociatePass::RewriteExprTree(BinaryOperator *I,
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
NotRewritable.insert(Ops[i].Op);

// ExpressionChanged - Non-null if the rewritten expression differs from the
// original in some non-trivial way, requiring the clearing of optional flags.
// Flags are cleared from the operator in ExpressionChanged up to I inclusive.
BinaryOperator *ExpressionChanged = nullptr;
// ExpressionChangedStart - Non-null if the rewritten expression differs from
// the original in some non-trivial way, requiring the clearing of optional
// flags. Flags are cleared from the operator in ExpressionChangedStart up to
// ExpressionChangedEnd inclusive.
BinaryOperator *ExpressionChangedStart = nullptr,
*ExpressionChangedEnd = nullptr;
for (unsigned i = 0; ; ++i) {
// The last operation (which comes earliest in the IR) is special as both
// operands will come from Ops, rather than just one with the other being
Expand Down Expand Up @@ -734,7 +736,9 @@ void ReassociatePass::RewriteExprTree(BinaryOperator *I,
}
LLVM_DEBUG(dbgs() << "TO: " << *Op << '\n');

ExpressionChanged = Op;
ExpressionChangedStart = Op;
if (!ExpressionChangedEnd)
ExpressionChangedEnd = Op;
MadeChange = true;
++NumChanged;

Expand All @@ -756,7 +760,9 @@ void ReassociatePass::RewriteExprTree(BinaryOperator *I,
if (BO && !NotRewritable.count(BO))
NodesToRewrite.push_back(BO);
Op->setOperand(1, NewRHS);
ExpressionChanged = Op;
ExpressionChangedStart = Op;
if (!ExpressionChangedEnd)
ExpressionChangedEnd = Op;
}
LLVM_DEBUG(dbgs() << "TO: " << *Op << '\n');
MadeChange = true;
Expand Down Expand Up @@ -793,7 +799,9 @@ void ReassociatePass::RewriteExprTree(BinaryOperator *I,
LLVM_DEBUG(dbgs() << "RA: " << *Op << '\n');
Op->setOperand(0, NewOp);
LLVM_DEBUG(dbgs() << "TO: " << *Op << '\n');
ExpressionChanged = Op;
ExpressionChangedStart = Op;
if (!ExpressionChangedEnd)
ExpressionChangedEnd = Op;
MadeChange = true;
++NumChanged;
Op = NewOp;
Expand All @@ -803,27 +811,36 @@ void ReassociatePass::RewriteExprTree(BinaryOperator *I,
// starting from the operator specified in ExpressionChanged, and compactify
// the operators to just before the expression root to guarantee that the
// expression tree is dominated by all of Ops.
if (ExpressionChanged)
if (ExpressionChangedStart) {
bool ClearFlags = true;
do {
// Preserve FastMathFlags.
if (isa<FPMathOperator>(I)) {
FastMathFlags Flags = I->getFastMathFlags();
ExpressionChanged->clearSubclassOptionalData();
ExpressionChanged->setFastMathFlags(Flags);
} else
ExpressionChanged->clearSubclassOptionalData();

if (ExpressionChanged == I)
if (ClearFlags) {
if (isa<FPMathOperator>(I)) {
FastMathFlags Flags = I->getFastMathFlags();
ExpressionChangedStart->clearSubclassOptionalData();
ExpressionChangedStart->setFastMathFlags(Flags);
} else
ExpressionChangedStart->clearSubclassOptionalData();
}

if (ExpressionChangedStart == ExpressionChangedEnd)
ClearFlags = false;
if (ExpressionChangedStart == I)
break;

// Discard any debug info related to the expressions that has changed (we
// can leave debug infor related to the root, since the result of the
// expression tree should be the same even after reassociation).
replaceDbgUsesWithUndef(ExpressionChanged);

ExpressionChanged->moveBefore(I);
ExpressionChanged = cast<BinaryOperator>(*ExpressionChanged->user_begin());
// can leave debug info related to the root and any operation that didn't
// change, since the result of the expression tree should be the same
// even after reassociation).
if (ClearFlags)
replaceDbgUsesWithUndef(ExpressionChangedStart);

ExpressionChangedStart->moveBefore(I);
ExpressionChangedStart =
cast<BinaryOperator>(*ExpressionChangedStart->user_begin());
} while (true);
}

// Throw away any left over nodes from the original expression.
for (unsigned i = 0, e = NodesToRewrite.size(); i != e; ++i)
Expand Down
6 changes: 3 additions & 3 deletions llvm/test/Transforms/Reassociate/cse-pairs.ll
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ define signext i32 @twoPairsAllOpInPairs(i32 signext %0, i32 signext %1, i32 sig
; CHECK-LABEL: @twoPairsAllOpInPairs(
; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP2:%.*]], [[TMP1:%.*]]
; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP5]], [[TMP0:%.*]]
; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], [[TMP3:%.*]]
; CHECK-NEXT: [[TMP7:%.*]] = add nsw i32 [[TMP6]], [[TMP3:%.*]]
; CHECK-NEXT: store i32 [[TMP7]], ptr @num1, align 4
; CHECK-NEXT: store i32 [[TMP5]], ptr @num2, align 4
; CHECK-NEXT: [[TMP8:%.*]] = add nsw i32 [[TMP3]], [[TMP0]]
Expand All @@ -57,8 +57,8 @@ define signext i32 @threePairsAllOpInPairs(i32 signext %0, i32 signext %1, i32 s
; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP3:%.*]], [[TMP2:%.*]]
; CHECK-NEXT: [[TMP8:%.*]] = add i32 [[TMP7]], [[TMP0:%.*]]
; CHECK-NEXT: [[TMP9:%.*]] = add i32 [[TMP8]], [[TMP1:%.*]]
; CHECK-NEXT: [[TMP10:%.*]] = add i32 [[TMP9]], [[TMP4:%.*]]
; CHECK-NEXT: [[TMP11:%.*]] = add i32 [[TMP10]], [[TMP5:%.*]]
; CHECK-NEXT: [[TMP10:%.*]] = add nsw i32 [[TMP9]], [[TMP4:%.*]]
; CHECK-NEXT: [[TMP11:%.*]] = add nsw i32 [[TMP10]], [[TMP5:%.*]]
; CHECK-NEXT: store i32 [[TMP11]], ptr @num1, align 4
; CHECK-NEXT: [[TMP12:%.*]] = add nsw i32 [[TMP5]], [[TMP0]]
; CHECK-NEXT: store i32 [[TMP12]], ptr @num2, align 4
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/Reassociate/local-cse.ll
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ define void @chain_spanning_several_blocks(i64 %inv1, i64 %inv2, i64 %inv3, i64
; CSE-NEXT: [[VAL_BB2:%.*]] = call i64 @get_val()
; CSE-NEXT: [[CHAIN_A0:%.*]] = add i64 [[VAL_BB2]], [[INV1]]
; CSE-NEXT: [[CHAIN_A1:%.*]] = add i64 [[CHAIN_A0]], [[INV2]]
; CSE-NEXT: [[CHAIN_A2:%.*]] = add i64 [[CHAIN_A1]], [[INV4]]
; CSE-NEXT: [[CHAIN_A2:%.*]] = add nuw nsw i64 [[CHAIN_A1]], [[INV4]]
; CSE-NEXT: [[CHAIN_B2:%.*]] = add nuw nsw i64 [[CHAIN_A1]], [[INV5]]
; CSE-NEXT: [[CHAIN_C1:%.*]] = add i64 [[CHAIN_A0]], [[INV3]]
; CSE-NEXT: call void @keep_alive(i64 [[CHAIN_A2]])
Expand Down Expand Up @@ -122,7 +122,7 @@ define void @chain_spanning_several_blocks_no_entry_anchor() {
; CSE-NEXT: [[VAL_BB2:%.*]] = call i64 @get_val()
; CSE-NEXT: [[CHAIN_A0:%.*]] = add i64 [[VAL_BB2]], [[INV1_BB1]]
; CSE-NEXT: [[CHAIN_A1:%.*]] = add i64 [[CHAIN_A0]], [[INV2_BB0]]
; CSE-NEXT: [[CHAIN_A2:%.*]] = add i64 [[CHAIN_A1]], [[INV4_BB2]]
; CSE-NEXT: [[CHAIN_A2:%.*]] = add nuw nsw i64 [[CHAIN_A1]], [[INV4_BB2]]
; CSE-NEXT: [[CHAIN_B2:%.*]] = add nuw nsw i64 [[CHAIN_A1]], [[INV5_BB2]]
; CSE-NEXT: [[CHAIN_C1:%.*]] = add i64 [[CHAIN_A0]], [[INV3_BB2]]
; CSE-NEXT: call void @keep_alive(i64 [[CHAIN_A2]])
Expand Down

0 comments on commit db32d11

Please sign in to comment.