Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,18 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
PatternMatch::m_Value()));
}

// Take the exact integer log2 of the value. If DoFold is true, create the
// actual instructions, otherwise return a non-null dummy value. Return
// nullptr on failure. Note, if DoFold is true the caller must ensure that
// takeLog2 will succeed, otherwise it may create stray instructions.
Value *takeLog2(Value *Op, unsigned Depth, bool AssumeNonZero, bool DoFold);

Value *tryGetLog2(Value *Op, bool AssumeNonZero) {
if (takeLog2(Op, /*Depth=*/0, AssumeNonZero, /*DoFold=*/false))
return takeLog2(Op, /*Depth=*/0, AssumeNonZero, /*DoFold=*/true);
return nullptr;
}

/// Return nonnull value if V is free to invert under the condition of
/// WillInvertAllUses.
/// If Builder is nonnull, it will return a simplified ~V.
Expand Down
124 changes: 3 additions & 121 deletions llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,6 @@ static Value *foldMulShl1(BinaryOperator &Mul, bool CommuteOperands,
return nullptr;
}

static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth,
bool AssumeNonZero, bool DoFold);

Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (Value *V =
Expand Down Expand Up @@ -531,19 +528,13 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
// (shl Op1, Log2(Op0))
// if Log2(Op1) folds away ->
// (shl Op0, Log2(Op1))
if (takeLog2(Builder, Op0, /*Depth*/ 0, /*AssumeNonZero*/ false,
/*DoFold*/ false)) {
Value *Res = takeLog2(Builder, Op0, /*Depth*/ 0, /*AssumeNonZero*/ false,
/*DoFold*/ true);
if (Value *Res = tryGetLog2(Op0, /*AssumeNonZero=*/false)) {
BinaryOperator *Shl = BinaryOperator::CreateShl(Op1, Res);
// We can only propegate nuw flag.
Shl->setHasNoUnsignedWrap(HasNUW);
return Shl;
}
if (takeLog2(Builder, Op1, /*Depth*/ 0, /*AssumeNonZero*/ false,
/*DoFold*/ false)) {
Value *Res = takeLog2(Builder, Op1, /*Depth*/ 0, /*AssumeNonZero*/ false,
/*DoFold*/ true);
if (Value *Res = tryGetLog2(Op0, /*AssumeNonZero=*/false)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mistake here.

BinaryOperator *Shl = BinaryOperator::CreateShl(Op0, Res);
// We can only propegate nuw flag.
Shl->setHasNoUnsignedWrap(HasNUW);
Expand Down Expand Up @@ -1407,111 +1398,6 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
return nullptr;
}

static const unsigned MaxDepth = 6;

// Take the exact integer log2 of the value. If DoFold is true, create the
// actual instructions, otherwise return a non-null dummy value. Return nullptr
// on failure.
static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth,
bool AssumeNonZero, bool DoFold) {
auto IfFold = [DoFold](function_ref<Value *()> Fn) {
if (!DoFold)
return reinterpret_cast<Value *>(-1);
return Fn();
};

// FIXME: assert that Op1 isn't/doesn't contain undef.

// log2(2^C) -> C
if (match(Op, m_Power2()))
return IfFold([&]() {
Constant *C = ConstantExpr::getExactLogBase2(cast<Constant>(Op));
if (!C)
llvm_unreachable("Failed to constant fold udiv -> logbase2");
return C;
});

// The remaining tests are all recursive, so bail out if we hit the limit.
if (Depth++ == MaxDepth)
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, AssumeNonZero, DoFold))
return IfFold([&]() { return Builder.CreateZExt(LogX, Op->getType()); });

// log2(trunc x) -> trunc log2(X)
// FIXME: Require one use?
if (match(Op, m_Trunc(m_Value(X)))) {
auto *TI = cast<TruncInst>(Op);
if (AssumeNonZero || TI->hasNoUnsignedWrap())
if (Value *LogX = takeLog2(Builder, X, Depth, AssumeNonZero, DoFold))
return IfFold([&]() {
return Builder.CreateTrunc(LogX, Op->getType(), "",
/*IsNUW=*/TI->hasNoUnsignedWrap());
});
}

// 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)))) {
auto *BO = cast<OverflowingBinaryOperator>(Op);
// nuw will be set if the `shl` is trivially non-zero.
if (AssumeNonZero || BO->hasNoUnsignedWrap() || BO->hasNoSignedWrap())
if (Value *LogX = takeLog2(Builder, X, Depth, AssumeNonZero, DoFold))
return IfFold([&]() { return Builder.CreateAdd(LogX, Y); });
}

