2011-04-29 14:27:02 +08:00
|
|
|
//===--------- ScopInfo.cpp - Create Scops from LLVM IR ------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Create a polyhedral description for a static control flow region.
|
|
|
|
//
|
|
|
|
// The pass creates a polyhedral description of the Scops detected by the Scop
|
|
|
|
// detection derived from their LLVM-IR code.
|
|
|
|
//
|
2014-10-30 03:58:28 +08:00
|
|
|
// This representation is shared among several tools in the polyhedral
|
2011-04-29 14:27:02 +08:00
|
|
|
// community, which are e.g. Cloog, Pluto, Loopo, Graphite.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "polly/LinkAllPasses.h"
|
2014-06-18 01:31:36 +08:00
|
|
|
#include "polly/Options.h"
|
2015-05-09 17:13:42 +08:00
|
|
|
#include "polly/ScopInfo.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "polly/Support/GICHelper.h"
|
2011-11-08 23:41:28 +08:00
|
|
|
#include "polly/Support/SCEVValidator.h"
|
2013-05-07 16:11:54 +08:00
|
|
|
#include "polly/Support/ScopHelper.h"
|
2013-03-23 06:07:43 +08:00
|
|
|
#include "polly/TempScopInfo.h"
|
2015-04-05 21:11:54 +08:00
|
|
|
#include "llvm/ADT/MapVector.h"
|
2015-05-09 17:13:42 +08:00
|
|
|
#include "llvm/ADT/SetVector.h"
|
2013-05-07 16:11:54 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2015-05-23 07:43:58 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2013-05-07 16:11:54 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2014-09-18 19:17:17 +08:00
|
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
2015-05-09 17:13:42 +08:00
|
|
|
#include "llvm/Analysis/LoopInfo.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "llvm/Analysis/RegionIterator.h"
|
2013-05-07 16:11:54 +08:00
|
|
|
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2011-08-18 14:31:50 +08:00
|
|
|
#include "isl/aff.h"
|
2015-05-09 17:13:42 +08:00
|
|
|
#include "isl/constraint.h"
|
2011-10-06 08:03:35 +08:00
|
|
|
#include "isl/local_space.h"
|
2015-05-09 17:13:42 +08:00
|
|
|
#include "isl/map.h"
|
2011-12-07 15:42:51 +08:00
|
|
|
#include "isl/options.h"
|
2015-05-09 17:13:42 +08:00
|
|
|
#include "isl/printer.h"
|
2015-07-14 17:33:13 +08:00
|
|
|
#include "isl/schedule.h"
|
|
|
|
#include "isl/schedule_node.h"
|
2015-05-09 17:13:42 +08:00
|
|
|
#include "isl/set.h"
|
|
|
|
#include "isl/union_map.h"
|
2015-05-09 17:36:38 +08:00
|
|
|
#include "isl/union_set.h"
|
2013-06-21 14:41:31 +08:00
|
|
|
#include "isl/val.h"
|
2011-04-29 14:27:02 +08:00
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace polly;
|
|
|
|
|
2014-04-22 11:30:19 +08:00
|
|
|
#define DEBUG_TYPE "polly-scops"
|
|
|
|
|
2013-01-15 06:40:23 +08:00
|
|
|
STATISTIC(ScopFound, "Number of valid Scops");
|
|
|
|
STATISTIC(RichScopFound, "Number of Scops containing a loop");
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-08-18 08:40:13 +08:00
|
|
|
// Multiplicative reductions can be disabled separately as these kind of
|
2014-06-18 01:31:36 +08:00
|
|
|
// operations can overflow easily. Additive reductions and bit operations
|
|
|
|
// are in contrast pretty stable.
|
2014-07-09 18:50:10 +08:00
|
|
|
static cl::opt<bool> DisableMultiplicativeReductions(
|
|
|
|
"polly-disable-multiplicative-reductions",
|
|
|
|
cl::desc("Disable multiplicative reductions"), cl::Hidden, cl::ZeroOrMore,
|
|
|
|
cl::init(false), cl::cat(PollyCategory));
|
2014-06-18 01:31:36 +08:00
|
|
|
|
2014-09-27 19:02:39 +08:00
|
|
|
static cl::opt<unsigned> RunTimeChecksMaxParameters(
|
|
|
|
"polly-rtc-max-parameters",
|
|
|
|
cl::desc("The maximal number of parameters allowed in RTCs."), cl::Hidden,
|
|
|
|
cl::ZeroOrMore, cl::init(8), cl::cat(PollyCategory));
|
|
|
|
|
2015-03-28 23:11:14 +08:00
|
|
|
static cl::opt<unsigned> RunTimeChecksMaxArraysPerGroup(
|
|
|
|
"polly-rtc-max-arrays-per-group",
|
|
|
|
cl::desc("The maximal number of arrays to compare in each alias group."),
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(20), cl::cat(PollyCategory));
|
2015-08-16 18:19:29 +08:00
|
|
|
static cl::opt<std::string> UserContextStr(
|
|
|
|
"polly-context", cl::value_desc("isl parameter set"),
|
|
|
|
cl::desc("Provide additional constraints on the context parameters"),
|
|
|
|
cl::init(""), cl::cat(PollyCategory));
|
2015-03-28 23:11:14 +08:00
|
|
|
|
2015-08-21 03:08:11 +08:00
|
|
|
static cl::opt<bool> DetectReductions("polly-detect-reductions",
|
|
|
|
cl::desc("Detect and exploit reductions"),
|
|
|
|
cl::Hidden, cl::ZeroOrMore,
|
|
|
|
cl::init(true), cl::cat(PollyCategory));
|
|
|
|
|
2015-08-10 21:01:57 +08:00
|
|
|
// Create a sequence of two schedules. Either argument may be null and is
|
|
|
|
// interpreted as the empty schedule. Can also return null if both schedules are
|
|
|
|
// empty.
|
|
|
|
static __isl_give isl_schedule *
|
|
|
|
combineInSequence(__isl_take isl_schedule *Prev,
|
|
|
|
__isl_take isl_schedule *Succ) {
|
|
|
|
if (!Prev)
|
|
|
|
return Succ;
|
|
|
|
if (!Succ)
|
|
|
|
return Prev;
|
|
|
|
|
|
|
|
return isl_schedule_sequence(Prev, Succ);
|
|
|
|
}
|
|
|
|
|
2015-02-24 19:58:30 +08:00
|
|
|
static __isl_give isl_set *addRangeBoundsToSet(__isl_take isl_set *S,
|
|
|
|
const ConstantRange &Range,
|
|
|
|
int dim,
|
|
|
|
enum isl_dim_type type) {
|
|
|
|
isl_val *V;
|
|
|
|
isl_ctx *ctx = isl_set_get_ctx(S);
|
|
|
|
|
2015-04-27 04:07:21 +08:00
|
|
|
bool useLowerUpperBound = Range.isSignWrappedSet() && !Range.isFullSet();
|
|
|
|
const auto LB = useLowerUpperBound ? Range.getLower() : Range.getSignedMin();
|
2015-03-09 03:49:50 +08:00
|
|
|
V = isl_valFromAPInt(ctx, LB, true);
|
2015-02-24 19:58:30 +08:00
|
|
|
isl_set *SLB = isl_set_lower_bound_val(isl_set_copy(S), type, dim, V);
|
|
|
|
|
2015-04-27 04:07:21 +08:00
|
|
|
const auto UB = useLowerUpperBound ? Range.getUpper() : Range.getSignedMax();
|
2015-03-09 03:49:50 +08:00
|
|
|
V = isl_valFromAPInt(ctx, UB, true);
|
2015-04-27 04:07:21 +08:00
|
|
|
if (useLowerUpperBound)
|
2015-03-09 03:49:50 +08:00
|
|
|
V = isl_val_sub_ui(V, 1);
|
2015-02-24 19:58:30 +08:00
|
|
|
isl_set *SUB = isl_set_upper_bound_val(S, type, dim, V);
|
|
|
|
|
2015-04-27 04:07:21 +08:00
|
|
|
if (useLowerUpperBound)
|
2015-02-24 19:58:30 +08:00
|
|
|
return isl_set_union(SLB, SUB);
|
|
|
|
else
|
|
|
|
return isl_set_intersect(SLB, SUB);
|
|
|
|
}
|
|
|
|
|
2015-08-21 02:04:22 +08:00
|
|
|
static const ScopArrayInfo *identifyBasePtrOriginSAI(Scop *S, Value *BasePtr) {
|
|
|
|
LoadInst *BasePtrLI = dyn_cast<LoadInst>(BasePtr);
|
|
|
|
if (!BasePtrLI)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (!S->getRegion().contains(BasePtrLI))
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
ScalarEvolution &SE = *S->getSE();
|
|
|
|
|
|
|
|
auto *OriginBaseSCEV =
|
|
|
|
SE.getPointerBase(SE.getSCEV(BasePtrLI->getPointerOperand()));
|
|
|
|
if (!OriginBaseSCEV)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
auto *OriginBaseSCEVUnknown = dyn_cast<SCEVUnknown>(OriginBaseSCEV);
|
|
|
|
if (!OriginBaseSCEVUnknown)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return S->getScopArrayInfo(OriginBaseSCEVUnknown->getValue());
|
|
|
|
}
|
|
|
|
|
2015-05-20 16:05:31 +08:00
|
|
|
ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *Ctx,
|
2015-07-28 22:53:44 +08:00
|
|
|
const SmallVector<const SCEV *, 4> &DimensionSizes,
|
2015-08-12 23:27:16 +08:00
|
|
|
bool IsPHI, Scop *S)
|
2015-05-20 16:05:31 +08:00
|
|
|
: BasePtr(BasePtr), ElementType(ElementType),
|
2015-07-28 22:53:44 +08:00
|
|
|
DimensionSizes(DimensionSizes), IsPHI(IsPHI) {
|
|
|
|
std::string BasePtrName =
|
|
|
|
getIslCompatibleName("MemRef_", BasePtr, IsPHI ? "__phi" : "");
|
2014-10-05 19:32:18 +08:00
|
|
|
Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this);
|
2015-08-12 23:27:16 +08:00
|
|
|
for (const SCEV *Expr : DimensionSizes) {
|
|
|
|
isl_pw_aff *Size = S->getPwAff(Expr);
|
|
|
|
DimensionSizesPw.push_back(Size);
|
|
|
|
}
|
2015-08-21 02:04:22 +08:00
|
|
|
|
|
|
|
BasePtrOriginSAI = identifyBasePtrOriginSAI(S, BasePtr);
|
|
|
|
if (BasePtrOriginSAI)
|
|
|
|
const_cast<ScopArrayInfo *>(BasePtrOriginSAI)->addDerivedSAI(this);
|
2014-10-05 19:32:18 +08:00
|
|
|
}
|
|
|
|
|
2015-08-12 23:27:16 +08:00
|
|
|
ScopArrayInfo::~ScopArrayInfo() {
|
|
|
|
isl_id_free(Id);
|
|
|
|
for (isl_pw_aff *Size : DimensionSizesPw)
|
|
|
|
isl_pw_aff_free(Size);
|
|
|
|
}
|
2014-10-05 19:32:18 +08:00
|
|
|
|
2015-05-20 16:05:31 +08:00
|
|
|
std::string ScopArrayInfo::getName() const { return isl_id_get_name(Id); }
|
|
|
|
|
|
|
|
int ScopArrayInfo::getElemSizeInBytes() const {
|
|
|
|
return ElementType->getPrimitiveSizeInBits() / 8;
|
|
|
|
}
|
|
|
|
|
2014-10-05 19:32:18 +08:00
|
|
|
isl_id *ScopArrayInfo::getBasePtrId() const { return isl_id_copy(Id); }
|
|
|
|
|
|
|
|
void ScopArrayInfo::dump() const { print(errs()); }
|
|
|
|
|
2015-08-12 23:27:16 +08:00
|
|
|
void ScopArrayInfo::print(raw_ostream &OS, bool SizeAsPwAff) const {
|
2015-05-20 16:05:31 +08:00
|
|
|
OS.indent(8) << *getElementType() << " " << getName() << "[*]";
|
2015-08-12 23:27:16 +08:00
|
|
|
for (unsigned u = 0; u < getNumberOfDimensions(); u++) {
|
|
|
|
OS << "[";
|
|
|
|
|
|
|
|
if (SizeAsPwAff)
|
|
|
|
OS << " " << DimensionSizesPw[u] << " ";
|
|
|
|
else
|
|
|
|
OS << *DimensionSizes[u];
|
|
|
|
|
|
|
|
OS << "]";
|
|
|
|
}
|
|
|
|
|
2015-08-21 02:04:22 +08:00
|
|
|
if (BasePtrOriginSAI)
|
|
|
|
OS << " [BasePtrOrigin: " << BasePtrOriginSAI->getName() << "]";
|
|
|
|
|
2015-05-20 16:05:31 +08:00
|
|
|
OS << " // Element size " << getElemSizeInBytes() << "\n";
|
2014-10-05 19:32:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const ScopArrayInfo *
|
|
|
|
ScopArrayInfo::getFromAccessFunction(__isl_keep isl_pw_multi_aff *PMA) {
|
|
|
|
isl_id *Id = isl_pw_multi_aff_get_tuple_id(PMA, isl_dim_out);
|
|
|
|
assert(Id && "Output dimension didn't have an ID");
|
|
|
|
return getFromId(Id);
|
|
|
|
}
|
|
|
|
|
|
|
|
const ScopArrayInfo *ScopArrayInfo::getFromId(isl_id *Id) {
|
|
|
|
void *User = isl_id_get_user(Id);
|
|
|
|
const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
|
|
|
|
isl_id_free(Id);
|
|
|
|
return SAI;
|
|
|
|
}
|
|
|
|
|
2014-08-01 16:13:25 +08:00
|
|
|
const std::string
|
|
|
|
MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT) {
|
|
|
|
switch (RT) {
|
|
|
|
case MemoryAccess::RT_NONE:
|
|
|
|
llvm_unreachable("Requested a reduction operator string for a memory "
|
|
|
|
"access which isn't a reduction");
|
|
|
|
case MemoryAccess::RT_ADD:
|
|
|
|
return "+";
|
|
|
|
case MemoryAccess::RT_MUL:
|
|
|
|
return "*";
|
|
|
|
case MemoryAccess::RT_BOR:
|
|
|
|
return "|";
|
|
|
|
case MemoryAccess::RT_BXOR:
|
|
|
|
return "^";
|
|
|
|
case MemoryAccess::RT_BAND:
|
|
|
|
return "&";
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unknown reduction type");
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2014-07-02 04:52:51 +08:00
|
|
|
/// @brief Return the reduction type for a given binary operator
|
|
|
|
static MemoryAccess::ReductionType getReductionType(const BinaryOperator *BinOp,
|
|
|
|
const Instruction *Load) {
|
|
|
|
if (!BinOp)
|
|
|
|
return MemoryAccess::RT_NONE;
|
|
|
|
switch (BinOp->getOpcode()) {
|
|
|
|
case Instruction::FAdd:
|
|
|
|
if (!BinOp->hasUnsafeAlgebra())
|
|
|
|
return MemoryAccess::RT_NONE;
|
|
|
|
// Fall through
|
|
|
|
case Instruction::Add:
|
|
|
|
return MemoryAccess::RT_ADD;
|
|
|
|
case Instruction::Or:
|
|
|
|
return MemoryAccess::RT_BOR;
|
|
|
|
case Instruction::Xor:
|
|
|
|
return MemoryAccess::RT_BXOR;
|
|
|
|
case Instruction::And:
|
|
|
|
return MemoryAccess::RT_BAND;
|
|
|
|
case Instruction::FMul:
|
|
|
|
if (!BinOp->hasUnsafeAlgebra())
|
|
|
|
return MemoryAccess::RT_NONE;
|
|
|
|
// Fall through
|
|
|
|
case Instruction::Mul:
|
|
|
|
if (DisableMultiplicativeReductions)
|
|
|
|
return MemoryAccess::RT_NONE;
|
|
|
|
return MemoryAccess::RT_MUL;
|
|
|
|
default:
|
|
|
|
return MemoryAccess::RT_NONE;
|
|
|
|
}
|
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
MemoryAccess::~MemoryAccess() {
|
2015-05-15 17:58:32 +08:00
|
|
|
isl_id_free(Id);
|
2011-08-18 14:31:46 +08:00
|
|
|
isl_map_free(AccessRelation);
|
2011-08-15 10:33:39 +08:00
|
|
|
isl_map_free(newAccessRelation);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2014-09-12 19:00:49 +08:00
|
|
|
static MemoryAccess::AccessType getMemoryAccessType(const IRAccess &Access) {
|
|
|
|
switch (Access.getType()) {
|
|
|
|
case IRAccess::READ:
|
|
|
|
return MemoryAccess::READ;
|
|
|
|
case IRAccess::MUST_WRITE:
|
|
|
|
return MemoryAccess::MUST_WRITE;
|
|
|
|
case IRAccess::MAY_WRITE:
|
|
|
|
return MemoryAccess::MAY_WRITE;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unknown IRAccess type!");
|
|
|
|
}
|
|
|
|
|
2014-10-05 19:32:18 +08:00
|
|
|
const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const {
|
|
|
|
isl_id *ArrayId = getArrayId();
|
|
|
|
void *User = isl_id_get_user(ArrayId);
|
|
|
|
const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
|
|
|
|
isl_id_free(ArrayId);
|
|
|
|
return SAI;
|
|
|
|
}
|
|
|
|
|
2015-03-30 19:52:59 +08:00
|
|
|
__isl_give isl_id *MemoryAccess::getArrayId() const {
|
2014-07-29 16:37:55 +08:00
|
|
|
return isl_map_get_tuple_id(AccessRelation, isl_dim_out);
|
|
|
|
}
|
|
|
|
|
2015-03-30 19:52:59 +08:00
|
|
|
__isl_give isl_pw_multi_aff *MemoryAccess::applyScheduleToAccessRelation(
|
|
|
|
__isl_take isl_union_map *USchedule) const {
|
2014-10-13 20:58:03 +08:00
|
|
|
isl_map *Schedule, *ScheduledAccRel;
|
|
|
|
isl_union_set *UDomain;
|
|
|
|
|
|
|
|
UDomain = isl_union_set_from_set(getStatement()->getDomain());
|
|
|
|
USchedule = isl_union_map_intersect_domain(USchedule, UDomain);
|
|
|
|
Schedule = isl_map_from_union_map(USchedule);
|
|
|
|
ScheduledAccRel = isl_map_apply_domain(getAccessRelation(), Schedule);
|
|
|
|
return isl_pw_multi_aff_from_map(ScheduledAccRel);
|
|
|
|
}
|
|
|
|
|
2015-03-30 19:52:59 +08:00
|
|
|
__isl_give isl_map *MemoryAccess::getOriginalAccessRelation() const {
|
2011-10-06 08:04:11 +08:00
|
|
|
return isl_map_copy(AccessRelation);
|
|
|
|
}
|
|
|
|
|
2014-10-13 20:58:03 +08:00
|
|
|
std::string MemoryAccess::getOriginalAccessRelationStr() const {
|
2011-10-06 08:04:11 +08:00
|
|
|
return stringFromIslObj(AccessRelation);
|
|
|
|
}
|
|
|
|
|
2014-10-13 20:58:03 +08:00
|
|
|
__isl_give isl_space *MemoryAccess::getOriginalAccessRelationSpace() const {
|
2014-07-03 01:47:48 +08:00
|
|
|
return isl_map_get_space(AccessRelation);
|
|
|
|
}
|
|
|
|
|
2015-03-30 19:52:59 +08:00
|
|
|
__isl_give isl_map *MemoryAccess::getNewAccessRelation() const {
|
2011-10-06 08:04:11 +08:00
|
|
|
return isl_map_copy(newAccessRelation);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2015-03-30 19:52:59 +08:00
|
|
|
__isl_give isl_basic_map *
|
|
|
|
MemoryAccess::createBasicAccessMap(ScopStmt *Statement) {
|
2012-05-29 17:29:44 +08:00
|
|
|
isl_space *Space = isl_space_set_alloc(Statement->getIslCtx(), 0, 1);
|
2012-09-11 21:50:21 +08:00
|
|
|
Space = isl_space_align_params(Space, Statement->getDomainSpace());
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-05-29 17:29:44 +08:00
|
|
|
return isl_basic_map_from_domain_and_range(
|
2013-02-05 20:09:06 +08:00
|
|
|
isl_basic_set_universe(Statement->getDomainSpace()),
|
|
|
|
isl_basic_set_universe(Space));
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2014-07-03 01:47:48 +08:00
|
|
|
// Formalize no out-of-bound access assumption
|
|
|
|
//
|
|
|
|
// When delinearizing array accesses we optimistically assume that the
|
|
|
|
// delinearized accesses do not access out of bound locations (the subscript
|
|
|
|
// expression of each array evaluates for each statement instance that is
|
|
|
|
// executed to a value that is larger than zero and strictly smaller than the
|
|
|
|
// size of the corresponding dimension). The only exception is the outermost
|
2014-08-04 05:07:30 +08:00
|
|
|
// dimension for which we do not need to assume any upper bound. At this point
|
|
|
|
// we formalize this assumption to ensure that at code generation time the
|
|
|
|
// relevant run-time checks can be generated.
|
2014-07-03 01:47:48 +08:00
|
|
|
//
|
|
|
|
// To find the set of constraints necessary to avoid out of bound accesses, we
|
|
|
|
// first build the set of data locations that are not within array bounds. We
|
|
|
|
// then apply the reverse access relation to obtain the set of iterations that
|
|
|
|
// may contain invalid accesses and reduce this set of iterations to the ones
|
|
|
|
// that are actually executed by intersecting them with the domain of the
|
|
|
|
// statement. If we now project out all loop dimensions, we obtain a set of
|
|
|
|
// parameters that may cause statement instances to be executed that may
|
|
|
|
// possibly yield out of bound memory accesses. The complement of these
|
|
|
|
// constraints is the set of constraints that needs to be assumed to ensure such
|
|
|
|
// statement instances are never executed.
|
|
|
|
void MemoryAccess::assumeNoOutOfBound(const IRAccess &Access) {
|
2014-10-13 20:58:03 +08:00
|
|
|
isl_space *Space = isl_space_range(getOriginalAccessRelationSpace());
|
2014-07-03 01:47:48 +08:00
|
|
|
isl_set *Outside = isl_set_empty(isl_space_copy(Space));
|
2014-08-04 05:07:30 +08:00
|
|
|
for (int i = 1, Size = Access.Subscripts.size(); i < Size; ++i) {
|
2014-07-03 01:47:48 +08:00
|
|
|
isl_local_space *LS = isl_local_space_from_space(isl_space_copy(Space));
|
|
|
|
isl_pw_aff *Var =
|
|
|
|
isl_pw_aff_var_on_domain(isl_local_space_copy(LS), isl_dim_set, i);
|
|
|
|
isl_pw_aff *Zero = isl_pw_aff_zero_on_domain(LS);
|
|
|
|
|
|
|
|
isl_set *DimOutside;
|
|
|
|
|
2014-08-04 05:07:30 +08:00
|
|
|
DimOutside = isl_pw_aff_lt_set(isl_pw_aff_copy(Var), Zero);
|
2015-08-12 18:19:50 +08:00
|
|
|
isl_pw_aff *SizeE = Statement->getPwAff(Access.Sizes[i - 1]);
|
2014-08-04 05:07:30 +08:00
|
|
|
|
|
|
|
SizeE = isl_pw_aff_drop_dims(SizeE, isl_dim_in, 0,
|
|
|
|
Statement->getNumIterators());
|
|
|
|
SizeE = isl_pw_aff_add_dims(SizeE, isl_dim_in,
|
|
|
|
isl_space_dim(Space, isl_dim_set));
|
|
|
|
SizeE = isl_pw_aff_set_tuple_id(SizeE, isl_dim_in,
|
|
|
|
isl_space_get_tuple_id(Space, isl_dim_set));
|
|
|
|
|
|
|
|
DimOutside = isl_set_union(DimOutside, isl_pw_aff_le_set(SizeE, Var));
|
2014-07-03 01:47:48 +08:00
|
|
|
|
|
|
|
Outside = isl_set_union(Outside, DimOutside);
|
|
|
|
}
|
|
|
|
|
|
|
|
Outside = isl_set_apply(Outside, isl_map_reverse(getAccessRelation()));
|
|
|
|
Outside = isl_set_intersect(Outside, Statement->getDomain());
|
|
|
|
Outside = isl_set_params(Outside);
|
2015-06-26 20:09:28 +08:00
|
|
|
|
|
|
|
// Remove divs to avoid the construction of overly complicated assumptions.
|
|
|
|
// Doing so increases the set of parameter combinations that are assumed to
|
|
|
|
// not appear. This is always save, but may make the resulting run-time check
|
|
|
|
// bail out more often than strictly necessary.
|
|
|
|
Outside = isl_set_remove_divs(Outside);
|
2014-07-03 01:47:48 +08:00
|
|
|
Outside = isl_set_complement(Outside);
|
|
|
|
Statement->getParent()->addAssumption(Outside);
|
|
|
|
isl_space_free(Space);
|
|
|
|
}
|
|
|
|
|
2015-02-24 19:58:30 +08:00
|
|
|
void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) {
|
|
|
|
ScalarEvolution *SE = Statement->getParent()->getSE();
|
|
|
|
|
|
|
|
Value *Ptr = getPointerOperand(*getAccessInstruction());
|
|
|
|
if (!Ptr || !SE->isSCEVable(Ptr->getType()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto *PtrSCEV = SE->getSCEV(Ptr);
|
|
|
|
if (isa<SCEVCouldNotCompute>(PtrSCEV))
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto *BasePtrSCEV = SE->getPointerBase(PtrSCEV);
|
|
|
|
if (BasePtrSCEV && !isa<SCEVCouldNotCompute>(BasePtrSCEV))
|
|
|
|
PtrSCEV = SE->getMinusSCEV(PtrSCEV, BasePtrSCEV);
|
|
|
|
|
|
|
|
const ConstantRange &Range = SE->getSignedRange(PtrSCEV);
|
|
|
|
if (Range.isFullSet())
|
|
|
|
return;
|
|
|
|
|
2015-03-09 03:49:50 +08:00
|
|
|
bool isWrapping = Range.isSignWrappedSet();
|
2015-02-24 19:58:30 +08:00
|
|
|
unsigned BW = Range.getBitWidth();
|
2015-03-09 03:49:50 +08:00
|
|
|
const auto LB = isWrapping ? Range.getLower() : Range.getSignedMin();
|
|
|
|
const auto UB = isWrapping ? Range.getUpper() : Range.getSignedMax();
|
|
|
|
|
|
|
|
auto Min = LB.sdiv(APInt(BW, ElementSize));
|
|
|
|
auto Max = (UB - APInt(BW, 1)).sdiv(APInt(BW, ElementSize));
|
2015-02-24 19:58:30 +08:00
|
|
|
|
|
|
|
isl_set *AccessRange = isl_map_range(isl_map_copy(AccessRelation));
|
|
|
|
AccessRange =
|
|
|
|
addRangeBoundsToSet(AccessRange, ConstantRange(Min, Max), 0, isl_dim_set);
|
|
|
|
AccessRelation = isl_map_intersect_range(AccessRelation, AccessRange);
|
|
|
|
}
|
|
|
|
|
2015-03-31 01:22:28 +08:00
|
|
|
__isl_give isl_map *MemoryAccess::foldAccess(const IRAccess &Access,
|
|
|
|
__isl_take isl_map *AccessRelation,
|
|
|
|
ScopStmt *Statement) {
|
|
|
|
int Size = Access.Subscripts.size();
|
|
|
|
|
|
|
|
for (int i = Size - 2; i >= 0; --i) {
|
|
|
|
isl_space *Space;
|
|
|
|
isl_map *MapOne, *MapTwo;
|
2015-08-12 18:19:50 +08:00
|
|
|
isl_pw_aff *DimSize = Statement->getPwAff(Access.Sizes[i]);
|
2015-03-31 01:22:28 +08:00
|
|
|
|
|
|
|
isl_space *SpaceSize = isl_pw_aff_get_space(DimSize);
|
|
|
|
isl_pw_aff_free(DimSize);
|
|
|
|
isl_id *ParamId = isl_space_get_dim_id(SpaceSize, isl_dim_param, 0);
|
|
|
|
|
|
|
|
Space = isl_map_get_space(AccessRelation);
|
|
|
|
Space = isl_space_map_from_set(isl_space_range(Space));
|
|
|
|
Space = isl_space_align_params(Space, SpaceSize);
|
|
|
|
|
|
|
|
int ParamLocation = isl_space_find_dim_by_id(Space, isl_dim_param, ParamId);
|
|
|
|
isl_id_free(ParamId);
|
|
|
|
|
|
|
|
MapOne = isl_map_universe(isl_space_copy(Space));
|
|
|
|
for (int j = 0; j < Size; ++j)
|
|
|
|
MapOne = isl_map_equate(MapOne, isl_dim_in, j, isl_dim_out, j);
|
|
|
|
MapOne = isl_map_lower_bound_si(MapOne, isl_dim_in, i + 1, 0);
|
|
|
|
|
|
|
|
MapTwo = isl_map_universe(isl_space_copy(Space));
|
|
|
|
for (int j = 0; j < Size; ++j)
|
|
|
|
if (j < i || j > i + 1)
|
|
|
|
MapTwo = isl_map_equate(MapTwo, isl_dim_in, j, isl_dim_out, j);
|
|
|
|
|
|
|
|
isl_local_space *LS = isl_local_space_from_space(Space);
|
|
|
|
isl_constraint *C;
|
|
|
|
C = isl_equality_alloc(isl_local_space_copy(LS));
|
|
|
|
C = isl_constraint_set_constant_si(C, -1);
|
|
|
|
C = isl_constraint_set_coefficient_si(C, isl_dim_in, i, 1);
|
|
|
|
C = isl_constraint_set_coefficient_si(C, isl_dim_out, i, -1);
|
|
|
|
MapTwo = isl_map_add_constraint(MapTwo, C);
|
|
|
|
C = isl_equality_alloc(LS);
|
|
|
|
C = isl_constraint_set_coefficient_si(C, isl_dim_in, i + 1, 1);
|
|
|
|
C = isl_constraint_set_coefficient_si(C, isl_dim_out, i + 1, -1);
|
|
|
|
C = isl_constraint_set_coefficient_si(C, isl_dim_param, ParamLocation, 1);
|
|
|
|
MapTwo = isl_map_add_constraint(MapTwo, C);
|
|
|
|
MapTwo = isl_map_upper_bound_si(MapTwo, isl_dim_in, i + 1, -1);
|
|
|
|
|
|
|
|
MapOne = isl_map_union(MapOne, MapTwo);
|
|
|
|
AccessRelation = isl_map_apply_range(AccessRelation, MapOne);
|
|
|
|
}
|
|
|
|
return AccessRelation;
|
|
|
|
}
|
|
|
|
|
2014-08-10 16:09:38 +08:00
|
|
|
MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst,
|
2015-05-15 17:58:32 +08:00
|
|
|
ScopStmt *Statement, const ScopArrayInfo *SAI,
|
|
|
|
int Identifier)
|
2015-08-17 18:58:17 +08:00
|
|
|
: AccType(getMemoryAccessType(Access)), Statement(Statement),
|
|
|
|
AccessInstruction(AccInst), AccessValue(Access.getAccessValue()),
|
2014-09-12 19:00:49 +08:00
|
|
|
newAccessRelation(nullptr) {
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-07-29 16:37:55 +08:00
|
|
|
isl_ctx *Ctx = Statement->getIslCtx();
|
2011-11-10 20:44:55 +08:00
|
|
|
BaseAddr = Access.getBase();
|
2014-07-25 07:48:02 +08:00
|
|
|
BaseName = getIslCompatibleName("MemRef_", getBaseAddr(), "");
|
2014-10-05 19:32:18 +08:00
|
|
|
|
|
|
|
isl_id *BaseAddrId = SAI->getBasePtrId();
|
2011-11-10 06:34:34 +08:00
|
|
|
|
2015-08-04 01:53:21 +08:00
|
|
|
auto IdName = "__polly_array_ref_" + std::to_string(Identifier);
|
2015-05-15 20:24:09 +08:00
|
|
|
Id = isl_id_alloc(Ctx, IdName.c_str(), nullptr);
|
2015-05-15 17:58:32 +08:00
|
|
|
|
2011-12-20 18:43:14 +08:00
|
|
|
if (!Access.isAffine()) {
|
2013-06-23 13:21:18 +08:00
|
|
|
// We overapproximate non-affine accesses with a possible access to the
|
|
|
|
// whole array. For read accesses it does not make a difference, if an
|
|
|
|
// access must or may happen. However, for write accesses it is important to
|
|
|
|
// differentiate between writes that must happen and writes that may happen.
|
2013-06-23 14:04:54 +08:00
|
|
|
AccessRelation = isl_map_from_basic_map(createBasicAccessMap(Statement));
|
2014-07-29 16:37:55 +08:00
|
|
|
AccessRelation =
|
|
|
|
isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId);
|
2015-02-24 19:58:30 +08:00
|
|
|
|
|
|
|
computeBoundsOnAccessRelation(Access.getElemSizeInBytes());
|
2011-12-20 18:43:14 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-29 16:37:55 +08:00
|
|
|
isl_space *Space = isl_space_alloc(Ctx, 0, Statement->getNumIterators(), 0);
|
2014-04-10 16:38:02 +08:00
|
|
|
AccessRelation = isl_map_universe(Space);
|
2014-04-09 05:20:44 +08:00
|
|
|
|
2014-04-10 16:38:02 +08:00
|
|
|
for (int i = 0, Size = Access.Subscripts.size(); i < Size; ++i) {
|
2015-08-12 18:19:50 +08:00
|
|
|
isl_pw_aff *Affine = Statement->getPwAff(Access.Subscripts[i]);
|
2014-04-09 05:20:44 +08:00
|
|
|
|
record delinearization result and reuse it in polyhedral translation
Without this patch, the testcase would fail on the delinearization of the second
array:
; void foo(long n, long m, long o, double A[n][m][o]) {
; for (long i = 0; i < n; i++)
; for (long j = 0; j < m; j++)
; for (long k = 0; k < o; k++) {
; A[i+3][j-4][k+7] = 1.0;
; A[i][0][k] = 2.0;
; }
; }
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, -4 + i1, 7 + i2] };
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
Here is the output of FileCheck on the testcase without this patch:
; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[i0, 0, i2] };
^
<stdin>:26:2: note: possible intended match here
[n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[o0] };
^
It is possible to find a good delinearization for A[i][0][k] only in the context
of the delinearization of both array accesses.
There are two ways to delinearize together all array subscripts touching the
same base address: either duplicate the code from scop detection to first gather
all array references and then run the delinearization; or as implemented in this
patch, use the same delinearization info that we computed during scop detection.
llvm-svn: 210117
2014-06-04 02:16:31 +08:00
|
|
|
if (Size == 1) {
|
|
|
|
// For the non delinearized arrays, divide the access function of the last
|
|
|
|
// subscript by the size of the elements in the array.
|
2014-04-09 05:20:44 +08:00
|
|
|
//
|
|
|
|
// A stride one array access in C expressed as A[i] is expressed in
|
|
|
|
// LLVM-IR as something like A[i * elementsize]. This hides the fact that
|
|
|
|
// two subsequent values of 'i' index two values that are stored next to
|
|
|
|
// each other in memory. By this division we make this characteristic
|
|
|
|
// obvious again.
|
2014-07-29 16:37:55 +08:00
|
|
|
isl_val *v = isl_val_int_from_si(Ctx, Access.getElemSizeInBytes());
|
2014-04-09 05:20:44 +08:00
|
|
|
Affine = isl_pw_aff_scale_down_val(Affine, v);
|
|
|
|
}
|
2011-12-20 18:43:14 +08:00
|
|
|
|
2014-04-09 05:20:44 +08:00
|
|
|
isl_map *SubscriptMap = isl_map_from_pw_aff(Affine);
|
|
|
|
|
2014-04-10 16:38:02 +08:00
|
|
|
AccessRelation = isl_map_flat_range_product(AccessRelation, SubscriptMap);
|
2014-04-09 05:20:44 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-03-31 01:22:28 +08:00
|
|
|
AccessRelation = foldAccess(Access, AccessRelation, Statement);
|
|
|
|
|
2014-04-10 16:38:02 +08:00
|
|
|
Space = Statement->getDomainSpace();
|
2013-02-05 20:09:06 +08:00
|
|
|
AccessRelation = isl_map_set_tuple_id(
|
|
|
|
AccessRelation, isl_dim_in, isl_space_get_tuple_id(Space, isl_dim_set));
|
2014-07-29 16:37:55 +08:00
|
|
|
AccessRelation =
|
|
|
|
isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId);
|
|
|
|
|
2014-07-03 01:47:48 +08:00
|
|
|
assumeNoOutOfBound(Access);
|
2015-03-30 08:07:50 +08:00
|
|
|
AccessRelation = isl_map_gist_domain(AccessRelation, Statement->getDomain());
|
2014-07-29 16:37:55 +08:00
|
|
|
isl_space_free(Space);
|
2011-11-08 23:41:08 +08:00
|
|
|
}
|
2011-08-18 15:51:37 +08:00
|
|
|
|
2011-11-08 23:41:08 +08:00
|
|
|
void MemoryAccess::realignParams() {
|
2014-04-10 16:37:44 +08:00
|
|
|
isl_space *ParamSpace = Statement->getParent()->getParamSpace();
|
2011-10-06 08:03:42 +08:00
|
|
|
AccessRelation = isl_map_align_params(AccessRelation, ParamSpace);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2014-08-01 16:13:25 +08:00
|
|
|
const std::string MemoryAccess::getReductionOperatorStr() const {
|
|
|
|
return MemoryAccess::getReductionOperatorStr(getReductionType());
|
|
|
|
}
|
|
|
|
|
2015-05-15 17:58:32 +08:00
|
|
|
__isl_give isl_id *MemoryAccess::getId() const { return isl_id_copy(Id); }
|
|
|
|
|
2014-07-02 04:52:51 +08:00
|
|
|
raw_ostream &polly::operator<<(raw_ostream &OS,
|
|
|
|
MemoryAccess::ReductionType RT) {
|
2014-08-01 16:13:25 +08:00
|
|
|
if (RT == MemoryAccess::RT_NONE)
|
2014-07-02 04:52:51 +08:00
|
|
|
OS << "NONE";
|
2014-08-01 16:13:25 +08:00
|
|
|
else
|
|
|
|
OS << MemoryAccess::getReductionOperatorStr(RT);
|
2014-07-02 04:52:51 +08:00
|
|
|
return OS;
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
void MemoryAccess::print(raw_ostream &OS) const {
|
2014-10-08 18:11:33 +08:00
|
|
|
switch (AccType) {
|
2013-07-14 04:41:24 +08:00
|
|
|
case READ:
|
2014-06-27 02:47:03 +08:00
|
|
|
OS.indent(12) << "ReadAccess :=\t";
|
2013-06-23 13:21:18 +08:00
|
|
|
break;
|
2013-07-14 04:41:24 +08:00
|
|
|
case MUST_WRITE:
|
2014-06-27 02:47:03 +08:00
|
|
|
OS.indent(12) << "MustWriteAccess :=\t";
|
2013-06-23 13:21:18 +08:00
|
|
|
break;
|
2013-07-14 04:41:24 +08:00
|
|
|
case MAY_WRITE:
|
2014-06-27 02:47:03 +08:00
|
|
|
OS.indent(12) << "MayWriteAccess :=\t";
|
2013-06-23 13:21:18 +08:00
|
|
|
break;
|
|
|
|
}
|
2015-02-07 04:13:15 +08:00
|
|
|
OS << "[Reduction Type: " << getReductionType() << "] ";
|
|
|
|
OS << "[Scalar: " << isScalar() << "]\n";
|
2014-10-13 20:58:03 +08:00
|
|
|
OS.indent(16) << getOriginalAccessRelationStr() << ";\n";
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2013-01-15 06:40:23 +08:00
|
|
|
void MemoryAccess::dump() const { print(errs()); }
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// Create a map in the size of the provided set domain, that maps from the
|
|
|
|
// one element of the provided set domain to another element of the provided
|
|
|
|
// set domain.
|
|
|
|
// The mapping is limited to all points that are equal in all but the last
|
|
|
|
// dimension and for which the last dimension of the input is strict smaller
|
|
|
|
// than the last dimension of the output.
|
|
|
|
//
|
|
|
|
// getEqualAndLarger(set[i0, i1, ..., iX]):
|
|
|
|
//
|
|
|
|
// set[i0, i1, ..., iX] -> set[o0, o1, ..., oX]
|
|
|
|
// : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1), iX < oX
|
|
|
|
//
|
2011-10-06 08:03:35 +08:00
|
|
|
static isl_map *getEqualAndLarger(isl_space *setDomain) {
|
2012-02-01 22:23:36 +08:00
|
|
|
isl_space *Space = isl_space_map_from_set(setDomain);
|
2015-05-22 03:02:44 +08:00
|
|
|
isl_map *Map = isl_map_universe(Space);
|
2013-10-05 01:14:53 +08:00
|
|
|
unsigned lastDimension = isl_map_dim(Map, isl_dim_in) - 1;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// Set all but the last dimension to be equal for the input and output
|
|
|
|
//
|
|
|
|
// input[i0, i1, ..., iX] -> output[o0, o1, ..., oX]
|
|
|
|
// : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1)
|
2013-10-05 01:14:53 +08:00
|
|
|
for (unsigned i = 0; i < lastDimension; ++i)
|
2012-02-01 22:23:36 +08:00
|
|
|
Map = isl_map_equate(Map, isl_dim_in, i, isl_dim_out, i);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// Set the last dimension of the input to be strict smaller than the
|
|
|
|
// last dimension of the output.
|
|
|
|
//
|
|
|
|
// input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX
|
2015-05-22 03:02:44 +08:00
|
|
|
Map = isl_map_order_lt(Map, isl_dim_in, lastDimension, isl_dim_out,
|
|
|
|
lastDimension);
|
2012-02-01 22:23:36 +08:00
|
|
|
return Map;
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2015-03-30 19:52:59 +08:00
|
|
|
__isl_give isl_set *
|
|
|
|
MemoryAccess::getStride(__isl_take const isl_map *Schedule) const {
|
2013-02-05 20:09:06 +08:00
|
|
|
isl_map *S = const_cast<isl_map *>(Schedule);
|
2014-10-13 20:58:03 +08:00
|
|
|
isl_map *AccessRelation = getAccessRelation();
|
2012-12-18 15:46:06 +08:00
|
|
|
isl_space *Space = isl_space_range(isl_map_get_space(S));
|
|
|
|
isl_map *NextScatt = getEqualAndLarger(Space);
|
|
|
|
|
|
|
|
S = isl_map_reverse(S);
|
|
|
|
NextScatt = isl_map_lexmin(NextScatt);
|
|
|
|
|
|
|
|
NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(S));
|
|
|
|
NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(AccessRelation));
|
|
|
|
NextScatt = isl_map_apply_domain(NextScatt, S);
|
|
|
|
NextScatt = isl_map_apply_domain(NextScatt, AccessRelation);
|
|
|
|
|
|
|
|
isl_set *Deltas = isl_map_deltas(NextScatt);
|
|
|
|
return Deltas;
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2012-12-18 15:46:06 +08:00
|
|
|
bool MemoryAccess::isStrideX(__isl_take const isl_map *Schedule,
|
2012-01-25 00:42:16 +08:00
|
|
|
int StrideWidth) const {
|
|
|
|
isl_set *Stride, *StrideX;
|
|
|
|
bool IsStrideX;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-12-18 15:46:06 +08:00
|
|
|
Stride = getStride(Schedule);
|
2012-01-25 00:42:16 +08:00
|
|
|
StrideX = isl_set_universe(isl_set_get_space(Stride));
|
|
|
|
StrideX = isl_set_fix_si(StrideX, isl_dim_set, 0, StrideWidth);
|
2015-08-19 00:12:05 +08:00
|
|
|
IsStrideX = isl_set_is_subset(Stride, StrideX);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2012-01-25 00:42:16 +08:00
|
|
|
isl_set_free(StrideX);
|
2012-01-18 04:34:27 +08:00
|
|
|
isl_set_free(Stride);
|
2011-08-20 19:11:25 +08:00
|
|
|
|
2012-01-25 00:42:16 +08:00
|
|
|
return IsStrideX;
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2012-12-18 15:46:06 +08:00
|
|
|
bool MemoryAccess::isStrideZero(const isl_map *Schedule) const {
|
|
|
|
return isStrideX(Schedule, 0);
|
2012-01-25 00:42:16 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-04-10 16:38:02 +08:00
|
|
|
bool MemoryAccess::isScalar() const {
|
|
|
|
return isl_map_n_out(AccessRelation) == 0;
|
|
|
|
}
|
|
|
|
|
2012-12-18 15:46:06 +08:00
|
|
|
bool MemoryAccess::isStrideOne(const isl_map *Schedule) const {
|
|
|
|
return isStrideX(Schedule, 1);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2011-10-06 08:04:11 +08:00
|
|
|
void MemoryAccess::setNewAccessRelation(isl_map *newAccess) {
|
2011-08-20 19:11:25 +08:00
|
|
|
isl_map_free(newAccessRelation);
|
2011-08-03 21:47:59 +08:00
|
|
|
newAccessRelation = newAccess;
|
2011-07-13 01:14:03 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
2011-10-06 08:04:05 +08:00
|
|
|
|
2015-07-14 17:33:13 +08:00
|
|
|
isl_map *ScopStmt::getSchedule() const {
|
|
|
|
isl_set *Domain = getDomain();
|
|
|
|
if (isl_set_is_empty(Domain)) {
|
|
|
|
isl_set_free(Domain);
|
|
|
|
return isl_map_from_aff(
|
|
|
|
isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace())));
|
|
|
|
}
|
|
|
|
auto *Schedule = getParent()->getSchedule();
|
|
|
|
Schedule = isl_union_map_intersect_domain(
|
|
|
|
Schedule, isl_union_set_from_set(isl_set_copy(Domain)));
|
|
|
|
if (isl_union_map_is_empty(Schedule)) {
|
|
|
|
isl_set_free(Domain);
|
|
|
|
isl_union_map_free(Schedule);
|
|
|
|
return isl_map_from_aff(
|
|
|
|
isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace())));
|
|
|
|
}
|
|
|
|
auto *M = isl_map_from_union_map(Schedule);
|
|
|
|
M = isl_map_coalesce(M);
|
|
|
|
M = isl_map_gist_domain(M, Domain);
|
|
|
|
M = isl_map_coalesce(M);
|
|
|
|
return M;
|
|
|
|
}
|
2011-10-06 08:04:05 +08:00
|
|
|
|
2015-08-12 18:19:50 +08:00
|
|
|
__isl_give isl_pw_aff *ScopStmt::getPwAff(const SCEV *E) {
|
|
|
|
return getParent()->getPwAff(E, this);
|
|
|
|
}
|
|
|
|
|
2014-02-21 05:43:54 +08:00
|
|
|
void ScopStmt::restrictDomain(__isl_take isl_set *NewDomain) {
|
|
|
|
assert(isl_set_is_subset(NewDomain, Domain) &&
|
|
|
|
"New domain is not a subset of old domain!");
|
|
|
|
isl_set_free(Domain);
|
|
|
|
Domain = NewDomain;
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2015-02-24 20:00:50 +08:00
|
|
|
void ScopStmt::buildAccesses(TempScop &tempScop, BasicBlock *Block,
|
|
|
|
bool isApproximated) {
|
|
|
|
AccFuncSetType *AFS = tempScop.getAccessFunctions(Block);
|
|
|
|
if (!AFS)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (auto &AccessPair : *AFS) {
|
|
|
|
IRAccess &Access = AccessPair.first;
|
2014-10-05 19:32:18 +08:00
|
|
|
Instruction *AccessInst = AccessPair.second;
|
2015-08-17 18:58:17 +08:00
|
|
|
Type *ElementType = Access.getAccessValue()->getType();
|
2014-10-05 19:32:18 +08:00
|
|
|
|
2014-11-07 16:31:31 +08:00
|
|
|
const ScopArrayInfo *SAI = getParent()->getOrCreateScopArrayInfo(
|
2015-07-28 22:53:44 +08:00
|
|
|
Access.getBase(), ElementType, Access.Sizes, Access.isPHI());
|
2014-11-07 16:31:31 +08:00
|
|
|
|
2015-02-24 20:00:50 +08:00
|
|
|
if (isApproximated && Access.isWrite())
|
|
|
|
Access.setMayWrite();
|
|
|
|
|
2015-05-23 07:43:58 +08:00
|
|
|
MemoryAccessList *&MAL = InstructionToAccess[AccessInst];
|
|
|
|
if (!MAL)
|
|
|
|
MAL = new MemoryAccessList();
|
|
|
|
MAL->emplace_front(Access, AccessInst, this, SAI, MemAccs.size());
|
|
|
|
MemAccs.push_back(&MAL->front());
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-08 23:41:08 +08:00
|
|
|
void ScopStmt::realignParams() {
|
2014-06-14 02:01:45 +08:00
|
|
|
for (MemoryAccess *MA : *this)
|
|
|
|
MA->realignParams();
|
2011-11-08 23:41:08 +08:00
|
|
|
|
|
|
|
Domain = isl_set_align_params(Domain, Parent.getParamSpace());
|
|
|
|
}
|
|
|
|
|
2011-11-08 23:41:19 +08:00
|
|
|
__isl_give isl_set *ScopStmt::buildConditionSet(const Comparison &Comp) {
|
2015-08-12 18:19:50 +08:00
|
|
|
isl_pw_aff *L = getPwAff(Comp.getLHS());
|
|
|
|
isl_pw_aff *R = getPwAff(Comp.getRHS());
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2011-08-18 15:51:40 +08:00
|
|
|
switch (Comp.getPred()) {
|
2011-04-29 14:27:02 +08:00
|
|
|
case ICmpInst::ICMP_EQ:
|
2011-10-24 04:59:20 +08:00
|
|
|
return isl_pw_aff_eq_set(L, R);
|
2011-04-29 14:27:02 +08:00
|
|
|
case ICmpInst::ICMP_NE:
|
2011-10-24 04:59:20 +08:00
|
|
|
return isl_pw_aff_ne_set(L, R);
|
2011-04-29 14:27:02 +08:00
|
|
|
case ICmpInst::ICMP_SLT:
|
2011-10-24 04:59:20 +08:00
|
|
|
return isl_pw_aff_lt_set(L, R);
|
2011-04-29 14:27:02 +08:00
|
|
|
case ICmpInst::ICMP_SLE:
|
2011-10-24 04:59:20 +08:00
|
|
|
return isl_pw_aff_le_set(L, R);
|
2011-08-18 15:51:40 +08:00
|
|
|
case ICmpInst::ICMP_SGT:
|
2011-10-24 04:59:20 +08:00
|
|
|
return isl_pw_aff_gt_set(L, R);
|
2011-04-29 14:27:02 +08:00
|
|
|
case ICmpInst::ICMP_SGE:
|
2011-10-24 04:59:20 +08:00
|
|
|
return isl_pw_aff_ge_set(L, R);
|
2011-08-18 15:51:40 +08:00
|
|
|
case ICmpInst::ICMP_ULT:
|
2015-01-09 08:01:33 +08:00
|
|
|
return isl_pw_aff_lt_set(L, R);
|
2011-08-18 15:51:40 +08:00
|
|
|
case ICmpInst::ICMP_UGT:
|
2015-01-09 08:01:33 +08:00
|
|
|
return isl_pw_aff_gt_set(L, R);
|
2011-08-18 15:51:40 +08:00
|
|
|
case ICmpInst::ICMP_ULE:
|
2015-01-09 08:01:33 +08:00
|
|
|
return isl_pw_aff_le_set(L, R);
|
2011-04-29 14:27:02 +08:00
|
|
|
case ICmpInst::ICMP_UGE:
|
2015-01-09 08:01:33 +08:00
|
|
|
return isl_pw_aff_ge_set(L, R);
|
2011-04-29 14:27:02 +08:00
|
|
|
default:
|
|
|
|
llvm_unreachable("Non integer predicate not supported");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-16 22:36:01 +08:00
|
|
|
void ScopStmt::addLoopBoundsToDomain(TempScop &tempScop) {
|
2011-10-07 16:46:57 +08:00
|
|
|
isl_space *Space;
|
|
|
|
isl_local_space *LocalSpace;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2011-10-07 16:46:57 +08:00
|
|
|
Space = isl_set_get_space(Domain);
|
|
|
|
LocalSpace = isl_local_space_from_space(Space);
|
2011-10-06 08:03:35 +08:00
|
|
|
|
2014-11-01 09:14:56 +08:00
|
|
|
ScalarEvolution *SE = getParent()->getSE();
|
2011-04-29 14:27:02 +08:00
|
|
|
for (int i = 0, e = getNumIterators(); i != e; ++i) {
|
2011-10-07 06:32:58 +08:00
|
|
|
isl_aff *Zero = isl_aff_zero_on_domain(isl_local_space_copy(LocalSpace));
|
2013-02-05 20:09:06 +08:00
|
|
|
isl_pw_aff *IV =
|
|
|
|
isl_pw_aff_from_aff(isl_aff_set_coefficient_si(Zero, isl_dim_in, i, 1));
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2011-10-07 06:32:58 +08:00
|
|
|
// 0 <= IV.
|
|
|
|
isl_set *LowerBound = isl_pw_aff_nonneg_set(isl_pw_aff_copy(IV));
|
|
|
|
Domain = isl_set_intersect(Domain, LowerBound);
|
|
|
|
|
|
|
|
// IV <= LatchExecutions.
|
2011-04-30 11:26:51 +08:00
|
|
|
const Loop *L = getLoopForDimension(i);
|
2014-11-01 09:14:56 +08:00
|
|
|
const SCEV *LatchExecutions = SE->getBackedgeTakenCount(L);
|
2015-08-12 18:19:50 +08:00
|
|
|
isl_pw_aff *UpperBound = getPwAff(LatchExecutions);
|
2011-10-07 06:32:58 +08:00
|
|
|
isl_set *UpperBoundSet = isl_pw_aff_le_set(IV, UpperBound);
|
2011-04-29 14:27:02 +08:00
|
|
|
Domain = isl_set_intersect(Domain, UpperBoundSet);
|
|
|
|
}
|
|
|
|
|
2011-10-06 08:03:35 +08:00
|
|
|
isl_local_space_free(LocalSpace);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2015-08-16 22:36:01 +08:00
|
|
|
void ScopStmt::addConditionsToDomain(TempScop &tempScop,
|
|
|
|
const Region &CurRegion) {
|
2011-10-07 16:46:57 +08:00
|
|
|
const Region *TopRegion = tempScop.getMaxRegion().getParent(),
|
2013-04-10 14:55:45 +08:00
|
|
|
*CurrentRegion = &CurRegion;
|
2015-02-24 20:00:50 +08:00
|
|
|
const BasicBlock *BranchingBB = BB ? BB : R->getEntry();
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
do {
|
2011-10-07 16:46:57 +08:00
|
|
|
if (BranchingBB != CurrentRegion->getEntry()) {
|
|
|
|
if (const BBCond *Condition = tempScop.getBBCond(BranchingBB))
|
2014-06-28 16:59:45 +08:00
|
|
|
for (const auto &C : *Condition) {
|
|
|
|
isl_set *ConditionSet = buildConditionSet(C);
|
2011-10-07 16:46:57 +08:00
|
|
|
Domain = isl_set_intersect(Domain, ConditionSet);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
}
|
2011-10-07 16:46:57 +08:00
|
|
|
BranchingBB = CurrentRegion->getEntry();
|
|
|
|
CurrentRegion = CurrentRegion->getParent();
|
|
|
|
} while (TopRegion != CurrentRegion);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2015-08-16 22:36:01 +08:00
|
|
|
void ScopStmt::buildDomain(TempScop &tempScop, const Region &CurRegion) {
|
2011-10-07 16:46:57 +08:00
|
|
|
isl_space *Space;
|
2012-05-29 17:29:44 +08:00
|
|
|
isl_id *Id;
|
2011-10-07 16:46:57 +08:00
|
|
|
|
|
|
|
Space = isl_space_set_alloc(getIslCtx(), 0, getNumIterators());
|
|
|
|
|
2012-05-29 17:29:44 +08:00
|
|
|
Id = isl_id_alloc(getIslCtx(), getBaseName(), this);
|
|
|
|
|
2011-10-07 16:46:57 +08:00
|
|
|
Domain = isl_set_universe(Space);
|
2015-08-16 22:36:01 +08:00
|
|
|
addLoopBoundsToDomain(tempScop);
|
|
|
|
addConditionsToDomain(tempScop, CurRegion);
|
2012-05-29 17:29:44 +08:00
|
|
|
Domain = isl_set_set_tuple_id(Domain, Id);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
Assume GetElementPtr offsets to be inbounds
In case a GEP instruction references into a fixed size array e.g., an access
A[i][j] into an array A[100x100], LLVM-IR does not guarantee that the subscripts
always compute values that are within array bounds. We now derive the set of
parameter values for which all accesses are within bounds and add the assumption
that the scop is only every executed with this set of parameter values.
Example:
void foo(float A[][20], long n, long m {
for (long i = 0; i < n; i++)
for (long j = 0; j < m; j++)
A[i][j] = ...
This loop yields out-of-bound accesses if m is at least 20 and at the same time
at least one iteration of the outer loop is executed. Hence, we assume:
n <= 0 or m <= 20.
Doing so simplifies the dependence analysis problem, allows us to perform
more optimizations and generate better code.
TODO: The location where the GEP instruction is executed is not necessarily the
location where the memory is actually accessed. As a result scanning for GEP[s]
is imprecise. Even though this is not a correctness problem, this imprecision
may result in missed optimizations or non-optimal run-time checks.
In polybench where this mismatch between parametric loop bounds and fixed size
arrays is common, we see with this patch significant reductions in compile time
(up to 50%) and execution time (up to 70%). We see two significant compile time
regressions (fdtd-2d, jacobi-2d-imper), and one execution time regression
(trmm). Both regressions arise due to additional optimizations that have been
enabled by this patch. They can be addressed in subsequent commits.
http://reviews.llvm.org/D6369
llvm-svn: 222754
2014-11-25 18:51:12 +08:00
|
|
|
void ScopStmt::deriveAssumptionsFromGEP(GetElementPtrInst *GEP) {
|
|
|
|
int Dimension = 0;
|
|
|
|
isl_ctx *Ctx = Parent.getIslCtx();
|
|
|
|
isl_local_space *LSpace = isl_local_space_from_space(getDomainSpace());
|
|
|
|
Type *Ty = GEP->getPointerOperandType();
|
|
|
|
ScalarEvolution &SE = *Parent.getSE();
|
|
|
|
|
|
|
|
if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
|
|
|
|
Dimension = 1;
|
|
|
|
Ty = PtrTy->getElementType();
|
|
|
|
}
|
|
|
|
|
|
|
|
while (auto ArrayTy = dyn_cast<ArrayType>(Ty)) {
|
|
|
|
unsigned int Operand = 1 + Dimension;
|
|
|
|
|
|
|
|
if (GEP->getNumOperands() <= Operand)
|
|
|
|
break;
|
|
|
|
|
|
|
|
const SCEV *Expr = SE.getSCEV(GEP->getOperand(Operand));
|
|
|
|
|
|
|
|
if (isAffineExpr(&Parent.getRegion(), Expr, SE)) {
|
2015-08-12 18:19:50 +08:00
|
|
|
isl_pw_aff *AccessOffset = getPwAff(Expr);
|
Assume GetElementPtr offsets to be inbounds
In case a GEP instruction references into a fixed size array e.g., an access
A[i][j] into an array A[100x100], LLVM-IR does not guarantee that the subscripts
always compute values that are within array bounds. We now derive the set of
parameter values for which all accesses are within bounds and add the assumption
that the scop is only every executed with this set of parameter values.
Example:
void foo(float A[][20], long n, long m {
for (long i = 0; i < n; i++)
for (long j = 0; j < m; j++)
A[i][j] = ...
This loop yields out-of-bound accesses if m is at least 20 and at the same time
at least one iteration of the outer loop is executed. Hence, we assume:
n <= 0 or m <= 20.
Doing so simplifies the dependence analysis problem, allows us to perform
more optimizations and generate better code.
TODO: The location where the GEP instruction is executed is not necessarily the
location where the memory is actually accessed. As a result scanning for GEP[s]
is imprecise. Even though this is not a correctness problem, this imprecision
may result in missed optimizations or non-optimal run-time checks.
In polybench where this mismatch between parametric loop bounds and fixed size
arrays is common, we see with this patch significant reductions in compile time
(up to 50%) and execution time (up to 70%). We see two significant compile time
regressions (fdtd-2d, jacobi-2d-imper), and one execution time regression
(trmm). Both regressions arise due to additional optimizations that have been
enabled by this patch. They can be addressed in subsequent commits.
http://reviews.llvm.org/D6369
llvm-svn: 222754
2014-11-25 18:51:12 +08:00
|
|
|
AccessOffset =
|
|
|
|
isl_pw_aff_set_tuple_id(AccessOffset, isl_dim_in, getDomainId());
|
|
|
|
|
|
|
|
isl_pw_aff *DimSize = isl_pw_aff_from_aff(isl_aff_val_on_domain(
|
|
|
|
isl_local_space_copy(LSpace),
|
|
|
|
isl_val_int_from_si(Ctx, ArrayTy->getNumElements())));
|
|
|
|
|
|
|
|
isl_set *OutOfBound = isl_pw_aff_ge_set(AccessOffset, DimSize);
|
|
|
|
OutOfBound = isl_set_intersect(getDomain(), OutOfBound);
|
|
|
|
OutOfBound = isl_set_params(OutOfBound);
|
|
|
|
isl_set *InBound = isl_set_complement(OutOfBound);
|
|
|
|
isl_set *Executed = isl_set_params(getDomain());
|
|
|
|
|
|
|
|
// A => B == !A or B
|
|
|
|
isl_set *InBoundIfExecuted =
|
|
|
|
isl_set_union(isl_set_complement(Executed), InBound);
|
|
|
|
|
|
|
|
Parent.addAssumption(InBoundIfExecuted);
|
|
|
|
}
|
|
|
|
|
|
|
|
Dimension += 1;
|
|
|
|
Ty = ArrayTy->getElementType();
|
|
|
|
}
|
|
|
|
|
|
|
|
isl_local_space_free(LSpace);
|
|
|
|
}
|
|
|
|
|
2015-02-24 20:00:50 +08:00
|
|
|
void ScopStmt::deriveAssumptions(BasicBlock *Block) {
|
|
|
|
for (Instruction &Inst : *Block)
|
Assume GetElementPtr offsets to be inbounds
In case a GEP instruction references into a fixed size array e.g., an access
A[i][j] into an array A[100x100], LLVM-IR does not guarantee that the subscripts
always compute values that are within array bounds. We now derive the set of
parameter values for which all accesses are within bounds and add the assumption
that the scop is only every executed with this set of parameter values.
Example:
void foo(float A[][20], long n, long m {
for (long i = 0; i < n; i++)
for (long j = 0; j < m; j++)
A[i][j] = ...
This loop yields out-of-bound accesses if m is at least 20 and at the same time
at least one iteration of the outer loop is executed. Hence, we assume:
n <= 0 or m <= 20.
Doing so simplifies the dependence analysis problem, allows us to perform
more optimizations and generate better code.
TODO: The location where the GEP instruction is executed is not necessarily the
location where the memory is actually accessed. As a result scanning for GEP[s]
is imprecise. Even though this is not a correctness problem, this imprecision
may result in missed optimizations or non-optimal run-time checks.
In polybench where this mismatch between parametric loop bounds and fixed size
arrays is common, we see with this patch significant reductions in compile time
(up to 50%) and execution time (up to 70%). We see two significant compile time
regressions (fdtd-2d, jacobi-2d-imper), and one execution time regression
(trmm). Both regressions arise due to additional optimizations that have been
enabled by this patch. They can be addressed in subsequent commits.
http://reviews.llvm.org/D6369
llvm-svn: 222754
2014-11-25 18:51:12 +08:00
|
|
|
if (auto *GEP = dyn_cast<GetElementPtrInst>(&Inst))
|
|
|
|
deriveAssumptionsFromGEP(GEP);
|
|
|
|
}
|
|
|
|
|
2015-02-24 20:00:50 +08:00
|
|
|
ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
|
2015-07-14 17:33:13 +08:00
|
|
|
Region &R, SmallVectorImpl<Loop *> &Nest)
|
2015-02-24 20:00:50 +08:00
|
|
|
: Parent(parent), BB(nullptr), R(&R), Build(nullptr),
|
|
|
|
NestLoops(Nest.size()) {
|
|
|
|
// Setup the induction variables.
|
|
|
|
for (unsigned i = 0, e = Nest.size(); i < e; ++i)
|
|
|
|
NestLoops[i] = Nest[i];
|
|
|
|
|
2015-07-09 15:31:45 +08:00
|
|
|
BaseName = getIslCompatibleName("Stmt_", R.getNameStr(), "");
|
2015-02-24 20:00:50 +08:00
|
|
|
|
2015-08-16 22:36:01 +08:00
|
|
|
buildDomain(tempScop, CurRegion);
|
2015-02-24 20:00:50 +08:00
|
|
|
|
|
|
|
BasicBlock *EntryBB = R.getEntry();
|
|
|
|
for (BasicBlock *Block : R.blocks()) {
|
|
|
|
buildAccesses(tempScop, Block, Block != EntryBB);
|
|
|
|
deriveAssumptions(Block);
|
|
|
|
}
|
2015-08-21 03:08:11 +08:00
|
|
|
if (DetectReductions)
|
|
|
|
checkForReductions();
|
2015-02-24 20:00:50 +08:00
|
|
|
}
|
|
|
|
|
2013-01-15 06:40:23 +08:00
|
|
|
ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
|
2015-07-14 17:33:13 +08:00
|
|
|
BasicBlock &bb, SmallVectorImpl<Loop *> &Nest)
|
2015-02-24 20:00:50 +08:00
|
|
|
: Parent(parent), BB(&bb), R(nullptr), Build(nullptr),
|
|
|
|
NestLoops(Nest.size()) {
|
2011-04-29 14:27:02 +08:00
|
|
|
// Setup the induction variables.
|
2014-11-30 22:33:31 +08:00
|
|
|
for (unsigned i = 0, e = Nest.size(); i < e; ++i)
|
2013-02-16 05:26:44 +08:00
|
|
|
NestLoops[i] = Nest[i];
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-07-25 07:48:02 +08:00
|
|
|
BaseName = getIslCompatibleName("Stmt_", &bb, "");
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-08-16 22:36:01 +08:00
|
|
|
buildDomain(tempScop, CurRegion);
|
2015-02-24 20:00:50 +08:00
|
|
|
buildAccesses(tempScop, BB);
|
|
|
|
deriveAssumptions(BB);
|
2015-08-21 03:08:11 +08:00
|
|
|
if (DetectReductions)
|
|
|
|
checkForReductions();
|
2014-06-28 04:31:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Collect loads which might form a reduction chain with @p StoreMA
|
|
|
|
///
|
2015-02-25 00:00:29 +08:00
|
|
|
/// Check if the stored value for @p StoreMA is a binary operator with one or
|
|
|
|
/// two loads as operands. If the binary operand is commutative & associative,
|
2014-06-28 04:31:28 +08:00
|
|
|
/// used only once (by @p StoreMA) and its load operands are also used only
|
|
|
|
/// once, we have found a possible reduction chain. It starts at an operand
|
|
|
|
/// load and includes the binary operator and @p StoreMA.
|
|
|
|
///
|
2015-02-25 00:00:29 +08:00
|
|
|
/// Note: We allow only one use to ensure the load and binary operator cannot
|
2014-06-28 04:31:28 +08:00
|
|
|
/// escape this block or into any other store except @p StoreMA.
|
|
|
|
void ScopStmt::collectCandiateReductionLoads(
|
|
|
|
MemoryAccess *StoreMA, SmallVectorImpl<MemoryAccess *> &Loads) {
|
|
|
|
auto *Store = dyn_cast<StoreInst>(StoreMA->getAccessInstruction());
|
|
|
|
if (!Store)
|
2014-06-18 01:31:36 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Skip if there is not one binary operator between the load and the store
|
|
|
|
auto *BinOp = dyn_cast<BinaryOperator>(Store->getValueOperand());
|
2014-06-28 04:31:28 +08:00
|
|
|
if (!BinOp)
|
2014-06-18 01:31:36 +08:00
|
|
|
return;
|
|
|
|
|
2014-06-28 04:31:28 +08:00
|
|
|
// Skip if the binary operators has multiple uses
|
|
|
|
if (BinOp->getNumUses() != 1)
|
2014-06-18 01:31:36 +08:00
|
|
|
return;
|
|
|
|
|
2015-02-25 00:00:29 +08:00
|
|
|
// Skip if the opcode of the binary operator is not commutative/associative
|
2014-06-28 04:31:28 +08:00
|
|
|
if (!BinOp->isCommutative() || !BinOp->isAssociative())
|
2014-06-18 01:31:36 +08:00
|
|
|
return;
|
|
|
|
|
2014-07-01 08:32:29 +08:00
|
|
|
// Skip if the binary operator is outside the current SCoP
|
|
|
|
if (BinOp->getParent() != Store->getParent())
|
|
|
|
return;
|
|
|
|
|
2014-06-18 01:31:36 +08:00
|
|
|
// Skip if it is a multiplicative reduction and we disabled them
|
|
|
|
if (DisableMultiplicativeReductions &&
|
|
|
|
(BinOp->getOpcode() == Instruction::Mul ||
|
|
|
|
BinOp->getOpcode() == Instruction::FMul))
|
|
|
|
return;
|
|
|
|
|
2014-06-28 04:31:28 +08:00
|
|
|
// Check the binary operator operands for a candidate load
|
|
|
|
auto *PossibleLoad0 = dyn_cast<LoadInst>(BinOp->getOperand(0));
|
|
|
|
auto *PossibleLoad1 = dyn_cast<LoadInst>(BinOp->getOperand(1));
|
|
|
|
if (!PossibleLoad0 && !PossibleLoad1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// A load is only a candidate if it cannot escape (thus has only this use)
|
|
|
|
if (PossibleLoad0 && PossibleLoad0->getNumUses() == 1)
|
2014-07-01 08:32:29 +08:00
|
|
|
if (PossibleLoad0->getParent() == Store->getParent())
|
|
|
|
Loads.push_back(lookupAccessFor(PossibleLoad0));
|
2014-06-28 04:31:28 +08:00
|
|
|
if (PossibleLoad1 && PossibleLoad1->getNumUses() == 1)
|
2014-07-01 08:32:29 +08:00
|
|
|
if (PossibleLoad1->getParent() == Store->getParent())
|
|
|
|
Loads.push_back(lookupAccessFor(PossibleLoad1));
|
2014-06-28 04:31:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Check for reductions in this ScopStmt
|
|
|
|
///
|
2015-02-25 00:00:29 +08:00
|
|
|
/// Iterate over all store memory accesses and check for valid binary reduction
|
|
|
|
/// like chains. For all candidates we check if they have the same base address
|
|
|
|
/// and there are no other accesses which overlap with them. The base address
|
|
|
|
/// check rules out impossible reductions candidates early. The overlap check,
|
|
|
|
/// together with the "only one user" check in collectCandiateReductionLoads,
|
2014-06-28 04:31:28 +08:00
|
|
|
/// guarantees that none of the intermediate results will escape during
|
|
|
|
/// execution of the loop nest. We basically check here that no other memory
|
|
|
|
/// access can access the same memory as the potential reduction.
|
|
|
|
void ScopStmt::checkForReductions() {
|
|
|
|
SmallVector<MemoryAccess *, 2> Loads;
|
|
|
|
SmallVector<std::pair<MemoryAccess *, MemoryAccess *>, 4> Candidates;
|
|
|
|
|
2015-02-25 00:00:29 +08:00
|
|
|
// First collect candidate load-store reduction chains by iterating over all
|
2014-06-28 04:31:28 +08:00
|
|
|
// stores and collecting possible reduction loads.
|
|
|
|
for (MemoryAccess *StoreMA : MemAccs) {
|
|
|
|
if (StoreMA->isRead())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Loads.clear();
|
|
|
|
collectCandiateReductionLoads(StoreMA, Loads);
|
|
|
|
for (MemoryAccess *LoadMA : Loads)
|
|
|
|
Candidates.push_back(std::make_pair(LoadMA, StoreMA));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then check each possible candidate pair.
|
|
|
|
for (const auto &CandidatePair : Candidates) {
|
|
|
|
bool Valid = true;
|
|
|
|
isl_map *LoadAccs = CandidatePair.first->getAccessRelation();
|
|
|
|
isl_map *StoreAccs = CandidatePair.second->getAccessRelation();
|
|
|
|
|
|
|
|
// Skip those with obviously unequal base addresses.
|
|
|
|
if (!isl_map_has_equal_space(LoadAccs, StoreAccs)) {
|
|
|
|
isl_map_free(LoadAccs);
|
|
|
|
isl_map_free(StoreAccs);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// And check if the remaining for overlap with other memory accesses.
|
|
|
|
isl_map *AllAccsRel = isl_map_union(LoadAccs, StoreAccs);
|
|
|
|
AllAccsRel = isl_map_intersect_domain(AllAccsRel, getDomain());
|
|
|
|
isl_set *AllAccs = isl_map_range(AllAccsRel);
|
|
|
|
|
|
|
|
for (MemoryAccess *MA : MemAccs) {
|
|
|
|
if (MA == CandidatePair.first || MA == CandidatePair.second)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
isl_map *AccRel =
|
|
|
|
isl_map_intersect_domain(MA->getAccessRelation(), getDomain());
|
|
|
|
isl_set *Accs = isl_map_range(AccRel);
|
|
|
|
|
|
|
|
if (isl_set_has_equal_space(AllAccs, Accs) || isl_set_free(Accs)) {
|
|
|
|
isl_set *OverlapAccs = isl_set_intersect(Accs, isl_set_copy(AllAccs));
|
|
|
|
Valid = Valid && isl_set_is_empty(OverlapAccs);
|
|
|
|
isl_set_free(OverlapAccs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
isl_set_free(AllAccs);
|
|
|
|
if (!Valid)
|
|
|
|
continue;
|
|
|
|
|
2014-07-02 04:52:51 +08:00
|
|
|
const LoadInst *Load =
|
|
|
|
dyn_cast<const LoadInst>(CandidatePair.first->getAccessInstruction());
|
|
|
|
MemoryAccess::ReductionType RT =
|
|
|
|
getReductionType(dyn_cast<BinaryOperator>(Load->user_back()), Load);
|
|
|
|
|
2014-06-28 04:31:28 +08:00
|
|
|
// If no overlapping access was found we mark the load and store as
|
|
|
|
// reduction like.
|
2014-07-02 04:52:51 +08:00
|
|
|
CandidatePair.first->markAsReductionLike(RT);
|
|
|
|
CandidatePair.second->markAsReductionLike(RT);
|
2014-06-28 04:31:28 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2013-01-15 06:40:23 +08:00
|
|
|
std::string ScopStmt::getDomainStr() const { return stringFromIslObj(Domain); }
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-04-21 19:37:25 +08:00
|
|
|
std::string ScopStmt::getScheduleStr() const {
|
2015-07-14 17:33:13 +08:00
|
|
|
auto *S = getSchedule();
|
|
|
|
auto Str = stringFromIslObj(S);
|
|
|
|
isl_map_free(S);
|
|
|
|
return Str;
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2013-01-15 06:40:23 +08:00
|
|
|
unsigned ScopStmt::getNumParams() const { return Parent.getNumParams(); }
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-02-20 06:16:12 +08:00
|
|
|
unsigned ScopStmt::getNumIterators() const { return NestLoops.size(); }
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
const char *ScopStmt::getBaseName() const { return BaseName.c_str(); }
|
|
|
|
|
2011-04-30 11:26:51 +08:00
|
|
|
const Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const {
|
2013-02-16 05:26:44 +08:00
|
|
|
return NestLoops[Dimension];
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2013-01-15 06:40:23 +08:00
|
|
|
isl_ctx *ScopStmt::getIslCtx() const { return Parent.getIslCtx(); }
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-03-30 19:52:59 +08:00
|
|
|
__isl_give isl_set *ScopStmt::getDomain() const { return isl_set_copy(Domain); }
|
2011-05-07 03:52:19 +08:00
|
|
|
|
2015-03-30 20:22:39 +08:00
|
|
|
__isl_give isl_space *ScopStmt::getDomainSpace() const {
|
2012-01-18 04:34:23 +08:00
|
|
|
return isl_set_get_space(Domain);
|
|
|
|
}
|
|
|
|
|
2015-03-30 19:52:59 +08:00
|
|
|
__isl_give isl_id *ScopStmt::getDomainId() const {
|
|
|
|
return isl_set_get_tuple_id(Domain);
|
|
|
|
}
|
2012-08-30 19:49:38 +08:00
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
ScopStmt::~ScopStmt() {
|
2015-05-23 07:43:58 +08:00
|
|
|
DeleteContainerSeconds(InstructionToAccess);
|
2011-04-29 14:27:02 +08:00
|
|
|
isl_set_free(Domain);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScopStmt::print(raw_ostream &OS) const {
|
|
|
|
OS << "\t" << getBaseName() << "\n";
|
|
|
|
OS.indent(12) << "Domain :=\n";
|
|
|
|
|
|
|
|
if (Domain) {
|
|
|
|
OS.indent(16) << getDomainStr() << ";\n";
|
|
|
|
} else
|
|
|
|
OS.indent(16) << "n/a\n";
|
|
|
|
|
2015-04-21 19:37:25 +08:00
|
|
|
OS.indent(12) << "Schedule :=\n";
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
if (Domain) {
|
2015-04-21 19:37:25 +08:00
|
|
|
OS.indent(16) << getScheduleStr() << ";\n";
|
2011-04-29 14:27:02 +08:00
|
|
|
} else
|
|
|
|
OS.indent(16) << "n/a\n";
|
|
|
|
|
2014-06-28 16:59:45 +08:00
|
|
|
for (MemoryAccess *Access : MemAccs)
|
|
|
|
Access->print(OS);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScopStmt::dump() const { print(dbgs()); }
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Scop class implement
|
2011-11-08 23:41:28 +08:00
|
|
|
|
2011-11-17 20:56:10 +08:00
|
|
|
void Scop::setContext(__isl_take isl_set *NewContext) {
|
2011-11-15 19:38:44 +08:00
|
|
|
NewContext = isl_set_align_params(NewContext, isl_set_get_space(Context));
|
|
|
|
isl_set_free(Context);
|
|
|
|
Context = NewContext;
|
|
|
|
}
|
|
|
|
|
2013-02-05 20:09:06 +08:00
|
|
|
void Scop::addParams(std::vector<const SCEV *> NewParameters) {
|
2014-06-28 16:59:45 +08:00
|
|
|
for (const SCEV *Parameter : NewParameters) {
|
2015-03-30 04:45:09 +08:00
|
|
|
Parameter = extractConstantFactor(Parameter, *SE).second;
|
2011-11-08 23:41:28 +08:00
|
|
|
if (ParameterIds.find(Parameter) != ParameterIds.end())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int dimension = Parameters.size();
|
|
|
|
|
|
|
|
Parameters.push_back(Parameter);
|
|
|
|
ParameterIds[Parameter] = dimension;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-08 23:41:03 +08:00
|
|
|
__isl_give isl_id *Scop::getIdForParam(const SCEV *Parameter) const {
|
|
|
|
ParamIdType::const_iterator IdIter = ParameterIds.find(Parameter);
|
2011-11-07 20:58:59 +08:00
|
|
|
|
2011-11-08 23:41:03 +08:00
|
|
|
if (IdIter == ParameterIds.end())
|
2014-04-16 15:33:47 +08:00
|
|
|
return nullptr;
|
2011-11-07 20:58:59 +08:00
|
|
|
|
2011-11-15 19:38:55 +08:00
|
|
|
std::string ParameterName;
|
|
|
|
|
|
|
|
if (const SCEVUnknown *ValueParameter = dyn_cast<SCEVUnknown>(Parameter)) {
|
|
|
|
Value *Val = ValueParameter->getValue();
|
2011-11-17 22:52:36 +08:00
|
|
|
ParameterName = Val->getName();
|
2011-11-15 19:38:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ParameterName == "" || ParameterName.substr(0, 2) == "p_")
|
2012-04-25 16:01:38 +08:00
|
|
|
ParameterName = "p_" + utostr_32(IdIter->second);
|
2011-11-15 19:38:55 +08:00
|
|
|
|
2014-04-12 01:56:49 +08:00
|
|
|
return isl_id_alloc(getIslCtx(), ParameterName.c_str(),
|
|
|
|
const_cast<void *>((const void *)Parameter));
|
2011-11-07 20:58:59 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-08-21 02:06:30 +08:00
|
|
|
isl_set *Scop::addNonEmptyDomainConstraints(isl_set *C) const {
|
|
|
|
isl_set *DomainContext = isl_union_set_params(getDomains());
|
|
|
|
return isl_set_intersect_params(C, DomainContext);
|
|
|
|
}
|
|
|
|
|
2015-08-16 18:19:29 +08:00
|
|
|
void Scop::addUserContext() {
|
|
|
|
if (UserContextStr.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
isl_set *UserContext = isl_set_read_from_str(IslCtx, UserContextStr.c_str());
|
|
|
|
isl_space *Space = getParamSpace();
|
|
|
|
if (isl_space_dim(Space, isl_dim_param) !=
|
|
|
|
isl_set_dim(UserContext, isl_dim_param)) {
|
|
|
|
auto SpaceStr = isl_space_to_str(Space);
|
|
|
|
errs() << "Error: the context provided in -polly-context has not the same "
|
|
|
|
<< "number of dimensions than the computed context. Due to this "
|
|
|
|
<< "mismatch, the -polly-context option is ignored. Please provide "
|
|
|
|
<< "the context in the parameter space: " << SpaceStr << ".\n";
|
|
|
|
free(SpaceStr);
|
|
|
|
isl_set_free(UserContext);
|
|
|
|
isl_space_free(Space);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < isl_space_dim(Space, isl_dim_param); i++) {
|
|
|
|
auto NameContext = isl_set_get_dim_name(Context, isl_dim_param, i);
|
|
|
|
auto NameUserContext = isl_set_get_dim_name(UserContext, isl_dim_param, i);
|
|
|
|
|
|
|
|
if (strcmp(NameContext, NameUserContext) != 0) {
|
|
|
|
auto SpaceStr = isl_space_to_str(Space);
|
|
|
|
errs() << "Error: the name of dimension " << i
|
|
|
|
<< " provided in -polly-context "
|
|
|
|
<< "is '" << NameUserContext << "', but the name in the computed "
|
|
|
|
<< "context is '" << NameContext
|
|
|
|
<< "'. Due to this name mismatch, "
|
|
|
|
<< "the -polly-context option is ignored. Please provide "
|
|
|
|
<< "the context in the parameter space: " << SpaceStr << ".\n";
|
|
|
|
free(SpaceStr);
|
|
|
|
isl_set_free(UserContext);
|
|
|
|
isl_space_free(Space);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
UserContext =
|
|
|
|
isl_set_set_dim_id(UserContext, isl_dim_param, i,
|
|
|
|
isl_space_get_dim_id(Space, isl_dim_param, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
Context = isl_set_intersect(Context, UserContext);
|
|
|
|
isl_space_free(Space);
|
|
|
|
}
|
|
|
|
|
2011-11-08 23:41:13 +08:00
|
|
|
void Scop::buildContext() {
|
|
|
|
isl_space *Space = isl_space_params_alloc(IslCtx, 0);
|
2013-10-30 05:05:49 +08:00
|
|
|
Context = isl_set_universe(isl_space_copy(Space));
|
|
|
|
AssumedContext = isl_set_universe(Space);
|
2011-10-06 08:03:48 +08:00
|
|
|
}
|
|
|
|
|
2012-05-22 18:47:27 +08:00
|
|
|
void Scop::addParameterBounds() {
|
2015-02-24 00:15:51 +08:00
|
|
|
for (const auto &ParamID : ParameterIds) {
|
|
|
|
int dim = ParamID.second;
|
2012-05-22 18:47:27 +08:00
|
|
|
|
2015-02-24 00:15:51 +08:00
|
|
|
ConstantRange SRange = SE->getSignedRange(ParamID.first);
|
2015-01-09 03:26:53 +08:00
|
|
|
|
2015-02-24 19:58:30 +08:00
|
|
|
Context = addRangeBoundsToSet(Context, SRange, dim, isl_dim_param);
|
2012-05-22 18:47:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-08 23:41:08 +08:00
|
|
|
void Scop::realignParams() {
|
2011-11-08 23:41:13 +08:00
|
|
|
// Add all parameters into a common model.
|
2011-11-08 23:41:28 +08:00
|
|
|
isl_space *Space = isl_space_params_alloc(IslCtx, ParameterIds.size());
|
2011-11-08 23:41:13 +08:00
|
|
|
|
2014-06-28 16:59:45 +08:00
|
|
|
for (const auto &ParamID : ParameterIds) {
|
|
|
|
const SCEV *Parameter = ParamID.first;
|
2011-11-08 23:41:13 +08:00
|
|
|
isl_id *id = getIdForParam(Parameter);
|
2014-06-28 16:59:45 +08:00
|
|
|
Space = isl_space_set_dim_id(Space, isl_dim_param, ParamID.second, id);
|
2011-11-08 23:41:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Align the parameters of all data structures to the model.
|
|
|
|
Context = isl_set_align_params(Context, Space);
|
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
for (ScopStmt &Stmt : *this)
|
|
|
|
Stmt.realignParams();
|
2011-11-08 23:41:08 +08:00
|
|
|
}
|
|
|
|
|
2014-07-03 01:47:48 +08:00
|
|
|
void Scop::simplifyAssumedContext() {
|
|
|
|
// The parameter constraints of the iteration domains give us a set of
|
|
|
|
// constraints that need to hold for all cases where at least a single
|
|
|
|
// statement iteration is executed in the whole scop. We now simplify the
|
|
|
|
// assumed context under the assumption that such constraints hold and at
|
|
|
|
// least a single statement iteration is executed. For cases where no
|
|
|
|
// statement instances are executed, the assumptions we have taken about
|
|
|
|
// the executed code do not matter and can be changed.
|
|
|
|
//
|
|
|
|
// WARNING: This only holds if the assumptions we have taken do not reduce
|
|
|
|
// the set of statement instances that are executed. Otherwise we
|
|
|
|
// may run into a case where the iteration domains suggest that
|
2015-02-25 00:00:29 +08:00
|
|
|
// for a certain set of parameter constraints no code is executed,
|
2014-07-03 01:47:48 +08:00
|
|
|
// but in the original program some computation would have been
|
2015-02-25 00:00:29 +08:00
|
|
|
// performed. In such a case, modifying the run-time conditions and
|
|
|
|
// possibly influencing the run-time check may cause certain scops
|
2014-07-03 01:47:48 +08:00
|
|
|
// to not be executed.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
//
|
|
|
|
// When delinearizing the following code:
|
|
|
|
//
|
|
|
|
// for (long i = 0; i < 100; i++)
|
|
|
|
// for (long j = 0; j < m; j++)
|
|
|
|
// A[i+p][j] = 1.0;
|
|
|
|
//
|
|
|
|
// we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as
|
2015-02-25 00:00:29 +08:00
|
|
|
// otherwise we would access out of bound data. Now, knowing that code is
|
2014-07-03 01:47:48 +08:00
|
|
|
// only executed for the case m >= 0, it is sufficient to assume p >= 0.
|
|
|
|
AssumedContext =
|
|
|
|
isl_set_gist_params(AssumedContext, isl_union_set_params(getDomains()));
|
2015-02-24 00:15:51 +08:00
|
|
|
AssumedContext = isl_set_gist_params(AssumedContext, getContext());
|
2014-07-03 01:47:48 +08:00
|
|
|
}
|
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
/// @brief Add the minimal/maximal access in @p Set to @p User.
|
2015-05-28 21:32:11 +08:00
|
|
|
static isl_stat buildMinMaxAccess(__isl_take isl_set *Set, void *User) {
|
2014-09-18 19:17:17 +08:00
|
|
|
Scop::MinMaxVectorTy *MinMaxAccesses = (Scop::MinMaxVectorTy *)User;
|
|
|
|
isl_pw_multi_aff *MinPMA, *MaxPMA;
|
|
|
|
isl_pw_aff *LastDimAff;
|
|
|
|
isl_aff *OneAff;
|
|
|
|
unsigned Pos;
|
|
|
|
|
2014-09-27 19:02:39 +08:00
|
|
|
// Restrict the number of parameters involved in the access as the lexmin/
|
|
|
|
// lexmax computation will take too long if this number is high.
|
|
|
|
//
|
|
|
|
// Experiments with a simple test case using an i7 4800MQ:
|
|
|
|
//
|
|
|
|
// #Parameters involved | Time (in sec)
|
|
|
|
// 6 | 0.01
|
|
|
|
// 7 | 0.04
|
|
|
|
// 8 | 0.12
|
|
|
|
// 9 | 0.40
|
|
|
|
// 10 | 1.54
|
|
|
|
// 11 | 6.78
|
|
|
|
// 12 | 30.38
|
|
|
|
//
|
|
|
|
if (isl_set_n_param(Set) > RunTimeChecksMaxParameters) {
|
|
|
|
unsigned InvolvedParams = 0;
|
|
|
|
for (unsigned u = 0, e = isl_set_n_param(Set); u < e; u++)
|
|
|
|
if (isl_set_involves_dims(Set, isl_dim_param, u, 1))
|
|
|
|
InvolvedParams++;
|
|
|
|
|
|
|
|
if (InvolvedParams > RunTimeChecksMaxParameters) {
|
|
|
|
isl_set_free(Set);
|
2015-05-28 21:32:11 +08:00
|
|
|
return isl_stat_error;
|
2014-09-27 19:02:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-14 20:00:06 +08:00
|
|
|
Set = isl_set_remove_divs(Set);
|
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
MinPMA = isl_set_lexmin_pw_multi_aff(isl_set_copy(Set));
|
|
|
|
MaxPMA = isl_set_lexmax_pw_multi_aff(isl_set_copy(Set));
|
|
|
|
|
2014-10-07 22:37:59 +08:00
|
|
|
MinPMA = isl_pw_multi_aff_coalesce(MinPMA);
|
|
|
|
MaxPMA = isl_pw_multi_aff_coalesce(MaxPMA);
|
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
// Adjust the last dimension of the maximal access by one as we want to
|
|
|
|
// enclose the accessed memory region by MinPMA and MaxPMA. The pointer
|
|
|
|
// we test during code generation might now point after the end of the
|
|
|
|
// allocated array but we will never dereference it anyway.
|
|
|
|
assert(isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) &&
|
|
|
|
"Assumed at least one output dimension");
|
|
|
|
Pos = isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) - 1;
|
|
|
|
LastDimAff = isl_pw_multi_aff_get_pw_aff(MaxPMA, Pos);
|
|
|
|
OneAff = isl_aff_zero_on_domain(
|
|
|
|
isl_local_space_from_space(isl_pw_aff_get_domain_space(LastDimAff)));
|
|
|
|
OneAff = isl_aff_add_constant_si(OneAff, 1);
|
|
|
|
LastDimAff = isl_pw_aff_add(LastDimAff, isl_pw_aff_from_aff(OneAff));
|
|
|
|
MaxPMA = isl_pw_multi_aff_set_pw_aff(MaxPMA, Pos, LastDimAff);
|
|
|
|
|
|
|
|
MinMaxAccesses->push_back(std::make_pair(MinPMA, MaxPMA));
|
|
|
|
|
|
|
|
isl_set_free(Set);
|
2015-05-28 21:32:11 +08:00
|
|
|
return isl_stat_ok;
|
2014-09-18 19:17:17 +08:00
|
|
|
}
|
|
|
|
|
2014-10-01 20:42:37 +08:00
|
|
|
static __isl_give isl_set *getAccessDomain(MemoryAccess *MA) {
|
|
|
|
isl_set *Domain = MA->getStatement()->getDomain();
|
|
|
|
Domain = isl_set_project_out(Domain, isl_dim_set, 0, isl_set_n_dim(Domain));
|
|
|
|
return isl_set_reset_tuple_id(Domain);
|
|
|
|
}
|
|
|
|
|
2015-07-24 01:04:54 +08:00
|
|
|
/// @brief Wrapper function to calculate minimal/maximal accesses to each array.
|
|
|
|
static bool calculateMinMaxAccess(__isl_take isl_union_map *Accesses,
|
2015-07-25 20:31:03 +08:00
|
|
|
__isl_take isl_union_set *Domains,
|
2015-07-26 21:14:38 +08:00
|
|
|
Scop::MinMaxVectorTy &MinMaxAccesses) {
|
2015-07-24 01:04:54 +08:00
|
|
|
|
|
|
|
Accesses = isl_union_map_intersect_domain(Accesses, Domains);
|
|
|
|
isl_union_set *Locations = isl_union_map_range(Accesses);
|
|
|
|
Locations = isl_union_set_coalesce(Locations);
|
|
|
|
Locations = isl_union_set_detect_equalities(Locations);
|
|
|
|
bool Valid = (0 == isl_union_set_foreach_set(Locations, buildMinMaxAccess,
|
2015-07-26 21:14:38 +08:00
|
|
|
&MinMaxAccesses));
|
2015-07-24 01:04:54 +08:00
|
|
|
isl_union_set_free(Locations);
|
|
|
|
return Valid;
|
|
|
|
}
|
|
|
|
|
2015-08-21 02:30:08 +08:00
|
|
|
void Scop::buildAliasChecks(AliasAnalysis &AA) {
|
|
|
|
if (!PollyUseRuntimeAliasChecks)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buildAliasGroups(AA))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If a problem occurs while building the alias groups we need to delete
|
|
|
|
// this SCoP and pretend it wasn't valid in the first place. To this end
|
|
|
|
// we make the assumed context infeasible.
|
|
|
|
addAssumption(isl_set_empty(getParamSpace()));
|
|
|
|
|
|
|
|
DEBUG(dbgs() << "\n\nNOTE: Run time checks for " << getNameStr()
|
|
|
|
<< " could not be created as the number of parameters involved "
|
|
|
|
"is too high. The SCoP will be "
|
|
|
|
"dismissed.\nUse:\n\t--polly-rtc-max-parameters=X\nto adjust "
|
|
|
|
"the maximal number of parameters but be advised that the "
|
|
|
|
"compile time might increase exponentially.\n\n");
|
|
|
|
}
|
|
|
|
|
2014-09-27 19:02:39 +08:00
|
|
|
bool Scop::buildAliasGroups(AliasAnalysis &AA) {
|
2014-09-18 19:17:17 +08:00
|
|
|
// To create sound alias checks we perform the following steps:
|
2015-02-25 00:00:29 +08:00
|
|
|
// o) Use the alias analysis and an alias set tracker to build alias sets
|
2014-09-18 19:17:17 +08:00
|
|
|
// for all memory accesses inside the SCoP.
|
|
|
|
// o) For each alias set we then map the aliasing pointers back to the
|
2015-02-25 00:00:29 +08:00
|
|
|
// memory accesses we know, thus obtain groups of memory accesses which
|
2014-09-18 19:17:17 +08:00
|
|
|
// might alias.
|
2014-10-01 20:42:37 +08:00
|
|
|
// o) We divide each group based on the domains of the minimal/maximal
|
2015-02-25 00:00:29 +08:00
|
|
|
// accesses. That means two minimal/maximal accesses are only in a group
|
2014-10-01 20:42:37 +08:00
|
|
|
// if their access domains intersect, otherwise they are in different
|
|
|
|
// ones.
|
2015-07-24 01:04:54 +08:00
|
|
|
// o) We partition each group into read only and non read only accesses.
|
2015-02-25 00:00:29 +08:00
|
|
|
// o) For each group with more than one base pointer we then compute minimal
|
2015-07-24 01:04:54 +08:00
|
|
|
// and maximal accesses to each array of a group in read only and non
|
|
|
|
// read only partitions separately.
|
2014-09-18 19:17:17 +08:00
|
|
|
using AliasGroupTy = SmallVector<MemoryAccess *, 4>;
|
|
|
|
|
|
|
|
AliasSetTracker AST(AA);
|
|
|
|
|
|
|
|
DenseMap<Value *, MemoryAccess *> PtrToAcc;
|
2014-10-01 20:40:46 +08:00
|
|
|
DenseSet<Value *> HasWriteAccess;
|
2015-05-27 13:16:57 +08:00
|
|
|
for (ScopStmt &Stmt : *this) {
|
2014-10-07 01:43:00 +08:00
|
|
|
|
|
|
|
// Skip statements with an empty domain as they will never be executed.
|
2015-05-27 13:16:57 +08:00
|
|
|
isl_set *StmtDomain = Stmt.getDomain();
|
2014-10-07 01:43:00 +08:00
|
|
|
bool StmtDomainEmpty = isl_set_is_empty(StmtDomain);
|
|
|
|
isl_set_free(StmtDomain);
|
|
|
|
if (StmtDomainEmpty)
|
|
|
|
continue;
|
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
for (MemoryAccess *MA : Stmt) {
|
2014-09-18 19:17:17 +08:00
|
|
|
if (MA->isScalar())
|
|
|
|
continue;
|
2014-10-01 20:40:46 +08:00
|
|
|
if (!MA->isRead())
|
|
|
|
HasWriteAccess.insert(MA->getBaseAddr());
|
2014-09-18 19:17:17 +08:00
|
|
|
Instruction *Acc = MA->getAccessInstruction();
|
|
|
|
PtrToAcc[getPointerOperand(*Acc)] = MA;
|
|
|
|
AST.add(Acc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallVector<AliasGroupTy, 4> AliasGroups;
|
|
|
|
for (AliasSet &AS : AST) {
|
2014-10-08 10:23:48 +08:00
|
|
|
if (AS.isMustAlias() || AS.isForwardingAliasSet())
|
2014-09-18 19:17:17 +08:00
|
|
|
continue;
|
|
|
|
AliasGroupTy AG;
|
|
|
|
for (auto PR : AS)
|
|
|
|
AG.push_back(PtrToAcc[PR.getValue()]);
|
|
|
|
assert(AG.size() > 1 &&
|
|
|
|
"Alias groups should contain at least two accesses");
|
|
|
|
AliasGroups.push_back(std::move(AG));
|
|
|
|
}
|
|
|
|
|
2014-10-01 20:42:37 +08:00
|
|
|
// Split the alias groups based on their domain.
|
|
|
|
for (unsigned u = 0; u < AliasGroups.size(); u++) {
|
|
|
|
AliasGroupTy NewAG;
|
|
|
|
AliasGroupTy &AG = AliasGroups[u];
|
|
|
|
AliasGroupTy::iterator AGI = AG.begin();
|
|
|
|
isl_set *AGDomain = getAccessDomain(*AGI);
|
|
|
|
while (AGI != AG.end()) {
|
|
|
|
MemoryAccess *MA = *AGI;
|
|
|
|
isl_set *MADomain = getAccessDomain(MA);
|
|
|
|
if (isl_set_is_disjoint(AGDomain, MADomain)) {
|
|
|
|
NewAG.push_back(MA);
|
|
|
|
AGI = AG.erase(AGI);
|
|
|
|
isl_set_free(MADomain);
|
|
|
|
} else {
|
|
|
|
AGDomain = isl_set_union(AGDomain, MADomain);
|
|
|
|
AGI++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NewAG.size() > 1)
|
|
|
|
AliasGroups.push_back(std::move(NewAG));
|
|
|
|
isl_set_free(AGDomain);
|
|
|
|
}
|
|
|
|
|
2015-04-05 21:11:54 +08:00
|
|
|
MapVector<const Value *, SmallPtrSet<MemoryAccess *, 8>> ReadOnlyPairs;
|
2014-10-01 20:40:46 +08:00
|
|
|
SmallPtrSet<const Value *, 4> NonReadOnlyBaseValues;
|
|
|
|
for (AliasGroupTy &AG : AliasGroups) {
|
|
|
|
NonReadOnlyBaseValues.clear();
|
|
|
|
ReadOnlyPairs.clear();
|
|
|
|
|
2014-10-01 20:42:37 +08:00
|
|
|
if (AG.size() < 2) {
|
|
|
|
AG.clear();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-10-01 20:40:46 +08:00
|
|
|
for (auto II = AG.begin(); II != AG.end();) {
|
|
|
|
Value *BaseAddr = (*II)->getBaseAddr();
|
|
|
|
if (HasWriteAccess.count(BaseAddr)) {
|
|
|
|
NonReadOnlyBaseValues.insert(BaseAddr);
|
|
|
|
II++;
|
|
|
|
} else {
|
|
|
|
ReadOnlyPairs[BaseAddr].insert(*II);
|
|
|
|
II = AG.erase(II);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't have read only pointers check if there are at least two
|
|
|
|
// non read only pointers, otherwise clear the alias group.
|
2015-07-25 20:31:03 +08:00
|
|
|
if (ReadOnlyPairs.empty() && NonReadOnlyBaseValues.size() <= 1) {
|
2015-07-24 01:04:54 +08:00
|
|
|
AG.clear();
|
2014-10-01 20:40:46 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't have non read only pointers clear the alias group.
|
|
|
|
if (NonReadOnlyBaseValues.empty()) {
|
|
|
|
AG.clear();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-07-24 01:04:54 +08:00
|
|
|
// Calculate minimal and maximal accesses for non read only accesses.
|
2015-07-26 21:14:38 +08:00
|
|
|
MinMaxAliasGroups.emplace_back();
|
|
|
|
MinMaxVectorPairTy &pair = MinMaxAliasGroups.back();
|
|
|
|
MinMaxVectorTy &MinMaxAccessesNonReadOnly = pair.first;
|
|
|
|
MinMaxVectorTy &MinMaxAccessesReadOnly = pair.second;
|
|
|
|
MinMaxAccessesNonReadOnly.reserve(AG.size());
|
2014-09-18 19:17:17 +08:00
|
|
|
|
|
|
|
isl_union_map *Accesses = isl_union_map_empty(getParamSpace());
|
2015-07-24 01:04:54 +08:00
|
|
|
|
|
|
|
// AG contains only non read only accesses.
|
2014-09-18 19:17:17 +08:00
|
|
|
for (MemoryAccess *MA : AG)
|
|
|
|
Accesses = isl_union_map_add_map(Accesses, MA->getAccessRelation());
|
|
|
|
|
2015-08-21 05:29:26 +08:00
|
|
|
bool Valid = calculateMinMaxAccess(Accesses, getDomains(),
|
|
|
|
MinMaxAccessesNonReadOnly);
|
2015-07-24 01:04:54 +08:00
|
|
|
|
|
|
|
// Bail out if the number of values we need to compare is too large.
|
|
|
|
// This is important as the number of comparisions grows quadratically with
|
|
|
|
// the number of values we need to compare.
|
2015-07-26 21:14:38 +08:00
|
|
|
if (!Valid || (MinMaxAccessesNonReadOnly.size() + !ReadOnlyPairs.empty() >
|
|
|
|
RunTimeChecksMaxArraysPerGroup))
|
2015-07-24 01:04:54 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Calculate minimal and maximal accesses for read only accesses.
|
2015-07-26 21:14:38 +08:00
|
|
|
MinMaxAccessesReadOnly.reserve(ReadOnlyPairs.size());
|
2015-07-24 01:04:54 +08:00
|
|
|
Accesses = isl_union_map_empty(getParamSpace());
|
|
|
|
|
|
|
|
for (const auto &ReadOnlyPair : ReadOnlyPairs)
|
|
|
|
for (MemoryAccess *MA : ReadOnlyPair.second)
|
|
|
|
Accesses = isl_union_map_add_map(Accesses, MA->getAccessRelation());
|
|
|
|
|
2015-08-21 05:29:26 +08:00
|
|
|
Valid =
|
|
|
|
calculateMinMaxAccess(Accesses, getDomains(), MinMaxAccessesReadOnly);
|
2014-09-27 19:02:39 +08:00
|
|
|
|
|
|
|
if (!Valid)
|
2015-03-28 22:50:32 +08:00
|
|
|
return false;
|
2014-09-18 19:17:17 +08:00
|
|
|
}
|
2014-09-27 19:02:39 +08:00
|
|
|
|
2015-03-28 22:50:32 +08:00
|
|
|
return true;
|
2014-09-18 19:17:17 +08:00
|
|
|
}
|
|
|
|
|
2015-04-13 06:58:40 +08:00
|
|
|
static unsigned getMaxLoopDepthInRegion(const Region &R, LoopInfo &LI,
|
|
|
|
ScopDetection &SD) {
|
|
|
|
|
|
|
|
const ScopDetection::BoxedLoopsSetTy *BoxedLoops = SD.getBoxedLoops(&R);
|
|
|
|
|
2014-11-01 08:12:13 +08:00
|
|
|
unsigned MinLD = INT_MAX, MaxLD = 0;
|
|
|
|
for (BasicBlock *BB : R.blocks()) {
|
|
|
|
if (Loop *L = LI.getLoopFor(BB)) {
|
2015-01-14 02:31:55 +08:00
|
|
|
if (!R.contains(L))
|
|
|
|
continue;
|
2015-04-13 06:58:40 +08:00
|
|
|
if (BoxedLoops && BoxedLoops->count(L))
|
|
|
|
continue;
|
2014-11-01 08:12:13 +08:00
|
|
|
unsigned LD = L->getLoopDepth();
|
|
|
|
MinLD = std::min(MinLD, LD);
|
|
|
|
MaxLD = std::max(MaxLD, LD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle the case that there is no loop in the SCoP first.
|
|
|
|
if (MaxLD == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
assert(MinLD >= 1 && "Minimal loop depth should be at least one");
|
|
|
|
assert(MaxLD >= MinLD &&
|
|
|
|
"Maximal loop depth was smaller than mininaml loop depth?");
|
|
|
|
return MaxLD - MinLD + 1;
|
|
|
|
}
|
|
|
|
|
2015-07-31 03:27:04 +08:00
|
|
|
Scop::Scop(Region &R, ScalarEvolution &ScalarEvolution, isl_ctx *Context,
|
|
|
|
unsigned MaxLoopDepth)
|
|
|
|
: SE(&ScalarEvolution), R(R), IsOptimized(false),
|
2015-08-12 18:19:50 +08:00
|
|
|
MaxLoopDepth(MaxLoopDepth), IslCtx(Context), Affinator(this) {}
|
2015-02-24 20:00:50 +08:00
|
|
|
|
2015-08-21 03:08:05 +08:00
|
|
|
void Scop::initFromTempScop(TempScop &TempScop, LoopInfo &LI, ScopDetection &SD,
|
|
|
|
AliasAnalysis &AA) {
|
2011-11-08 23:41:13 +08:00
|
|
|
buildContext();
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2013-02-05 20:09:06 +08:00
|
|
|
SmallVector<Loop *, 8> NestLoops;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-04-21 19:37:25 +08:00
|
|
|
// Build the iteration domain, access functions and schedule functions
|
2011-04-29 14:27:02 +08:00
|
|
|
// traversing the region tree.
|
2015-07-31 03:27:04 +08:00
|
|
|
Schedule = buildScop(TempScop, getRegion(), NestLoops, LI, SD);
|
2015-07-14 17:33:13 +08:00
|
|
|
if (!Schedule)
|
|
|
|
Schedule = isl_schedule_empty(getParamSpace());
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2011-11-08 23:41:08 +08:00
|
|
|
realignParams();
|
2012-05-22 18:47:27 +08:00
|
|
|
addParameterBounds();
|
2015-08-16 18:19:29 +08:00
|
|
|
addUserContext();
|
2014-07-03 01:47:48 +08:00
|
|
|
simplifyAssumedContext();
|
2015-08-21 02:30:08 +08:00
|
|
|
buildAliasChecks(AA);
|
2011-11-08 23:41:08 +08:00
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
assert(NestLoops.empty() && "NestLoops not empty at top level!");
|
|
|
|
}
|
|
|
|
|
2015-07-31 03:27:04 +08:00
|
|
|
Scop *Scop::createFromTempScop(TempScop &TempScop, LoopInfo &LI,
|
|
|
|
ScalarEvolution &SE, ScopDetection &SD,
|
2015-08-21 02:30:08 +08:00
|
|
|
AliasAnalysis &AA, isl_ctx *ctx) {
|
2015-07-31 03:27:04 +08:00
|
|
|
auto &R = TempScop.getMaxRegion();
|
|
|
|
auto MaxLoopDepth = getMaxLoopDepthInRegion(R, LI, SD);
|
|
|
|
auto S = new Scop(R, SE, ctx, MaxLoopDepth);
|
2015-08-21 02:30:08 +08:00
|
|
|
S->initFromTempScop(TempScop, LI, SD, AA);
|
|
|
|
|
2015-07-31 03:27:04 +08:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
Scop::~Scop() {
|
|
|
|
isl_set_free(Context);
|
2013-10-30 05:05:49 +08:00
|
|
|
isl_set_free(AssumedContext);
|
2015-07-14 17:33:13 +08:00
|
|
|
isl_schedule_free(Schedule);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
// Free the alias groups
|
2015-07-24 01:04:54 +08:00
|
|
|
for (MinMaxVectorPairTy &MinMaxAccessPair : MinMaxAliasGroups) {
|
2015-07-26 21:14:38 +08:00
|
|
|
for (MinMaxAccessTy &MMA : MinMaxAccessPair.first) {
|
2014-09-18 19:17:17 +08:00
|
|
|
isl_pw_multi_aff_free(MMA.first);
|
|
|
|
isl_pw_multi_aff_free(MMA.second);
|
|
|
|
}
|
2015-07-26 21:14:38 +08:00
|
|
|
for (MinMaxAccessTy &MMA : MinMaxAccessPair.second) {
|
2015-07-24 01:04:54 +08:00
|
|
|
isl_pw_multi_aff_free(MMA.first);
|
|
|
|
isl_pw_multi_aff_free(MMA.second);
|
|
|
|
}
|
2014-09-18 19:17:17 +08:00
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2014-11-07 16:31:31 +08:00
|
|
|
const ScopArrayInfo *
|
|
|
|
Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *AccessType,
|
2015-07-28 22:53:44 +08:00
|
|
|
const SmallVector<const SCEV *, 4> &Sizes,
|
|
|
|
bool IsPHI) {
|
|
|
|
auto &SAI = ScopArrayInfoMap[std::make_pair(BasePtr, IsPHI)];
|
2014-11-07 16:31:31 +08:00
|
|
|
if (!SAI)
|
2015-08-12 23:27:16 +08:00
|
|
|
SAI.reset(new ScopArrayInfo(BasePtr, AccessType, getIslCtx(), Sizes, IsPHI,
|
|
|
|
this));
|
2015-05-23 13:58:27 +08:00
|
|
|
return SAI.get();
|
2014-10-05 19:32:18 +08:00
|
|
|
}
|
|
|
|
|
2015-07-28 22:53:44 +08:00
|
|
|
const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, bool IsPHI) {
|
|
|
|
auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, IsPHI)].get();
|
2014-10-05 19:32:18 +08:00
|
|
|
assert(SAI && "No ScopArrayInfo available for this base pointer");
|
|
|
|
return SAI;
|
|
|
|
}
|
|
|
|
|
2013-01-15 06:40:23 +08:00
|
|
|
std::string Scop::getContextStr() const { return stringFromIslObj(Context); }
|
2014-07-03 01:47:48 +08:00
|
|
|
std::string Scop::getAssumedContextStr() const {
|
|
|
|
return stringFromIslObj(AssumedContext);
|
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
std::string Scop::getNameStr() const {
|
|
|
|
std::string ExitName, EntryName;
|
|
|
|
raw_string_ostream ExitStr(ExitName);
|
|
|
|
raw_string_ostream EntryStr(EntryName);
|
|
|
|
|
2014-01-09 18:42:15 +08:00
|
|
|
R.getEntry()->printAsOperand(EntryStr, false);
|
2011-04-29 14:27:02 +08:00
|
|
|
EntryStr.str();
|
|
|
|
|
|
|
|
if (R.getExit()) {
|
2014-01-09 18:42:15 +08:00
|
|
|
R.getExit()->printAsOperand(ExitStr, false);
|
2011-04-29 14:27:02 +08:00
|
|
|
ExitStr.str();
|
|
|
|
} else
|
|
|
|
ExitName = "FunctionExit";
|
|
|
|
|
|
|
|
return EntryName + "---" + ExitName;
|
|
|
|
}
|
|
|
|
|
2013-01-15 06:40:23 +08:00
|
|
|
__isl_give isl_set *Scop::getContext() const { return isl_set_copy(Context); }
|
2011-10-06 08:03:42 +08:00
|
|
|
__isl_give isl_space *Scop::getParamSpace() const {
|
2015-05-27 05:37:31 +08:00
|
|
|
return isl_set_get_space(Context);
|
2011-10-06 08:03:42 +08:00
|
|
|
}
|
|
|
|
|
2013-10-30 05:05:49 +08:00
|
|
|
__isl_give isl_set *Scop::getAssumedContext() const {
|
|
|
|
return isl_set_copy(AssumedContext);
|
|
|
|
}
|
|
|
|
|
2015-08-20 13:58:56 +08:00
|
|
|
__isl_give isl_set *Scop::getRuntimeCheckContext() const {
|
|
|
|
isl_set *RuntimeCheckContext = getAssumedContext();
|
|
|
|
return RuntimeCheckContext;
|
|
|
|
}
|
|
|
|
|
2015-08-21 02:06:30 +08:00
|
|
|
bool Scop::hasFeasibleRuntimeContext() const {
|
2015-08-20 13:58:56 +08:00
|
|
|
isl_set *RuntimeCheckContext = getRuntimeCheckContext();
|
2015-08-21 02:06:30 +08:00
|
|
|
RuntimeCheckContext = addNonEmptyDomainConstraints(RuntimeCheckContext);
|
2015-08-20 13:58:56 +08:00
|
|
|
bool IsFeasible = !isl_set_is_empty(RuntimeCheckContext);
|
|
|
|
isl_set_free(RuntimeCheckContext);
|
|
|
|
return IsFeasible;
|
|
|
|
}
|
|
|
|
|
2014-07-03 01:47:48 +08:00
|
|
|
void Scop::addAssumption(__isl_take isl_set *Set) {
|
|
|
|
AssumedContext = isl_set_intersect(AssumedContext, Set);
|
Assume GetElementPtr offsets to be inbounds
In case a GEP instruction references into a fixed size array e.g., an access
A[i][j] into an array A[100x100], LLVM-IR does not guarantee that the subscripts
always compute values that are within array bounds. We now derive the set of
parameter values for which all accesses are within bounds and add the assumption
that the scop is only every executed with this set of parameter values.
Example:
void foo(float A[][20], long n, long m {
for (long i = 0; i < n; i++)
for (long j = 0; j < m; j++)
A[i][j] = ...
This loop yields out-of-bound accesses if m is at least 20 and at the same time
at least one iteration of the outer loop is executed. Hence, we assume:
n <= 0 or m <= 20.
Doing so simplifies the dependence analysis problem, allows us to perform
more optimizations and generate better code.
TODO: The location where the GEP instruction is executed is not necessarily the
location where the memory is actually accessed. As a result scanning for GEP[s]
is imprecise. Even though this is not a correctness problem, this imprecision
may result in missed optimizations or non-optimal run-time checks.
In polybench where this mismatch between parametric loop bounds and fixed size
arrays is common, we see with this patch significant reductions in compile time
(up to 50%) and execution time (up to 70%). We see two significant compile time
regressions (fdtd-2d, jacobi-2d-imper), and one execution time regression
(trmm). Both regressions arise due to additional optimizations that have been
enabled by this patch. They can be addressed in subsequent commits.
http://reviews.llvm.org/D6369
llvm-svn: 222754
2014-11-25 18:51:12 +08:00
|
|
|
AssumedContext = isl_set_coalesce(AssumedContext);
|
2014-07-03 01:47:48 +08:00
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
void Scop::printContext(raw_ostream &OS) const {
|
|
|
|
OS << "Context:\n";
|
|
|
|
|
|
|
|
if (!Context) {
|
|
|
|
OS.indent(4) << "n/a\n\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
OS.indent(4) << getContextStr() << "\n";
|
2011-11-08 23:41:28 +08:00
|
|
|
|
2014-07-03 01:47:48 +08:00
|
|
|
OS.indent(4) << "Assumed Context:\n";
|
|
|
|
if (!AssumedContext) {
|
|
|
|
OS.indent(4) << "n/a\n\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
OS.indent(4) << getAssumedContextStr() << "\n";
|
|
|
|
|
2014-06-28 16:59:45 +08:00
|
|
|
for (const SCEV *Parameter : Parameters) {
|
2011-11-08 23:41:28 +08:00
|
|
|
int Dim = ParameterIds.find(Parameter)->second;
|
|
|
|
OS.indent(4) << "p" << Dim << ": " << *Parameter << "\n";
|
|
|
|
}
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2014-09-18 19:17:17 +08:00
|
|
|
void Scop::printAliasAssumptions(raw_ostream &OS) const {
|
2015-07-25 20:31:03 +08:00
|
|
|
int noOfGroups = 0;
|
|
|
|
for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) {
|
2015-07-26 21:14:38 +08:00
|
|
|
if (Pair.second.size() == 0)
|
2015-07-24 01:04:54 +08:00
|
|
|
noOfGroups += 1;
|
|
|
|
else
|
2015-07-26 21:14:38 +08:00
|
|
|
noOfGroups += Pair.second.size();
|
2015-07-24 01:04:54 +08:00
|
|
|
}
|
|
|
|
|
2015-07-25 20:31:03 +08:00
|
|
|
OS.indent(4) << "Alias Groups (" << noOfGroups << "):\n";
|
2014-09-18 19:17:17 +08:00
|
|
|
if (MinMaxAliasGroups.empty()) {
|
|
|
|
OS.indent(8) << "n/a\n";
|
|
|
|
return;
|
|
|
|
}
|
2015-07-24 01:04:54 +08:00
|
|
|
|
2015-07-25 20:31:03 +08:00
|
|
|
for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) {
|
2015-07-24 01:04:54 +08:00
|
|
|
|
|
|
|
// If the group has no read only accesses print the write accesses.
|
2015-07-26 21:14:38 +08:00
|
|
|
if (Pair.second.empty()) {
|
2015-07-24 01:04:54 +08:00
|
|
|
OS.indent(8) << "[[";
|
2015-07-26 21:14:38 +08:00
|
|
|
for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) {
|
2015-07-25 20:31:03 +08:00
|
|
|
OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second
|
|
|
|
<< ">";
|
2015-07-24 01:04:54 +08:00
|
|
|
}
|
|
|
|
OS << " ]]\n";
|
|
|
|
}
|
|
|
|
|
2015-07-26 21:14:38 +08:00
|
|
|
for (const MinMaxAccessTy &MMAReadOnly : Pair.second) {
|
2015-07-24 01:04:54 +08:00
|
|
|
OS.indent(8) << "[[";
|
2015-07-25 20:31:03 +08:00
|
|
|
OS << " <" << MMAReadOnly.first << ", " << MMAReadOnly.second << ">";
|
2015-07-26 21:14:38 +08:00
|
|
|
for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) {
|
2015-07-25 20:31:03 +08:00
|
|
|
OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second
|
|
|
|
<< ">";
|
2015-07-24 01:04:54 +08:00
|
|
|
}
|
|
|
|
OS << " ]]\n";
|
|
|
|
}
|
2014-09-18 19:17:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
void Scop::printStatements(raw_ostream &OS) const {
|
|
|
|
OS << "Statements {\n";
|
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
for (const ScopStmt &Stmt : *this)
|
|
|
|
OS.indent(4) << Stmt;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
OS.indent(4) << "}\n";
|
|
|
|
}
|
|
|
|
|
2015-05-20 16:05:31 +08:00
|
|
|
void Scop::printArrayInfo(raw_ostream &OS) const {
|
|
|
|
OS << "Arrays {\n";
|
|
|
|
|
2015-05-23 13:58:27 +08:00
|
|
|
for (auto &Array : arrays())
|
2015-05-20 16:05:31 +08:00
|
|
|
Array.second->print(OS);
|
|
|
|
|
|
|
|
OS.indent(4) << "}\n";
|
2015-08-12 23:27:16 +08:00
|
|
|
|
|
|
|
OS.indent(4) << "Arrays (Bounds as pw_affs) {\n";
|
|
|
|
|
|
|
|
for (auto &Array : arrays())
|
|
|
|
Array.second->print(OS, /* SizeAsPwAff */ true);
|
|
|
|
|
|
|
|
OS.indent(4) << "}\n";
|
2015-05-20 16:05:31 +08:00
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
void Scop::print(raw_ostream &OS) const {
|
2014-03-19 02:51:11 +08:00
|
|
|
OS.indent(4) << "Function: " << getRegion().getEntry()->getParent()->getName()
|
|
|
|
<< "\n";
|
2014-03-19 02:05:38 +08:00
|
|
|
OS.indent(4) << "Region: " << getNameStr() << "\n";
|
2015-01-14 02:31:55 +08:00
|
|
|
OS.indent(4) << "Max Loop Depth: " << getMaxLoopDepth() << "\n";
|
2011-04-29 14:27:02 +08:00
|
|
|
printContext(OS.indent(4));
|
2015-05-20 16:05:31 +08:00
|
|
|
printArrayInfo(OS.indent(4));
|
2014-09-18 19:17:17 +08:00
|
|
|
printAliasAssumptions(OS);
|
2011-04-29 14:27:02 +08:00
|
|
|
printStatements(OS.indent(4));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Scop::dump() const { print(dbgs()); }
|
|
|
|
|
2011-11-08 23:41:03 +08:00
|
|
|
isl_ctx *Scop::getIslCtx() const { return IslCtx; }
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-08-12 18:19:50 +08:00
|
|
|
__isl_give isl_pw_aff *Scop::getPwAff(const SCEV *E, ScopStmt *Stmt) {
|
|
|
|
return Affinator.getPwAff(E, Stmt);
|
|
|
|
}
|
|
|
|
|
2015-07-14 17:33:13 +08:00
|
|
|
__isl_give isl_union_set *Scop::getDomains() const {
|
2014-06-28 16:59:38 +08:00
|
|
|
isl_union_set *Domain = isl_union_set_empty(getParamSpace());
|
2012-02-14 22:02:40 +08:00
|
|
|
|
2015-07-14 17:33:13 +08:00
|
|
|
for (const ScopStmt &Stmt : *this)
|
2015-05-27 13:16:57 +08:00
|
|
|
Domain = isl_union_set_add_set(Domain, Stmt.getDomain());
|
2012-02-14 22:02:40 +08:00
|
|
|
|
|
|
|
return Domain;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:12:10 +08:00
|
|
|
__isl_give isl_union_map *Scop::getMustWrites() {
|
2015-05-27 05:37:31 +08:00
|
|
|
isl_union_map *Write = isl_union_map_empty(getParamSpace());
|
2014-07-11 15:12:10 +08:00
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
for (ScopStmt &Stmt : *this) {
|
|
|
|
for (MemoryAccess *MA : Stmt) {
|
2014-07-11 15:12:10 +08:00
|
|
|
if (!MA->isMustWrite())
|
|
|
|
continue;
|
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
isl_set *Domain = Stmt.getDomain();
|
2014-07-11 15:12:10 +08:00
|
|
|
isl_map *AccessDomain = MA->getAccessRelation();
|
|
|
|
AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
|
|
|
|
Write = isl_union_map_add_map(Write, AccessDomain);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return isl_union_map_coalesce(Write);
|
|
|
|
}
|
|
|
|
|
|
|
|
__isl_give isl_union_map *Scop::getMayWrites() {
|
2015-05-27 05:37:31 +08:00
|
|
|
isl_union_map *Write = isl_union_map_empty(getParamSpace());
|
2014-07-11 15:12:10 +08:00
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
for (ScopStmt &Stmt : *this) {
|
|
|
|
for (MemoryAccess *MA : Stmt) {
|
2014-07-11 15:12:10 +08:00
|
|
|
if (!MA->isMayWrite())
|
|
|
|
continue;
|
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
isl_set *Domain = Stmt.getDomain();
|
2014-07-11 15:12:10 +08:00
|
|
|
isl_map *AccessDomain = MA->getAccessRelation();
|
|
|
|
AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
|
|
|
|
Write = isl_union_map_add_map(Write, AccessDomain);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return isl_union_map_coalesce(Write);
|
|
|
|
}
|
|
|
|
|
2014-02-21 05:43:54 +08:00
|
|
|
__isl_give isl_union_map *Scop::getWrites() {
|
2015-05-27 05:37:31 +08:00
|
|
|
isl_union_map *Write = isl_union_map_empty(getParamSpace());
|
2014-02-21 05:43:54 +08:00
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
for (ScopStmt &Stmt : *this) {
|
|
|
|
for (MemoryAccess *MA : Stmt) {
|
2014-06-14 02:01:45 +08:00
|
|
|
if (!MA->isWrite())
|
2014-02-21 05:43:54 +08:00
|
|
|
continue;
|
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
isl_set *Domain = Stmt.getDomain();
|
2014-06-14 02:01:45 +08:00
|
|
|
isl_map *AccessDomain = MA->getAccessRelation();
|
2014-02-21 05:43:54 +08:00
|
|
|
AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
|
|
|
|
Write = isl_union_map_add_map(Write, AccessDomain);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return isl_union_map_coalesce(Write);
|
|
|
|
}
|
|
|
|
|
|
|
|
__isl_give isl_union_map *Scop::getReads() {
|
2014-06-28 16:59:38 +08:00
|
|
|
isl_union_map *Read = isl_union_map_empty(getParamSpace());
|
2014-02-21 05:43:54 +08:00
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
for (ScopStmt &Stmt : *this) {
|
|
|
|
for (MemoryAccess *MA : Stmt) {
|
2014-06-14 02:01:45 +08:00
|
|
|
if (!MA->isRead())
|
2014-02-21 05:43:54 +08:00
|
|
|
continue;
|
|
|
|
|
2015-05-27 13:16:57 +08:00
|
|
|
isl_set *Domain = Stmt.getDomain();
|
2014-06-14 02:01:45 +08:00
|
|
|
isl_map *AccessDomain = MA->getAccessRelation();
|
2014-02-21 05:43:54 +08:00
|
|
|
|
|
|
|
AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
|
|
|
|
Read = isl_union_map_add_map(Read, AccessDomain);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return isl_union_map_coalesce(Read);
|
|
|
|
}
|
|
|
|
|
2015-07-14 17:33:13 +08:00
|
|
|
__isl_give isl_union_map *Scop::getSchedule() const {
|
|
|
|
auto Tree = getScheduleTree();
|
|
|
|
auto S = isl_schedule_get_map(Tree);
|
|
|
|
isl_schedule_free(Tree);
|
|
|
|
return S;
|
|
|
|
}
|
2014-02-21 05:43:54 +08:00
|
|
|
|
2015-07-14 17:33:13 +08:00
|
|
|
__isl_give isl_schedule *Scop::getScheduleTree() const {
|
|
|
|
return isl_schedule_intersect_domain(isl_schedule_copy(Schedule),
|
|
|
|
getDomains());
|
|
|
|
}
|
2014-06-28 16:59:38 +08:00
|
|
|
|
2015-07-14 17:33:13 +08:00
|
|
|
void Scop::setSchedule(__isl_take isl_union_map *NewSchedule) {
|
|
|
|
auto *S = isl_schedule_from_domain(getDomains());
|
|
|
|
S = isl_schedule_insert_partial_schedule(
|
|
|
|
S, isl_multi_union_pw_aff_from_union_map(NewSchedule));
|
|
|
|
isl_schedule_free(Schedule);
|
|
|
|
Schedule = S;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Scop::setScheduleTree(__isl_take isl_schedule *NewSchedule) {
|
|
|
|
isl_schedule_free(Schedule);
|
|
|
|
Schedule = NewSchedule;
|
2014-02-21 05:43:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Scop::restrictDomains(__isl_take isl_union_set *Domain) {
|
|
|
|
bool Changed = false;
|
2015-05-27 13:16:57 +08:00
|
|
|
for (ScopStmt &Stmt : *this) {
|
|
|
|
isl_union_set *StmtDomain = isl_union_set_from_set(Stmt.getDomain());
|
2014-02-21 05:43:54 +08:00
|
|
|
isl_union_set *NewStmtDomain = isl_union_set_intersect(
|
|
|
|
isl_union_set_copy(StmtDomain), isl_union_set_copy(Domain));
|
|
|
|
|
|
|
|
if (isl_union_set_is_subset(StmtDomain, NewStmtDomain)) {
|
|
|
|
isl_union_set_free(StmtDomain);
|
|
|
|
isl_union_set_free(NewStmtDomain);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Changed = true;
|
|
|
|
|
|
|
|
isl_union_set_free(StmtDomain);
|
|
|
|
NewStmtDomain = isl_union_set_coalesce(NewStmtDomain);
|
|
|
|
|
|
|
|
if (isl_union_set_is_empty(NewStmtDomain)) {
|
2015-05-27 13:16:57 +08:00
|
|
|
Stmt.restrictDomain(isl_set_empty(Stmt.getDomainSpace()));
|
2014-02-21 05:43:54 +08:00
|
|
|
isl_union_set_free(NewStmtDomain);
|
|
|
|
} else
|
2015-05-27 13:16:57 +08:00
|
|
|
Stmt.restrictDomain(isl_set_from_union_set(NewStmtDomain));
|
2014-02-21 05:43:54 +08:00
|
|
|
}
|
|
|
|
isl_union_set_free(Domain);
|
|
|
|
return Changed;
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
ScalarEvolution *Scop::getSE() const { return SE; }
|
|
|
|
|
|
|
|
bool Scop::isTrivialBB(BasicBlock *BB, TempScop &tempScop) {
|
|
|
|
if (tempScop.getAccessFunctions(BB))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-14 17:33:13 +08:00
|
|
|
struct MapToDimensionDataTy {
|
|
|
|
int N;
|
|
|
|
isl_union_pw_multi_aff *Res;
|
|
|
|
};
|
|
|
|
|
|
|
|
// @brief Create a function that maps the elements of 'Set' to its N-th
|
|
|
|
// dimension.
|
|
|
|
//
|
|
|
|
// The result is added to 'User->Res'.
|
|
|
|
//
|
|
|
|
// @param Set The input set.
|
|
|
|
// @param N The dimension to map to.
|
|
|
|
//
|
|
|
|
// @returns Zero if no error occurred, non-zero otherwise.
|
|
|
|
static isl_stat mapToDimension_AddSet(__isl_take isl_set *Set, void *User) {
|
|
|
|
struct MapToDimensionDataTy *Data = (struct MapToDimensionDataTy *)User;
|
|
|
|
int Dim;
|
|
|
|
isl_space *Space;
|
|
|
|
isl_pw_multi_aff *PMA;
|
|
|
|
|
|
|
|
Dim = isl_set_dim(Set, isl_dim_set);
|
|
|
|
Space = isl_set_get_space(Set);
|
|
|
|
PMA = isl_pw_multi_aff_project_out_map(Space, isl_dim_set, Data->N,
|
|
|
|
Dim - Data->N);
|
|
|
|
if (Data->N > 1)
|
|
|
|
PMA = isl_pw_multi_aff_drop_dims(PMA, isl_dim_out, 0, Data->N - 1);
|
|
|
|
Data->Res = isl_union_pw_multi_aff_add_pw_multi_aff(Data->Res, PMA);
|
|
|
|
|
|
|
|
isl_set_free(Set);
|
|
|
|
|
|
|
|
return isl_stat_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// @brief Create a function that maps the elements of Domain to their Nth
|
|
|
|
// dimension.
|
|
|
|
//
|
|
|
|
// @param Domain The set of elements to map.
|
|
|
|
// @param N The dimension to map to.
|
|
|
|
static __isl_give isl_multi_union_pw_aff *
|
|
|
|
mapToDimension(__isl_take isl_union_set *Domain, int N) {
|
|
|
|
struct MapToDimensionDataTy Data;
|
|
|
|
isl_space *Space;
|
|
|
|
|
|
|
|
Space = isl_union_set_get_space(Domain);
|
|
|
|
Data.N = N;
|
|
|
|
Data.Res = isl_union_pw_multi_aff_empty(Space);
|
|
|
|
if (isl_union_set_foreach_set(Domain, &mapToDimension_AddSet, &Data) < 0)
|
|
|
|
Data.Res = isl_union_pw_multi_aff_free(Data.Res);
|
|
|
|
|
|
|
|
isl_union_set_free(Domain);
|
|
|
|
return isl_multi_union_pw_aff_from_union_pw_multi_aff(Data.Res);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScopStmt *Scop::addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop,
|
|
|
|
const Region &CurRegion,
|
|
|
|
SmallVectorImpl<Loop *> &NestLoops) {
|
|
|
|
ScopStmt *Stmt;
|
2015-02-24 20:00:50 +08:00
|
|
|
if (BB) {
|
2015-07-14 17:33:13 +08:00
|
|
|
Stmts.emplace_back(*this, tempScop, CurRegion, *BB, NestLoops);
|
|
|
|
Stmt = &Stmts.back();
|
|
|
|
StmtMap[BB] = Stmt;
|
2015-02-24 20:00:50 +08:00
|
|
|
} else {
|
2015-05-27 13:16:57 +08:00
|
|
|
assert(R && "Either basic block or a region expected.");
|
2015-07-14 17:33:13 +08:00
|
|
|
Stmts.emplace_back(*this, tempScop, CurRegion, *R, NestLoops);
|
|
|
|
Stmt = &Stmts.back();
|
2015-02-24 20:00:50 +08:00
|
|
|
for (BasicBlock *BB : R->blocks())
|
2015-07-14 17:33:13 +08:00
|
|
|
StmtMap[BB] = Stmt;
|
|
|
|
}
|
|
|
|
return Stmt;
|
|
|
|
}
|
|
|
|
|
2015-08-10 21:01:57 +08:00
|
|
|
__isl_give isl_schedule *
|
|
|
|
Scop::buildBBScopStmt(BasicBlock *BB, TempScop &tempScop,
|
|
|
|
const Region &CurRegion,
|
|
|
|
SmallVectorImpl<Loop *> &NestLoops) {
|
|
|
|
if (isTrivialBB(BB, tempScop))
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
auto *Stmt = addScopStmt(BB, nullptr, tempScop, CurRegion, NestLoops);
|
|
|
|
auto *Domain = Stmt->getDomain();
|
|
|
|
return isl_schedule_from_domain(isl_union_set_from_set(Domain));
|
|
|
|
}
|
|
|
|
|
2015-07-14 17:33:13 +08:00
|
|
|
__isl_give isl_schedule *Scop::buildScop(TempScop &tempScop,
|
|
|
|
const Region &CurRegion,
|
|
|
|
SmallVectorImpl<Loop *> &NestLoops,
|
|
|
|
LoopInfo &LI, ScopDetection &SD) {
|
|
|
|
if (SD.isNonAffineSubRegion(&CurRegion, &getRegion())) {
|
|
|
|
auto *Stmt = addScopStmt(nullptr, const_cast<Region *>(&CurRegion),
|
|
|
|
tempScop, CurRegion, NestLoops);
|
|
|
|
auto *Domain = Stmt->getDomain();
|
|
|
|
return isl_schedule_from_domain(isl_union_set_from_set(Domain));
|
2015-02-24 20:00:50 +08:00
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
Loop *L = castToLoop(CurRegion, LI);
|
|
|
|
|
|
|
|
if (L)
|
|
|
|
NestLoops.push_back(L);
|
|
|
|
|
|
|
|
unsigned loopDepth = NestLoops.size();
|
2015-07-14 17:33:13 +08:00
|
|
|
isl_schedule *Schedule = nullptr;
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
for (Region::const_element_iterator I = CurRegion.element_begin(),
|
2013-02-05 20:09:06 +08:00
|
|
|
E = CurRegion.element_end();
|
2015-07-14 17:33:13 +08:00
|
|
|
I != E; ++I) {
|
|
|
|
isl_schedule *StmtSchedule = nullptr;
|
2015-02-24 20:00:50 +08:00
|
|
|
if (I->isSubRegion()) {
|
2015-07-14 17:33:13 +08:00
|
|
|
StmtSchedule =
|
|
|
|
buildScop(tempScop, *I->getNodeAs<Region>(), NestLoops, LI, SD);
|
2015-02-24 20:00:50 +08:00
|
|
|
} else {
|
2015-08-10 21:01:57 +08:00
|
|
|
StmtSchedule = buildBBScopStmt(I->getNodeAs<BasicBlock>(), tempScop,
|
|
|
|
CurRegion, NestLoops);
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
2015-08-10 21:01:57 +08:00
|
|
|
Schedule = combineInSequence(Schedule, StmtSchedule);
|
2015-07-14 17:33:13 +08:00
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
if (!L)
|
2015-07-14 17:33:13 +08:00
|
|
|
return Schedule;
|
|
|
|
|
|
|
|
auto *Domain = isl_schedule_get_domain(Schedule);
|
|
|
|
if (!isl_union_set_is_empty(Domain)) {
|
|
|
|
auto *MUPA = mapToDimension(isl_union_set_copy(Domain), loopDepth);
|
|
|
|
Schedule = isl_schedule_insert_partial_schedule(Schedule, MUPA);
|
|
|
|
}
|
|
|
|
isl_union_set_free(Domain);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
NestLoops.pop_back();
|
2015-07-14 17:33:13 +08:00
|
|
|
return Schedule;
|
2011-04-29 14:27:02 +08:00
|
|
|
}
|
|
|
|
|
2014-11-01 07:13:39 +08:00
|
|
|
ScopStmt *Scop::getStmtForBasicBlock(BasicBlock *BB) const {
|
2015-05-27 14:51:34 +08:00
|
|
|
auto StmtMapIt = StmtMap.find(BB);
|
2014-11-01 07:13:39 +08:00
|
|
|
if (StmtMapIt == StmtMap.end())
|
|
|
|
return nullptr;
|
|
|
|
return StmtMapIt->second;
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2011-08-20 19:11:25 +08:00
|
|
|
ScopInfo::ScopInfo() : RegionPass(ID), scop(0) {
|
|
|
|
ctx = isl_ctx_alloc();
|
2011-12-07 15:42:51 +08:00
|
|
|
isl_options_set_on_error(ctx, ISL_ON_ERROR_ABORT);
|
2011-08-20 19:11:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ScopInfo::~ScopInfo() {
|
|
|
|
clear();
|
|
|
|
isl_ctx_free(ctx);
|
|
|
|
}
|
|
|
|
|
2011-04-29 14:27:02 +08:00
|
|
|
void ScopInfo::getAnalysisUsage(AnalysisUsage &AU) const {
|
2015-01-17 22:16:56 +08:00
|
|
|
AU.addRequired<LoopInfoWrapperPass>();
|
2014-07-20 02:40:17 +08:00
|
|
|
AU.addRequired<RegionInfoPass>();
|
2015-08-17 18:57:08 +08:00
|
|
|
AU.addRequired<ScalarEvolutionWrapperPass>();
|
2015-02-24 20:00:50 +08:00
|
|
|
AU.addRequired<ScopDetection>();
|
2011-04-29 14:27:02 +08:00
|
|
|
AU.addRequired<TempScopInfo>();
|
2014-09-18 19:17:17 +08:00
|
|
|
AU.addRequired<AliasAnalysis>();
|
2011-04-29 14:27:02 +08:00
|
|
|
AU.setPreservesAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScopInfo::runOnRegion(Region *R, RGPassManager &RGM) {
|
2015-01-17 22:16:56 +08:00
|
|
|
LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
|
2014-09-18 19:17:17 +08:00
|
|
|
AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
|
2015-02-24 20:00:50 +08:00
|
|
|
ScopDetection &SD = getAnalysis<ScopDetection>();
|
2015-08-17 18:57:08 +08:00
|
|
|
ScalarEvolution &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-08-15 04:10:27 +08:00
|
|
|
TempScop *tempScop = getAnalysis<TempScopInfo>().getTempScop();
|
2011-04-29 14:27:02 +08:00
|
|
|
|
|
|
|
// This region is no Scop.
|
|
|
|
if (!tempScop) {
|
2014-11-14 19:12:31 +08:00
|
|
|
scop = nullptr;
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-21 02:30:08 +08:00
|
|
|
scop = Scop::createFromTempScop(*tempScop, LI, SE, SD, AA, ctx);
|
2011-04-29 14:27:02 +08:00
|
|
|
|
2015-05-30 14:26:21 +08:00
|
|
|
DEBUG(scop->print(dbgs()));
|
|
|
|
|
2015-08-21 02:06:30 +08:00
|
|
|
if (!scop->hasFeasibleRuntimeContext()) {
|
2015-08-20 13:58:56 +08:00
|
|
|
delete scop;
|
|
|
|
scop = nullptr;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-21 02:30:08 +08:00
|
|
|
// Statistics.
|
|
|
|
++ScopFound;
|
|
|
|
if (scop->getMaxLoopDepth() > 0)
|
|
|
|
++RichScopFound;
|
2011-04-29 14:27:02 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char ScopInfo::ID = 0;
|
|
|
|
|
2013-03-23 09:05:07 +08:00
|
|
|
Pass *polly::createScopInfoPass() { return new ScopInfo(); }
|
|
|
|
|
2011-10-08 08:30:40 +08:00
|
|
|
INITIALIZE_PASS_BEGIN(ScopInfo, "polly-scops",
|
|
|
|
"Polly - Create polyhedral description of Scops", false,
|
2013-03-23 09:05:07 +08:00
|
|
|
false);
|
2014-09-18 19:17:17 +08:00
|
|
|
INITIALIZE_AG_DEPENDENCY(AliasAnalysis);
|
2015-01-17 22:16:56 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
|
2014-07-20 02:40:17 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
|
2015-08-17 18:57:08 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
|
2015-02-24 20:00:50 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(ScopDetection);
|
2013-03-23 09:05:07 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(TempScopInfo);
|
2011-10-08 08:30:40 +08:00
|
|
|
INITIALIZE_PASS_END(ScopInfo, "polly-scops",
|
|
|
|
"Polly - Create polyhedral description of Scops", false,
|
|
|
|
false)
|