diff options
author | Hiroshi Yamauchi <yamauchi@google.com> | 2017-08-03 21:11:30 +0000 |
---|---|---|
committer | Hiroshi Yamauchi <yamauchi@google.com> | 2017-08-03 21:11:30 +0000 |
commit | a75318a16e56461562aa81f6d68c98961971066a (patch) | |
tree | 9072d1dc8e281aa23aa998c1502dd267f2a983b3 /lib/Analysis/LazyValueInfo.cpp | |
parent | 357013f05ef2ed4fb6274719d1f71d1ff1c85a1a (diff) |
[LVI] Constant-propagate a zero extension of the switch condition value through case edges
Summary:
(This is a second attempt as https://reviews.llvm.org/D34822 was reverted.)
LazyValueInfo currently computes the constant value of the switch condition through case edges, which allows the constant value to be propagated through the case edges.
But we have seen a case where a zero-extended value of the switch condition is used past case edges for which the constant propagation doesn't occur.
This patch adds a small logic to handle such a case in getEdgeValueLocal().
This is motivated by the Python 2.7 eval loop in PyEval_EvalFrameEx() where the lack of the constant propagation causes longer live ranges and more spill code than necessary.
With this patch, we see that the code size of PyEval_EvalFrameEx() decreases by ~5.4% and a performance test improves by ~4.6%.
Reviewers: sanjoy
Reviewed By: sanjoy
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D36247
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@309986 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/LazyValueInfo.cpp')
-rw-r--r-- | lib/Analysis/LazyValueInfo.cpp | 120 |
1 files changed, 114 insertions, 6 deletions
diff --git a/lib/Analysis/LazyValueInfo.cpp b/lib/Analysis/LazyValueInfo.cpp index 102081e721a..e6b013f79a7 100644 --- a/lib/Analysis/LazyValueInfo.cpp +++ b/lib/Analysis/LazyValueInfo.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/ConstantFolding.h" +#include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/AssemblyAnnotationWriter.h" @@ -148,6 +149,15 @@ public: return Range; } + Optional<APInt> asConstantInteger() const { + if (isConstant() && isa<ConstantInt>(Val)) { + return Val->getUniqueInteger(); + } else if (isConstantRange() && Range.isSingleElement()) { + return *Range.getSingleElement(); + } + return None; + } + private: void markOverdefined() { if (isOverdefined()) @@ -1355,6 +1365,42 @@ LVILatticeVal getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest) { return getValueFromCondition(Val, Cond, isTrueDest, Visited); } +// Return true if Usr has Op as an operand, otherwise false. +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 +// 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, + const APInt &OpConstVal, + const DataLayout &DL) { + Constant* OpConst = Constant::getIntegerValue(Op->getType(), OpConstVal); + // Check if Val can be simplified to a constant. + if (auto *CI = dyn_cast<CastInst>(Val)) { + 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->getUniqueInteger())); + } + } else if (auto *BO = dyn_cast<BinaryOperator>(Val)) { + bool Op0Match = BO->getOperand(0) == Op; + bool Op1Match = BO->getOperand(1) == Op; + assert((Op0Match || Op1Match) && + "Operand 0 nor Operand 1 isn't a match"); + Value *LHS = Op0Match ? OpConst : BO->getOperand(0); + Value *RHS = Op1Match ? OpConst : BO->getOperand(1); + if (auto *C = dyn_cast_or_null<ConstantInt>( + SimplifyBinOp(BO->getOpcode(), LHS, RHS, DL))) { + return LVILatticeVal::getRange(ConstantRange(C->getUniqueInteger())); + } + } + return LVILatticeVal::getOverdefined(); +} + /// \brief Compute the value of Val on the edge BBFrom -> BBTo. Returns false if /// Val is not constrained on the edge. Result is unspecified if return value /// is false. @@ -1370,10 +1416,11 @@ static bool getEdgeValueLocal(Value *Val, BasicBlock *BBFrom, bool isTrueDest = BI->getSuccessor(0) == BBTo; assert(BI->getSuccessor(!isTrueDest) == BBTo && "BBTo isn't a successor of BBFrom"); + Value *Condition = BI->getCondition(); // If V is the condition of the branch itself, then we know exactly what // it is. - if (BI->getCondition() == Val) { + if (Condition == Val) { Result = LVILatticeVal::get(ConstantInt::get( Type::getInt1Ty(Val->getContext()), isTrueDest)); return true; @@ -1381,7 +1428,44 @@ static bool getEdgeValueLocal(Value *Val, BasicBlock *BBFrom, // If the condition of the branch is an equality comparison, we may be // able to infer the value. - Result = getValueFromCondition(Val, BI->getCondition(), isTrueDest); + Result = getValueFromCondition(Val, Condition, isTrueDest); + if (!Result.isOverdefined()) + return true; + + if (User *Usr = dyn_cast<User>(Val)) { + assert(Result.isOverdefined() && "Result isn't overdefined"); + if (isa<IntegerType>(Val->getType())) { + const DataLayout &DL = BBTo->getModule()->getDataLayout(); + if (usesOperand(Usr, Condition)) { + // If Val has Condition as an operand and Val can be folded into a + // constant with either Condition == true or Condition == false, + // propagate the constant. + // eg. + // ; %Val is true on the edge to %then. + // %Val = and i1 %Condition, true. + // br %Condition, label %then, label %else + APInt ConditionVal(1, isTrueDest ? 1 : 0); + Result = constantFoldUser(Val, Condition, ConditionVal, DL); + } else { + // If one of Val's operand has an inferred value, we may be able to + // infer the value of Val. + // eg. + // ; %Val is 94 on the edge to %then. + // %Val = add i8 %Op, 1 + // %Condition = icmp eq i8 %Op, 93 + // br i1 %Condition, label %then, label %else + for (unsigned i = 0; i < Usr->getNumOperands(); ++i) { + Value *Op = Usr->getOperand(i); + LVILatticeVal OpLatticeVal = + getValueFromCondition(Op, Condition, isTrueDest); + if (Optional<APInt> OpConst = OpLatticeVal.asConstantInteger()) { + Result = constantFoldUser(Val, Op, OpConst.getValue(), DL); + break; + } + } + } + } + } if (!Result.isOverdefined()) return true; } @@ -1390,19 +1474,43 @@ static bool getEdgeValueLocal(Value *Val, BasicBlock *BBFrom, // If the edge was formed by a switch on the value, then we may know exactly // what it is. if (SwitchInst *SI = dyn_cast<SwitchInst>(BBFrom->getTerminator())) { - if (SI->getCondition() != Val) + Value *Condition = SI->getCondition(); + if (!isa<IntegerType>(Val->getType())) return false; + bool ValUsesCondition = 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) + return false; + } + assert((Condition == Val || ValUsesCondition) && + "Condition != Val nor Val doesn't use Condition"); bool DefaultCase = SI->getDefaultDest() == BBTo; unsigned BitWidth = Val->getType()->getIntegerBitWidth(); ConstantRange EdgesVals(BitWidth, DefaultCase/*isFullSet*/); for (auto Case : SI->cases()) { - ConstantRange EdgeVal(Case.getCaseValue()->getValue()); + APInt CaseValue = Case.getCaseValue()->getValue(); + ConstantRange EdgeVal(CaseValue); + if (ValUsesCondition) { + const DataLayout &DL = BBTo->getModule()->getDataLayout(); + LVILatticeVal EdgeLatticeVal = + constantFoldUser(Val, Condition, CaseValue, DL); + if (EdgeLatticeVal.isOverdefined()) + return false; + EdgeVal = EdgeLatticeVal.getConstantRange(); + } if (DefaultCase) { // It is possible that the default destination is the destination of - // some cases. There is no need to perform difference for those cases. - if (Case.getCaseSuccessor() != BBTo) + // some cases. We cannot perform difference for those cases. + // We know Condition != CaseValue in BBTo. In some cases we can use + // this to infer Val == f(Condition) is != f(CaseValue). For now, we + // only do this when f is identity (i.e. Val == Condition), but we + // should be able to do this for any injective f. + if (Case.getCaseSuccessor() != BBTo && Condition == Val) EdgesVals = EdgesVals.difference(EdgeVal); } else if (Case.getCaseSuccessor() == BBTo) EdgesVals = EdgesVals.unionWith(EdgeVal); |