From 39ae61ad2b2bcd60fb0fa524ef2022f7a7b3599e Mon Sep 17 00:00:00 2001 From: Rose Date: Fri, 21 Jun 2024 11:37:49 -0400 Subject: [PATCH] [InstCombine] Add freeze for lshr (mul (X, 2^N + 1)), N -> add (X, lshr(X, N)) --- .../InstCombine/InstCombineShifts.cpp | 5 +- llvm/test/Transforms/InstCombine/ashr-lshr.ll | 53 ++++++++++++------- llvm/test/Transforms/InstCombine/lshr.ll | 2 +- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp index 38f8a41214b682..90e97b020b9fe9 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -1499,7 +1499,7 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) { return replaceInstUsesWith(I, X); // lshr (mul nuw (X, 2^N + 1)), N -> add nuw (X, lshr(X, N)) - if (Op0->hasOneUse()) { + if (Op0->hasOneUse() && isGuaranteedNotToBeUndef(X, &AC, &I, &DT)) { auto *NewAdd = BinaryOperator::CreateNUWAdd( X, Builder.CreateLShr(X, ConstantInt::get(Ty, ShAmtC), "", I.isExact())); @@ -1528,7 +1528,8 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) { } // lshr (mul nsw (X, 2^N + 1)), N -> add nsw (X, lshr(X, N)) - if (match(Op0, m_OneUse(m_NSWMul(m_Value(X), m_APInt(MulC))))) { + if (match(Op0, m_OneUse(m_NSWMul(m_Value(X), m_APInt(MulC)))) && + isGuaranteedNotToBeUndef(X, &AC, &I, &DT)) { if (BitWidth > 2 && (*MulC - 1).isPowerOf2() && MulC->logBase2() == ShAmtC) { return BinaryOperator::CreateNSWAdd( diff --git a/llvm/test/Transforms/InstCombine/ashr-lshr.ll b/llvm/test/Transforms/InstCombine/ashr-lshr.ll index c2a4f35412670b..55aae49996fd04 100644 --- a/llvm/test/Transforms/InstCombine/ashr-lshr.ll +++ b/llvm/test/Transforms/InstCombine/ashr-lshr.ll @@ -605,7 +605,7 @@ define <2 x i8> @ashr_known_pos_exact_vec(<2 x i8> %x, <2 x i8> %y) { ret <2 x i8> %r } -define i32 @lshr_mul_times_3_div_2(i32 %0) { +define i32 @lshr_mul_times_3_div_2(i32 noundef %0) { ; CHECK-LABEL: @lshr_mul_times_3_div_2( ; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP0:%.*]], 1 ; CHECK-NEXT: [[LSHR:%.*]] = add nuw nsw i32 [[TMP2]], [[TMP0]] @@ -616,7 +616,20 @@ define i32 @lshr_mul_times_3_div_2(i32 %0) { ret i32 %lshr } -define i32 @lshr_mul_times_3_div_2_exact(i32 %x) { +; Negative test + +define i32 @lshr_mul_times_3_div_2_undef(i32 %0) { +; CHECK-LABEL: @lshr_mul_times_3_div_2_undef( +; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i32 [[TMP0:%.*]], 3 +; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[MUL]], 1 +; CHECK-NEXT: ret i32 [[LSHR]] +; + %mul = mul nsw nuw i32 %0, 3 + %lshr = lshr i32 %mul, 1 + ret i32 %lshr +} + +define i32 @lshr_mul_times_3_div_2_exact(i32 noundef %x) { ; CHECK-LABEL: @lshr_mul_times_3_div_2_exact( ; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 1 ; CHECK-NEXT: [[LSHR:%.*]] = add nsw i32 [[TMP1]], [[X]] @@ -629,7 +642,7 @@ define i32 @lshr_mul_times_3_div_2_exact(i32 %x) { ; Negative test -define i32 @lshr_mul_times_3_div_2_no_flags(i32 %0) { +define i32 @lshr_mul_times_3_div_2_no_flags(i32 noundef %0) { ; CHECK-LABEL: @lshr_mul_times_3_div_2_no_flags( ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP0:%.*]], 3 ; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[MUL]], 1 @@ -642,7 +655,7 @@ define i32 @lshr_mul_times_3_div_2_no_flags(i32 %0) { ; Negative test -define i32 @mul_times_3_div_2_multiuse_lshr(i32 %x) { +define i32 @mul_times_3_div_2_multiuse_lshr(i32 noundef %x) { ; CHECK-LABEL: @mul_times_3_div_2_multiuse_lshr( ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i32 [[X:%.*]], 3 ; CHECK-NEXT: [[RES:%.*]] = lshr i32 [[MUL]], 1 @@ -655,7 +668,7 @@ define i32 @mul_times_3_div_2_multiuse_lshr(i32 %x) { ret i32 %res } -define i32 @lshr_mul_times_3_div_2_exact_2(i32 %x) { +define i32 @lshr_mul_times_3_div_2_exact_2(i32 noundef %x) { ; CHECK-LABEL: @lshr_mul_times_3_div_2_exact_2( ; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 1 ; CHECK-NEXT: [[LSHR:%.*]] = add nuw i32 [[TMP1]], [[X]] @@ -666,7 +679,7 @@ define i32 @lshr_mul_times_3_div_2_exact_2(i32 %x) { ret i32 %lshr } -define i32 @lshr_mul_times_5_div_4(i32 %0) { +define i32 @lshr_mul_times_5_div_4(i32 noundef %0) { ; CHECK-LABEL: @lshr_mul_times_5_div_4( ; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP0:%.*]], 2 ; CHECK-NEXT: [[LSHR:%.*]] = add nuw nsw i32 [[TMP2]], [[TMP0]] @@ -677,7 +690,7 @@ define i32 @lshr_mul_times_5_div_4(i32 %0) { ret i32 %lshr } -define i32 @lshr_mul_times_5_div_4_exact(i32 %x) { +define i32 @lshr_mul_times_5_div_4_exact(i32 noundef %x) { ; CHECK-LABEL: @lshr_mul_times_5_div_4_exact( ; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 2 ; CHECK-NEXT: [[LSHR:%.*]] = add nsw i32 [[TMP1]], [[X]] @@ -690,7 +703,7 @@ define i32 @lshr_mul_times_5_div_4_exact(i32 %x) { ; Negative test -define i32 @lshr_mul_times_5_div_4_no_flags(i32 %0) { +define i32 @lshr_mul_times_5_div_4_no_flags(i32 noundef %0) { ; CHECK-LABEL: @lshr_mul_times_5_div_4_no_flags( ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP0:%.*]], 5 ; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[MUL]], 2 @@ -703,7 +716,7 @@ define i32 @lshr_mul_times_5_div_4_no_flags(i32 %0) { ; Negative test -define i32 @mul_times_5_div_4_multiuse_lshr(i32 %x) { +define i32 @mul_times_5_div_4_multiuse_lshr(i32 noundef %x) { ; CHECK-LABEL: @mul_times_5_div_4_multiuse_lshr( ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i32 [[X:%.*]], 5 ; CHECK-NEXT: [[RES:%.*]] = lshr i32 [[MUL]], 2 @@ -716,7 +729,7 @@ define i32 @mul_times_5_div_4_multiuse_lshr(i32 %x) { ret i32 %res } -define i32 @lshr_mul_times_5_div_4_exact_2(i32 %x) { +define i32 @lshr_mul_times_5_div_4_exact_2(i32 noundef %x) { ; CHECK-LABEL: @lshr_mul_times_5_div_4_exact_2( ; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 2 ; CHECK-NEXT: [[LSHR:%.*]] = add nuw i32 [[TMP1]], [[X]] @@ -727,7 +740,7 @@ define i32 @lshr_mul_times_5_div_4_exact_2(i32 %x) { ret i32 %lshr } -define i32 @ashr_mul_times_3_div_2(i32 %0) { +define i32 @ashr_mul_times_3_div_2(i32 noundef %0) { ; CHECK-LABEL: @ashr_mul_times_3_div_2( ; CHECK-NEXT: [[TMP2:%.*]] = ashr i32 [[TMP0:%.*]], 1 ; CHECK-NEXT: [[ASHR:%.*]] = add nuw nsw i32 [[TMP2]], [[TMP0]] @@ -738,7 +751,7 @@ define i32 @ashr_mul_times_3_div_2(i32 %0) { ret i32 %ashr } -define i32 @ashr_mul_times_3_div_2_exact(i32 %x) { +define i32 @ashr_mul_times_3_div_2_exact(i32 noundef %x) { ; CHECK-LABEL: @ashr_mul_times_3_div_2_exact( ; CHECK-NEXT: [[TMP1:%.*]] = ashr exact i32 [[X:%.*]], 1 ; CHECK-NEXT: [[ASHR:%.*]] = add nsw i32 [[TMP1]], [[X]] @@ -751,7 +764,7 @@ define i32 @ashr_mul_times_3_div_2_exact(i32 %x) { ; Negative test -define i32 @ashr_mul_times_3_div_2_no_flags(i32 %0) { +define i32 @ashr_mul_times_3_div_2_no_flags(i32 noundef %0) { ; CHECK-LABEL: @ashr_mul_times_3_div_2_no_flags( ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP0:%.*]], 3 ; CHECK-NEXT: [[ASHR:%.*]] = ashr i32 [[MUL]], 1 @@ -764,7 +777,7 @@ define i32 @ashr_mul_times_3_div_2_no_flags(i32 %0) { ; Negative test -define i32 @ashr_mul_times_3_div_2_no_nsw(i32 %0) { +define i32 @ashr_mul_times_3_div_2_no_nsw(i32 noundef %0) { ; CHECK-LABEL: @ashr_mul_times_3_div_2_no_nsw( ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i32 [[TMP0:%.*]], 3 ; CHECK-NEXT: [[ASHR:%.*]] = ashr i32 [[MUL]], 1 @@ -777,7 +790,7 @@ define i32 @ashr_mul_times_3_div_2_no_nsw(i32 %0) { ; Negative test -define i32 @mul_times_3_div_2_multiuse_ashr(i32 %x) { +define i32 @mul_times_3_div_2_multiuse_ashr(i32 noundef %x) { ; CHECK-LABEL: @mul_times_3_div_2_multiuse_ashr( ; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[X:%.*]], 3 ; CHECK-NEXT: [[RES:%.*]] = ashr i32 [[MUL]], 1 @@ -790,7 +803,7 @@ define i32 @mul_times_3_div_2_multiuse_ashr(i32 %x) { ret i32 %res } -define i32 @ashr_mul_times_3_div_2_exact_2(i32 %x) { +define i32 @ashr_mul_times_3_div_2_exact_2(i32 noundef %x) { ; CHECK-LABEL: @ashr_mul_times_3_div_2_exact_2( ; CHECK-NEXT: [[TMP1:%.*]] = ashr exact i32 [[X:%.*]], 1 ; CHECK-NEXT: [[ASHR:%.*]] = add nsw i32 [[TMP1]], [[X]] @@ -801,7 +814,7 @@ define i32 @ashr_mul_times_3_div_2_exact_2(i32 %x) { ret i32 %ashr } -define i32 @ashr_mul_times_5_div_4(i32 %0) { +define i32 @ashr_mul_times_5_div_4(i32 noundef %0) { ; CHECK-LABEL: @ashr_mul_times_5_div_4( ; CHECK-NEXT: [[TMP2:%.*]] = ashr i32 [[TMP0:%.*]], 2 ; CHECK-NEXT: [[ASHR:%.*]] = add nuw nsw i32 [[TMP2]], [[TMP0]] @@ -825,7 +838,7 @@ define i32 @ashr_mul_times_5_div_4_exact(i32 %x) { ; Negative test -define i32 @ashr_mul_times_5_div_4_no_flags(i32 %0) { +define i32 @ashr_mul_times_5_div_4_no_flags(i32 noundef %0) { ; CHECK-LABEL: @ashr_mul_times_5_div_4_no_flags( ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[TMP0:%.*]], 5 ; CHECK-NEXT: [[ASHR:%.*]] = ashr i32 [[MUL]], 2 @@ -838,7 +851,7 @@ define i32 @ashr_mul_times_5_div_4_no_flags(i32 %0) { ; Negative test -define i32 @mul_times_5_div_4_multiuse_ashr(i32 %x) { +define i32 @mul_times_5_div_4_multiuse_ashr(i32 noundef %x) { ; CHECK-LABEL: @mul_times_5_div_4_multiuse_ashr( ; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[X:%.*]], 5 ; CHECK-NEXT: [[RES:%.*]] = ashr i32 [[MUL]], 2 @@ -851,7 +864,7 @@ define i32 @mul_times_5_div_4_multiuse_ashr(i32 %x) { ret i32 %res } -define i32 @ashr_mul_times_5_div_4_exact_2(i32 %x) { +define i32 @ashr_mul_times_5_div_4_exact_2(i32 noundef %x) { ; CHECK-LABEL: @ashr_mul_times_5_div_4_exact_2( ; CHECK-NEXT: [[TMP1:%.*]] = ashr exact i32 [[X:%.*]], 2 ; CHECK-NEXT: [[ASHR:%.*]] = add nsw i32 [[TMP1]], [[X]] diff --git a/llvm/test/Transforms/InstCombine/lshr.ll b/llvm/test/Transforms/InstCombine/lshr.ll index 01e07985ba6ab5..51a2982f16f34b 100644 --- a/llvm/test/Transforms/InstCombine/lshr.ll +++ b/llvm/test/Transforms/InstCombine/lshr.ll @@ -739,7 +739,7 @@ define i32 @mul_splat_fold_wrong_lshr_const(i32 %x) { ret i32 %t } -define i32 @mul_splat_fold_no_nuw(i32 %x) { +define i32 @mul_splat_fold_no_nuw(i32 noundef %x) { ; CHECK-LABEL: @mul_splat_fold_no_nuw( ; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 16 ; CHECK-NEXT: [[T:%.*]] = add nsw i32 [[TMP1]], [[X]]