ScopDetection: Add new SCEV Validator

The SCEV Validator is used to check if the bound of a loop can be translated
into a polyhedral constraint. The new validator is more general as the check
used previously and e.g. allows bounds like 'smax 1, %a'. At the moment, we
only allow signed comparisons. Also, the new validator is only used to verify
loop bounds. Memory accesses are still handled by the old validator.

llvm-svn: 143576
This commit is contained in:
Tobias Grosser 2011-11-02 21:40:08 +00:00
parent 1179afafca
commit 3fb4992221
1 changed files with 157 additions and 1 deletions

View File

@ -109,6 +109,162 @@ BADSCOP_STAT(Other, "Others");
//===----------------------------------------------------------------------===//
// ScopDetection.
namespace SCEVType {
enum TYPE {INT, PARAM, IV, INVALID};
}
/// Check if a SCEV is valid in a SCoP.
struct SCEVValidator : public SCEVVisitor<SCEVValidator, SCEVType::TYPE> {
private:
const Region *R;
ScalarEvolution &SE;
const Value **BaseAddress;
public:
static bool isValid(const Region *R, const SCEV *Scev,
ScalarEvolution &SE,
const Value **BaseAddress = NULL) {
if (isa<SCEVCouldNotCompute>(Scev))
return false;
SCEVValidator Validator(R, SE, BaseAddress);
return Validator.visit(Scev) != SCEVType::INVALID;
}
SCEVValidator(const Region *R, ScalarEvolution &SE,
const Value **BaseAddress) : R(R), SE(SE),
BaseAddress(BaseAddress) {};
SCEVType::TYPE visitConstant(const SCEVConstant *Constant) {
return SCEVType::INT;
}
SCEVType::TYPE visitTruncateExpr(const SCEVTruncateExpr* Expr) {
SCEVType::TYPE Op = visit(Expr->getOperand());
// We cannot represent this as a affine expression yet. If it is constant
// during Scop execution treat this as a parameter, otherwise bail out.
if (Op == SCEVType::INT || Op == SCEVType::PARAM)
return SCEVType::PARAM;
return SCEVType::INVALID;
}
SCEVType::TYPE visitZeroExtendExpr(const SCEVZeroExtendExpr * Expr) {
SCEVType::TYPE Op = visit(Expr->getOperand());
// We cannot represent this as a affine expression yet. If it is constant
// during Scop execution treat this as a parameter, otherwise bail out.
if (Op == SCEVType::INT || Op == SCEVType::PARAM)
return SCEVType::PARAM;
return SCEVType::INVALID;
}
SCEVType::TYPE visitSignExtendExpr(const SCEVSignExtendExpr* Expr) {
// Assuming the value is signed, a sign extension is basically a noop.
// TODO: Reconsider this as soon as we support unsigned values.
return visit(Expr->getOperand());
}
SCEVType::TYPE visitAddExpr(const SCEVAddExpr* Expr) {
SCEVType::TYPE Return = SCEVType::INT;
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
SCEVType::TYPE OpType = visit(Expr->getOperand(i));
Return = std::max(Return, OpType);
}
// TODO: Check for NSW and NUW.
return Return;
}
SCEVType::TYPE visitMulExpr(const SCEVMulExpr* Expr) {
SCEVType::TYPE Return = SCEVType::INT;
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
SCEVType::TYPE OpType = visit(Expr->getOperand(i));
if (OpType == SCEVType::INVALID)
return SCEVType::INVALID;
if (OpType == SCEVType::IV) {
if (Return == SCEVType::PARAM || Return == SCEVType::IV)
return SCEVType::INVALID;
Return = OpType;
continue;
}
if (OpType == SCEVType::PARAM) {
if (Return == SCEVType::PARAM)
return SCEVType::INVALID;
Return = SCEVType::PARAM;
continue;
}
// OpType == SCEVType::INT, no need to change anything.
}
// TODO: Check for NSW and NUW.
return Return;
}
SCEVType::TYPE visitUDivExpr(const SCEVUDivExpr* Expr) {
// We do not yet support unsigned operations.
return SCEVType::INVALID;
}
SCEVType::TYPE visitAddRecExpr(const SCEVAddRecExpr* Expr) {
if (!Expr->isAffine())
return SCEVType::INVALID;
SCEVType::TYPE Start = visit(Expr->getStart());
if (Start == SCEVType::INVALID)
return Start;
SCEVType::TYPE Recurrence = visit(Expr->getStepRecurrence(SE));
if (Recurrence != SCEVType::INT)
return SCEVType::INVALID;
return SCEVType::PARAM;
}
SCEVType::TYPE visitSMaxExpr(const SCEVSMaxExpr* Expr) {
SCEVType::TYPE Return = SCEVType::INT;
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
SCEVType::TYPE OpType = visit(Expr->getOperand(i));
if (OpType == SCEVType::INVALID)
return SCEVType::INVALID;
if (OpType == SCEVType::PARAM)
Return = SCEVType::PARAM;
}
return Return;
}
SCEVType::TYPE visitUMaxExpr(const SCEVUMaxExpr* Expr) {
// We do not yet support unsigned operations. If 'Expr' is constant
// during Scop execution treat this as a parameter, otherwise bail out.
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
SCEVType::TYPE OpType = visit(Expr->getOperand(i));
if (OpType != SCEVType::INT && OpType != SCEVType::PARAM)
return SCEVType::PARAM;
}
return SCEVType::PARAM;
}
SCEVType::TYPE visitUnknown(const SCEVUnknown* Expr) {
return SCEVType::PARAM;
}
};
bool ScopDetection::isMaxRegionInScop(const Region &R) const {
// The Region is valid only if it could be found in the set.
return ValidRegions.count(&R);
@ -401,7 +557,7 @@ bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
// Is the loop count affine?
const SCEV *LoopCount = SE->getBackedgeTakenCount(L);
if (!isValidAffineFunction(LoopCount, Context.CurRegion))
if (!SCEVValidator::isValid(&Context.CurRegion, LoopCount, *SE))
INVALID(LoopBound, "Non affine loop bound '" << *LoopCount << "' in loop: "
<< L->getHeader()->getNameStr());