From: Nikita Popov Date: Wed, 23 Feb 2022 14:49:12 +0000 (+0100) Subject: [InstCombine] Support min/max intrinsics in udiv->lshr fold X-Git-Tag: upstream/15.0.7~15539 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=587c7ff15c26d3a751fb6a10b2af60d4a25640c9;p=platform%2Fupstream%2Fllvm.git [InstCombine] Support min/max intrinsics in udiv->lshr fold This complements the existing fold for selects. This fold is a bit more conservative, requiring one-use. The other folds here should probably also be subjected to a one-use restriction. https://alive2.llvm.org/ce/z/Q9eCDU https://alive2.llvm.org/ce/z/8YK2CJ --- diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index aeae254..dd866eaa 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -927,12 +927,14 @@ static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth, return nullptr; // log2(zext X) -> zext log2(X) + // FIXME: Require one use? Value *X, *Y; if (match(Op, m_ZExt(m_Value(X)))) if (Value *LogX = takeLog2(Builder, X, Depth, DoFold)) return IfFold([&]() { return Builder.CreateZExt(LogX, Op->getType()); }); // log2(X << Y) -> log2(X) + Y + // FIXME: Require one use unless X is 1? if (match(Op, m_Shl(m_Value(X), m_Value(Y)))) if (Value *LogX = takeLog2(Builder, X, Depth, DoFold)) return IfFold([&]() { return Builder.CreateAdd(LogX, Y); }); @@ -941,6 +943,7 @@ static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth, // FIXME: missed optimization: if one of the hands of select is/contains // undef, just directly pick the other one. // FIXME: can both hands contain undef? + // FIXME: Require one use? if (SelectInst *SI = dyn_cast(Op)) if (Value *LogX = takeLog2(Builder, SI->getOperand(1), Depth, DoFold)) if (Value *LogY = takeLog2(Builder, SI->getOperand(2), Depth, DoFold)) @@ -948,6 +951,17 @@ static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth, return Builder.CreateSelect(SI->getOperand(0), LogX, LogY); }); + // log2(umin(X, Y)) -> umin(log2(X), log2(Y)) + // log2(umax(X, Y)) -> umax(log2(X), log2(Y)) + auto *MinMax = dyn_cast(Op); + if (MinMax && MinMax->hasOneUse() && !MinMax->isSigned()) + if (Value *LogX = takeLog2(Builder, MinMax->getLHS(), Depth, DoFold)) + if (Value *LogY = takeLog2(Builder, MinMax->getRHS(), Depth, DoFold)) + return IfFold([&]() { + return Builder.CreateBinaryIntrinsic( + MinMax->getIntrinsicID(), LogX, LogY); + }); + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/div-shift.ll b/llvm/test/Transforms/InstCombine/div-shift.ll index a2399df..ec7ee56 100644 --- a/llvm/test/Transforms/InstCombine/div-shift.ll +++ b/llvm/test/Transforms/InstCombine/div-shift.ll @@ -108,11 +108,9 @@ define i32 @t6(i32 %x, i32 %z) { define i8 @udiv_umin(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @udiv_umin( -; CHECK-NEXT: [[Y2:%.*]] = shl i8 1, [[Y:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = shl i8 1, [[Z:%.*]] -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[Y2]], i8 [[Z2]]) -; CHECK-NEXT: [[D:%.*]] = udiv i8 [[X:%.*]], [[M]] -; CHECK-NEXT: ret i8 [[D]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[Y:%.*]], i8 [[Z:%.*]]) +; CHECK-NEXT: [[D1:%.*]] = lshr i8 [[X:%.*]], [[TMP1]] +; CHECK-NEXT: ret i8 [[D1]] ; %y2 = shl i8 1, %y %z2 = shl i8 1, %z @@ -123,11 +121,9 @@ define i8 @udiv_umin(i8 %x, i8 %y, i8 %z) { define i8 @udiv_umax(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @udiv_umax( -; CHECK-NEXT: [[Y2:%.*]] = shl i8 1, [[Y:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = shl i8 1, [[Z:%.*]] -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[Y2]], i8 [[Z2]]) -; CHECK-NEXT: [[D:%.*]] = udiv i8 [[X:%.*]], [[M]] -; CHECK-NEXT: ret i8 [[D]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[Y:%.*]], i8 [[Z:%.*]]) +; CHECK-NEXT: [[D1:%.*]] = lshr i8 [[X:%.*]], [[TMP1]] +; CHECK-NEXT: ret i8 [[D1]] ; %y2 = shl i8 1, %y %z2 = shl i8 1, %z