Skip to content

Commit

Permalink
[LVI] Fix LVI compile time regression around constantFoldUser()
Browse files Browse the repository at this point in the history
Summary:
Avoid checking each operand and calling getValueFromCondition() before calling
constantFoldUser() when the instruction type isn't supported by
constantFoldUser().

This fixes a large compile time regression in an internal build.

Reviewers: sanjoy

Reviewed By: sanjoy

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D36552

llvm-svn: 310545
  • Loading branch information
hjyamauchi committed Aug 10, 2017
1 parent 58933c5 commit ccd412f
Showing 1 changed file with 28 additions and 14 deletions.
42 changes: 28 additions & 14 deletions llvm/lib/Analysis/LazyValueInfo.cpp
Expand Up @@ -1370,23 +1370,32 @@ static bool usesOperand(User *Usr, Value *Op) {
return find(Usr->operands(), Op) != Usr->op_end();
}

// Check if Val can be simplified to an integer constant when the value of one
// Return true if the instruction type of Val is supported by
// constantFoldUser(). Currently CastInst and BinaryOperator only. Call this
// before calling constantFoldUser() to find out if it's even worth attempting
// to call it.
static bool isOperationFoldable(User *Usr) {
return isa<CastInst>(Usr) || isa<BinaryOperator>(Usr);
}

// Check if Usr can be simplified to an integer constant when the value of one
// of its operands Op is an integer constant OpConstVal. If so, return it as an
// lattice value range with a single element or otherwise return an overdefined
// lattice value.
static LVILatticeVal constantFoldUser(Value *Val, Value *Op,
static LVILatticeVal constantFoldUser(User *Usr, Value *Op,
const APInt &OpConstVal,
const DataLayout &DL) {
assert(isOperationFoldable(Usr) && "Precondition");
Constant* OpConst = Constant::getIntegerValue(Op->getType(), OpConstVal);
// Check if Val can be simplified to a constant.
if (auto *CI = dyn_cast<CastInst>(Val)) {
// Check if Usr can be simplified to a constant.
if (auto *CI = dyn_cast<CastInst>(Usr)) {
assert(CI->getOperand(0) == Op && "Operand 0 isn't Op");
if (auto *C = dyn_cast_or_null<ConstantInt>(
SimplifyCastInst(CI->getOpcode(), OpConst,
CI->getDestTy(), DL))) {
return LVILatticeVal::getRange(ConstantRange(C->getValue()));
}
} else if (auto *BO = dyn_cast<BinaryOperator>(Val)) {
} else if (auto *BO = dyn_cast<BinaryOperator>(Usr)) {
bool Op0Match = BO->getOperand(0) == Op;
bool Op1Match = BO->getOperand(1) == Op;
assert((Op0Match || Op1Match) &&
Expand Down Expand Up @@ -1434,7 +1443,10 @@ static bool getEdgeValueLocal(Value *Val, BasicBlock *BBFrom,

if (User *Usr = dyn_cast<User>(Val)) {
assert(Result.isOverdefined() && "Result isn't overdefined");
if (isa<IntegerType>(Val->getType())) {
// Check with isOperationFoldable() first to avoid linearly iterating
// over the operands unnecessarily which can be expensive for
// instructions with many operands.
if (isa<IntegerType>(Usr->getType()) && isOperationFoldable(Usr)) {
const DataLayout &DL = BBTo->getModule()->getDataLayout();
if (usesOperand(Usr, Condition)) {
// If Val has Condition as an operand and Val can be folded into a
Expand All @@ -1445,7 +1457,7 @@ static bool getEdgeValueLocal(Value *Val, BasicBlock *BBFrom,
// %Val = and i1 %Condition, true.
// br %Condition, label %then, label %else
APInt ConditionVal(1, isTrueDest ? 1 : 0);
Result = constantFoldUser(Val, Condition, ConditionVal, DL);
Result = constantFoldUser(Usr, Condition, ConditionVal, DL);
} else {
// If one of Val's operand has an inferred value, we may be able to
// infer the value of Val.
Expand All @@ -1459,7 +1471,7 @@ static bool getEdgeValueLocal(Value *Val, BasicBlock *BBFrom,
LVILatticeVal OpLatticeVal =
getValueFromCondition(Op, Condition, isTrueDest);
if (Optional<APInt> OpConst = OpLatticeVal.asConstantInteger()) {
Result = constantFoldUser(Val, Op, OpConst.getValue(), DL);
Result = constantFoldUser(Usr, Op, OpConst.getValue(), DL);
break;
}
}
Expand All @@ -1477,15 +1489,16 @@ static bool getEdgeValueLocal(Value *Val, BasicBlock *BBFrom,
Value *Condition = SI->getCondition();
if (!isa<IntegerType>(Val->getType()))
return false;
bool ValUsesCondition = false;
bool ValUsesConditionAndMayBeFoldable = false;
if (Condition != Val) {
// Check if Val has Condition as an operand.
if (User *Usr = dyn_cast<User>(Val))
ValUsesCondition = usesOperand(Usr, Condition);
if (!ValUsesCondition)
ValUsesConditionAndMayBeFoldable = isOperationFoldable(Usr) &&
usesOperand(Usr, Condition);
if (!ValUsesConditionAndMayBeFoldable)
return false;
}
assert((Condition == Val || ValUsesCondition) &&
assert((Condition == Val || ValUsesConditionAndMayBeFoldable) &&
"Condition != Val nor Val doesn't use Condition");

bool DefaultCase = SI->getDefaultDest() == BBTo;
Expand All @@ -1495,10 +1508,11 @@ static bool getEdgeValueLocal(Value *Val, BasicBlock *BBFrom,
for (auto Case : SI->cases()) {
APInt CaseValue = Case.getCaseValue()->getValue();
ConstantRange EdgeVal(CaseValue);
if (ValUsesCondition) {
if (ValUsesConditionAndMayBeFoldable) {
User *Usr = cast<User>(Val);
const DataLayout &DL = BBTo->getModule()->getDataLayout();
LVILatticeVal EdgeLatticeVal =
constantFoldUser(Val, Condition, CaseValue, DL);
constantFoldUser(Usr, Condition, CaseValue, DL);
if (EdgeLatticeVal.isOverdefined())
return false;
EdgeVal = EdgeLatticeVal.getConstantRange();
Expand Down

0 comments on commit ccd412f

Please sign in to comment.