diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index c55c40c88bc845..0db7d8818fbd0b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1847,6 +1847,37 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { return CastInst::Create(Instruction::ZExt, NarrowMaxMin, II->getType()); } } + // If C0 is not 0: + // umax(nuw_shl(x, C0), x + 1) -> x == 0 ? 1 : nuw_shl(x, C0) + // If C0 is not 0 or 1: + // umax(nuw_mul(x, C0), x + 1) -> x == 0 ? 1 : nuw_mul(x, C0) + ConstantInt *C0; + bool isShl = false; + BinaryOperator *Op = nullptr; + auto matchShiftOrMul = [&](Value *I) { + if (match(I, m_OneUse(m_NUWShl(m_Value(X), m_ConstantInt(C0))))) { + isShl = true; + return true; + } else if (match(I, m_OneUse(m_NUWMul(m_Value(X), m_ConstantInt(C0)))) && + C0 && !C0->isOne()) { + isShl = false; + return true; + } + return false; + }; + if (((matchShiftOrMul(I0) && + match(I1, m_OneUse(m_Add(m_Specific(X), m_One())))) || + (matchShiftOrMul(I1) && + match(I0, m_OneUse(m_Add(m_Specific(X), m_One()))))) && + C0 && !C0->isZero()) { + Op = isShl ? BinaryOperator::CreateNUWShl(X, C0) + : BinaryOperator::CreateNUWMul(X, C0); + Builder.Insert(Op); + Value *Cmp = Builder.CreateICmpEQ(X, ConstantInt::get(X->getType(), 0)); + Value *NewSelect = + Builder.CreateSelect(Cmp, ConstantInt::get(X->getType(), 1), Op); + return replaceInstUsesWith(*II, NewSelect); + } // If both operands of unsigned min/max are sign-extended, it is still ok // to narrow the operation. [[fallthrough]]; diff --git a/llvm/test/Transforms/InstCombine/add-shl-mul-umax.ll b/llvm/test/Transforms/InstCombine/add-shl-mul-umax.ll index 88a69e3dc6384e..86ce5dc06ce031 100644 --- a/llvm/test/Transforms/InstCombine/add-shl-mul-umax.ll +++ b/llvm/test/Transforms/InstCombine/add-shl-mul-umax.ll @@ -13,9 +13,9 @@ define i64 @test_shl_by_2(i64 %x) { ; CHECK-LABEL: define i64 @test_shl_by_2( ; CHECK-SAME: i64 [[X:%.*]]) { -; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw i64 [[X]], 2 -; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2]], i64 [[X1]]) +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[X]], 0 +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP3]], i64 1, i64 [[TMP2]] ; CHECK-NEXT: ret i64 [[MAX]] ; %x1 = add i64 %x, 1 @@ -27,9 +27,9 @@ define i64 @test_shl_by_2(i64 %x) { define i64 @test_shl_by_5(i64 %x) { ; CHECK-LABEL: define i64 @test_shl_by_5( ; CHECK-SAME: i64 [[X:%.*]]) { -; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw i64 [[X]], 5 -; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2]], i64 [[X1]]) +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[X]], 0 +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP3]], i64 1, i64 [[TMP2]] ; CHECK-NEXT: ret i64 [[MAX]] ; %x1 = add i64 %x, 1 @@ -43,9 +43,9 @@ define i64 @test_shl_by_5(i64 %x) { define i64 @test_shl_umax_commuted(i64 %x) { ; CHECK-LABEL: define i64 @test_shl_umax_commuted( ; CHECK-SAME: i64 [[X:%.*]]) { -; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i64 [[X]], 2 -; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[X1]], i64 [[SHL]]) +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[X]], 0 +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP2]], i64 1, i64 [[SHL]] ; CHECK-NEXT: ret i64 [[MAX]] ; %x1 = add i64 %x, 1 @@ -135,9 +135,9 @@ define i64 @test_shl_multi_use_shl(i64 %x) { define i64 @test_shl_multi_use_max(i64 %x) { ; CHECK-LABEL: define i64 @test_shl_multi_use_max( ; CHECK-SAME: i64 [[X:%.*]]) { -; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw i64 [[X]], 3 -; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2]], i64 [[X1]]) +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[X]], 0 +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP3]], i64 1, i64 [[TMP2]] ; CHECK-NEXT: call void @use(i64 [[MAX]]) ; CHECK-NEXT: ret i64 [[MAX]] ; @@ -153,9 +153,9 @@ define i64 @test_shl_multi_use_max(i64 %x) { define i64 @test_mul_by_2(i64 %x) { ; CHECK-LABEL: define i64 @test_mul_by_2( ; CHECK-SAME: i64 [[X:%.*]]) { -; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw i64 [[X]], 1 -; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2]], i64 [[X1]]) +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[X]], 0 +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP3]], i64 1, i64 [[TMP2]] ; CHECK-NEXT: ret i64 [[MAX]] ; %x1 = add i64 %x, 1 @@ -167,9 +167,9 @@ define i64 @test_mul_by_2(i64 %x) { define i64 @test_mul_by_5(i64 %x) { ; CHECK-LABEL: define i64 @test_mul_by_5( ; CHECK-SAME: i64 [[X:%.*]]) { -; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i64 [[X]], 5 -; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[MUL]], i64 [[X1]]) +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[X]], 0 +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP2]], i64 1, i64 [[MUL]] ; CHECK-NEXT: ret i64 [[MAX]] ; %x1 = add i64 %x, 1 @@ -183,9 +183,9 @@ define i64 @test_mul_by_5(i64 %x) { define i64 @test_mul_max_commuted(i64 %x) { ; CHECK-LABEL: define i64 @test_mul_max_commuted( ; CHECK-SAME: i64 [[X:%.*]]) { -; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 ; CHECK-NEXT: [[MUL:%.*]] = shl nuw i64 [[X]], 1 -; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[X1]], i64 [[MUL]]) +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[X]], 0 +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP2]], i64 1, i64 [[MUL]] ; CHECK-NEXT: ret i64 [[MAX]] ; %x1 = add i64 %x, 1 @@ -286,9 +286,9 @@ define i64 @test_mul_multi_use_mul(i64 %x) { define i64 @test_mul_multi_use_max(i64 %x) { ; CHECK-LABEL: define i64 @test_mul_multi_use_max( ; CHECK-SAME: i64 [[X:%.*]]) { -; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw i64 [[X]], 1 -; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2]], i64 [[X1]]) +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i64 [[X]], 0 +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP3]], i64 1, i64 [[TMP2]] ; CHECK-NEXT: call void @use(i64 [[MAX]]) ; CHECK-NEXT: ret i64 [[MAX]] ;