Skip to content

Commit 6e379de

Browse files
committed
[Reassociate] Preserve nuw and nsw on mul chains
Basically the same rules as `add` but we also need to ensure all operands a non-zero. Proofs: https://alive2.llvm.org/ce/z/jzsYht Closes #97040
1 parent c857916 commit 6e379de

File tree

3 files changed

+28
-16
lines changed

3 files changed

+28
-16
lines changed

llvm/include/llvm/Transforms/Scalar/Reassociate.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,13 @@ struct OverflowTracking {
6868
bool HasNUW;
6969
bool HasNSW;
7070
bool AllKnownNonNegative;
71+
bool AllKnownNonZero;
7172
// Note: AllKnownNonNegative can be true in a case where one of the operands
7273
// is negative, but one the operators is not NSW. AllKnownNonNegative should
7374
// not be used independently of HasNSW
74-
OverflowTracking() : HasNUW(true), HasNSW(true), AllKnownNonNegative(true) {}
75+
OverflowTracking()
76+
: HasNUW(true), HasNSW(true), AllKnownNonNegative(true),
77+
AllKnownNonZero(true) {}
7578
};
7679

7780
class XorOpnd;

llvm/lib/Transforms/Scalar/Reassociate.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,16 @@ static bool LinearizeExprTree(Instruction *I,
539539
Ops.push_back(std::make_pair(V, Weight));
540540
if (Opcode == Instruction::Add && Flags.AllKnownNonNegative && Flags.HasNSW)
541541
Flags.AllKnownNonNegative &= isKnownNonNegative(V, SimplifyQuery(DL));
542+
else if (Opcode == Instruction::Mul) {
543+
// To preserve NUW we need all inputs non-zero.
544+
// To preserve NSW we need all inputs strictly positive.
545+
if (Flags.AllKnownNonZero &&
546+
(Flags.HasNUW || (Flags.HasNSW && Flags.AllKnownNonNegative))) {
547+
Flags.AllKnownNonZero &= isKnownNonZero(V, SimplifyQuery(DL));
548+
if (Flags.HasNSW && Flags.AllKnownNonNegative)
549+
Flags.AllKnownNonNegative &= isKnownNonNegative(V, SimplifyQuery(DL));
550+
}
551+
}
542552
}
543553

