From a773c26b7d7e69d95756078514d00f6f7a4b38c2 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Sat, 4 Jan 2025 17:10:59 +0800 Subject: [PATCH 1/3] [InstCombine] Add pre-commit tests. NFC. --- llvm/test/Transforms/InstCombine/rem-mul-shl.ll | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll index e7d6cc7102c71..0ac94865459a0 100644 --- a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll +++ b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll @@ -372,6 +372,17 @@ define <2 x i8> @srem_XY_XZ_with_CY_gt_CZ_no_nuw_out(<2 x i8> %X) { ret <2 x i8> %r } +define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw(i8 noundef %X) { +; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_drop_nsw( +; CHECK-NEXT: [[R:%.*]] = sub nsw i8 0, [[X:%.*]] +; CHECK-NEXT: ret i8 [[R]] +; + %BO0 = mul nsw i8 %X, 127 + %BO1 = shl nsw i8 %X, 7 + %r = srem i8 %BO1, %BO0 + ret i8 %r +} + define i8 @srem_XY_XZ_with_CY_gt_CZ_fail_missing_flag1(i8 %X) { ; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_fail_missing_flag1( ; CHECK-NEXT: [[BO0:%.*]] = mul nuw nsw i8 [[X:%.*]], 10 From eed542e16a34bf47adf33cf41cba01053863ff52 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Sat, 4 Jan 2025 17:19:10 +0800 Subject: [PATCH 2/3] [InstCombine] Drop NSW when converting `shl X, BW - 1` back into mul --- .../InstCombine/InstCombineMulDivRem.cpp | 16 +++++++++++----- llvm/test/Transforms/InstCombine/rem-mul-shl.ll | 4 +++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index f85a3c9365135..97a765ecfb6bd 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -2066,14 +2066,18 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I, bool ShiftByX = false; // If V is not nullptr, it will be matched using m_Specific. - auto MatchShiftOrMulXC = [](Value *Op, Value *&V, APInt &C) -> bool { + auto MatchShiftOrMulXC = [](Value *Op, Value *&V, APInt &C, + bool &PreserveNSW) -> bool { const APInt *Tmp = nullptr; if ((!V && match(Op, m_Mul(m_Value(V), m_APInt(Tmp)))) || (V && match(Op, m_Mul(m_Specific(V), m_APInt(Tmp))))) C = *Tmp; else if ((!V && match(Op, m_Shl(m_Value(V), m_APInt(Tmp)))) || - (V && match(Op, m_Shl(m_Specific(V), m_APInt(Tmp))))) + (V && match(Op, m_Shl(m_Specific(V), m_APInt(Tmp))))) { C = APInt(Tmp->getBitWidth(), 1) << *Tmp; + // We cannot preserve NSW when shifting by BW - 1. + PreserveNSW = Tmp->ult(Tmp->getBitWidth() - 1); + } if (Tmp != nullptr) return true; @@ -2095,7 +2099,9 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I, return false; }; - if (MatchShiftOrMulXC(Op0, X, Y) && MatchShiftOrMulXC(Op1, X, Z)) { + bool Op0PreserveNSW = true, Op1PreserveNSW = true; + if (MatchShiftOrMulXC(Op0, X, Y, Op0PreserveNSW) && + MatchShiftOrMulXC(Op1, X, Z, Op1PreserveNSW)) { // pass } else if (MatchShiftCX(Op0, Y, X) && MatchShiftCX(Op1, Z, X)) { ShiftByX = true; @@ -2108,7 +2114,7 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I, OverflowingBinaryOperator *BO0 = cast(Op0); // TODO: We may be able to deduce more about nsw/nuw of BO0/BO1 based on Y >= // Z or Z >= Y. - bool BO0HasNSW = BO0->hasNoSignedWrap(); + bool BO0HasNSW = Op0PreserveNSW && BO0->hasNoSignedWrap(); bool BO0HasNUW = BO0->hasNoUnsignedWrap(); bool BO0NoWrap = IsSRem ? BO0HasNSW : BO0HasNUW; @@ -2131,7 +2137,7 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I, }; OverflowingBinaryOperator *BO1 = cast(Op1); - bool BO1HasNSW = BO1->hasNoSignedWrap(); + bool BO1HasNSW = Op1PreserveNSW && BO1->hasNoSignedWrap(); bool BO1HasNUW = BO1->hasNoUnsignedWrap(); bool BO1NoWrap = IsSRem ? BO1HasNSW : BO1HasNUW; // (rem (mul X, Y), (mul nuw/nsw X, Z)) diff --git a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll index 0ac94865459a0..aa087129e45d3 100644 --- a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll +++ b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll @@ -374,7 +374,9 @@ define <2 x i8> @srem_XY_XZ_with_CY_gt_CZ_no_nuw_out(<2 x i8> %X) { define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw(i8 noundef %X) { ; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_drop_nsw( -; CHECK-NEXT: [[R:%.*]] = sub nsw i8 0, [[X:%.*]] +; CHECK-NEXT: [[BO0:%.*]] = mul nsw i8 [[X:%.*]], 127 +; CHECK-NEXT: [[BO1:%.*]] = shl nsw i8 [[X]], 7 +; CHECK-NEXT: [[R:%.*]] = srem i8 [[BO1]], [[BO0]] ; CHECK-NEXT: ret i8 [[R]] ; %BO0 = mul nsw i8 %X, 127 From 138b4ec97e21c49ce4546b2e6a469c2e9c572f45 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Sat, 4 Jan 2025 20:31:50 +0800 Subject: [PATCH 3/3] [InstCombine] Add commuted tests. NFC. --- llvm/test/Transforms/InstCombine/rem-mul-shl.ll | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll index aa087129e45d3..920497c07e380 100644 --- a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll +++ b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll @@ -385,6 +385,19 @@ define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw(i8 noundef %X) { ret i8 %r } +define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw_commuted(i8 noundef %X) { +; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_drop_nsw_commuted( +; CHECK-NEXT: [[BO0:%.*]] = mul nsw i8 [[X:%.*]], 127 +; CHECK-NEXT: [[BO1:%.*]] = shl nsw i8 [[X]], 7 +; CHECK-NEXT: [[R:%.*]] = srem i8 [[BO0]], [[BO1]] +; CHECK-NEXT: ret i8 [[R]] +; + %BO0 = mul nsw i8 %X, 127 + %BO1 = shl nsw i8 %X, 7 + %r = srem i8 %BO0, %BO1 + ret i8 %r +} + define i8 @srem_XY_XZ_with_CY_gt_CZ_fail_missing_flag1(i8 %X) { ; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_fail_missing_flag1( ; CHECK-NEXT: [[BO0:%.*]] = mul nuw nsw i8 [[X:%.*]], 10