forked from OSchip/llvm-project
232 lines
6.3 KiB
C++
232 lines
6.3 KiB
C++
|
|
||
|
#include "polly/Support/SCEVValidator.h"
|
||
|
|
||
|
#include "llvm/Analysis/ScalarEvolution.h"
|
||
|
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
||
|
#include "llvm/Analysis/RegionInfo.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
namespace SCEVType {
|
||
|
enum TYPE {INT, PARAM, IV, INVALID};
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult {
|
||
|
SCEVType::TYPE type;
|
||
|
|
||
|
ValidatorResult() : type(SCEVType::INVALID) {};
|
||
|
|
||
|
ValidatorResult(const ValidatorResult &vres) {
|
||
|
type = vres.type;
|
||
|
};
|
||
|
|
||
|
ValidatorResult(SCEVType::TYPE type) : type(type) {};
|
||
|
|
||
|
bool isConstant() {
|
||
|
return type == SCEVType::INT || type == SCEVType::PARAM;
|
||
|
}
|
||
|
|
||
|
bool isValid() {
|
||
|
return type != SCEVType::INVALID;
|
||
|
}
|
||
|
|
||
|
bool isIV() {
|
||
|
return type == SCEVType::IV;
|
||
|
}
|
||
|
|
||
|
bool isINT() {
|
||
|
return type == SCEVType::INT;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// Check if a SCEV is valid in a SCoP.
|
||
|
struct SCEVValidator
|
||
|
: public SCEVVisitor<SCEVValidator, struct ValidatorResult> {
|
||
|
private:
|
||
|
const Region *R;
|
||
|
ScalarEvolution &SE;
|
||
|
Value **BaseAddress;
|
||
|
|
||
|
public:
|
||
|
SCEVValidator(const Region *R, ScalarEvolution &SE,
|
||
|
Value **BaseAddress) : R(R), SE(SE),
|
||
|
BaseAddress(BaseAddress) {};
|
||
|
|
||
|
struct ValidatorResult visitConstant(const SCEVConstant *Constant) {
|
||
|
return ValidatorResult(SCEVType::INT);
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult visitTruncateExpr(const SCEVTruncateExpr* Expr) {
|
||
|
ValidatorResult Op = visit(Expr->getOperand());
|
||
|
|
||
|
// We currently do not represent a truncate expression as an affine
|
||
|
// expression. If it is constant during Scop execution, we treat it as a
|
||
|
// parameter, otherwise we bail out.
|
||
|
if (Op.isConstant())
|
||
|
return ValidatorResult(SCEVType::PARAM);
|
||
|
|
||
|
return ValidatorResult (SCEVType::INVALID);
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult visitZeroExtendExpr(const SCEVZeroExtendExpr * Expr) {
|
||
|
ValidatorResult Op = visit(Expr->getOperand());
|
||
|
|
||
|
// We currently do not represent a zero extend expression as an affine
|
||
|
// expression. If it is constant during Scop execution, we treat it as a
|
||
|
// parameter, otherwise we bail out.
|
||
|
if (Op.isConstant())
|
||
|
return ValidatorResult (SCEVType::PARAM);
|
||
|
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult visitSignExtendExpr(const SCEVSignExtendExpr* Expr) {
|
||
|
// We currently allow only signed SCEV expressions. In the case of a
|
||
|
// signed value, a sign extend is a noop.
|
||
|
//
|
||
|
// TODO: Reconsider this when we add support for unsigned values.
|
||
|
return visit(Expr->getOperand());
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult visitAddExpr(const SCEVAddExpr* Expr) {
|
||
|
ValidatorResult Return(SCEVType::INT);
|
||
|
|
||
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
|
||
|
ValidatorResult Op = visit(Expr->getOperand(i));
|
||
|
|
||
|
if (!Op.isValid())
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
|
||
|
Return.type = std::max(Return.type, Op.type);
|
||
|
}
|
||
|
|
||
|
// TODO: Check for NSW and NUW.
|
||
|
return Return;
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult visitMulExpr(const SCEVMulExpr* Expr) {
|
||
|
ValidatorResult Return(SCEVType::INT);
|
||
|
|
||
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
|
||
|
ValidatorResult Op = visit(Expr->getOperand(i));
|
||
|
|
||
|
if (Op.type == SCEVType::INT)
|
||
|
continue;
|
||
|
|
||
|
if (Op.type == SCEVType::INVALID || Return.type != SCEVType::INT)
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
|
||
|
Return.type = Op.type;
|
||
|
}
|
||
|
|
||
|
// TODO: Check for NSW and NUW.
|
||
|
return Return;
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult visitUDivExpr(const SCEVUDivExpr* Expr) {
|
||
|
ValidatorResult LHS = visit(Expr->getLHS());
|
||
|
ValidatorResult RHS = visit(Expr->getRHS());
|
||
|
|
||
|
// We currently do not represent a unsigned devision as an affine
|
||
|
// expression. If the division is constant during Scop execution we treat it
|
||
|
// as a parameter, otherwise we bail out.
|
||
|
if (LHS.isConstant() && RHS.isConstant())
|
||
|
return ValidatorResult(SCEVType::PARAM);
|
||
|
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult visitAddRecExpr(const SCEVAddRecExpr* Expr) {
|
||
|
if (!Expr->isAffine())
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
|
||
|
ValidatorResult Start = visit(Expr->getStart());
|
||
|
ValidatorResult Recurrence = visit(Expr->getStepRecurrence(SE));
|
||
|
|
||
|
if (!Start.isValid() || !Recurrence.isValid() || Recurrence.isIV())
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
|
||
|
|
||
|
if (!R->contains(Expr->getLoop())) {
|
||
|
if (Start.isIV())
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
else
|
||
|
return ValidatorResult(SCEVType::PARAM);
|
||
|
}
|
||
|
|
||
|
if (!Recurrence.isINT())
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
|
||
|
return ValidatorResult(SCEVType::IV);
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult visitSMaxExpr(const SCEVSMaxExpr* Expr) {
|
||
|
ValidatorResult Return(SCEVType::INT);
|
||
|
|
||
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
|
||
|
ValidatorResult Op = visit(Expr->getOperand(i));
|
||
|
|
||
|
if (!Op.isValid())
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
|
||
|
Return.type = std::max(Return.type, Op.type);
|
||
|
}
|
||
|
|
||
|
return Return;
|
||
|
}
|
||
|
|
||
|
struct ValidatorResult visitUMaxExpr(const SCEVUMaxExpr* Expr) {
|
||
|
// We do not support unsigned operations. If 'Expr' is constant during Scop
|
||
|
// execution we treat this as a parameter, otherwise we bail out.
|
||
|
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
|
||
|
ValidatorResult Op = visit(Expr->getOperand(i));
|
||
|
|
||
|
if (!Op.isConstant())
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
}
|
||
|
|
||
|
return ValidatorResult(SCEVType::PARAM);
|
||
|
}
|
||
|
|
||
|
ValidatorResult visitUnknown(const SCEVUnknown* Expr) {
|
||
|
Value *V = Expr->getValue();
|
||
|
|
||
|
if (isa<UndefValue>(V))
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
|
||
|
if (BaseAddress) {
|
||
|
if (*BaseAddress)
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
else
|
||
|
*BaseAddress = V;
|
||
|
}
|
||
|
|
||
|
if (Instruction *I = dyn_cast<Instruction>(Expr->getValue()))
|
||
|
if (R->contains(I))
|
||
|
return ValidatorResult(SCEVType::INVALID);
|
||
|
|
||
|
if (BaseAddress)
|
||
|
return ValidatorResult(SCEVType::PARAM);
|
||
|
else
|
||
|
return ValidatorResult(SCEVType::PARAM);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
namespace polly {
|
||
|
bool isAffineExpr(const Region *R, const SCEV *Expr, ScalarEvolution &SE,
|
||
|
Value **BaseAddress) {
|
||
|
if (isa<SCEVCouldNotCompute>(Expr))
|
||
|
return false;
|
||
|
|
||
|
if (BaseAddress)
|
||
|
*BaseAddress = NULL;
|
||
|
|
||
|
SCEVValidator Validator(R, SE, BaseAddress);
|
||
|
ValidatorResult Result = Validator.visit(Expr);
|
||
|
|
||
|
return Result.isValid();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|