1 //===--------- ScopInfo.cpp - Create Scops from LLVM IR ------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Create a polyhedral description for a static control flow region. 11 // 12 // The pass creates a polyhedral description of the Scops detected by the Scop 13 // detection derived from their LLVM-IR code. 14 // 15 // This representation is shared among several tools in the polyhedral 16 // community, which are e.g. Cloog, Pluto, Loopo, Graphite. 17 // 18 //===----------------------------------------------------------------------===// 19 20 #include "polly/LinkAllPasses.h" 21 #include "polly/Options.h" 22 #include "polly/ScopInfo.h" 23 #include "polly/Support/GICHelper.h" 24 #include "polly/Support/SCEVValidator.h" 25 #include "polly/Support/ScopHelper.h" 26 #include "polly/TempScopInfo.h" 27 #include "llvm/ADT/MapVector.h" 28 #include "llvm/ADT/SetVector.h" 29 #include "llvm/ADT/Statistic.h" 30 #include "llvm/ADT/STLExtras.h" 31 #include "llvm/ADT/StringExtras.h" 32 #include "llvm/Analysis/AliasAnalysis.h" 33 #include "llvm/Analysis/LoopInfo.h" 34 #include "llvm/Analysis/RegionIterator.h" 35 #include "llvm/Analysis/ScalarEvolutionExpressions.h" 36 #include "llvm/Support/Debug.h" 37 #include "isl/aff.h" 38 #include "isl/constraint.h" 39 #include "isl/local_space.h" 40 #include "isl/map.h" 41 #include "isl/options.h" 42 #include "isl/printer.h" 43 #include "isl/schedule.h" 44 #include "isl/schedule_node.h" 45 #include "isl/set.h" 46 #include "isl/union_map.h" 47 #include "isl/union_set.h" 48 #include "isl/val.h" 49 #include <sstream> 50 #include <string> 51 #include <vector> 52 53 using namespace llvm; 54 using namespace polly; 55 56 #define DEBUG_TYPE "polly-scops" 57 58 STATISTIC(ScopFound, "Number of valid Scops"); 59 STATISTIC(RichScopFound, "Number of Scops containing a loop"); 60 61 // Multiplicative reductions can be disabled separately as these kind of 62 // operations can overflow easily. Additive reductions and bit operations 63 // are in contrast pretty stable. 64 static cl::opt<bool> DisableMultiplicativeReductions( 65 "polly-disable-multiplicative-reductions", 66 cl::desc("Disable multiplicative reductions"), cl::Hidden, cl::ZeroOrMore, 67 cl::init(false), cl::cat(PollyCategory)); 68 69 static cl::opt<unsigned> RunTimeChecksMaxParameters( 70 "polly-rtc-max-parameters", 71 cl::desc("The maximal number of parameters allowed in RTCs."), cl::Hidden, 72 cl::ZeroOrMore, cl::init(8), cl::cat(PollyCategory)); 73 74 static cl::opt<unsigned> RunTimeChecksMaxArraysPerGroup( 75 "polly-rtc-max-arrays-per-group", 76 cl::desc("The maximal number of arrays to compare in each alias group."), 77 cl::Hidden, cl::ZeroOrMore, cl::init(20), cl::cat(PollyCategory)); 78 79 /// Translate a 'const SCEV *' expression in an isl_pw_aff. 80 struct SCEVAffinator : public SCEVVisitor<SCEVAffinator, isl_pw_aff *> { 81 public: 82 /// @brief Translate a 'const SCEV *' to an isl_pw_aff. 83 /// 84 /// @param Stmt The location at which the scalar evolution expression 85 /// is evaluated. 86 /// @param Expr The expression that is translated. 87 static __isl_give isl_pw_aff *getPwAff(ScopStmt *Stmt, const SCEV *Expr); 88 89 private: 90 isl_ctx *Ctx; 91 int NbLoopSpaces; 92 const Scop *S; 93 94 SCEVAffinator(const ScopStmt *Stmt); 95 int getLoopDepth(const Loop *L); 96 97 __isl_give isl_pw_aff *visit(const SCEV *Expr); 98 __isl_give isl_pw_aff *visitConstant(const SCEVConstant *Expr); 99 __isl_give isl_pw_aff *visitTruncateExpr(const SCEVTruncateExpr *Expr); 100 __isl_give isl_pw_aff *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr); 101 __isl_give isl_pw_aff *visitSignExtendExpr(const SCEVSignExtendExpr *Expr); 102 __isl_give isl_pw_aff *visitAddExpr(const SCEVAddExpr *Expr); 103 __isl_give isl_pw_aff *visitMulExpr(const SCEVMulExpr *Expr); 104 __isl_give isl_pw_aff *visitUDivExpr(const SCEVUDivExpr *Expr); 105 __isl_give isl_pw_aff *visitAddRecExpr(const SCEVAddRecExpr *Expr); 106 __isl_give isl_pw_aff *visitSMaxExpr(const SCEVSMaxExpr *Expr); 107 __isl_give isl_pw_aff *visitUMaxExpr(const SCEVUMaxExpr *Expr); 108 __isl_give isl_pw_aff *visitUnknown(const SCEVUnknown *Expr); 109 __isl_give isl_pw_aff *visitSDivInstruction(Instruction *SDiv); 110 __isl_give isl_pw_aff *visitSRemInstruction(Instruction *SDiv); 111 112 friend struct SCEVVisitor<SCEVAffinator, isl_pw_aff *>; 113 }; 114 115 SCEVAffinator::SCEVAffinator(const ScopStmt *Stmt) 116 : Ctx(Stmt->getIslCtx()), NbLoopSpaces(Stmt->getNumIterators()), 117 S(Stmt->getParent()) {} 118 119 __isl_give isl_pw_aff *SCEVAffinator::getPwAff(ScopStmt *Stmt, 120 const SCEV *Scev) { 121 Scop *S = Stmt->getParent(); 122 const Region *Reg = &S->getRegion(); 123 124 S->addParams(getParamsInAffineExpr(Reg, Scev, *S->getSE())); 125 126 SCEVAffinator Affinator(Stmt); 127 return Affinator.visit(Scev); 128 } 129 130 __isl_give isl_pw_aff *SCEVAffinator::visit(const SCEV *Expr) { 131 // In case the scev is a valid parameter, we do not further analyze this 132 // expression, but create a new parameter in the isl_pw_aff. This allows us 133 // to treat subexpressions that we cannot translate into an piecewise affine 134 // expression, as constant parameters of the piecewise affine expression. 135 if (isl_id *Id = S->getIdForParam(Expr)) { 136 isl_space *Space = isl_space_set_alloc(Ctx, 1, NbLoopSpaces); 137 Space = isl_space_set_dim_id(Space, isl_dim_param, 0, Id); 138 139 isl_set *Domain = isl_set_universe(isl_space_copy(Space)); 140 isl_aff *Affine = isl_aff_zero_on_domain(isl_local_space_from_space(Space)); 141 Affine = isl_aff_add_coefficient_si(Affine, isl_dim_param, 0, 1); 142 143 return isl_pw_aff_alloc(Domain, Affine); 144 } 145 146 return SCEVVisitor<SCEVAffinator, isl_pw_aff *>::visit(Expr); 147 } 148 149 __isl_give isl_pw_aff *SCEVAffinator::visitConstant(const SCEVConstant *Expr) { 150 ConstantInt *Value = Expr->getValue(); 151 isl_val *v; 152 153 // LLVM does not define if an integer value is interpreted as a signed or 154 // unsigned value. Hence, without further information, it is unknown how 155 // this value needs to be converted to GMP. At the moment, we only support 156 // signed operations. So we just interpret it as signed. Later, there are 157 // two options: 158 // 159 // 1. We always interpret any value as signed and convert the values on 160 // demand. 161 // 2. We pass down the signedness of the calculation and use it to interpret 162 // this constant correctly. 163 v = isl_valFromAPInt(Ctx, Value->getValue(), /* isSigned */ true); 164 165 isl_space *Space = isl_space_set_alloc(Ctx, 0, NbLoopSpaces); 166 isl_local_space *ls = isl_local_space_from_space(Space); 167 return isl_pw_aff_from_aff(isl_aff_val_on_domain(ls, v)); 168 } 169 170 __isl_give isl_pw_aff * 171 SCEVAffinator::visitTruncateExpr(const SCEVTruncateExpr *Expr) { 172 llvm_unreachable("SCEVTruncateExpr not yet supported"); 173 } 174 175 __isl_give isl_pw_aff * 176 SCEVAffinator::visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) { 177 llvm_unreachable("SCEVZeroExtendExpr not yet supported"); 178 } 179 180 __isl_give isl_pw_aff * 181 SCEVAffinator::visitSignExtendExpr(const SCEVSignExtendExpr *Expr) { 182 // Assuming the value is signed, a sign extension is basically a noop. 183 // TODO: Reconsider this as soon as we support unsigned values. 184 return visit(Expr->getOperand()); 185 } 186 187 __isl_give isl_pw_aff *SCEVAffinator::visitAddExpr(const SCEVAddExpr *Expr) { 188 isl_pw_aff *Sum = visit(Expr->getOperand(0)); 189 190 for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) { 191 isl_pw_aff *NextSummand = visit(Expr->getOperand(i)); 192 Sum = isl_pw_aff_add(Sum, NextSummand); 193 } 194 195 // TODO: Check for NSW and NUW. 196 197 return Sum; 198 } 199 200 __isl_give isl_pw_aff *SCEVAffinator::visitMulExpr(const SCEVMulExpr *Expr) { 201 // Divide Expr into a constant part and the rest. Then visit both and multiply 202 // the result to obtain the representation for Expr. While the second part of 203 // ConstantAndLeftOverPair might still be a SCEVMulExpr we will not get to 204 // this point again. The reason is that if it is a multiplication it consists 205 // only of parameters and we will stop in the visit(const SCEV *) function and 206 // return the isl_pw_aff for that parameter. 207 auto ConstantAndLeftOverPair = extractConstantFactor(Expr, *S->getSE()); 208 return isl_pw_aff_mul(visit(ConstantAndLeftOverPair.first), 209 visit(ConstantAndLeftOverPair.second)); 210 } 211 212 __isl_give isl_pw_aff *SCEVAffinator::visitUDivExpr(const SCEVUDivExpr *Expr) { 213 llvm_unreachable("SCEVUDivExpr not yet supported"); 214 } 215 216 __isl_give isl_pw_aff * 217 SCEVAffinator::visitAddRecExpr(const SCEVAddRecExpr *Expr) { 218 assert(Expr->isAffine() && "Only affine AddRecurrences allowed"); 219 220 auto Flags = Expr->getNoWrapFlags(); 221 222 // Directly generate isl_pw_aff for Expr if 'start' is zero. 223 if (Expr->getStart()->isZero()) { 224 assert(S->getRegion().contains(Expr->getLoop()) && 225 "Scop does not contain the loop referenced in this AddRec"); 226 227 isl_pw_aff *Start = visit(Expr->getStart()); 228 isl_pw_aff *Step = visit(Expr->getOperand(1)); 229 isl_space *Space = isl_space_set_alloc(Ctx, 0, NbLoopSpaces); 230 isl_local_space *LocalSpace = isl_local_space_from_space(Space); 231 232 int loopDimension = getLoopDepth(Expr->getLoop()); 233 234 isl_aff *LAff = isl_aff_set_coefficient_si( 235 isl_aff_zero_on_domain(LocalSpace), isl_dim_in, loopDimension, 1); 236 isl_pw_aff *LPwAff = isl_pw_aff_from_aff(LAff); 237 238 // TODO: Do we need to check for NSW and NUW? 239 return isl_pw_aff_add(Start, isl_pw_aff_mul(Step, LPwAff)); 240 } 241 242 // Translate AddRecExpr from '{start, +, inc}' into 'start + {0, +, inc}' 243 // if 'start' is not zero. 244 // TODO: Using the original SCEV no-wrap flags is not always safe, however 245 // as our code generation is reordering the expression anyway it doesn't 246 // really matter. 247 ScalarEvolution &SE = *S->getSE(); 248 const SCEV *ZeroStartExpr = 249 SE.getAddRecExpr(SE.getConstant(Expr->getStart()->getType(), 0), 250 Expr->getStepRecurrence(SE), Expr->getLoop(), Flags); 251 252 isl_pw_aff *ZeroStartResult = visit(ZeroStartExpr); 253 isl_pw_aff *Start = visit(Expr->getStart()); 254 255 return isl_pw_aff_add(ZeroStartResult, Start); 256 } 257 258 __isl_give isl_pw_aff *SCEVAffinator::visitSMaxExpr(const SCEVSMaxExpr *Expr) { 259 isl_pw_aff *Max = visit(Expr->getOperand(0)); 260 261 for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) { 262 isl_pw_aff *NextOperand = visit(Expr->getOperand(i)); 263 Max = isl_pw_aff_max(Max, NextOperand); 264 } 265 266 return Max; 267 } 268 269 __isl_give isl_pw_aff *SCEVAffinator::visitUMaxExpr(const SCEVUMaxExpr *Expr) { 270 llvm_unreachable("SCEVUMaxExpr not yet supported"); 271 } 272 273 __isl_give isl_pw_aff *SCEVAffinator::visitSDivInstruction(Instruction *SDiv) { 274 assert(SDiv->getOpcode() == Instruction::SDiv && "Assumed SDiv instruction!"); 275 auto *SE = S->getSE(); 276 277 auto *Divisor = SDiv->getOperand(1); 278 auto *DivisorSCEV = SE->getSCEV(Divisor); 279 auto *DivisorPWA = visit(DivisorSCEV); 280 assert(isa<ConstantInt>(Divisor) && 281 "SDiv is no parameter but has a non-constant RHS."); 282 283 auto *Dividend = SDiv->getOperand(0); 284 auto *DividendSCEV = SE->getSCEV(Dividend); 285 auto *DividendPWA = visit(DividendSCEV); 286 return isl_pw_aff_tdiv_q(DividendPWA, DivisorPWA); 287 } 288 289 __isl_give isl_pw_aff *SCEVAffinator::visitSRemInstruction(Instruction *SRem) { 290 assert(SRem->getOpcode() == Instruction::SRem && "Assumed SRem instruction!"); 291 auto *SE = S->getSE(); 292 293 auto *Divisor = dyn_cast<ConstantInt>(SRem->getOperand(1)); 294 assert(Divisor && "SRem is no parameter but has a non-constant RHS."); 295 auto *DivisorVal = isl_valFromAPInt(Ctx, Divisor->getValue(), 296 /* isSigned */ true); 297 298 auto *Dividend = SRem->getOperand(0); 299 auto *DividendSCEV = SE->getSCEV(Dividend); 300 auto *DividendPWA = visit(DividendSCEV); 301 302 return isl_pw_aff_mod_val(DividendPWA, isl_val_abs(DivisorVal)); 303 } 304 305 __isl_give isl_pw_aff *SCEVAffinator::visitUnknown(const SCEVUnknown *Expr) { 306 if (Instruction *I = dyn_cast<Instruction>(Expr->getValue())) { 307 switch (I->getOpcode()) { 308 case Instruction::SDiv: 309 return visitSDivInstruction(I); 310 case Instruction::SRem: 311 return visitSRemInstruction(I); 312 default: 313 break; // Fall through. 314 } 315 } 316 317 llvm_unreachable( 318 "Unknowns SCEV was neither parameter nor a valid instruction."); 319 } 320 321 int SCEVAffinator::getLoopDepth(const Loop *L) { 322 Loop *outerLoop = S->getRegion().outermostLoopInRegion(const_cast<Loop *>(L)); 323 assert(outerLoop && "Scop does not contain this loop"); 324 return L->getLoopDepth() - outerLoop->getLoopDepth(); 325 } 326 327 /// @brief Add the bounds of @p Range to the set @p S for dimension @p dim. 328 static __isl_give isl_set *addRangeBoundsToSet(__isl_take isl_set *S, 329 const ConstantRange &Range, 330 int dim, 331 enum isl_dim_type type) { 332 isl_val *V; 333 isl_ctx *ctx = isl_set_get_ctx(S); 334 335 bool useLowerUpperBound = Range.isSignWrappedSet() && !Range.isFullSet(); 336 const auto LB = useLowerUpperBound ? Range.getLower() : Range.getSignedMin(); 337 V = isl_valFromAPInt(ctx, LB, true); 338 isl_set *SLB = isl_set_lower_bound_val(isl_set_copy(S), type, dim, V); 339 340 const auto UB = useLowerUpperBound ? Range.getUpper() : Range.getSignedMax(); 341 V = isl_valFromAPInt(ctx, UB, true); 342 if (useLowerUpperBound) 343 V = isl_val_sub_ui(V, 1); 344 isl_set *SUB = isl_set_upper_bound_val(S, type, dim, V); 345 346 if (useLowerUpperBound) 347 return isl_set_union(SLB, SUB); 348 else 349 return isl_set_intersect(SLB, SUB); 350 } 351 352 ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *Ctx, 353 const SmallVector<const SCEV *, 4> &DimensionSizes, 354 bool IsPHI) 355 : BasePtr(BasePtr), ElementType(ElementType), 356 DimensionSizes(DimensionSizes), IsPHI(IsPHI) { 357 std::string BasePtrName = 358 getIslCompatibleName("MemRef_", BasePtr, IsPHI ? "__phi" : ""); 359 Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this); 360 } 361 362 ScopArrayInfo::~ScopArrayInfo() { isl_id_free(Id); } 363 364 std::string ScopArrayInfo::getName() const { return isl_id_get_name(Id); } 365 366 int ScopArrayInfo::getElemSizeInBytes() const { 367 return ElementType->getPrimitiveSizeInBits() / 8; 368 } 369 370 isl_id *ScopArrayInfo::getBasePtrId() const { return isl_id_copy(Id); } 371 372 void ScopArrayInfo::dump() const { print(errs()); } 373 374 void ScopArrayInfo::print(raw_ostream &OS) const { 375 OS.indent(8) << *getElementType() << " " << getName() << "[*]"; 376 for (unsigned u = 0; u < getNumberOfDimensions(); u++) 377 OS << "[" << *DimensionSizes[u] << "]"; 378 OS << " // Element size " << getElemSizeInBytes() << "\n"; 379 } 380 381 const ScopArrayInfo * 382 ScopArrayInfo::getFromAccessFunction(__isl_keep isl_pw_multi_aff *PMA) { 383 isl_id *Id = isl_pw_multi_aff_get_tuple_id(PMA, isl_dim_out); 384 assert(Id && "Output dimension didn't have an ID"); 385 return getFromId(Id); 386 } 387 388 const ScopArrayInfo *ScopArrayInfo::getFromId(isl_id *Id) { 389 void *User = isl_id_get_user(Id); 390 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User); 391 isl_id_free(Id); 392 return SAI; 393 } 394 395 const std::string 396 MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT) { 397 switch (RT) { 398 case MemoryAccess::RT_NONE: 399 llvm_unreachable("Requested a reduction operator string for a memory " 400 "access which isn't a reduction"); 401 case MemoryAccess::RT_ADD: 402 return "+"; 403 case MemoryAccess::RT_MUL: 404 return "*"; 405 case MemoryAccess::RT_BOR: 406 return "|"; 407 case MemoryAccess::RT_BXOR: 408 return "^"; 409 case MemoryAccess::RT_BAND: 410 return "&"; 411 } 412 llvm_unreachable("Unknown reduction type"); 413 return ""; 414 } 415 416 /// @brief Return the reduction type for a given binary operator 417 static MemoryAccess::ReductionType getReductionType(const BinaryOperator *BinOp, 418 const Instruction *Load) { 419 if (!BinOp) 420 return MemoryAccess::RT_NONE; 421 switch (BinOp->getOpcode()) { 422 case Instruction::FAdd: 423 if (!BinOp->hasUnsafeAlgebra()) 424 return MemoryAccess::RT_NONE; 425 // Fall through 426 case Instruction::Add: 427 return MemoryAccess::RT_ADD; 428 case Instruction::Or: 429 return MemoryAccess::RT_BOR; 430 case Instruction::Xor: 431 return MemoryAccess::RT_BXOR; 432 case Instruction::And: 433 return MemoryAccess::RT_BAND; 434 case Instruction::FMul: 435 if (!BinOp->hasUnsafeAlgebra()) 436 return MemoryAccess::RT_NONE; 437 // Fall through 438 case Instruction::Mul: 439 if (DisableMultiplicativeReductions) 440 return MemoryAccess::RT_NONE; 441 return MemoryAccess::RT_MUL; 442 default: 443 return MemoryAccess::RT_NONE; 444 } 445 } 446 //===----------------------------------------------------------------------===// 447 448 MemoryAccess::~MemoryAccess() { 449 isl_id_free(Id); 450 isl_map_free(AccessRelation); 451 isl_map_free(newAccessRelation); 452 } 453 454 static MemoryAccess::AccessType getMemoryAccessType(const IRAccess &Access) { 455 switch (Access.getType()) { 456 case IRAccess::READ: 457 return MemoryAccess::READ; 458 case IRAccess::MUST_WRITE: 459 return MemoryAccess::MUST_WRITE; 460 case IRAccess::MAY_WRITE: 461 return MemoryAccess::MAY_WRITE; 462 } 463 llvm_unreachable("Unknown IRAccess type!"); 464 } 465 466 const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const { 467 isl_id *ArrayId = getArrayId(); 468 void *User = isl_id_get_user(ArrayId); 469 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User); 470 isl_id_free(ArrayId); 471 return SAI; 472 } 473 474 __isl_give isl_id *MemoryAccess::getArrayId() const { 475 return isl_map_get_tuple_id(AccessRelation, isl_dim_out); 476 } 477 478 __isl_give isl_pw_multi_aff *MemoryAccess::applyScheduleToAccessRelation( 479 __isl_take isl_union_map *USchedule) const { 480 isl_map *Schedule, *ScheduledAccRel; 481 isl_union_set *UDomain; 482 483 UDomain = isl_union_set_from_set(getStatement()->getDomain()); 484 USchedule = isl_union_map_intersect_domain(USchedule, UDomain); 485 Schedule = isl_map_from_union_map(USchedule); 486 ScheduledAccRel = isl_map_apply_domain(getAccessRelation(), Schedule); 487 return isl_pw_multi_aff_from_map(ScheduledAccRel); 488 } 489 490 __isl_give isl_map *MemoryAccess::getOriginalAccessRelation() const { 491 return isl_map_copy(AccessRelation); 492 } 493 494 std::string MemoryAccess::getOriginalAccessRelationStr() const { 495 return stringFromIslObj(AccessRelation); 496 } 497 498 __isl_give isl_space *MemoryAccess::getOriginalAccessRelationSpace() const { 499 return isl_map_get_space(AccessRelation); 500 } 501 502 __isl_give isl_map *MemoryAccess::getNewAccessRelation() const { 503 return isl_map_copy(newAccessRelation); 504 } 505 506 __isl_give isl_basic_map * 507 MemoryAccess::createBasicAccessMap(ScopStmt *Statement) { 508 isl_space *Space = isl_space_set_alloc(Statement->getIslCtx(), 0, 1); 509 Space = isl_space_align_params(Space, Statement->getDomainSpace()); 510 511 return isl_basic_map_from_domain_and_range( 512 isl_basic_set_universe(Statement->getDomainSpace()), 513 isl_basic_set_universe(Space)); 514 } 515 516 // Formalize no out-of-bound access assumption 517 // 518 // When delinearizing array accesses we optimistically assume that the 519 // delinearized accesses do not access out of bound locations (the subscript 520 // expression of each array evaluates for each statement instance that is 521 // executed to a value that is larger than zero and strictly smaller than the 522 // size of the corresponding dimension). The only exception is the outermost 523 // dimension for which we do not need to assume any upper bound. At this point 524 // we formalize this assumption to ensure that at code generation time the 525 // relevant run-time checks can be generated. 526 // 527 // To find the set of constraints necessary to avoid out of bound accesses, we 528 // first build the set of data locations that are not within array bounds. We 529 // then apply the reverse access relation to obtain the set of iterations that 530 // may contain invalid accesses and reduce this set of iterations to the ones 531 // that are actually executed by intersecting them with the domain of the 532 // statement. If we now project out all loop dimensions, we obtain a set of 533 // parameters that may cause statement instances to be executed that may 534 // possibly yield out of bound memory accesses. The complement of these 535 // constraints is the set of constraints that needs to be assumed to ensure such 536 // statement instances are never executed. 537 void MemoryAccess::assumeNoOutOfBound(const IRAccess &Access) { 538 isl_space *Space = isl_space_range(getOriginalAccessRelationSpace()); 539 isl_set *Outside = isl_set_empty(isl_space_copy(Space)); 540 for (int i = 1, Size = Access.Subscripts.size(); i < Size; ++i) { 541 isl_local_space *LS = isl_local_space_from_space(isl_space_copy(Space)); 542 isl_pw_aff *Var = 543 isl_pw_aff_var_on_domain(isl_local_space_copy(LS), isl_dim_set, i); 544 isl_pw_aff *Zero = isl_pw_aff_zero_on_domain(LS); 545 546 isl_set *DimOutside; 547 548 DimOutside = isl_pw_aff_lt_set(isl_pw_aff_copy(Var), Zero); 549 isl_pw_aff *SizeE = SCEVAffinator::getPwAff(Statement, Access.Sizes[i - 1]); 550 551 SizeE = isl_pw_aff_drop_dims(SizeE, isl_dim_in, 0, 552 Statement->getNumIterators()); 553 SizeE = isl_pw_aff_add_dims(SizeE, isl_dim_in, 554 isl_space_dim(Space, isl_dim_set)); 555 SizeE = isl_pw_aff_set_tuple_id(SizeE, isl_dim_in, 556 isl_space_get_tuple_id(Space, isl_dim_set)); 557 558 DimOutside = isl_set_union(DimOutside, isl_pw_aff_le_set(SizeE, Var)); 559 560 Outside = isl_set_union(Outside, DimOutside); 561 } 562 563 Outside = isl_set_apply(Outside, isl_map_reverse(getAccessRelation())); 564 Outside = isl_set_intersect(Outside, Statement->getDomain()); 565 Outside = isl_set_params(Outside); 566 567 // Remove divs to avoid the construction of overly complicated assumptions. 568 // Doing so increases the set of parameter combinations that are assumed to 569 // not appear. This is always save, but may make the resulting run-time check 570 // bail out more often than strictly necessary. 571 Outside = isl_set_remove_divs(Outside); 572 Outside = isl_set_complement(Outside); 573 Statement->getParent()->addAssumption(Outside); 574 isl_space_free(Space); 575 } 576 577 void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) { 578 ScalarEvolution *SE = Statement->getParent()->getSE(); 579 580 Value *Ptr = getPointerOperand(*getAccessInstruction()); 581 if (!Ptr || !SE->isSCEVable(Ptr->getType())) 582 return; 583 584 auto *PtrSCEV = SE->getSCEV(Ptr); 585 if (isa<SCEVCouldNotCompute>(PtrSCEV)) 586 return; 587 588 auto *BasePtrSCEV = SE->getPointerBase(PtrSCEV); 589 if (BasePtrSCEV && !isa<SCEVCouldNotCompute>(BasePtrSCEV)) 590 PtrSCEV = SE->getMinusSCEV(PtrSCEV, BasePtrSCEV); 591 592 const ConstantRange &Range = SE->getSignedRange(PtrSCEV); 593 if (Range.isFullSet()) 594 return; 595 596 bool isWrapping = Range.isSignWrappedSet(); 597 unsigned BW = Range.getBitWidth(); 598 const auto LB = isWrapping ? Range.getLower() : Range.getSignedMin(); 599 const auto UB = isWrapping ? Range.getUpper() : Range.getSignedMax(); 600 601 auto Min = LB.sdiv(APInt(BW, ElementSize)); 602 auto Max = (UB - APInt(BW, 1)).sdiv(APInt(BW, ElementSize)); 603 604 isl_set *AccessRange = isl_map_range(isl_map_copy(AccessRelation)); 605 AccessRange = 606 addRangeBoundsToSet(AccessRange, ConstantRange(Min, Max), 0, isl_dim_set); 607 AccessRelation = isl_map_intersect_range(AccessRelation, AccessRange); 608 } 609 610 __isl_give isl_map *MemoryAccess::foldAccess(const IRAccess &Access, 611 __isl_take isl_map *AccessRelation, 612 ScopStmt *Statement) { 613 int Size = Access.Subscripts.size(); 614 615 for (int i = Size - 2; i >= 0; --i) { 616 isl_space *Space; 617 isl_map *MapOne, *MapTwo; 618 isl_pw_aff *DimSize = SCEVAffinator::getPwAff(Statement, Access.Sizes[i]); 619 620 isl_space *SpaceSize = isl_pw_aff_get_space(DimSize); 621 isl_pw_aff_free(DimSize); 622 isl_id *ParamId = isl_space_get_dim_id(SpaceSize, isl_dim_param, 0); 623 624 Space = isl_map_get_space(AccessRelation); 625 Space = isl_space_map_from_set(isl_space_range(Space)); 626 Space = isl_space_align_params(Space, SpaceSize); 627 628 int ParamLocation = isl_space_find_dim_by_id(Space, isl_dim_param, ParamId); 629 isl_id_free(ParamId); 630 631 MapOne = isl_map_universe(isl_space_copy(Space)); 632 for (int j = 0; j < Size; ++j) 633 MapOne = isl_map_equate(MapOne, isl_dim_in, j, isl_dim_out, j); 634 MapOne = isl_map_lower_bound_si(MapOne, isl_dim_in, i + 1, 0); 635 636 MapTwo = isl_map_universe(isl_space_copy(Space)); 637 for (int j = 0; j < Size; ++j) 638 if (j < i || j > i + 1) 639 MapTwo = isl_map_equate(MapTwo, isl_dim_in, j, isl_dim_out, j); 640 641 isl_local_space *LS = isl_local_space_from_space(Space); 642 isl_constraint *C; 643 C = isl_equality_alloc(isl_local_space_copy(LS)); 644 C = isl_constraint_set_constant_si(C, -1); 645 C = isl_constraint_set_coefficient_si(C, isl_dim_in, i, 1); 646 C = isl_constraint_set_coefficient_si(C, isl_dim_out, i, -1); 647 MapTwo = isl_map_add_constraint(MapTwo, C); 648 C = isl_equality_alloc(LS); 649 C = isl_constraint_set_coefficient_si(C, isl_dim_in, i + 1, 1); 650 C = isl_constraint_set_coefficient_si(C, isl_dim_out, i + 1, -1); 651 C = isl_constraint_set_coefficient_si(C, isl_dim_param, ParamLocation, 1); 652 MapTwo = isl_map_add_constraint(MapTwo, C); 653 MapTwo = isl_map_upper_bound_si(MapTwo, isl_dim_in, i + 1, -1); 654 655 MapOne = isl_map_union(MapOne, MapTwo); 656 AccessRelation = isl_map_apply_range(AccessRelation, MapOne); 657 } 658 return AccessRelation; 659 } 660 661 MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst, 662 ScopStmt *Statement, const ScopArrayInfo *SAI, 663 int Identifier) 664 : AccType(getMemoryAccessType(Access)), Statement(Statement), Inst(AccInst), 665 newAccessRelation(nullptr) { 666 667 isl_ctx *Ctx = Statement->getIslCtx(); 668 BaseAddr = Access.getBase(); 669 BaseName = getIslCompatibleName("MemRef_", getBaseAddr(), ""); 670 671 isl_id *BaseAddrId = SAI->getBasePtrId(); 672 673 auto IdName = "__polly_array_ref_ " + std::to_string(Identifier); 674 Id = isl_id_alloc(Ctx, IdName.c_str(), nullptr); 675 676 if (!Access.isAffine()) { 677 // We overapproximate non-affine accesses with a possible access to the 678 // whole array. For read accesses it does not make a difference, if an 679 // access must or may happen. However, for write accesses it is important to 680 // differentiate between writes that must happen and writes that may happen. 681 AccessRelation = isl_map_from_basic_map(createBasicAccessMap(Statement)); 682 AccessRelation = 683 isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId); 684 685 computeBoundsOnAccessRelation(Access.getElemSizeInBytes()); 686 return; 687 } 688 689 isl_space *Space = isl_space_alloc(Ctx, 0, Statement->getNumIterators(), 0); 690 AccessRelation = isl_map_universe(Space); 691 692 for (int i = 0, Size = Access.Subscripts.size(); i < Size; ++i) { 693 isl_pw_aff *Affine = 694 SCEVAffinator::getPwAff(Statement, Access.Subscripts[i]); 695 696 if (Size == 1) { 697 // For the non delinearized arrays, divide the access function of the last 698 // subscript by the size of the elements in the array. 699 // 700 // A stride one array access in C expressed as A[i] is expressed in 701 // LLVM-IR as something like A[i * elementsize]. This hides the fact that 702 // two subsequent values of 'i' index two values that are stored next to 703 // each other in memory. By this division we make this characteristic 704 // obvious again. 705 isl_val *v = isl_val_int_from_si(Ctx, Access.getElemSizeInBytes()); 706 Affine = isl_pw_aff_scale_down_val(Affine, v); 707 } 708 709 isl_map *SubscriptMap = isl_map_from_pw_aff(Affine); 710 711 AccessRelation = isl_map_flat_range_product(AccessRelation, SubscriptMap); 712 } 713 714 AccessRelation = foldAccess(Access, AccessRelation, Statement); 715 716 Space = Statement->getDomainSpace(); 717 AccessRelation = isl_map_set_tuple_id( 718 AccessRelation, isl_dim_in, isl_space_get_tuple_id(Space, isl_dim_set)); 719 AccessRelation = 720 isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId); 721 722 assumeNoOutOfBound(Access); 723 AccessRelation = isl_map_gist_domain(AccessRelation, Statement->getDomain()); 724 isl_space_free(Space); 725 } 726 727 void MemoryAccess::realignParams() { 728 isl_space *ParamSpace = Statement->getParent()->getParamSpace(); 729 AccessRelation = isl_map_align_params(AccessRelation, ParamSpace); 730 } 731 732 const std::string MemoryAccess::getReductionOperatorStr() const { 733 return MemoryAccess::getReductionOperatorStr(getReductionType()); 734 } 735 736 __isl_give isl_id *MemoryAccess::getId() const { return isl_id_copy(Id); } 737 738 raw_ostream &polly::operator<<(raw_ostream &OS, 739 MemoryAccess::ReductionType RT) { 740 if (RT == MemoryAccess::RT_NONE) 741 OS << "NONE"; 742 else 743 OS << MemoryAccess::getReductionOperatorStr(RT); 744 return OS; 745 } 746 747 void MemoryAccess::print(raw_ostream &OS) const { 748 switch (AccType) { 749 case READ: 750 OS.indent(12) << "ReadAccess :=\t"; 751 break; 752 case MUST_WRITE: 753 OS.indent(12) << "MustWriteAccess :=\t"; 754 break; 755 case MAY_WRITE: 756 OS.indent(12) << "MayWriteAccess :=\t"; 757 break; 758 } 759 OS << "[Reduction Type: " << getReductionType() << "] "; 760 OS << "[Scalar: " << isScalar() << "]\n"; 761 OS.indent(16) << getOriginalAccessRelationStr() << ";\n"; 762 } 763 764 void MemoryAccess::dump() const { print(errs()); } 765 766 // Create a map in the size of the provided set domain, that maps from the 767 // one element of the provided set domain to another element of the provided 768 // set domain. 769 // The mapping is limited to all points that are equal in all but the last 770 // dimension and for which the last dimension of the input is strict smaller 771 // than the last dimension of the output. 772 // 773 // getEqualAndLarger(set[i0, i1, ..., iX]): 774 // 775 // set[i0, i1, ..., iX] -> set[o0, o1, ..., oX] 776 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1), iX < oX 777 // 778 static isl_map *getEqualAndLarger(isl_space *setDomain) { 779 isl_space *Space = isl_space_map_from_set(setDomain); 780 isl_map *Map = isl_map_universe(Space); 781 unsigned lastDimension = isl_map_dim(Map, isl_dim_in) - 1; 782 783 // Set all but the last dimension to be equal for the input and output 784 // 785 // input[i0, i1, ..., iX] -> output[o0, o1, ..., oX] 786 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1) 787 for (unsigned i = 0; i < lastDimension; ++i) 788 Map = isl_map_equate(Map, isl_dim_in, i, isl_dim_out, i); 789 790 // Set the last dimension of the input to be strict smaller than the 791 // last dimension of the output. 792 // 793 // input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX 794 Map = isl_map_order_lt(Map, isl_dim_in, lastDimension, isl_dim_out, 795 lastDimension); 796 return Map; 797 } 798 799 __isl_give isl_set * 800 MemoryAccess::getStride(__isl_take const isl_map *Schedule) const { 801 isl_map *S = const_cast<isl_map *>(Schedule); 802 isl_map *AccessRelation = getAccessRelation(); 803 isl_space *Space = isl_space_range(isl_map_get_space(S)); 804 isl_map *NextScatt = getEqualAndLarger(Space); 805 806 S = isl_map_reverse(S); 807 NextScatt = isl_map_lexmin(NextScatt); 808 809 NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(S)); 810 NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(AccessRelation)); 811 NextScatt = isl_map_apply_domain(NextScatt, S); 812 NextScatt = isl_map_apply_domain(NextScatt, AccessRelation); 813 814 isl_set *Deltas = isl_map_deltas(NextScatt); 815 return Deltas; 816 } 817 818 bool MemoryAccess::isStrideX(__isl_take const isl_map *Schedule, 819 int StrideWidth) const { 820 isl_set *Stride, *StrideX; 821 bool IsStrideX; 822 823 Stride = getStride(Schedule); 824 StrideX = isl_set_universe(isl_set_get_space(Stride)); 825 StrideX = isl_set_fix_si(StrideX, isl_dim_set, 0, StrideWidth); 826 IsStrideX = isl_set_is_equal(Stride, StrideX); 827 828 isl_set_free(StrideX); 829 isl_set_free(Stride); 830 831 return IsStrideX; 832 } 833 834 bool MemoryAccess::isStrideZero(const isl_map *Schedule) const { 835 return isStrideX(Schedule, 0); 836 } 837 838 bool MemoryAccess::isScalar() const { 839 return isl_map_n_out(AccessRelation) == 0; 840 } 841 842 bool MemoryAccess::isStrideOne(const isl_map *Schedule) const { 843 return isStrideX(Schedule, 1); 844 } 845 846 void MemoryAccess::setNewAccessRelation(isl_map *newAccess) { 847 isl_map_free(newAccessRelation); 848 newAccessRelation = newAccess; 849 } 850 851 //===----------------------------------------------------------------------===// 852 853 isl_map *ScopStmt::getSchedule() const { 854 isl_set *Domain = getDomain(); 855 if (isl_set_is_empty(Domain)) { 856 isl_set_free(Domain); 857 return isl_map_from_aff( 858 isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace()))); 859 } 860 auto *Schedule = getParent()->getSchedule(); 861 Schedule = isl_union_map_intersect_domain( 862 Schedule, isl_union_set_from_set(isl_set_copy(Domain))); 863 if (isl_union_map_is_empty(Schedule)) { 864 isl_set_free(Domain); 865 isl_union_map_free(Schedule); 866 return isl_map_from_aff( 867 isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace()))); 868 } 869 auto *M = isl_map_from_union_map(Schedule); 870 M = isl_map_coalesce(M); 871 M = isl_map_gist_domain(M, Domain); 872 M = isl_map_coalesce(M); 873 return M; 874 } 875 876 void ScopStmt::restrictDomain(__isl_take isl_set *NewDomain) { 877 assert(isl_set_is_subset(NewDomain, Domain) && 878 "New domain is not a subset of old domain!"); 879 isl_set_free(Domain); 880 Domain = NewDomain; 881 } 882 883 void ScopStmt::buildAccesses(TempScop &tempScop, BasicBlock *Block, 884 bool isApproximated) { 885 AccFuncSetType *AFS = tempScop.getAccessFunctions(Block); 886 if (!AFS) 887 return; 888 889 for (auto &AccessPair : *AFS) { 890 IRAccess &Access = AccessPair.first; 891 Instruction *AccessInst = AccessPair.second; 892 893 Type *ElementType = getAccessInstType(AccessInst); 894 const ScopArrayInfo *SAI = getParent()->getOrCreateScopArrayInfo( 895 Access.getBase(), ElementType, Access.Sizes, Access.isPHI()); 896 897 if (isApproximated && Access.isWrite()) 898 Access.setMayWrite(); 899 900 MemoryAccessList *&MAL = InstructionToAccess[AccessInst]; 901 if (!MAL) 902 MAL = new MemoryAccessList(); 903 MAL->emplace_front(Access, AccessInst, this, SAI, MemAccs.size()); 904 MemAccs.push_back(&MAL->front()); 905 } 906 } 907 908 void ScopStmt::realignParams() { 909 for (MemoryAccess *MA : *this) 910 MA->realignParams(); 911 912 Domain = isl_set_align_params(Domain, Parent.getParamSpace()); 913 } 914 915 __isl_give isl_set *ScopStmt::buildConditionSet(const Comparison &Comp) { 916 isl_pw_aff *L = SCEVAffinator::getPwAff(this, Comp.getLHS()); 917 isl_pw_aff *R = SCEVAffinator::getPwAff(this, Comp.getRHS()); 918 919 switch (Comp.getPred()) { 920 case ICmpInst::ICMP_EQ: 921 return isl_pw_aff_eq_set(L, R); 922 case ICmpInst::ICMP_NE: 923 return isl_pw_aff_ne_set(L, R); 924 case ICmpInst::ICMP_SLT: 925 return isl_pw_aff_lt_set(L, R); 926 case ICmpInst::ICMP_SLE: 927 return isl_pw_aff_le_set(L, R); 928 case ICmpInst::ICMP_SGT: 929 return isl_pw_aff_gt_set(L, R); 930 case ICmpInst::ICMP_SGE: 931 return isl_pw_aff_ge_set(L, R); 932 case ICmpInst::ICMP_ULT: 933 return isl_pw_aff_lt_set(L, R); 934 case ICmpInst::ICMP_UGT: 935 return isl_pw_aff_gt_set(L, R); 936 case ICmpInst::ICMP_ULE: 937 return isl_pw_aff_le_set(L, R); 938 case ICmpInst::ICMP_UGE: 939 return isl_pw_aff_ge_set(L, R); 940 default: 941 llvm_unreachable("Non integer predicate not supported"); 942 } 943 } 944 945 __isl_give isl_set *ScopStmt::addLoopBoundsToDomain(__isl_take isl_set *Domain, 946 TempScop &tempScop) { 947 isl_space *Space; 948 isl_local_space *LocalSpace; 949 950 Space = isl_set_get_space(Domain); 951 LocalSpace = isl_local_space_from_space(Space); 952 953 ScalarEvolution *SE = getParent()->getSE(); 954 for (int i = 0, e = getNumIterators(); i != e; ++i) { 955 isl_aff *Zero = isl_aff_zero_on_domain(isl_local_space_copy(LocalSpace)); 956 isl_pw_aff *IV = 957 isl_pw_aff_from_aff(isl_aff_set_coefficient_si(Zero, isl_dim_in, i, 1)); 958 959 // 0 <= IV. 960 isl_set *LowerBound = isl_pw_aff_nonneg_set(isl_pw_aff_copy(IV)); 961 Domain = isl_set_intersect(Domain, LowerBound); 962 963 // IV <= LatchExecutions. 964 const Loop *L = getLoopForDimension(i); 965 const SCEV *LatchExecutions = SE->getBackedgeTakenCount(L); 966 isl_pw_aff *UpperBound = SCEVAffinator::getPwAff(this, LatchExecutions); 967 isl_set *UpperBoundSet = isl_pw_aff_le_set(IV, UpperBound); 968 Domain = isl_set_intersect(Domain, UpperBoundSet); 969 } 970 971 isl_local_space_free(LocalSpace); 972 return Domain; 973 } 974 975 __isl_give isl_set *ScopStmt::addConditionsToDomain(__isl_take isl_set *Domain, 976 TempScop &tempScop, 977 const Region &CurRegion) { 978 const Region *TopRegion = tempScop.getMaxRegion().getParent(), 979 *CurrentRegion = &CurRegion; 980 const BasicBlock *BranchingBB = BB ? BB : R->getEntry(); 981 982 do { 983 if (BranchingBB != CurrentRegion->getEntry()) { 984 if (const BBCond *Condition = tempScop.getBBCond(BranchingBB)) 985 for (const auto &C : *Condition) { 986 isl_set *ConditionSet = buildConditionSet(C); 987 Domain = isl_set_intersect(Domain, ConditionSet); 988 } 989 } 990 BranchingBB = CurrentRegion->getEntry(); 991 CurrentRegion = CurrentRegion->getParent(); 992 } while (TopRegion != CurrentRegion); 993 994 return Domain; 995 } 996 997 __isl_give isl_set *ScopStmt::buildDomain(TempScop &tempScop, 998 const Region &CurRegion) { 999 isl_space *Space; 1000 isl_set *Domain; 1001 isl_id *Id; 1002 1003 Space = isl_space_set_alloc(getIslCtx(), 0, getNumIterators()); 1004 1005 Id = isl_id_alloc(getIslCtx(), getBaseName(), this); 1006 1007 Domain = isl_set_universe(Space); 1008 Domain = addLoopBoundsToDomain(Domain, tempScop); 1009 Domain = addConditionsToDomain(Domain, tempScop, CurRegion); 1010 Domain = isl_set_set_tuple_id(Domain, Id); 1011 1012 return Domain; 1013 } 1014 1015 void ScopStmt::deriveAssumptionsFromGEP(GetElementPtrInst *GEP) { 1016 int Dimension = 0; 1017 isl_ctx *Ctx = Parent.getIslCtx(); 1018 isl_local_space *LSpace = isl_local_space_from_space(getDomainSpace()); 1019 Type *Ty = GEP->getPointerOperandType(); 1020 ScalarEvolution &SE = *Parent.getSE(); 1021 1022 if (auto *PtrTy = dyn_cast<PointerType>(Ty)) { 1023 Dimension = 1; 1024 Ty = PtrTy->getElementType(); 1025 } 1026 1027 while (auto ArrayTy = dyn_cast<ArrayType>(Ty)) { 1028 unsigned int Operand = 1 + Dimension; 1029 1030 if (GEP->getNumOperands() <= Operand) 1031 break; 1032 1033 const SCEV *Expr = SE.getSCEV(GEP->getOperand(Operand)); 1034 1035 if (isAffineExpr(&Parent.getRegion(), Expr, SE)) { 1036 isl_pw_aff *AccessOffset = SCEVAffinator::getPwAff(this, Expr); 1037 AccessOffset = 1038 isl_pw_aff_set_tuple_id(AccessOffset, isl_dim_in, getDomainId()); 1039 1040 isl_pw_aff *DimSize = isl_pw_aff_from_aff(isl_aff_val_on_domain( 1041 isl_local_space_copy(LSpace), 1042 isl_val_int_from_si(Ctx, ArrayTy->getNumElements()))); 1043 1044 isl_set *OutOfBound = isl_pw_aff_ge_set(AccessOffset, DimSize); 1045 OutOfBound = isl_set_intersect(getDomain(), OutOfBound); 1046 OutOfBound = isl_set_params(OutOfBound); 1047 isl_set *InBound = isl_set_complement(OutOfBound); 1048 isl_set *Executed = isl_set_params(getDomain()); 1049 1050 // A => B == !A or B 1051 isl_set *InBoundIfExecuted = 1052 isl_set_union(isl_set_complement(Executed), InBound); 1053 1054 Parent.addAssumption(InBoundIfExecuted); 1055 } 1056 1057 Dimension += 1; 1058 Ty = ArrayTy->getElementType(); 1059 } 1060 1061 isl_local_space_free(LSpace); 1062 } 1063 1064 void ScopStmt::deriveAssumptions(BasicBlock *Block) { 1065 for (Instruction &Inst : *Block) 1066 if (auto *GEP = dyn_cast<GetElementPtrInst>(&Inst)) 1067 deriveAssumptionsFromGEP(GEP); 1068 } 1069 1070 ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion, 1071 Region &R, SmallVectorImpl<Loop *> &Nest) 1072 : Parent(parent), BB(nullptr), R(&R), Build(nullptr), 1073 NestLoops(Nest.size()) { 1074 // Setup the induction variables. 1075 for (unsigned i = 0, e = Nest.size(); i < e; ++i) 1076 NestLoops[i] = Nest[i]; 1077 1078 BaseName = getIslCompatibleName("Stmt_", R.getNameStr(), ""); 1079 1080 Domain = buildDomain(tempScop, CurRegion); 1081 1082 BasicBlock *EntryBB = R.getEntry(); 1083 for (BasicBlock *Block : R.blocks()) { 1084 buildAccesses(tempScop, Block, Block != EntryBB); 1085 deriveAssumptions(Block); 1086 } 1087 checkForReductions(); 1088 } 1089 1090 ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion, 1091 BasicBlock &bb, SmallVectorImpl<Loop *> &Nest) 1092 : Parent(parent), BB(&bb), R(nullptr), Build(nullptr), 1093 NestLoops(Nest.size()) { 1094 // Setup the induction variables. 1095 for (unsigned i = 0, e = Nest.size(); i < e; ++i) 1096 NestLoops[i] = Nest[i]; 1097 1098 BaseName = getIslCompatibleName("Stmt_", &bb, ""); 1099 1100 Domain = buildDomain(tempScop, CurRegion); 1101 buildAccesses(tempScop, BB); 1102 deriveAssumptions(BB); 1103 checkForReductions(); 1104 } 1105 1106 /// @brief Collect loads which might form a reduction chain with @p StoreMA 1107 /// 1108 /// Check if the stored value for @p StoreMA is a binary operator with one or 1109 /// two loads as operands. If the binary operand is commutative & associative, 1110 /// used only once (by @p StoreMA) and its load operands are also used only 1111 /// once, we have found a possible reduction chain. It starts at an operand 1112 /// load and includes the binary operator and @p StoreMA. 1113 /// 1114 /// Note: We allow only one use to ensure the load and binary operator cannot 1115 /// escape this block or into any other store except @p StoreMA. 1116 void ScopStmt::collectCandiateReductionLoads( 1117 MemoryAccess *StoreMA, SmallVectorImpl<MemoryAccess *> &Loads) { 1118 auto *Store = dyn_cast<StoreInst>(StoreMA->getAccessInstruction()); 1119 if (!Store) 1120 return; 1121 1122 // Skip if there is not one binary operator between the load and the store 1123 auto *BinOp = dyn_cast<BinaryOperator>(Store->getValueOperand()); 1124 if (!BinOp) 1125 return; 1126 1127 // Skip if the binary operators has multiple uses 1128 if (BinOp->getNumUses() != 1) 1129 return; 1130 1131 // Skip if the opcode of the binary operator is not commutative/associative 1132 if (!BinOp->isCommutative() || !BinOp->isAssociative()) 1133 return; 1134 1135 // Skip if the binary operator is outside the current SCoP 1136 if (BinOp->getParent() != Store->getParent()) 1137 return; 1138 1139 // Skip if it is a multiplicative reduction and we disabled them 1140 if (DisableMultiplicativeReductions && 1141 (BinOp->getOpcode() == Instruction::Mul || 1142 BinOp->getOpcode() == Instruction::FMul)) 1143 return; 1144 1145 // Check the binary operator operands for a candidate load 1146 auto *PossibleLoad0 = dyn_cast<LoadInst>(BinOp->getOperand(0)); 1147 auto *PossibleLoad1 = dyn_cast<LoadInst>(BinOp->getOperand(1)); 1148 if (!PossibleLoad0 && !PossibleLoad1) 1149 return; 1150 1151 // A load is only a candidate if it cannot escape (thus has only this use) 1152 if (PossibleLoad0 && PossibleLoad0->getNumUses() == 1) 1153 if (PossibleLoad0->getParent() == Store->getParent()) 1154 Loads.push_back(lookupAccessFor(PossibleLoad0)); 1155 if (PossibleLoad1 && PossibleLoad1->getNumUses() == 1) 1156 if (PossibleLoad1->getParent() == Store->getParent()) 1157 Loads.push_back(lookupAccessFor(PossibleLoad1)); 1158 } 1159 1160 /// @brief Check for reductions in this ScopStmt 1161 /// 1162 /// Iterate over all store memory accesses and check for valid binary reduction 1163 /// like chains. For all candidates we check if they have the same base address 1164 /// and there are no other accesses which overlap with them. The base address 1165 /// check rules out impossible reductions candidates early. The overlap check, 1166 /// together with the "only one user" check in collectCandiateReductionLoads, 1167 /// guarantees that none of the intermediate results will escape during 1168 /// execution of the loop nest. We basically check here that no other memory 1169 /// access can access the same memory as the potential reduction. 1170 void ScopStmt::checkForReductions() { 1171 SmallVector<MemoryAccess *, 2> Loads; 1172 SmallVector<std::pair<MemoryAccess *, MemoryAccess *>, 4> Candidates; 1173 1174 // First collect candidate load-store reduction chains by iterating over all 1175 // stores and collecting possible reduction loads. 1176 for (MemoryAccess *StoreMA : MemAccs) { 1177 if (StoreMA->isRead()) 1178 continue; 1179 1180 Loads.clear(); 1181 collectCandiateReductionLoads(StoreMA, Loads); 1182 for (MemoryAccess *LoadMA : Loads) 1183 Candidates.push_back(std::make_pair(LoadMA, StoreMA)); 1184 } 1185 1186 // Then check each possible candidate pair. 1187 for (const auto &CandidatePair : Candidates) { 1188 bool Valid = true; 1189 isl_map *LoadAccs = CandidatePair.first->getAccessRelation(); 1190 isl_map *StoreAccs = CandidatePair.second->getAccessRelation(); 1191 1192 // Skip those with obviously unequal base addresses. 1193 if (!isl_map_has_equal_space(LoadAccs, StoreAccs)) { 1194 isl_map_free(LoadAccs); 1195 isl_map_free(StoreAccs); 1196 continue; 1197 } 1198 1199 // And check if the remaining for overlap with other memory accesses. 1200 isl_map *AllAccsRel = isl_map_union(LoadAccs, StoreAccs); 1201 AllAccsRel = isl_map_intersect_domain(AllAccsRel, getDomain()); 1202 isl_set *AllAccs = isl_map_range(AllAccsRel); 1203 1204 for (MemoryAccess *MA : MemAccs) { 1205 if (MA == CandidatePair.first || MA == CandidatePair.second) 1206 continue; 1207 1208 isl_map *AccRel = 1209 isl_map_intersect_domain(MA->getAccessRelation(), getDomain()); 1210 isl_set *Accs = isl_map_range(AccRel); 1211 1212 if (isl_set_has_equal_space(AllAccs, Accs) || isl_set_free(Accs)) { 1213 isl_set *OverlapAccs = isl_set_intersect(Accs, isl_set_copy(AllAccs)); 1214 Valid = Valid && isl_set_is_empty(OverlapAccs); 1215 isl_set_free(OverlapAccs); 1216 } 1217 } 1218 1219 isl_set_free(AllAccs); 1220 if (!Valid) 1221 continue; 1222 1223 const LoadInst *Load = 1224 dyn_cast<const LoadInst>(CandidatePair.first->getAccessInstruction()); 1225 MemoryAccess::ReductionType RT = 1226 getReductionType(dyn_cast<BinaryOperator>(Load->user_back()), Load); 1227 1228 // If no overlapping access was found we mark the load and store as 1229 // reduction like. 1230 CandidatePair.first->markAsReductionLike(RT); 1231 CandidatePair.second->markAsReductionLike(RT); 1232 } 1233 } 1234 1235 std::string ScopStmt::getDomainStr() const { return stringFromIslObj(Domain); } 1236 1237 std::string ScopStmt::getScheduleStr() const { 1238 auto *S = getSchedule(); 1239 auto Str = stringFromIslObj(S); 1240 isl_map_free(S); 1241 return Str; 1242 } 1243 1244 unsigned ScopStmt::getNumParams() const { return Parent.getNumParams(); } 1245 1246 unsigned ScopStmt::getNumIterators() const { return NestLoops.size(); } 1247 1248 const char *ScopStmt::getBaseName() const { return BaseName.c_str(); } 1249 1250 const Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const { 1251 return NestLoops[Dimension]; 1252 } 1253 1254 isl_ctx *ScopStmt::getIslCtx() const { return Parent.getIslCtx(); } 1255 1256 __isl_give isl_set *ScopStmt::getDomain() const { return isl_set_copy(Domain); } 1257 1258 __isl_give isl_space *ScopStmt::getDomainSpace() const { 1259 return isl_set_get_space(Domain); 1260 } 1261 1262 __isl_give isl_id *ScopStmt::getDomainId() const { 1263 return isl_set_get_tuple_id(Domain); 1264 } 1265 1266 ScopStmt::~ScopStmt() { 1267 DeleteContainerSeconds(InstructionToAccess); 1268 isl_set_free(Domain); 1269 } 1270 1271 void ScopStmt::print(raw_ostream &OS) const { 1272 OS << "\t" << getBaseName() << "\n"; 1273 OS.indent(12) << "Domain :=\n"; 1274 1275 if (Domain) { 1276 OS.indent(16) << getDomainStr() << ";\n"; 1277 } else 1278 OS.indent(16) << "n/a\n"; 1279 1280 OS.indent(12) << "Schedule :=\n"; 1281 1282 if (Domain) { 1283 OS.indent(16) << getScheduleStr() << ";\n"; 1284 } else 1285 OS.indent(16) << "n/a\n"; 1286 1287 for (MemoryAccess *Access : MemAccs) 1288 Access->print(OS); 1289 } 1290 1291 void ScopStmt::dump() const { print(dbgs()); } 1292 1293 //===----------------------------------------------------------------------===// 1294 /// Scop class implement 1295 1296 void Scop::setContext(__isl_take isl_set *NewContext) { 1297 NewContext = isl_set_align_params(NewContext, isl_set_get_space(Context)); 1298 isl_set_free(Context); 1299 Context = NewContext; 1300 } 1301 1302 void Scop::addParams(std::vector<const SCEV *> NewParameters) { 1303 for (const SCEV *Parameter : NewParameters) { 1304 Parameter = extractConstantFactor(Parameter, *SE).second; 1305 if (ParameterIds.find(Parameter) != ParameterIds.end()) 1306 continue; 1307 1308 int dimension = Parameters.size(); 1309 1310 Parameters.push_back(Parameter); 1311 ParameterIds[Parameter] = dimension; 1312 } 1313 } 1314 1315 __isl_give isl_id *Scop::getIdForParam(const SCEV *Parameter) const { 1316 ParamIdType::const_iterator IdIter = ParameterIds.find(Parameter); 1317 1318 if (IdIter == ParameterIds.end()) 1319 return nullptr; 1320 1321 std::string ParameterName; 1322 1323 if (const SCEVUnknown *ValueParameter = dyn_cast<SCEVUnknown>(Parameter)) { 1324 Value *Val = ValueParameter->getValue(); 1325 ParameterName = Val->getName(); 1326 } 1327 1328 if (ParameterName == "" || ParameterName.substr(0, 2) == "p_") 1329 ParameterName = "p_" + utostr_32(IdIter->second); 1330 1331 return isl_id_alloc(getIslCtx(), ParameterName.c_str(), 1332 const_cast<void *>((const void *)Parameter)); 1333 } 1334 1335 void Scop::buildContext() { 1336 isl_space *Space = isl_space_params_alloc(IslCtx, 0); 1337 Context = isl_set_universe(isl_space_copy(Space)); 1338 AssumedContext = isl_set_universe(Space); 1339 } 1340 1341 void Scop::addParameterBounds() { 1342 for (const auto &ParamID : ParameterIds) { 1343 int dim = ParamID.second; 1344 1345 ConstantRange SRange = SE->getSignedRange(ParamID.first); 1346 1347 Context = addRangeBoundsToSet(Context, SRange, dim, isl_dim_param); 1348 } 1349 } 1350 1351 void Scop::realignParams() { 1352 // Add all parameters into a common model. 1353 isl_space *Space = isl_space_params_alloc(IslCtx, ParameterIds.size()); 1354 1355 for (const auto &ParamID : ParameterIds) { 1356 const SCEV *Parameter = ParamID.first; 1357 isl_id *id = getIdForParam(Parameter); 1358 Space = isl_space_set_dim_id(Space, isl_dim_param, ParamID.second, id); 1359 } 1360 1361 // Align the parameters of all data structures to the model. 1362 Context = isl_set_align_params(Context, Space); 1363 1364 for (ScopStmt &Stmt : *this) 1365 Stmt.realignParams(); 1366 } 1367 1368 void Scop::simplifyAssumedContext() { 1369 // The parameter constraints of the iteration domains give us a set of 1370 // constraints that need to hold for all cases where at least a single 1371 // statement iteration is executed in the whole scop. We now simplify the 1372 // assumed context under the assumption that such constraints hold and at 1373 // least a single statement iteration is executed. For cases where no 1374 // statement instances are executed, the assumptions we have taken about 1375 // the executed code do not matter and can be changed. 1376 // 1377 // WARNING: This only holds if the assumptions we have taken do not reduce 1378 // the set of statement instances that are executed. Otherwise we 1379 // may run into a case where the iteration domains suggest that 1380 // for a certain set of parameter constraints no code is executed, 1381 // but in the original program some computation would have been 1382 // performed. In such a case, modifying the run-time conditions and 1383 // possibly influencing the run-time check may cause certain scops 1384 // to not be executed. 1385 // 1386 // Example: 1387 // 1388 // When delinearizing the following code: 1389 // 1390 // for (long i = 0; i < 100; i++) 1391 // for (long j = 0; j < m; j++) 1392 // A[i+p][j] = 1.0; 1393 // 1394 // we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as 1395 // otherwise we would access out of bound data. Now, knowing that code is 1396 // only executed for the case m >= 0, it is sufficient to assume p >= 0. 1397 AssumedContext = 1398 isl_set_gist_params(AssumedContext, isl_union_set_params(getDomains())); 1399 AssumedContext = isl_set_gist_params(AssumedContext, getContext()); 1400 } 1401 1402 /// @brief Add the minimal/maximal access in @p Set to @p User. 1403 static isl_stat buildMinMaxAccess(__isl_take isl_set *Set, void *User) { 1404 Scop::MinMaxVectorTy *MinMaxAccesses = (Scop::MinMaxVectorTy *)User; 1405 isl_pw_multi_aff *MinPMA, *MaxPMA; 1406 isl_pw_aff *LastDimAff; 1407 isl_aff *OneAff; 1408 unsigned Pos; 1409 1410 // Restrict the number of parameters involved in the access as the lexmin/ 1411 // lexmax computation will take too long if this number is high. 1412 // 1413 // Experiments with a simple test case using an i7 4800MQ: 1414 // 1415 // #Parameters involved | Time (in sec) 1416 // 6 | 0.01 1417 // 7 | 0.04 1418 // 8 | 0.12 1419 // 9 | 0.40 1420 // 10 | 1.54 1421 // 11 | 6.78 1422 // 12 | 30.38 1423 // 1424 if (isl_set_n_param(Set) > RunTimeChecksMaxParameters) { 1425 unsigned InvolvedParams = 0; 1426 for (unsigned u = 0, e = isl_set_n_param(Set); u < e; u++) 1427 if (isl_set_involves_dims(Set, isl_dim_param, u, 1)) 1428 InvolvedParams++; 1429 1430 if (InvolvedParams > RunTimeChecksMaxParameters) { 1431 isl_set_free(Set); 1432 return isl_stat_error; 1433 } 1434 } 1435 1436 Set = isl_set_remove_divs(Set); 1437 1438 MinPMA = isl_set_lexmin_pw_multi_aff(isl_set_copy(Set)); 1439 MaxPMA = isl_set_lexmax_pw_multi_aff(isl_set_copy(Set)); 1440 1441 MinPMA = isl_pw_multi_aff_coalesce(MinPMA); 1442 MaxPMA = isl_pw_multi_aff_coalesce(MaxPMA); 1443 1444 // Adjust the last dimension of the maximal access by one as we want to 1445 // enclose the accessed memory region by MinPMA and MaxPMA. The pointer 1446 // we test during code generation might now point after the end of the 1447 // allocated array but we will never dereference it anyway. 1448 assert(isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) && 1449 "Assumed at least one output dimension"); 1450 Pos = isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) - 1; 1451 LastDimAff = isl_pw_multi_aff_get_pw_aff(MaxPMA, Pos); 1452 OneAff = isl_aff_zero_on_domain( 1453 isl_local_space_from_space(isl_pw_aff_get_domain_space(LastDimAff))); 1454 OneAff = isl_aff_add_constant_si(OneAff, 1); 1455 LastDimAff = isl_pw_aff_add(LastDimAff, isl_pw_aff_from_aff(OneAff)); 1456 MaxPMA = isl_pw_multi_aff_set_pw_aff(MaxPMA, Pos, LastDimAff); 1457 1458 MinMaxAccesses->push_back(std::make_pair(MinPMA, MaxPMA)); 1459 1460 isl_set_free(Set); 1461 return isl_stat_ok; 1462 } 1463 1464 static __isl_give isl_set *getAccessDomain(MemoryAccess *MA) { 1465 isl_set *Domain = MA->getStatement()->getDomain(); 1466 Domain = isl_set_project_out(Domain, isl_dim_set, 0, isl_set_n_dim(Domain)); 1467 return isl_set_reset_tuple_id(Domain); 1468 } 1469 1470 /// @brief Wrapper function to calculate minimal/maximal accesses to each array. 1471 static bool calculateMinMaxAccess(__isl_take isl_union_map *Accesses, 1472 __isl_take isl_union_set *Domains, 1473 __isl_take isl_set *AssumedContext, 1474 Scop::MinMaxVectorTy &MinMaxAccesses) { 1475 1476 Accesses = isl_union_map_intersect_domain(Accesses, Domains); 1477 isl_union_set *Locations = isl_union_map_range(Accesses); 1478 Locations = isl_union_set_intersect_params(Locations, AssumedContext); 1479 Locations = isl_union_set_coalesce(Locations); 1480 Locations = isl_union_set_detect_equalities(Locations); 1481 bool Valid = (0 == isl_union_set_foreach_set(Locations, buildMinMaxAccess, 1482 &MinMaxAccesses)); 1483 isl_union_set_free(Locations); 1484 return Valid; 1485 } 1486 1487 bool Scop::buildAliasGroups(AliasAnalysis &AA) { 1488 // To create sound alias checks we perform the following steps: 1489 // o) Use the alias analysis and an alias set tracker to build alias sets 1490 // for all memory accesses inside the SCoP. 1491 // o) For each alias set we then map the aliasing pointers back to the 1492 // memory accesses we know, thus obtain groups of memory accesses which 1493 // might alias. 1494 // o) We divide each group based on the domains of the minimal/maximal 1495 // accesses. That means two minimal/maximal accesses are only in a group 1496 // if their access domains intersect, otherwise they are in different 1497 // ones. 1498 // o) We partition each group into read only and non read only accesses. 1499 // o) For each group with more than one base pointer we then compute minimal 1500 // and maximal accesses to each array of a group in read only and non 1501 // read only partitions separately. 1502 using AliasGroupTy = SmallVector<MemoryAccess *, 4>; 1503 1504 AliasSetTracker AST(AA); 1505 1506 DenseMap<Value *, MemoryAccess *> PtrToAcc; 1507 DenseSet<Value *> HasWriteAccess; 1508 for (ScopStmt &Stmt : *this) { 1509 1510 // Skip statements with an empty domain as they will never be executed. 1511 isl_set *StmtDomain = Stmt.getDomain(); 1512 bool StmtDomainEmpty = isl_set_is_empty(StmtDomain); 1513 isl_set_free(StmtDomain); 1514 if (StmtDomainEmpty) 1515 continue; 1516 1517 for (MemoryAccess *MA : Stmt) { 1518 if (MA->isScalar()) 1519 continue; 1520 if (!MA->isRead()) 1521 HasWriteAccess.insert(MA->getBaseAddr()); 1522 Instruction *Acc = MA->getAccessInstruction(); 1523 PtrToAcc[getPointerOperand(*Acc)] = MA; 1524 AST.add(Acc); 1525 } 1526 } 1527 1528 SmallVector<AliasGroupTy, 4> AliasGroups; 1529 for (AliasSet &AS : AST) { 1530 if (AS.isMustAlias() || AS.isForwardingAliasSet()) 1531 continue; 1532 AliasGroupTy AG; 1533 for (auto PR : AS) 1534 AG.push_back(PtrToAcc[PR.getValue()]); 1535 assert(AG.size() > 1 && 1536 "Alias groups should contain at least two accesses"); 1537 AliasGroups.push_back(std::move(AG)); 1538 } 1539 1540 // Split the alias groups based on their domain. 1541 for (unsigned u = 0; u < AliasGroups.size(); u++) { 1542 AliasGroupTy NewAG; 1543 AliasGroupTy &AG = AliasGroups[u]; 1544 AliasGroupTy::iterator AGI = AG.begin(); 1545 isl_set *AGDomain = getAccessDomain(*AGI); 1546 while (AGI != AG.end()) { 1547 MemoryAccess *MA = *AGI; 1548 isl_set *MADomain = getAccessDomain(MA); 1549 if (isl_set_is_disjoint(AGDomain, MADomain)) { 1550 NewAG.push_back(MA); 1551 AGI = AG.erase(AGI); 1552 isl_set_free(MADomain); 1553 } else { 1554 AGDomain = isl_set_union(AGDomain, MADomain); 1555 AGI++; 1556 } 1557 } 1558 if (NewAG.size() > 1) 1559 AliasGroups.push_back(std::move(NewAG)); 1560 isl_set_free(AGDomain); 1561 } 1562 1563 MapVector<const Value *, SmallPtrSet<MemoryAccess *, 8>> ReadOnlyPairs; 1564 SmallPtrSet<const Value *, 4> NonReadOnlyBaseValues; 1565 for (AliasGroupTy &AG : AliasGroups) { 1566 NonReadOnlyBaseValues.clear(); 1567 ReadOnlyPairs.clear(); 1568 1569 if (AG.size() < 2) { 1570 AG.clear(); 1571 continue; 1572 } 1573 1574 for (auto II = AG.begin(); II != AG.end();) { 1575 Value *BaseAddr = (*II)->getBaseAddr(); 1576 if (HasWriteAccess.count(BaseAddr)) { 1577 NonReadOnlyBaseValues.insert(BaseAddr); 1578 II++; 1579 } else { 1580 ReadOnlyPairs[BaseAddr].insert(*II); 1581 II = AG.erase(II); 1582 } 1583 } 1584 1585 // If we don't have read only pointers check if there are at least two 1586 // non read only pointers, otherwise clear the alias group. 1587 if (ReadOnlyPairs.empty() && NonReadOnlyBaseValues.size() <= 1) { 1588 AG.clear(); 1589 continue; 1590 } 1591 1592 // If we don't have non read only pointers clear the alias group. 1593 if (NonReadOnlyBaseValues.empty()) { 1594 AG.clear(); 1595 continue; 1596 } 1597 1598 // Calculate minimal and maximal accesses for non read only accesses. 1599 MinMaxAliasGroups.emplace_back(); 1600 MinMaxVectorPairTy &pair = MinMaxAliasGroups.back(); 1601 MinMaxVectorTy &MinMaxAccessesNonReadOnly = pair.first; 1602 MinMaxVectorTy &MinMaxAccessesReadOnly = pair.second; 1603 MinMaxAccessesNonReadOnly.reserve(AG.size()); 1604 1605 isl_union_map *Accesses = isl_union_map_empty(getParamSpace()); 1606 1607 // AG contains only non read only accesses. 1608 for (MemoryAccess *MA : AG) 1609 Accesses = isl_union_map_add_map(Accesses, MA->getAccessRelation()); 1610 1611 bool Valid = calculateMinMaxAccess( 1612 Accesses, getDomains(), getAssumedContext(), MinMaxAccessesNonReadOnly); 1613 1614 // Bail out if the number of values we need to compare is too large. 1615 // This is important as the number of comparisions grows quadratically with 1616 // the number of values we need to compare. 1617 if (!Valid || (MinMaxAccessesNonReadOnly.size() + !ReadOnlyPairs.empty() > 1618 RunTimeChecksMaxArraysPerGroup)) 1619 return false; 1620 1621 // Calculate minimal and maximal accesses for read only accesses. 1622 MinMaxAccessesReadOnly.reserve(ReadOnlyPairs.size()); 1623 Accesses = isl_union_map_empty(getParamSpace()); 1624 1625 for (const auto &ReadOnlyPair : ReadOnlyPairs) 1626 for (MemoryAccess *MA : ReadOnlyPair.second) 1627 Accesses = isl_union_map_add_map(Accesses, MA->getAccessRelation()); 1628 1629 Valid = calculateMinMaxAccess(Accesses, getDomains(), getAssumedContext(), 1630 MinMaxAccessesReadOnly); 1631 1632 if (!Valid) 1633 return false; 1634 } 1635 1636 return true; 1637 } 1638 1639 static unsigned getMaxLoopDepthInRegion(const Region &R, LoopInfo &LI, 1640 ScopDetection &SD) { 1641 1642 const ScopDetection::BoxedLoopsSetTy *BoxedLoops = SD.getBoxedLoops(&R); 1643 1644 unsigned MinLD = INT_MAX, MaxLD = 0; 1645 for (BasicBlock *BB : R.blocks()) { 1646 if (Loop *L = LI.getLoopFor(BB)) { 1647 if (!R.contains(L)) 1648 continue; 1649 if (BoxedLoops && BoxedLoops->count(L)) 1650 continue; 1651 unsigned LD = L->getLoopDepth(); 1652 MinLD = std::min(MinLD, LD); 1653 MaxLD = std::max(MaxLD, LD); 1654 } 1655 } 1656 1657 // Handle the case that there is no loop in the SCoP first. 1658 if (MaxLD == 0) 1659 return 1; 1660 1661 assert(MinLD >= 1 && "Minimal loop depth should be at least one"); 1662 assert(MaxLD >= MinLD && 1663 "Maximal loop depth was smaller than mininaml loop depth?"); 1664 return MaxLD - MinLD + 1; 1665 } 1666 1667 Scop::Scop(TempScop &tempScop, LoopInfo &LI, ScalarEvolution &ScalarEvolution, 1668 ScopDetection &SD, isl_ctx *Context) 1669 : SE(&ScalarEvolution), R(tempScop.getMaxRegion()), IsOptimized(false), 1670 MaxLoopDepth(getMaxLoopDepthInRegion(tempScop.getMaxRegion(), LI, SD)) { 1671 IslCtx = Context; 1672 1673 buildContext(); 1674 1675 SmallVector<Loop *, 8> NestLoops; 1676 1677 // Build the iteration domain, access functions and schedule functions 1678 // traversing the region tree. 1679 Schedule = buildScop(tempScop, getRegion(), NestLoops, LI, SD); 1680 if (!Schedule) 1681 Schedule = isl_schedule_empty(getParamSpace()); 1682 1683 realignParams(); 1684 addParameterBounds(); 1685 simplifyAssumedContext(); 1686 1687 assert(NestLoops.empty() && "NestLoops not empty at top level!"); 1688 } 1689 1690 Scop::~Scop() { 1691 isl_set_free(Context); 1692 isl_set_free(AssumedContext); 1693 isl_schedule_free(Schedule); 1694 1695 // Free the alias groups 1696 for (MinMaxVectorPairTy &MinMaxAccessPair : MinMaxAliasGroups) { 1697 for (MinMaxAccessTy &MMA : MinMaxAccessPair.first) { 1698 isl_pw_multi_aff_free(MMA.first); 1699 isl_pw_multi_aff_free(MMA.second); 1700 } 1701 for (MinMaxAccessTy &MMA : MinMaxAccessPair.second) { 1702 isl_pw_multi_aff_free(MMA.first); 1703 isl_pw_multi_aff_free(MMA.second); 1704 } 1705 } 1706 } 1707 1708 const ScopArrayInfo * 1709 Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *AccessType, 1710 const SmallVector<const SCEV *, 4> &Sizes, 1711 bool IsPHI) { 1712 auto &SAI = ScopArrayInfoMap[std::make_pair(BasePtr, IsPHI)]; 1713 if (!SAI) 1714 SAI.reset( 1715 new ScopArrayInfo(BasePtr, AccessType, getIslCtx(), Sizes, IsPHI)); 1716 return SAI.get(); 1717 } 1718 1719 const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, bool IsPHI) { 1720 auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, IsPHI)].get(); 1721 assert(SAI && "No ScopArrayInfo available for this base pointer"); 1722 return SAI; 1723 } 1724 1725 std::string Scop::getContextStr() const { return stringFromIslObj(Context); } 1726 std::string Scop::getAssumedContextStr() const { 1727 return stringFromIslObj(AssumedContext); 1728 } 1729 1730 std::string Scop::getNameStr() const { 1731 std::string ExitName, EntryName; 1732 raw_string_ostream ExitStr(ExitName); 1733 raw_string_ostream EntryStr(EntryName); 1734 1735 R.getEntry()->printAsOperand(EntryStr, false); 1736 EntryStr.str(); 1737 1738 if (R.getExit()) { 1739 R.getExit()->printAsOperand(ExitStr, false); 1740 ExitStr.str(); 1741 } else 1742 ExitName = "FunctionExit"; 1743 1744 return EntryName + "---" + ExitName; 1745 } 1746 1747 __isl_give isl_set *Scop::getContext() const { return isl_set_copy(Context); } 1748 __isl_give isl_space *Scop::getParamSpace() const { 1749 return isl_set_get_space(Context); 1750 } 1751 1752 __isl_give isl_set *Scop::getAssumedContext() const { 1753 return isl_set_copy(AssumedContext); 1754 } 1755 1756 void Scop::addAssumption(__isl_take isl_set *Set) { 1757 AssumedContext = isl_set_intersect(AssumedContext, Set); 1758 AssumedContext = isl_set_coalesce(AssumedContext); 1759 } 1760 1761 void Scop::printContext(raw_ostream &OS) const { 1762 OS << "Context:\n"; 1763 1764 if (!Context) { 1765 OS.indent(4) << "n/a\n\n"; 1766 return; 1767 } 1768 1769 OS.indent(4) << getContextStr() << "\n"; 1770 1771 OS.indent(4) << "Assumed Context:\n"; 1772 if (!AssumedContext) { 1773 OS.indent(4) << "n/a\n\n"; 1774 return; 1775 } 1776 1777 OS.indent(4) << getAssumedContextStr() << "\n"; 1778 1779 for (const SCEV *Parameter : Parameters) { 1780 int Dim = ParameterIds.find(Parameter)->second; 1781 OS.indent(4) << "p" << Dim << ": " << *Parameter << "\n"; 1782 } 1783 } 1784 1785 void Scop::printAliasAssumptions(raw_ostream &OS) const { 1786 int noOfGroups = 0; 1787 for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) { 1788 if (Pair.second.size() == 0) 1789 noOfGroups += 1; 1790 else 1791 noOfGroups += Pair.second.size(); 1792 } 1793 1794 OS.indent(4) << "Alias Groups (" << noOfGroups << "):\n"; 1795 if (MinMaxAliasGroups.empty()) { 1796 OS.indent(8) << "n/a\n"; 1797 return; 1798 } 1799 1800 for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) { 1801 1802 // If the group has no read only accesses print the write accesses. 1803 if (Pair.second.empty()) { 1804 OS.indent(8) << "[["; 1805 for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) { 1806 OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second 1807 << ">"; 1808 } 1809 OS << " ]]\n"; 1810 } 1811 1812 for (const MinMaxAccessTy &MMAReadOnly : Pair.second) { 1813 OS.indent(8) << "[["; 1814 OS << " <" << MMAReadOnly.first << ", " << MMAReadOnly.second << ">"; 1815 for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) { 1816 OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second 1817 << ">"; 1818 } 1819 OS << " ]]\n"; 1820 } 1821 } 1822 } 1823 1824 void Scop::printStatements(raw_ostream &OS) const { 1825 OS << "Statements {\n"; 1826 1827 for (const ScopStmt &Stmt : *this) 1828 OS.indent(4) << Stmt; 1829 1830 OS.indent(4) << "}\n"; 1831 } 1832 1833 void Scop::printArrayInfo(raw_ostream &OS) const { 1834 OS << "Arrays {\n"; 1835 1836 for (auto &Array : arrays()) 1837 Array.second->print(OS); 1838 1839 OS.indent(4) << "}\n"; 1840 } 1841 1842 void Scop::print(raw_ostream &OS) const { 1843 OS.indent(4) << "Function: " << getRegion().getEntry()->getParent()->getName() 1844 << "\n"; 1845 OS.indent(4) << "Region: " << getNameStr() << "\n"; 1846 OS.indent(4) << "Max Loop Depth: " << getMaxLoopDepth() << "\n"; 1847 printContext(OS.indent(4)); 1848 printArrayInfo(OS.indent(4)); 1849 printAliasAssumptions(OS); 1850 printStatements(OS.indent(4)); 1851 } 1852 1853 void Scop::dump() const { print(dbgs()); } 1854 1855 isl_ctx *Scop::getIslCtx() const { return IslCtx; } 1856 1857 __isl_give isl_union_set *Scop::getDomains() const { 1858 isl_union_set *Domain = isl_union_set_empty(getParamSpace()); 1859 1860 for (const ScopStmt &Stmt : *this) 1861 Domain = isl_union_set_add_set(Domain, Stmt.getDomain()); 1862 1863 return Domain; 1864 } 1865 1866 __isl_give isl_union_map *Scop::getMustWrites() { 1867 isl_union_map *Write = isl_union_map_empty(getParamSpace()); 1868 1869 for (ScopStmt &Stmt : *this) { 1870 for (MemoryAccess *MA : Stmt) { 1871 if (!MA->isMustWrite()) 1872 continue; 1873 1874 isl_set *Domain = Stmt.getDomain(); 1875 isl_map *AccessDomain = MA->getAccessRelation(); 1876 AccessDomain = isl_map_intersect_domain(AccessDomain, Domain); 1877 Write = isl_union_map_add_map(Write, AccessDomain); 1878 } 1879 } 1880 return isl_union_map_coalesce(Write); 1881 } 1882 1883 __isl_give isl_union_map *Scop::getMayWrites() { 1884 isl_union_map *Write = isl_union_map_empty(getParamSpace()); 1885 1886 for (ScopStmt &Stmt : *this) { 1887 for (MemoryAccess *MA : Stmt) { 1888 if (!MA->isMayWrite()) 1889 continue; 1890 1891 isl_set *Domain = Stmt.getDomain(); 1892 isl_map *AccessDomain = MA->getAccessRelation(); 1893 AccessDomain = isl_map_intersect_domain(AccessDomain, Domain); 1894 Write = isl_union_map_add_map(Write, AccessDomain); 1895 } 1896 } 1897 return isl_union_map_coalesce(Write); 1898 } 1899 1900 __isl_give isl_union_map *Scop::getWrites() { 1901 isl_union_map *Write = isl_union_map_empty(getParamSpace()); 1902 1903 for (ScopStmt &Stmt : *this) { 1904 for (MemoryAccess *MA : Stmt) { 1905 if (!MA->isWrite()) 1906 continue; 1907 1908 isl_set *Domain = Stmt.getDomain(); 1909 isl_map *AccessDomain = MA->getAccessRelation(); 1910 AccessDomain = isl_map_intersect_domain(AccessDomain, Domain); 1911 Write = isl_union_map_add_map(Write, AccessDomain); 1912 } 1913 } 1914 return isl_union_map_coalesce(Write); 1915 } 1916 1917 __isl_give isl_union_map *Scop::getReads() { 1918 isl_union_map *Read = isl_union_map_empty(getParamSpace()); 1919 1920 for (ScopStmt &Stmt : *this) { 1921 for (MemoryAccess *MA : Stmt) { 1922 if (!MA->isRead()) 1923 continue; 1924 1925 isl_set *Domain = Stmt.getDomain(); 1926 isl_map *AccessDomain = MA->getAccessRelation(); 1927 1928 AccessDomain = isl_map_intersect_domain(AccessDomain, Domain); 1929 Read = isl_union_map_add_map(Read, AccessDomain); 1930 } 1931 } 1932 return isl_union_map_coalesce(Read); 1933 } 1934 1935 __isl_give isl_union_map *Scop::getSchedule() const { 1936 auto Tree = getScheduleTree(); 1937 auto S = isl_schedule_get_map(Tree); 1938 isl_schedule_free(Tree); 1939 return S; 1940 } 1941 1942 __isl_give isl_schedule *Scop::getScheduleTree() const { 1943 return isl_schedule_intersect_domain(isl_schedule_copy(Schedule), 1944 getDomains()); 1945 } 1946 1947 void Scop::setSchedule(__isl_take isl_union_map *NewSchedule) { 1948 auto *S = isl_schedule_from_domain(getDomains()); 1949 S = isl_schedule_insert_partial_schedule( 1950 S, isl_multi_union_pw_aff_from_union_map(NewSchedule)); 1951 isl_schedule_free(Schedule); 1952 Schedule = S; 1953 } 1954 1955 void Scop::setScheduleTree(__isl_take isl_schedule *NewSchedule) { 1956 isl_schedule_free(Schedule); 1957 Schedule = NewSchedule; 1958 } 1959 1960 bool Scop::restrictDomains(__isl_take isl_union_set *Domain) { 1961 bool Changed = false; 1962 for (ScopStmt &Stmt : *this) { 1963 isl_union_set *StmtDomain = isl_union_set_from_set(Stmt.getDomain()); 1964 isl_union_set *NewStmtDomain = isl_union_set_intersect( 1965 isl_union_set_copy(StmtDomain), isl_union_set_copy(Domain)); 1966 1967 if (isl_union_set_is_subset(StmtDomain, NewStmtDomain)) { 1968 isl_union_set_free(StmtDomain); 1969 isl_union_set_free(NewStmtDomain); 1970 continue; 1971 } 1972 1973 Changed = true; 1974 1975 isl_union_set_free(StmtDomain); 1976 NewStmtDomain = isl_union_set_coalesce(NewStmtDomain); 1977 1978 if (isl_union_set_is_empty(NewStmtDomain)) { 1979 Stmt.restrictDomain(isl_set_empty(Stmt.getDomainSpace())); 1980 isl_union_set_free(NewStmtDomain); 1981 } else 1982 Stmt.restrictDomain(isl_set_from_union_set(NewStmtDomain)); 1983 } 1984 isl_union_set_free(Domain); 1985 return Changed; 1986 } 1987 1988 ScalarEvolution *Scop::getSE() const { return SE; } 1989 1990 bool Scop::isTrivialBB(BasicBlock *BB, TempScop &tempScop) { 1991 if (tempScop.getAccessFunctions(BB)) 1992 return false; 1993 1994 return true; 1995 } 1996 1997 struct MapToDimensionDataTy { 1998 int N; 1999 isl_union_pw_multi_aff *Res; 2000 }; 2001 2002 // @brief Create a function that maps the elements of 'Set' to its N-th 2003 // dimension. 2004 // 2005 // The result is added to 'User->Res'. 2006 // 2007 // @param Set The input set. 2008 // @param N The dimension to map to. 2009 // 2010 // @returns Zero if no error occurred, non-zero otherwise. 2011 static isl_stat mapToDimension_AddSet(__isl_take isl_set *Set, void *User) { 2012 struct MapToDimensionDataTy *Data = (struct MapToDimensionDataTy *)User; 2013 int Dim; 2014 isl_space *Space; 2015 isl_pw_multi_aff *PMA; 2016 2017 Dim = isl_set_dim(Set, isl_dim_set); 2018 Space = isl_set_get_space(Set); 2019 PMA = isl_pw_multi_aff_project_out_map(Space, isl_dim_set, Data->N, 2020 Dim - Data->N); 2021 if (Data->N > 1) 2022 PMA = isl_pw_multi_aff_drop_dims(PMA, isl_dim_out, 0, Data->N - 1); 2023 Data->Res = isl_union_pw_multi_aff_add_pw_multi_aff(Data->Res, PMA); 2024 2025 isl_set_free(Set); 2026 2027 return isl_stat_ok; 2028 } 2029 2030 // @brief Create a function that maps the elements of Domain to their Nth 2031 // dimension. 2032 // 2033 // @param Domain The set of elements to map. 2034 // @param N The dimension to map to. 2035 static __isl_give isl_multi_union_pw_aff * 2036 mapToDimension(__isl_take isl_union_set *Domain, int N) { 2037 struct MapToDimensionDataTy Data; 2038 isl_space *Space; 2039 2040 Space = isl_union_set_get_space(Domain); 2041 Data.N = N; 2042 Data.Res = isl_union_pw_multi_aff_empty(Space); 2043 if (isl_union_set_foreach_set(Domain, &mapToDimension_AddSet, &Data) < 0) 2044 Data.Res = isl_union_pw_multi_aff_free(Data.Res); 2045 2046 isl_union_set_free(Domain); 2047 return isl_multi_union_pw_aff_from_union_pw_multi_aff(Data.Res); 2048 } 2049 2050 ScopStmt *Scop::addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop, 2051 const Region &CurRegion, 2052 SmallVectorImpl<Loop *> &NestLoops) { 2053 ScopStmt *Stmt; 2054 if (BB) { 2055 Stmts.emplace_back(*this, tempScop, CurRegion, *BB, NestLoops); 2056 Stmt = &Stmts.back(); 2057 StmtMap[BB] = Stmt; 2058 } else { 2059 assert(R && "Either basic block or a region expected."); 2060 Stmts.emplace_back(*this, tempScop, CurRegion, *R, NestLoops); 2061 Stmt = &Stmts.back(); 2062 for (BasicBlock *BB : R->blocks()) 2063 StmtMap[BB] = Stmt; 2064 } 2065 return Stmt; 2066 } 2067 2068 __isl_give isl_schedule *Scop::buildScop(TempScop &tempScop, 2069 const Region &CurRegion, 2070 SmallVectorImpl<Loop *> &NestLoops, 2071 LoopInfo &LI, ScopDetection &SD) { 2072 if (SD.isNonAffineSubRegion(&CurRegion, &getRegion())) { 2073 auto *Stmt = addScopStmt(nullptr, const_cast<Region *>(&CurRegion), 2074 tempScop, CurRegion, NestLoops); 2075 auto *Domain = Stmt->getDomain(); 2076 return isl_schedule_from_domain(isl_union_set_from_set(Domain)); 2077 } 2078 2079 Loop *L = castToLoop(CurRegion, LI); 2080 2081 if (L) 2082 NestLoops.push_back(L); 2083 2084 unsigned loopDepth = NestLoops.size(); 2085 isl_schedule *Schedule = nullptr; 2086 2087 for (Region::const_element_iterator I = CurRegion.element_begin(), 2088 E = CurRegion.element_end(); 2089 I != E; ++I) { 2090 isl_schedule *StmtSchedule = nullptr; 2091 if (I->isSubRegion()) { 2092 StmtSchedule = 2093 buildScop(tempScop, *I->getNodeAs<Region>(), NestLoops, LI, SD); 2094 } else { 2095 BasicBlock *BB = I->getNodeAs<BasicBlock>(); 2096 2097 if (isTrivialBB(BB, tempScop)) { 2098 continue; 2099 } else { 2100 auto *Stmt = addScopStmt(BB, nullptr, tempScop, CurRegion, NestLoops); 2101 auto *Domain = Stmt->getDomain(); 2102 StmtSchedule = isl_schedule_from_domain(isl_union_set_from_set(Domain)); 2103 } 2104 } 2105 2106 if (!Schedule) 2107 Schedule = StmtSchedule; 2108 else if (StmtSchedule) 2109 Schedule = isl_schedule_sequence(Schedule, StmtSchedule); 2110 } 2111 2112 if (!L) 2113 return Schedule; 2114 2115 auto *Domain = isl_schedule_get_domain(Schedule); 2116 if (!isl_union_set_is_empty(Domain)) { 2117 auto *MUPA = mapToDimension(isl_union_set_copy(Domain), loopDepth); 2118 Schedule = isl_schedule_insert_partial_schedule(Schedule, MUPA); 2119 } 2120 isl_union_set_free(Domain); 2121 2122 NestLoops.pop_back(); 2123 return Schedule; 2124 } 2125 2126 ScopStmt *Scop::getStmtForBasicBlock(BasicBlock *BB) const { 2127 auto StmtMapIt = StmtMap.find(BB); 2128 if (StmtMapIt == StmtMap.end()) 2129 return nullptr; 2130 return StmtMapIt->second; 2131 } 2132 2133 //===----------------------------------------------------------------------===// 2134 ScopInfo::ScopInfo() : RegionPass(ID), scop(0) { 2135 ctx = isl_ctx_alloc(); 2136 isl_options_set_on_error(ctx, ISL_ON_ERROR_ABORT); 2137 } 2138 2139 ScopInfo::~ScopInfo() { 2140 clear(); 2141 isl_ctx_free(ctx); 2142 } 2143 2144 void ScopInfo::getAnalysisUsage(AnalysisUsage &AU) const { 2145 AU.addRequired<LoopInfoWrapperPass>(); 2146 AU.addRequired<RegionInfoPass>(); 2147 AU.addRequired<ScalarEvolution>(); 2148 AU.addRequired<ScopDetection>(); 2149 AU.addRequired<TempScopInfo>(); 2150 AU.addRequired<AliasAnalysis>(); 2151 AU.setPreservesAll(); 2152 } 2153 2154 bool ScopInfo::runOnRegion(Region *R, RGPassManager &RGM) { 2155 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 2156 AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); 2157 ScopDetection &SD = getAnalysis<ScopDetection>(); 2158 ScalarEvolution &SE = getAnalysis<ScalarEvolution>(); 2159 2160 TempScop *tempScop = getAnalysis<TempScopInfo>().getTempScop(R); 2161 2162 // This region is no Scop. 2163 if (!tempScop) { 2164 scop = nullptr; 2165 return false; 2166 } 2167 2168 scop = new Scop(*tempScop, LI, SE, SD, ctx); 2169 2170 DEBUG(scop->print(dbgs())); 2171 2172 if (!PollyUseRuntimeAliasChecks) { 2173 // Statistics. 2174 ++ScopFound; 2175 if (scop->getMaxLoopDepth() > 0) 2176 ++RichScopFound; 2177 return false; 2178 } 2179 2180 // If a problem occurs while building the alias groups we need to delete 2181 // this SCoP and pretend it wasn't valid in the first place. 2182 if (scop->buildAliasGroups(AA)) { 2183 // Statistics. 2184 ++ScopFound; 2185 if (scop->getMaxLoopDepth() > 0) 2186 ++RichScopFound; 2187 return false; 2188 } 2189 2190 DEBUG(dbgs() 2191 << "\n\nNOTE: Run time checks for " << scop->getNameStr() 2192 << " could not be created as the number of parameters involved is too " 2193 "high. The SCoP will be " 2194 "dismissed.\nUse:\n\t--polly-rtc-max-parameters=X\nto adjust the " 2195 "maximal number of parameters but be advised that the compile time " 2196 "might increase exponentially.\n\n"); 2197 2198 delete scop; 2199 scop = nullptr; 2200 return false; 2201 } 2202 2203 char ScopInfo::ID = 0; 2204 2205 Pass *polly::createScopInfoPass() { return new ScopInfo(); } 2206 2207 INITIALIZE_PASS_BEGIN(ScopInfo, "polly-scops", 2208 "Polly - Create polyhedral description of Scops", false, 2209 false); 2210 INITIALIZE_AG_DEPENDENCY(AliasAnalysis); 2211 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass); 2212 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass); 2213 INITIALIZE_PASS_DEPENDENCY(ScalarEvolution); 2214 INITIALIZE_PASS_DEPENDENCY(ScopDetection); 2215 INITIALIZE_PASS_DEPENDENCY(TempScopInfo); 2216 INITIALIZE_PASS_END(ScopInfo, "polly-scops", 2217 "Polly - Create polyhedral description of Scops", false, 2218 false) 2219