// log2(X >>u Y) -> log2(X) - Y
// FIXME: Require one use?
if (match(Op, m_LShr(m_Value(X), m_Value(Y)))) {
auto *PEO = cast<PossiblyExactOperator>(Op);
if (AssumeNonZero || PEO->isExact())
if (Value *LogX = takeLog2(Builder, X, Depth, AssumeNonZero, DoFold))
return IfFold([&]() { return Builder.CreateSub(LogX, Y); });
}

// log2(X & Y) -> either log2(X) or log2(Y)
// This requires `AssumeNonZero` as `X & Y` may be zero when X != Y.
if (AssumeNonZero && match(Op, m_And(m_Value(X), m_Value(Y)))) {
if (Value *LogX = takeLog2(Builder, X, Depth, AssumeNonZero, DoFold))
return IfFold([&]() { return LogX; });
if (Value *LogY = takeLog2(Builder, Y, Depth, AssumeNonZero, DoFold))
return IfFold([&]() { return LogY; });
}

// log2(Cond ? X : Y) -> Cond ? log2(X) : log2(Y)
// FIXME: Require one use?
if (SelectInst *SI = dyn_cast<SelectInst>(Op))
if (Value *LogX = takeLog2(Builder, SI->getOperand(1), Depth,
AssumeNonZero, DoFold))
if (Value *LogY = takeLog2(Builder, SI->getOperand(2), Depth,
AssumeNonZero, DoFold))
return IfFold([&]() {
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<MinMaxIntrinsic>(Op);
if (MinMax && MinMax->hasOneUse() && !MinMax->isSigned()) {
// Use AssumeNonZero as false here. Otherwise we can hit case where
// log2(umax(X, Y)) != umax(log2(X), log2(Y)) (because overflow).
if (Value *LogX = takeLog2(Builder, MinMax->getLHS(), Depth,
/*AssumeNonZero*/ false, DoFold))
if (Value *LogY = takeLog2(Builder, MinMax->getRHS(), Depth,
/*AssumeNonZero*/ false, DoFold))
return IfFold([&]() {
return Builder.CreateBinaryIntrinsic(MinMax->getIntrinsicID(), LogX,
LogY);
});
}

return nullptr;
}

/// If we have zero-extended operands of an unsigned div or rem, we may be able
/// to narrow the operation (sink the zext below the math).
static Instruction *narrowUDivURem(BinaryOperator &I,
Expand Down Expand Up @@ -1614,13 +1500,9 @@ Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) {
}

// Op1 udiv Op2 -> Op1 lshr log2(Op2), if log2() folds away.
if (takeLog2(Builder, Op1, /*Depth*/ 0, /*AssumeNonZero*/ true,
/*DoFold*/ false)) {
Value *Res = takeLog2(Builder, Op1, /*Depth*/ 0,
/*AssumeNonZero*/ true, /*DoFold*/ true);
if (Value *Res = tryGetLog2(Op1, /*AssumeNonZero=*/true))
return replaceInstUsesWith(
I, Builder.CreateLShr(Op0, Res, I.getName(), I.isExact()));
}

return nullptr;
}
Expand Down
99 changes: 99 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2565,6 +2565,105 @@ Instruction *InstCombinerImpl::visitGEPOfGEP(GetElementPtrInst &GEP,
return nullptr;
}