544554
// For nilpotent operations or addition there may be no operands, for example
@@ -722,10 +732,9 @@ void ReassociatePass::RewriteExprTree(BinaryOperator *I,
722732
ExpressionChangedStart->setFastMathFlags(Flags);
723733
} else {
724734
ExpressionChangedStart->clearSubclassOptionalData();
725-
// Note that it doesn't hold for mul if one of the operands is zero.
726-
// TODO: We can preserve NUW flag if we prove that all mul operands
727-
// are non-zero.
728-
if (ExpressionChangedStart->getOpcode() == Instruction::Add) {
735+
if (ExpressionChangedStart->getOpcode() == Instruction::Add ||
736+
(ExpressionChangedStart->getOpcode() == Instruction::Mul &&
737+
Flags.AllKnownNonZero)) {
729738
if (Flags.HasNUW)
730739
ExpressionChangedStart->setHasNoUnsignedWrap();
731740
if (Flags.HasNSW && (Flags.AllKnownNonNegative || Flags.HasNUW))

llvm/test/Transforms/Reassociate/reassoc-mul-nuw.ll

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ define i4 @nuw_preserve_non_zero(i4 %a, i4 %b, i4 %c) {
2121
; CHECK-NEXT: [[A0:%.*]] = add nuw i4 [[A]], 1
2222
; CHECK-NEXT: [[B0:%.*]] = add nuw i4 [[B]], 1
2323
; CHECK-NEXT: [[C0:%.*]] = add nuw i4 [[C]], 1
24-
; CHECK-NEXT: [[V0:%.*]] = mul i4 [[B0]], [[A0]]
25-
; CHECK-NEXT: [[V1:%.*]] = mul i4 [[V0]], [[C0]]
24+
; CHECK-NEXT: [[V0:%.*]] = mul nuw i4 [[B0]], [[A0]]
25+
; CHECK-NEXT: [[V1:%.*]] = mul nuw i4 [[V0]], [[C0]]
2626
; CHECK-NEXT: ret i4 [[V1]]
2727
;
2828
%a0 = add nuw i4 %a, 1
@@ -40,9 +40,9 @@ define i4 @re_order_mul_nuw(i4 %xx0, i4 %xx1, i4 %xx2, i4 %xx3) {
4040
; CHECK-NEXT: [[X1:%.*]] = add nuw i4 [[XX1]], 1
4141
; CHECK-NEXT: [[X2:%.*]] = add nuw i4 [[XX2]], 1
4242
; CHECK-NEXT: [[X3:%.*]] = add nuw i4 [[XX3]], 1
43-
; CHECK-NEXT: [[MUL_B:%.*]] = mul i4 [[X1]], [[X0]]
44-
; CHECK-NEXT: [[MUL_A:%.*]] = mul i4 [[MUL_B]], [[X2]]
45-
; CHECK-NEXT: [[MUL_C:%.*]] = mul i4 [[MUL_A]], [[X3]]
43+
; CHECK-NEXT: [[MUL_B:%.*]] = mul nuw i4 [[X1]], [[X0]]
44+
; CHECK-NEXT: [[MUL_A:%.*]] = mul nuw i4 [[MUL_B]], [[X2]]
45+
; CHECK-NEXT: [[MUL_C:%.*]] = mul nuw i4 [[MUL_A]], [[X3]]
4646
; CHECK-NEXT: ret i4 [[MUL_C]]
4747
;
4848
%x0 = add nuw i4 %xx0, 1
@@ -88,9 +88,9 @@ define i4 @re_order_mul_nsw(i4 %xx0, i4 %xx1, i4 %xx2, i4 %xx3) {
8888
; CHECK-NEXT: [[X1:%.*]] = call i4 @llvm.smax.i4(i4 [[X1_NZ]], i4 1)
8989
; CHECK-NEXT: [[X2:%.*]] = call i4 @llvm.smax.i4(i4 [[X2_NZ]], i4 1)
9090
; CHECK-NEXT: [[X3:%.*]] = call i4 @llvm.smax.i4(i4 [[X3_NZ]], i4 1)
91-
; CHECK-NEXT: [[MUL_B:%.*]] = mul i4 [[X1]], [[X0]]
92-
; CHECK-NEXT: [[MUL_A:%.*]] = mul i4 [[MUL_B]], [[X2]]
93-
; CHECK-NEXT: [[MUL_C:%.*]] = mul i4 [[MUL_A]], [[X3]]
91+
; CHECK-NEXT: [[MUL_B:%.*]] = mul nsw i4 [[X1]], [[X0]]
92+
; CHECK-NEXT: [[MUL_A:%.*]] = mul nsw i4 [[MUL_B]], [[X2]]
93+
; CHECK-NEXT: [[MUL_C:%.*]] = mul nsw i4 [[MUL_A]], [[X3]]
9494
; CHECK-NEXT: ret i4 [[MUL_C]]
9595
;
9696
%x0_nz = add nuw i4 %xx0, 1
@@ -114,9 +114,9 @@ define i4 @re_order_mul_nsw_nuw(i4 %xx0, i4 %xx1, i4 %xx2, i4 %xx3) {
114114
; CHECK-NEXT: [[X1:%.*]] = add nuw i4 [[XX1]], 1
115115
; CHECK-NEXT: [[X2:%.*]] = add nuw i4 [[XX2]], 1
116116
; CHECK-NEXT: [[X3:%.*]] = add nuw i4 [[XX3]], 1
117-
; CHECK-NEXT: [[MUL_B:%.*]] = mul i4 [[X1]], [[X0]]
118-
; CHECK-NEXT: [[MUL_A:%.*]] = mul i4 [[MUL_B]], [[X2]]
119-
; CHECK-NEXT: [[MUL_C:%.*]] = mul i4 [[MUL_A]], [[X3]]
117+
; CHECK-NEXT: [[MUL_B:%.*]] = mul nuw nsw i4 [[X1]], [[X0]]
118+
; CHECK-NEXT: [[MUL_A:%.*]] = mul nuw nsw i4 [[MUL_B]], [[X2]]
119+
; CHECK-NEXT: [[MUL_C:%.*]] = mul nuw nsw i4 [[MUL_A]], [[X3]]
120120
; CHECK-NEXT: ret i4 [[MUL_C]]
121121
;
122122
%x0 = add nuw i4 %xx0, 1

0 commit comments

Comments
 (0)