Value *InstCombiner::takeLog2(Value *Op, unsigned Depth, bool AssumeNonZero,
bool DoFold) {
auto IfFold = [DoFold](function_ref<Value *()> Fn) {
if (!DoFold)
return reinterpret_cast<Value *>(-1);
return Fn();
};

// FIXME: assert that Op1 isn't/doesn't contain undef.

// log2(2^C) -> C
if (match(Op, m_Power2()))
return IfFold([&]() {
Constant *C = ConstantExpr::getExactLogBase2(cast<Constant>(Op));
if (!C)
llvm_unreachable("Failed to constant fold udiv -> logbase2");
return C;
});

// The remaining tests are all recursive, so bail out if we hit the limit.
if (Depth++ == MaxAnalysisRecursionDepth)
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(X, Depth, AssumeNonZero, DoFold))
return IfFold([&]() { return Builder.CreateZExt(LogX, Op->getType()); });

// log2(trunc x) -> trunc log2(X)
// FIXME: Require one use?
if (match(Op, m_Trunc(m_Value(X)))) {
auto *TI = cast<TruncInst>(Op);
if (AssumeNonZero || TI->hasNoUnsignedWrap())
if (Value *LogX = takeLog2(X, Depth, AssumeNonZero, DoFold))
return IfFold([&]() {
return Builder.CreateTrunc(LogX, Op->getType(), "",
/*IsNUW=*/TI->hasNoUnsignedWrap());
});
}

// 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)))) {
auto *BO = cast<OverflowingBinaryOperator>(Op);
// nuw will be set if the `shl` is trivially non-zero.
if (AssumeNonZero || BO->hasNoUnsignedWrap() || BO->hasNoSignedWrap())
if (Value *LogX = takeLog2(X, Depth, AssumeNonZero, DoFold))
return IfFold([&]() { return Builder.CreateAdd(LogX, Y); });
}

// log2(X >>u Y) -> log2(X) - Y
// FIXME: Require one use?
if (match(Op, m_LShr(m_Value(X), m_Value(Y)))) {
auto *PEO = cast<PossiblyExactOperator>(Op);
if (AssumeNonZero || PEO->isExact())
if (Value *LogX = takeLog2(X, Depth, AssumeNonZero, DoFold))
return IfFold([&]() { return Builder.CreateSub(LogX, Y); });
}

// log2(X & Y) -> either log2(X) or log2(Y)
// This requires `AssumeNonZero` as `X & Y` may be zero when X != Y.
if (AssumeNonZero && match(Op, m_And(m_Value(X), m_Value(Y)))) {
if (Value *LogX = takeLog2(X, Depth, AssumeNonZero, DoFold))
return IfFold([&]() { return LogX; });
if (Value *LogY = takeLog2(Y, Depth, AssumeNonZero, DoFold))
return IfFold([&]() { return LogY; });
}

// log2(Cond ? X : Y) -> Cond ? log2(X) : log2(Y)
// FIXME: Require one use?
if (SelectInst *SI = dyn_cast<SelectInst>(Op))
if (Value *LogX = takeLog2(SI->getOperand(1), Depth, AssumeNonZero, DoFold))
if (Value *LogY =
takeLog2(SI->getOperand(2), Depth, AssumeNonZero, DoFold))
return IfFold([&]() {
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<MinMaxIntrinsic>(Op);
if (MinMax && MinMax->hasOneUse() && !MinMax->isSigned()) {
// Use AssumeNonZero as false here. Otherwise we can hit case where
// log2(umax(X, Y)) != umax(log2(X), log2(Y)) (because overflow).
if (Value *LogX = takeLog2(MinMax->getLHS(), Depth,
/*AssumeNonZero*/ false, DoFold))
if (Value *LogY = takeLog2(MinMax->getRHS(), Depth,
/*AssumeNonZero*/ false, DoFold))
return IfFold([&]() {
return Builder.CreateBinaryIntrinsic(MinMax->getIntrinsicID(), LogX,
LogY);
});
}

return nullptr;
}

Value *InstCombiner::getFreelyInvertedImpl(Value *V, bool WillInvertAllUses,
BuilderTy *Builder,
bool &DoesConsume, unsigned Depth) {
Expand Down
Loading