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 represantation is shared among several tools in the polyhedral 16 // community, which are e.g. Cloog, Pluto, Loopo, Graphite. 17 // 18 //===----------------------------------------------------------------------===// 19 20 #include "polly/CodeGen/BlockGenerators.h" 21 #include "polly/LinkAllPasses.h" 22 #include "polly/ScopInfo.h" 23 #include "polly/Options.h" 24 #include "polly/Support/GICHelper.h" 25 #include "polly/Support/SCEVValidator.h" 26 #include "polly/Support/ScopHelper.h" 27 #include "polly/TempScopInfo.h" 28 #include "llvm/ADT/SetVector.h" 29 #include "llvm/ADT/Statistic.h" 30 #include "llvm/ADT/StringExtras.h" 31 #include "llvm/Analysis/LoopInfo.h" 32 #include "llvm/Analysis/AliasAnalysis.h" 33 #include "llvm/Analysis/RegionIterator.h" 34 #include "llvm/Analysis/ScalarEvolutionExpressions.h" 35 #include "llvm/Support/Debug.h" 36 37 #include "isl/constraint.h" 38 #include "isl/set.h" 39 #include "isl/map.h" 40 #include "isl/union_map.h" 41 #include "isl/aff.h" 42 #include "isl/printer.h" 43 #include "isl/local_space.h" 44 #include "isl/options.h" 45 #include "isl/val.h" 46 47 #include <sstream> 48 #include <string> 49 #include <vector> 50 51 using namespace llvm; 52 using namespace polly; 53 54 #define DEBUG_TYPE "polly-scops" 55 56 STATISTIC(ScopFound, "Number of valid Scops"); 57 STATISTIC(RichScopFound, "Number of Scops containing a loop"); 58 59 // Multiplicative reductions can be disabled separately as these kind of 60 // operations can overflow easily. Additive reductions and bit operations 61 // are in contrast pretty stable. 62 static cl::opt<bool> DisableMultiplicativeReductions( 63 "polly-disable-multiplicative-reductions", 64 cl::desc("Disable multiplicative reductions"), cl::Hidden, cl::ZeroOrMore, 65 cl::init(false), cl::cat(PollyCategory)); 66 67 static cl::opt<unsigned> RunTimeChecksMaxParameters( 68 "polly-rtc-max-parameters", 69 cl::desc("The maximal number of parameters allowed in RTCs."), cl::Hidden, 70 cl::ZeroOrMore, cl::init(8), cl::cat(PollyCategory)); 71 72 /// Translate a 'const SCEV *' expression in an isl_pw_aff. 73 struct SCEVAffinator : public SCEVVisitor<SCEVAffinator, isl_pw_aff *> { 74 public: 75 /// @brief Translate a 'const SCEV *' to an isl_pw_aff. 76 /// 77 /// @param Stmt The location at which the scalar evolution expression 78 /// is evaluated. 79 /// @param Expr The expression that is translated. 80 static __isl_give isl_pw_aff *getPwAff(ScopStmt *Stmt, const SCEV *Expr); 81 82 private: 83 isl_ctx *Ctx; 84 int NbLoopSpaces; 85 const Scop *S; 86 87 SCEVAffinator(const ScopStmt *Stmt); 88 int getLoopDepth(const Loop *L); 89 90 __isl_give isl_pw_aff *visit(const SCEV *Expr); 91 __isl_give isl_pw_aff *visitConstant(const SCEVConstant *Expr); 92 __isl_give isl_pw_aff *visitTruncateExpr(const SCEVTruncateExpr *Expr); 93 __isl_give isl_pw_aff *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr); 94 __isl_give isl_pw_aff *visitSignExtendExpr(const SCEVSignExtendExpr *Expr); 95 __isl_give isl_pw_aff *visitAddExpr(const SCEVAddExpr *Expr); 96 __isl_give isl_pw_aff *visitMulExpr(const SCEVMulExpr *Expr); 97 __isl_give isl_pw_aff *visitUDivExpr(const SCEVUDivExpr *Expr); 98 __isl_give isl_pw_aff *visitAddRecExpr(const SCEVAddRecExpr *Expr); 99 __isl_give isl_pw_aff *visitSMaxExpr(const SCEVSMaxExpr *Expr); 100 __isl_give isl_pw_aff *visitUMaxExpr(const SCEVUMaxExpr *Expr); 101 __isl_give isl_pw_aff *visitUnknown(const SCEVUnknown *Expr); 102 103 friend struct SCEVVisitor<SCEVAffinator, isl_pw_aff *>; 104 }; 105 106 SCEVAffinator::SCEVAffinator(const ScopStmt *Stmt) 107 : Ctx(Stmt->getIslCtx()), NbLoopSpaces(Stmt->getNumIterators()), 108 S(Stmt->getParent()) {} 109 110 __isl_give isl_pw_aff *SCEVAffinator::getPwAff(ScopStmt *Stmt, 111 const SCEV *Scev) { 112 Scop *S = Stmt->getParent(); 113 const Region *Reg = &S->getRegion(); 114 115 S->addParams(getParamsInAffineExpr(Reg, Scev, *S->getSE())); 116 117 SCEVAffinator Affinator(Stmt); 118 return Affinator.visit(Scev); 119 } 120 121 __isl_give isl_pw_aff *SCEVAffinator::visit(const SCEV *Expr) { 122 // In case the scev is a valid parameter, we do not further analyze this 123 // expression, but create a new parameter in the isl_pw_aff. This allows us 124 // to treat subexpressions that we cannot translate into an piecewise affine 125 // expression, as constant parameters of the piecewise affine expression. 126 if (isl_id *Id = S->getIdForParam(Expr)) { 127 isl_space *Space = isl_space_set_alloc(Ctx, 1, NbLoopSpaces); 128 Space = isl_space_set_dim_id(Space, isl_dim_param, 0, Id); 129 130 isl_set *Domain = isl_set_universe(isl_space_copy(Space)); 131 isl_aff *Affine = isl_aff_zero_on_domain(isl_local_space_from_space(Space)); 132 Affine = isl_aff_add_coefficient_si(Affine, isl_dim_param, 0, 1); 133 134 return isl_pw_aff_alloc(Domain, Affine); 135 } 136 137 return SCEVVisitor<SCEVAffinator, isl_pw_aff *>::visit(Expr); 138 } 139 140 __isl_give isl_pw_aff *SCEVAffinator::visitConstant(const SCEVConstant *Expr) { 141 ConstantInt *Value = Expr->getValue(); 142 isl_val *v; 143 144 // LLVM does not define if an integer value is interpreted as a signed or 145 // unsigned value. Hence, without further information, it is unknown how 146 // this value needs to be converted to GMP. At the moment, we only support 147 // signed operations. So we just interpret it as signed. Later, there are 148 // two options: 149 // 150 // 1. We always interpret any value as signed and convert the values on 151 // demand. 152 // 2. We pass down the signedness of the calculation and use it to interpret 153 // this constant correctly. 154 v = isl_valFromAPInt(Ctx, Value->getValue(), /* isSigned */ true); 155 156 isl_space *Space = isl_space_set_alloc(Ctx, 0, NbLoopSpaces); 157 isl_local_space *ls = isl_local_space_from_space(isl_space_copy(Space)); 158 isl_aff *Affine = isl_aff_zero_on_domain(ls); 159 isl_set *Domain = isl_set_universe(Space); 160 161 Affine = isl_aff_add_constant_val(Affine, v); 162 163 return isl_pw_aff_alloc(Domain, Affine); 164 } 165 166 __isl_give isl_pw_aff * 167 SCEVAffinator::visitTruncateExpr(const SCEVTruncateExpr *Expr) { 168 llvm_unreachable("SCEVTruncateExpr not yet supported"); 169 } 170 171 __isl_give isl_pw_aff * 172 SCEVAffinator::visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) { 173 llvm_unreachable("SCEVZeroExtendExpr not yet supported"); 174 } 175 176 __isl_give isl_pw_aff * 177 SCEVAffinator::visitSignExtendExpr(const SCEVSignExtendExpr *Expr) { 178 // Assuming the value is signed, a sign extension is basically a noop. 179 // TODO: Reconsider this as soon as we support unsigned values. 180 return visit(Expr->getOperand()); 181 } 182 183 __isl_give isl_pw_aff *SCEVAffinator::visitAddExpr(const SCEVAddExpr *Expr) { 184 isl_pw_aff *Sum = visit(Expr->getOperand(0)); 185 186 for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) { 187 isl_pw_aff *NextSummand = visit(Expr->getOperand(i)); 188 Sum = isl_pw_aff_add(Sum, NextSummand); 189 } 190 191 // TODO: Check for NSW and NUW. 192 193 return Sum; 194 } 195 196 __isl_give isl_pw_aff *SCEVAffinator::visitMulExpr(const SCEVMulExpr *Expr) { 197 isl_pw_aff *Product = visit(Expr->getOperand(0)); 198 199 for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) { 200 isl_pw_aff *NextOperand = visit(Expr->getOperand(i)); 201 202 if (!isl_pw_aff_is_cst(Product) && !isl_pw_aff_is_cst(NextOperand)) { 203 isl_pw_aff_free(Product); 204 isl_pw_aff_free(NextOperand); 205 return nullptr; 206 } 207 208 Product = isl_pw_aff_mul(Product, NextOperand); 209 } 210 211 // TODO: Check for NSW and NUW. 212 return Product; 213 } 214 215 __isl_give isl_pw_aff *SCEVAffinator::visitUDivExpr(const SCEVUDivExpr *Expr) { 216 llvm_unreachable("SCEVUDivExpr not yet supported"); 217 } 218 219 __isl_give isl_pw_aff * 220 SCEVAffinator::visitAddRecExpr(const SCEVAddRecExpr *Expr) { 221 assert(Expr->isAffine() && "Only affine AddRecurrences allowed"); 222 223 // Directly generate isl_pw_aff for Expr if 'start' is zero. 224 if (Expr->getStart()->isZero()) { 225 assert(S->getRegion().contains(Expr->getLoop()) && 226 "Scop does not contain the loop referenced in this AddRec"); 227 228 isl_pw_aff *Start = visit(Expr->getStart()); 229 isl_pw_aff *Step = visit(Expr->getOperand(1)); 230 isl_space *Space = isl_space_set_alloc(Ctx, 0, NbLoopSpaces); 231 isl_local_space *LocalSpace = isl_local_space_from_space(Space); 232 233 int loopDimension = getLoopDepth(Expr->getLoop()); 234 235 isl_aff *LAff = isl_aff_set_coefficient_si( 236 isl_aff_zero_on_domain(LocalSpace), isl_dim_in, loopDimension, 1); 237 isl_pw_aff *LPwAff = isl_pw_aff_from_aff(LAff); 238 239 // TODO: Do we need to check for NSW and NUW? 240 return isl_pw_aff_add(Start, isl_pw_aff_mul(Step, LPwAff)); 241 } 242 243 // Translate AddRecExpr from '{start, +, inc}' into 'start + {0, +, inc}' 244 // if 'start' is not zero. 245 ScalarEvolution &SE = *S->getSE(); 246 const SCEV *ZeroStartExpr = SE.getAddRecExpr( 247 SE.getConstant(Expr->getStart()->getType(), 0), 248 Expr->getStepRecurrence(SE), Expr->getLoop(), SCEV::FlagAnyWrap); 249 250 isl_pw_aff *ZeroStartResult = visit(ZeroStartExpr); 251 isl_pw_aff *Start = visit(Expr->getStart()); 252 253 return isl_pw_aff_add(ZeroStartResult, Start); 254 } 255 256 __isl_give isl_pw_aff *SCEVAffinator::visitSMaxExpr(const SCEVSMaxExpr *Expr) { 257 isl_pw_aff *Max = visit(Expr->getOperand(0)); 258 259 for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) { 260 isl_pw_aff *NextOperand = visit(Expr->getOperand(i)); 261 Max = isl_pw_aff_max(Max, NextOperand); 262 } 263 264 return Max; 265 } 266 267 __isl_give isl_pw_aff *SCEVAffinator::visitUMaxExpr(const SCEVUMaxExpr *Expr) { 268 llvm_unreachable("SCEVUMaxExpr not yet supported"); 269 } 270 271 __isl_give isl_pw_aff *SCEVAffinator::visitUnknown(const SCEVUnknown *Expr) { 272 llvm_unreachable("Unknowns are always parameters"); 273 } 274 275 int SCEVAffinator::getLoopDepth(const Loop *L) { 276 Loop *outerLoop = S->getRegion().outermostLoopInRegion(const_cast<Loop *>(L)); 277 assert(outerLoop && "Scop does not contain this loop"); 278 return L->getLoopDepth() - outerLoop->getLoopDepth(); 279 } 280 281 const std::string 282 MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT) { 283 switch (RT) { 284 case MemoryAccess::RT_NONE: 285 llvm_unreachable("Requested a reduction operator string for a memory " 286 "access which isn't a reduction"); 287 case MemoryAccess::RT_ADD: 288 return "+"; 289 case MemoryAccess::RT_MUL: 290 return "*"; 291 case MemoryAccess::RT_BOR: 292 return "|"; 293 case MemoryAccess::RT_BXOR: 294 return "^"; 295 case MemoryAccess::RT_BAND: 296 return "&"; 297 } 298 llvm_unreachable("Unknown reduction type"); 299 return ""; 300 } 301 302 /// @brief Return the reduction type for a given binary operator 303 static MemoryAccess::ReductionType getReductionType(const BinaryOperator *BinOp, 304 const Instruction *Load) { 305 if (!BinOp) 306 return MemoryAccess::RT_NONE; 307 switch (BinOp->getOpcode()) { 308 case Instruction::FAdd: 309 if (!BinOp->hasUnsafeAlgebra()) 310 return MemoryAccess::RT_NONE; 311 // Fall through 312 case Instruction::Add: 313 return MemoryAccess::RT_ADD; 314 case Instruction::Or: 315 return MemoryAccess::RT_BOR; 316 case Instruction::Xor: 317 return MemoryAccess::RT_BXOR; 318 case Instruction::And: 319 return MemoryAccess::RT_BAND; 320 case Instruction::FMul: 321 if (!BinOp->hasUnsafeAlgebra()) 322 return MemoryAccess::RT_NONE; 323 // Fall through 324 case Instruction::Mul: 325 if (DisableMultiplicativeReductions) 326 return MemoryAccess::RT_NONE; 327 return MemoryAccess::RT_MUL; 328 default: 329 return MemoryAccess::RT_NONE; 330 } 331 } 332 //===----------------------------------------------------------------------===// 333 334 MemoryAccess::~MemoryAccess() { 335 isl_map_free(AccessRelation); 336 isl_map_free(newAccessRelation); 337 } 338 339 static MemoryAccess::AccessType getMemoryAccessType(const IRAccess &Access) { 340 switch (Access.getType()) { 341 case IRAccess::READ: 342 return MemoryAccess::READ; 343 case IRAccess::MUST_WRITE: 344 return MemoryAccess::MUST_WRITE; 345 case IRAccess::MAY_WRITE: 346 return MemoryAccess::MAY_WRITE; 347 } 348 llvm_unreachable("Unknown IRAccess type!"); 349 } 350 351 isl_id *MemoryAccess::getArrayId() const { 352 return isl_map_get_tuple_id(AccessRelation, isl_dim_out); 353 } 354 355 isl_map *MemoryAccess::getAccessRelation() const { 356 return isl_map_copy(AccessRelation); 357 } 358 359 std::string MemoryAccess::getAccessRelationStr() const { 360 return stringFromIslObj(AccessRelation); 361 } 362 363 __isl_give isl_space *MemoryAccess::getAccessRelationSpace() const { 364 return isl_map_get_space(AccessRelation); 365 } 366 367 isl_map *MemoryAccess::getNewAccessRelation() const { 368 return isl_map_copy(newAccessRelation); 369 } 370 371 isl_basic_map *MemoryAccess::createBasicAccessMap(ScopStmt *Statement) { 372 isl_space *Space = isl_space_set_alloc(Statement->getIslCtx(), 0, 1); 373 Space = isl_space_align_params(Space, Statement->getDomainSpace()); 374 375 return isl_basic_map_from_domain_and_range( 376 isl_basic_set_universe(Statement->getDomainSpace()), 377 isl_basic_set_universe(Space)); 378 } 379 380 // Formalize no out-of-bound access assumption 381 // 382 // When delinearizing array accesses we optimistically assume that the 383 // delinearized accesses do not access out of bound locations (the subscript 384 // expression of each array evaluates for each statement instance that is 385 // executed to a value that is larger than zero and strictly smaller than the 386 // size of the corresponding dimension). The only exception is the outermost 387 // dimension for which we do not need to assume any upper bound. At this point 388 // we formalize this assumption to ensure that at code generation time the 389 // relevant run-time checks can be generated. 390 // 391 // To find the set of constraints necessary to avoid out of bound accesses, we 392 // first build the set of data locations that are not within array bounds. We 393 // then apply the reverse access relation to obtain the set of iterations that 394 // may contain invalid accesses and reduce this set of iterations to the ones 395 // that are actually executed by intersecting them with the domain of the 396 // statement. If we now project out all loop dimensions, we obtain a set of 397 // parameters that may cause statement instances to be executed that may 398 // possibly yield out of bound memory accesses. The complement of these 399 // constraints is the set of constraints that needs to be assumed to ensure such 400 // statement instances are never executed. 401 void MemoryAccess::assumeNoOutOfBound(const IRAccess &Access) { 402 isl_space *Space = isl_space_range(getAccessRelationSpace()); 403 isl_set *Outside = isl_set_empty(isl_space_copy(Space)); 404 for (int i = 1, Size = Access.Subscripts.size(); i < Size; ++i) { 405 isl_local_space *LS = isl_local_space_from_space(isl_space_copy(Space)); 406 isl_pw_aff *Var = 407 isl_pw_aff_var_on_domain(isl_local_space_copy(LS), isl_dim_set, i); 408 isl_pw_aff *Zero = isl_pw_aff_zero_on_domain(LS); 409 410 isl_set *DimOutside; 411 412 DimOutside = isl_pw_aff_lt_set(isl_pw_aff_copy(Var), Zero); 413 isl_pw_aff *SizeE = SCEVAffinator::getPwAff(Statement, Access.Sizes[i - 1]); 414 415 SizeE = isl_pw_aff_drop_dims(SizeE, isl_dim_in, 0, 416 Statement->getNumIterators()); 417 SizeE = isl_pw_aff_add_dims(SizeE, isl_dim_in, 418 isl_space_dim(Space, isl_dim_set)); 419 SizeE = isl_pw_aff_set_tuple_id(SizeE, isl_dim_in, 420 isl_space_get_tuple_id(Space, isl_dim_set)); 421 422 DimOutside = isl_set_union(DimOutside, isl_pw_aff_le_set(SizeE, Var)); 423 424 Outside = isl_set_union(Outside, DimOutside); 425 } 426 427 Outside = isl_set_apply(Outside, isl_map_reverse(getAccessRelation())); 428 Outside = isl_set_intersect(Outside, Statement->getDomain()); 429 Outside = isl_set_params(Outside); 430 Outside = isl_set_complement(Outside); 431 Statement->getParent()->addAssumption(Outside); 432 isl_space_free(Space); 433 } 434 435 MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst, 436 ScopStmt *Statement) 437 : Type(getMemoryAccessType(Access)), Statement(Statement), Inst(AccInst), 438 newAccessRelation(nullptr) { 439 440 isl_ctx *Ctx = Statement->getIslCtx(); 441 BaseAddr = Access.getBase(); 442 BaseName = getIslCompatibleName("MemRef_", getBaseAddr(), ""); 443 isl_id *BaseAddrId = isl_id_alloc(Ctx, getBaseName().c_str(), nullptr); 444 445 if (!Access.isAffine()) { 446 // We overapproximate non-affine accesses with a possible access to the 447 // whole array. For read accesses it does not make a difference, if an 448 // access must or may happen. However, for write accesses it is important to 449 // differentiate between writes that must happen and writes that may happen. 450 AccessRelation = isl_map_from_basic_map(createBasicAccessMap(Statement)); 451 AccessRelation = 452 isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId); 453 return; 454 } 455 456 isl_space *Space = isl_space_alloc(Ctx, 0, Statement->getNumIterators(), 0); 457 AccessRelation = isl_map_universe(Space); 458 459 for (int i = 0, Size = Access.Subscripts.size(); i < Size; ++i) { 460 isl_pw_aff *Affine = 461 SCEVAffinator::getPwAff(Statement, Access.Subscripts[i]); 462 463 if (Size == 1) { 464 // For the non delinearized arrays, divide the access function of the last 465 // subscript by the size of the elements in the array. 466 // 467 // A stride one array access in C expressed as A[i] is expressed in 468 // LLVM-IR as something like A[i * elementsize]. This hides the fact that 469 // two subsequent values of 'i' index two values that are stored next to 470 // each other in memory. By this division we make this characteristic 471 // obvious again. 472 isl_val *v = isl_val_int_from_si(Ctx, Access.getElemSizeInBytes()); 473 Affine = isl_pw_aff_scale_down_val(Affine, v); 474 } 475 476 isl_map *SubscriptMap = isl_map_from_pw_aff(Affine); 477 478 AccessRelation = isl_map_flat_range_product(AccessRelation, SubscriptMap); 479 } 480 481 Space = Statement->getDomainSpace(); 482 AccessRelation = isl_map_set_tuple_id( 483 AccessRelation, isl_dim_in, isl_space_get_tuple_id(Space, isl_dim_set)); 484 AccessRelation = 485 isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId); 486 487 assumeNoOutOfBound(Access); 488 isl_space_free(Space); 489 } 490 491 void MemoryAccess::realignParams() { 492 isl_space *ParamSpace = Statement->getParent()->getParamSpace(); 493 AccessRelation = isl_map_align_params(AccessRelation, ParamSpace); 494 } 495 496 const std::string MemoryAccess::getReductionOperatorStr() const { 497 return MemoryAccess::getReductionOperatorStr(getReductionType()); 498 } 499 500 raw_ostream &polly::operator<<(raw_ostream &OS, 501 MemoryAccess::ReductionType RT) { 502 if (RT == MemoryAccess::RT_NONE) 503 OS << "NONE"; 504 else 505 OS << MemoryAccess::getReductionOperatorStr(RT); 506 return OS; 507 } 508 509 void MemoryAccess::print(raw_ostream &OS) const { 510 switch (Type) { 511 case READ: 512 OS.indent(12) << "ReadAccess :=\t"; 513 break; 514 case MUST_WRITE: 515 OS.indent(12) << "MustWriteAccess :=\t"; 516 break; 517 case MAY_WRITE: 518 OS.indent(12) << "MayWriteAccess :=\t"; 519 break; 520 } 521 OS << "[Reduction Type: " << getReductionType() << "]\n"; 522 OS.indent(16) << getAccessRelationStr() << ";\n"; 523 } 524 525 void MemoryAccess::dump() const { print(errs()); } 526 527 // Create a map in the size of the provided set domain, that maps from the 528 // one element of the provided set domain to another element of the provided 529 // set domain. 530 // The mapping is limited to all points that are equal in all but the last 531 // dimension and for which the last dimension of the input is strict smaller 532 // than the last dimension of the output. 533 // 534 // getEqualAndLarger(set[i0, i1, ..., iX]): 535 // 536 // set[i0, i1, ..., iX] -> set[o0, o1, ..., oX] 537 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1), iX < oX 538 // 539 static isl_map *getEqualAndLarger(isl_space *setDomain) { 540 isl_space *Space = isl_space_map_from_set(setDomain); 541 isl_map *Map = isl_map_universe(isl_space_copy(Space)); 542 isl_local_space *MapLocalSpace = isl_local_space_from_space(Space); 543 unsigned lastDimension = isl_map_dim(Map, isl_dim_in) - 1; 544 545 // Set all but the last dimension to be equal for the input and output 546 // 547 // input[i0, i1, ..., iX] -> output[o0, o1, ..., oX] 548 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1) 549 for (unsigned i = 0; i < lastDimension; ++i) 550 Map = isl_map_equate(Map, isl_dim_in, i, isl_dim_out, i); 551 552 // Set the last dimension of the input to be strict smaller than the 553 // last dimension of the output. 554 // 555 // input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX 556 // 557 isl_val *v; 558 isl_ctx *Ctx = isl_map_get_ctx(Map); 559 isl_constraint *c = isl_inequality_alloc(isl_local_space_copy(MapLocalSpace)); 560 v = isl_val_int_from_si(Ctx, -1); 561 c = isl_constraint_set_coefficient_val(c, isl_dim_in, lastDimension, v); 562 v = isl_val_int_from_si(Ctx, 1); 563 c = isl_constraint_set_coefficient_val(c, isl_dim_out, lastDimension, v); 564 v = isl_val_int_from_si(Ctx, -1); 565 c = isl_constraint_set_constant_val(c, v); 566 567 Map = isl_map_add_constraint(Map, c); 568 569 isl_local_space_free(MapLocalSpace); 570 return Map; 571 } 572 573 isl_set *MemoryAccess::getStride(__isl_take const isl_map *Schedule) const { 574 isl_map *S = const_cast<isl_map *>(Schedule); 575 isl_map *AccessRelation = getAccessRelation(); 576 isl_space *Space = isl_space_range(isl_map_get_space(S)); 577 isl_map *NextScatt = getEqualAndLarger(Space); 578 579 S = isl_map_reverse(S); 580 NextScatt = isl_map_lexmin(NextScatt); 581 582 NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(S)); 583 NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(AccessRelation)); 584 NextScatt = isl_map_apply_domain(NextScatt, S); 585 NextScatt = isl_map_apply_domain(NextScatt, AccessRelation); 586 587 isl_set *Deltas = isl_map_deltas(NextScatt); 588 return Deltas; 589 } 590 591 bool MemoryAccess::isStrideX(__isl_take const isl_map *Schedule, 592 int StrideWidth) const { 593 isl_set *Stride, *StrideX; 594 bool IsStrideX; 595 596 Stride = getStride(Schedule); 597 StrideX = isl_set_universe(isl_set_get_space(Stride)); 598 StrideX = isl_set_fix_si(StrideX, isl_dim_set, 0, StrideWidth); 599 IsStrideX = isl_set_is_equal(Stride, StrideX); 600 601 isl_set_free(StrideX); 602 isl_set_free(Stride); 603 604 return IsStrideX; 605 } 606 607 bool MemoryAccess::isStrideZero(const isl_map *Schedule) const { 608 return isStrideX(Schedule, 0); 609 } 610 611 bool MemoryAccess::isScalar() const { 612 return isl_map_n_out(AccessRelation) == 0; 613 } 614 615 bool MemoryAccess::isStrideOne(const isl_map *Schedule) const { 616 return isStrideX(Schedule, 1); 617 } 618 619 void MemoryAccess::setNewAccessRelation(isl_map *newAccess) { 620 isl_map_free(newAccessRelation); 621 newAccessRelation = newAccess; 622 } 623 624 //===----------------------------------------------------------------------===// 625 626 isl_map *ScopStmt::getScattering() const { return isl_map_copy(Scattering); } 627 628 void ScopStmt::restrictDomain(__isl_take isl_set *NewDomain) { 629 assert(isl_set_is_subset(NewDomain, Domain) && 630 "New domain is not a subset of old domain!"); 631 isl_set_free(Domain); 632 Domain = NewDomain; 633 Scattering = isl_map_intersect_domain(Scattering, isl_set_copy(Domain)); 634 } 635 636 void ScopStmt::setScattering(isl_map *NewScattering) { 637 assert(NewScattering && "New scattering is nullptr"); 638 isl_map_free(Scattering); 639 Scattering = NewScattering; 640 } 641 642 void ScopStmt::buildScattering(SmallVectorImpl<unsigned> &Scatter) { 643 unsigned NbIterators = getNumIterators(); 644 unsigned NbScatteringDims = Parent.getMaxLoopDepth() * 2 + 1; 645 646 isl_space *Space = isl_space_set_alloc(getIslCtx(), 0, NbScatteringDims); 647 Space = isl_space_set_tuple_name(Space, isl_dim_out, "scattering"); 648 649 Scattering = isl_map_from_domain_and_range(isl_set_universe(getDomainSpace()), 650 isl_set_universe(Space)); 651 652 // Loop dimensions. 653 for (unsigned i = 0; i < NbIterators; ++i) 654 Scattering = 655 isl_map_equate(Scattering, isl_dim_out, 2 * i + 1, isl_dim_in, i); 656 657 // Constant dimensions 658 for (unsigned i = 0; i < NbIterators + 1; ++i) 659 Scattering = isl_map_fix_si(Scattering, isl_dim_out, 2 * i, Scatter[i]); 660 661 // Fill scattering dimensions. 662 for (unsigned i = 2 * NbIterators + 1; i < NbScatteringDims; ++i) 663 Scattering = isl_map_fix_si(Scattering, isl_dim_out, i, 0); 664 665 Scattering = isl_map_align_params(Scattering, Parent.getParamSpace()); 666 } 667 668 void ScopStmt::buildAccesses(TempScop &tempScop, const Region &CurRegion) { 669 for (auto &&Access : *tempScop.getAccessFunctions(BB)) { 670 MemAccs.push_back(new MemoryAccess(Access.first, Access.second, this)); 671 672 // We do not track locations for scalar memory accesses at the moment. 673 // 674 // We do not have a use for this information at the moment. If we need this 675 // at some point, the "instruction -> access" mapping needs to be enhanced 676 // as a single instruction could then possibly perform multiple accesses. 677 if (!Access.first.isScalar()) { 678 assert(!InstructionToAccess.count(Access.second) && 679 "Unexpected 1-to-N mapping on instruction to access map!"); 680 InstructionToAccess[Access.second] = MemAccs.back(); 681 } 682 } 683 } 684 685 void ScopStmt::realignParams() { 686 for (MemoryAccess *MA : *this) 687 MA->realignParams(); 688 689 Domain = isl_set_align_params(Domain, Parent.getParamSpace()); 690 Scattering = isl_map_align_params(Scattering, Parent.getParamSpace()); 691 } 692 693 __isl_give isl_set *ScopStmt::buildConditionSet(const Comparison &Comp) { 694 isl_pw_aff *L = SCEVAffinator::getPwAff(this, Comp.getLHS()); 695 isl_pw_aff *R = SCEVAffinator::getPwAff(this, Comp.getRHS()); 696 697 switch (Comp.getPred()) { 698 case ICmpInst::ICMP_EQ: 699 return isl_pw_aff_eq_set(L, R); 700 case ICmpInst::ICMP_NE: 701 return isl_pw_aff_ne_set(L, R); 702 case ICmpInst::ICMP_SLT: 703 return isl_pw_aff_lt_set(L, R); 704 case ICmpInst::ICMP_SLE: 705 return isl_pw_aff_le_set(L, R); 706 case ICmpInst::ICMP_SGT: 707 return isl_pw_aff_gt_set(L, R); 708 case ICmpInst::ICMP_SGE: 709 return isl_pw_aff_ge_set(L, R); 710 case ICmpInst::ICMP_ULT: 711 case ICmpInst::ICMP_UGT: 712 case ICmpInst::ICMP_ULE: 713 case ICmpInst::ICMP_UGE: 714 llvm_unreachable("Unsigned comparisons not yet supported"); 715 default: 716 llvm_unreachable("Non integer predicate not supported"); 717 } 718 } 719 720 __isl_give isl_set *ScopStmt::addLoopBoundsToDomain(__isl_take isl_set *Domain, 721 TempScop &tempScop) { 722 isl_space *Space; 723 isl_local_space *LocalSpace; 724 725 Space = isl_set_get_space(Domain); 726 LocalSpace = isl_local_space_from_space(Space); 727 728 for (int i = 0, e = getNumIterators(); i != e; ++i) { 729 isl_aff *Zero = isl_aff_zero_on_domain(isl_local_space_copy(LocalSpace)); 730 isl_pw_aff *IV = 731 isl_pw_aff_from_aff(isl_aff_set_coefficient_si(Zero, isl_dim_in, i, 1)); 732 733 // 0 <= IV. 734 isl_set *LowerBound = isl_pw_aff_nonneg_set(isl_pw_aff_copy(IV)); 735 Domain = isl_set_intersect(Domain, LowerBound); 736 737 // IV <= LatchExecutions. 738 const Loop *L = getLoopForDimension(i); 739 const SCEV *LatchExecutions = tempScop.getLoopBound(L); 740 isl_pw_aff *UpperBound = SCEVAffinator::getPwAff(this, LatchExecutions); 741 isl_set *UpperBoundSet = isl_pw_aff_le_set(IV, UpperBound); 742 Domain = isl_set_intersect(Domain, UpperBoundSet); 743 } 744 745 isl_local_space_free(LocalSpace); 746 return Domain; 747 } 748 749 __isl_give isl_set *ScopStmt::addConditionsToDomain(__isl_take isl_set *Domain, 750 TempScop &tempScop, 751 const Region &CurRegion) { 752 const Region *TopRegion = tempScop.getMaxRegion().getParent(), 753 *CurrentRegion = &CurRegion; 754 const BasicBlock *BranchingBB = BB; 755 756 do { 757 if (BranchingBB != CurrentRegion->getEntry()) { 758 if (const BBCond *Condition = tempScop.getBBCond(BranchingBB)) 759 for (const auto &C : *Condition) { 760 isl_set *ConditionSet = buildConditionSet(C); 761 Domain = isl_set_intersect(Domain, ConditionSet); 762 } 763 } 764 BranchingBB = CurrentRegion->getEntry(); 765 CurrentRegion = CurrentRegion->getParent(); 766 } while (TopRegion != CurrentRegion); 767 768 return Domain; 769 } 770 771 __isl_give isl_set *ScopStmt::buildDomain(TempScop &tempScop, 772 const Region &CurRegion) { 773 isl_space *Space; 774 isl_set *Domain; 775 isl_id *Id; 776 777 Space = isl_space_set_alloc(getIslCtx(), 0, getNumIterators()); 778 779 Id = isl_id_alloc(getIslCtx(), getBaseName(), this); 780 781 Domain = isl_set_universe(Space); 782 Domain = addLoopBoundsToDomain(Domain, tempScop); 783 Domain = addConditionsToDomain(Domain, tempScop, CurRegion); 784 Domain = isl_set_set_tuple_id(Domain, Id); 785 786 return Domain; 787 } 788 789 ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion, 790 BasicBlock &bb, SmallVectorImpl<Loop *> &Nest, 791 SmallVectorImpl<unsigned> &Scatter) 792 : Parent(parent), BB(&bb), IVS(Nest.size()), NestLoops(Nest.size()) { 793 // Setup the induction variables. 794 for (unsigned i = 0, e = Nest.size(); i < e; ++i) { 795 if (!SCEVCodegen) { 796 PHINode *PN = Nest[i]->getCanonicalInductionVariable(); 797 assert(PN && "Non canonical IV in Scop!"); 798 IVS[i] = PN; 799 } 800 NestLoops[i] = Nest[i]; 801 } 802 803 BaseName = getIslCompatibleName("Stmt_", &bb, ""); 804 805 Domain = buildDomain(tempScop, CurRegion); 806 buildScattering(Scatter); 807 buildAccesses(tempScop, CurRegion); 808 checkForReductions(); 809 } 810 811 /// @brief Collect loads which might form a reduction chain with @p StoreMA 812 /// 813 /// Check if the stored value for @p StoreMA is a binary operator with one or 814 /// two loads as operands. If the binary operand is commutative & associative, 815 /// used only once (by @p StoreMA) and its load operands are also used only 816 /// once, we have found a possible reduction chain. It starts at an operand 817 /// load and includes the binary operator and @p StoreMA. 818 /// 819 /// Note: We allow only one use to ensure the load and binary operator cannot 820 /// escape this block or into any other store except @p StoreMA. 821 void ScopStmt::collectCandiateReductionLoads( 822 MemoryAccess *StoreMA, SmallVectorImpl<MemoryAccess *> &Loads) { 823 auto *Store = dyn_cast<StoreInst>(StoreMA->getAccessInstruction()); 824 if (!Store) 825 return; 826 827 // Skip if there is not one binary operator between the load and the store 828 auto *BinOp = dyn_cast<BinaryOperator>(Store->getValueOperand()); 829 if (!BinOp) 830 return; 831 832 // Skip if the binary operators has multiple uses 833 if (BinOp->getNumUses() != 1) 834 return; 835 836 // Skip if the opcode of the binary operator is not commutative/associative 837 if (!BinOp->isCommutative() || !BinOp->isAssociative()) 838 return; 839 840 // Skip if the binary operator is outside the current SCoP 841 if (BinOp->getParent() != Store->getParent()) 842 return; 843 844 // Skip if it is a multiplicative reduction and we disabled them 845 if (DisableMultiplicativeReductions && 846 (BinOp->getOpcode() == Instruction::Mul || 847 BinOp->getOpcode() == Instruction::FMul)) 848 return; 849 850 // Check the binary operator operands for a candidate load 851 auto *PossibleLoad0 = dyn_cast<LoadInst>(BinOp->getOperand(0)); 852 auto *PossibleLoad1 = dyn_cast<LoadInst>(BinOp->getOperand(1)); 853 if (!PossibleLoad0 && !PossibleLoad1) 854 return; 855 856 // A load is only a candidate if it cannot escape (thus has only this use) 857 if (PossibleLoad0 && PossibleLoad0->getNumUses() == 1) 858 if (PossibleLoad0->getParent() == Store->getParent()) 859 Loads.push_back(lookupAccessFor(PossibleLoad0)); 860 if (PossibleLoad1 && PossibleLoad1->getNumUses() == 1) 861 if (PossibleLoad1->getParent() == Store->getParent()) 862 Loads.push_back(lookupAccessFor(PossibleLoad1)); 863 } 864 865 /// @brief Check for reductions in this ScopStmt 866 /// 867 /// Iterate over all store memory accesses and check for valid binary reduction 868 /// like chains. For all candidates we check if they have the same base address 869 /// and there are no other accesses which overlap with them. The base address 870 /// check rules out impossible reductions candidates early. The overlap check, 871 /// together with the "only one user" check in collectCandiateReductionLoads, 872 /// guarantees that none of the intermediate results will escape during 873 /// execution of the loop nest. We basically check here that no other memory 874 /// access can access the same memory as the potential reduction. 875 void ScopStmt::checkForReductions() { 876 SmallVector<MemoryAccess *, 2> Loads; 877 SmallVector<std::pair<MemoryAccess *, MemoryAccess *>, 4> Candidates; 878 879 // First collect candidate load-store reduction chains by iterating over all 880 // stores and collecting possible reduction loads. 881 for (MemoryAccess *StoreMA : MemAccs) { 882 if (StoreMA->isRead()) 883 continue; 884 885 Loads.clear(); 886 collectCandiateReductionLoads(StoreMA, Loads); 887 for (MemoryAccess *LoadMA : Loads) 888 Candidates.push_back(std::make_pair(LoadMA, StoreMA)); 889 } 890 891 // Then check each possible candidate pair. 892 for (const auto &CandidatePair : Candidates) { 893 bool Valid = true; 894 isl_map *LoadAccs = CandidatePair.first->getAccessRelation(); 895 isl_map *StoreAccs = CandidatePair.second->getAccessRelation(); 896 897 // Skip those with obviously unequal base addresses. 898 if (!isl_map_has_equal_space(LoadAccs, StoreAccs)) { 899 isl_map_free(LoadAccs); 900 isl_map_free(StoreAccs); 901 continue; 902 } 903 904 // And check if the remaining for overlap with other memory accesses. 905 isl_map *AllAccsRel = isl_map_union(LoadAccs, StoreAccs); 906 AllAccsRel = isl_map_intersect_domain(AllAccsRel, getDomain()); 907 isl_set *AllAccs = isl_map_range(AllAccsRel); 908 909 for (MemoryAccess *MA : MemAccs) { 910 if (MA == CandidatePair.first || MA == CandidatePair.second) 911 continue; 912 913 isl_map *AccRel = 914 isl_map_intersect_domain(MA->getAccessRelation(), getDomain()); 915 isl_set *Accs = isl_map_range(AccRel); 916 917 if (isl_set_has_equal_space(AllAccs, Accs) || isl_set_free(Accs)) { 918 isl_set *OverlapAccs = isl_set_intersect(Accs, isl_set_copy(AllAccs)); 919 Valid = Valid && isl_set_is_empty(OverlapAccs); 920 isl_set_free(OverlapAccs); 921 } 922 } 923 924 isl_set_free(AllAccs); 925 if (!Valid) 926 continue; 927 928 const LoadInst *Load = 929 dyn_cast<const LoadInst>(CandidatePair.first->getAccessInstruction()); 930 MemoryAccess::ReductionType RT = 931 getReductionType(dyn_cast<BinaryOperator>(Load->user_back()), Load); 932 933 // If no overlapping access was found we mark the load and store as 934 // reduction like. 935 CandidatePair.first->markAsReductionLike(RT); 936 CandidatePair.second->markAsReductionLike(RT); 937 } 938 } 939 940 std::string ScopStmt::getDomainStr() const { return stringFromIslObj(Domain); } 941 942 std::string ScopStmt::getScatteringStr() const { 943 return stringFromIslObj(Scattering); 944 } 945 946 unsigned ScopStmt::getNumParams() const { return Parent.getNumParams(); } 947 948 unsigned ScopStmt::getNumIterators() const { 949 // The final read has one dimension with one element. 950 if (!BB) 951 return 1; 952 953 return NestLoops.size(); 954 } 955 956 unsigned ScopStmt::getNumScattering() const { 957 return isl_map_dim(Scattering, isl_dim_out); 958 } 959 960 const char *ScopStmt::getBaseName() const { return BaseName.c_str(); } 961 962 const PHINode * 963 ScopStmt::getInductionVariableForDimension(unsigned Dimension) const { 964 return IVS[Dimension]; 965 } 966 967 const Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const { 968 return NestLoops[Dimension]; 969 } 970 971 isl_ctx *ScopStmt::getIslCtx() const { return Parent.getIslCtx(); } 972 973 isl_set *ScopStmt::getDomain() const { return isl_set_copy(Domain); } 974 975 isl_space *ScopStmt::getDomainSpace() const { 976 return isl_set_get_space(Domain); 977 } 978 979 isl_id *ScopStmt::getDomainId() const { return isl_set_get_tuple_id(Domain); } 980 981 ScopStmt::~ScopStmt() { 982 while (!MemAccs.empty()) { 983 delete MemAccs.back(); 984 MemAccs.pop_back(); 985 } 986 987 isl_set_free(Domain); 988 isl_map_free(Scattering); 989 } 990 991 void ScopStmt::print(raw_ostream &OS) const { 992 OS << "\t" << getBaseName() << "\n"; 993 OS.indent(12) << "Domain :=\n"; 994 995 if (Domain) { 996 OS.indent(16) << getDomainStr() << ";\n"; 997 } else 998 OS.indent(16) << "n/a\n"; 999 1000 OS.indent(12) << "Scattering :=\n"; 1001 1002 if (Domain) { 1003 OS.indent(16) << getScatteringStr() << ";\n"; 1004 } else 1005 OS.indent(16) << "n/a\n"; 1006 1007 for (MemoryAccess *Access : MemAccs) 1008 Access->print(OS); 1009 } 1010 1011 void ScopStmt::dump() const { print(dbgs()); } 1012 1013 //===----------------------------------------------------------------------===// 1014 /// Scop class implement 1015 1016 void Scop::setContext(__isl_take isl_set *NewContext) { 1017 NewContext = isl_set_align_params(NewContext, isl_set_get_space(Context)); 1018 isl_set_free(Context); 1019 Context = NewContext; 1020 } 1021 1022 void Scop::addParams(std::vector<const SCEV *> NewParameters) { 1023 for (const SCEV *Parameter : NewParameters) { 1024 if (ParameterIds.find(Parameter) != ParameterIds.end()) 1025 continue; 1026 1027 int dimension = Parameters.size(); 1028 1029 Parameters.push_back(Parameter); 1030 ParameterIds[Parameter] = dimension; 1031 } 1032 } 1033 1034 __isl_give isl_id *Scop::getIdForParam(const SCEV *Parameter) const { 1035 ParamIdType::const_iterator IdIter = ParameterIds.find(Parameter); 1036 1037 if (IdIter == ParameterIds.end()) 1038 return nullptr; 1039 1040 std::string ParameterName; 1041 1042 if (const SCEVUnknown *ValueParameter = dyn_cast<SCEVUnknown>(Parameter)) { 1043 Value *Val = ValueParameter->getValue(); 1044 ParameterName = Val->getName(); 1045 } 1046 1047 if (ParameterName == "" || ParameterName.substr(0, 2) == "p_") 1048 ParameterName = "p_" + utostr_32(IdIter->second); 1049 1050 return isl_id_alloc(getIslCtx(), ParameterName.c_str(), 1051 const_cast<void *>((const void *)Parameter)); 1052 } 1053 1054 void Scop::buildContext() { 1055 isl_space *Space = isl_space_params_alloc(IslCtx, 0); 1056 Context = isl_set_universe(isl_space_copy(Space)); 1057 AssumedContext = isl_set_universe(Space); 1058 } 1059 1060 void Scop::addParameterBounds() { 1061 for (unsigned i = 0; i < isl_set_dim(Context, isl_dim_param); ++i) { 1062 isl_val *V; 1063 isl_id *Id; 1064 const SCEV *Scev; 1065 const IntegerType *T; 1066 1067 Id = isl_set_get_dim_id(Context, isl_dim_param, i); 1068 Scev = (const SCEV *)isl_id_get_user(Id); 1069 T = dyn_cast<IntegerType>(Scev->getType()); 1070 isl_id_free(Id); 1071 1072 assert(T && "Not an integer type"); 1073 int Width = T->getBitWidth(); 1074 1075 V = isl_val_int_from_si(IslCtx, Width - 1); 1076 V = isl_val_2exp(V); 1077 V = isl_val_neg(V); 1078 Context = isl_set_lower_bound_val(Context, isl_dim_param, i, V); 1079 1080 V = isl_val_int_from_si(IslCtx, Width - 1); 1081 V = isl_val_2exp(V); 1082 V = isl_val_sub_ui(V, 1); 1083 Context = isl_set_upper_bound_val(Context, isl_dim_param, i, V); 1084 } 1085 } 1086 1087 void Scop::realignParams() { 1088 // Add all parameters into a common model. 1089 isl_space *Space = isl_space_params_alloc(IslCtx, ParameterIds.size()); 1090 1091 for (const auto &ParamID : ParameterIds) { 1092 const SCEV *Parameter = ParamID.first; 1093 isl_id *id = getIdForParam(Parameter); 1094 Space = isl_space_set_dim_id(Space, isl_dim_param, ParamID.second, id); 1095 } 1096 1097 // Align the parameters of all data structures to the model. 1098 Context = isl_set_align_params(Context, Space); 1099 1100 for (ScopStmt *Stmt : *this) 1101 Stmt->realignParams(); 1102 } 1103 1104 void Scop::simplifyAssumedContext() { 1105 // The parameter constraints of the iteration domains give us a set of 1106 // constraints that need to hold for all cases where at least a single 1107 // statement iteration is executed in the whole scop. We now simplify the 1108 // assumed context under the assumption that such constraints hold and at 1109 // least a single statement iteration is executed. For cases where no 1110 // statement instances are executed, the assumptions we have taken about 1111 // the executed code do not matter and can be changed. 1112 // 1113 // WARNING: This only holds if the assumptions we have taken do not reduce 1114 // the set of statement instances that are executed. Otherwise we 1115 // may run into a case where the iteration domains suggest that 1116 // for a certain set of parameter constraints no code is executed, 1117 // but in the original program some computation would have been 1118 // performed. In such a case, modifying the run-time conditions and 1119 // possibly influencing the run-time check may cause certain scops 1120 // to not be executed. 1121 // 1122 // Example: 1123 // 1124 // When delinearizing the following code: 1125 // 1126 // for (long i = 0; i < 100; i++) 1127 // for (long j = 0; j < m; j++) 1128 // A[i+p][j] = 1.0; 1129 // 1130 // we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as 1131 // otherwise we would access out of bound data. Now, knowing that code is 1132 // only executed for the case m >= 0, it is sufficient to assume p >= 0. 1133 AssumedContext = 1134 isl_set_gist_params(AssumedContext, isl_union_set_params(getDomains())); 1135 } 1136 1137 /// @brief Add the minimal/maximal access in @p Set to @p User. 1138 static int buildMinMaxAccess(__isl_take isl_set *Set, void *User) { 1139 Scop::MinMaxVectorTy *MinMaxAccesses = (Scop::MinMaxVectorTy *)User; 1140 isl_pw_multi_aff *MinPMA, *MaxPMA; 1141 isl_pw_aff *LastDimAff; 1142 isl_aff *OneAff; 1143 unsigned Pos; 1144 1145 // Restrict the number of parameters involved in the access as the lexmin/ 1146 // lexmax computation will take too long if this number is high. 1147 // 1148 // Experiments with a simple test case using an i7 4800MQ: 1149 // 1150 // #Parameters involved | Time (in sec) 1151 // 6 | 0.01 1152 // 7 | 0.04 1153 // 8 | 0.12 1154 // 9 | 0.40 1155 // 10 | 1.54 1156 // 11 | 6.78 1157 // 12 | 30.38 1158 // 1159 if (isl_set_n_param(Set) > RunTimeChecksMaxParameters) { 1160 unsigned InvolvedParams = 0; 1161 for (unsigned u = 0, e = isl_set_n_param(Set); u < e; u++) 1162 if (isl_set_involves_dims(Set, isl_dim_param, u, 1)) 1163 InvolvedParams++; 1164 1165 if (InvolvedParams > RunTimeChecksMaxParameters) { 1166 isl_set_free(Set); 1167 return -1; 1168 } 1169 } 1170 1171 MinPMA = isl_set_lexmin_pw_multi_aff(isl_set_copy(Set)); 1172 MaxPMA = isl_set_lexmax_pw_multi_aff(isl_set_copy(Set)); 1173 1174 // Adjust the last dimension of the maximal access by one as we want to 1175 // enclose the accessed memory region by MinPMA and MaxPMA. The pointer 1176 // we test during code generation might now point after the end of the 1177 // allocated array but we will never dereference it anyway. 1178 assert(isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) && 1179 "Assumed at least one output dimension"); 1180 Pos = isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) - 1; 1181 LastDimAff = isl_pw_multi_aff_get_pw_aff(MaxPMA, Pos); 1182 OneAff = isl_aff_zero_on_domain( 1183 isl_local_space_from_space(isl_pw_aff_get_domain_space(LastDimAff))); 1184 OneAff = isl_aff_add_constant_si(OneAff, 1); 1185 LastDimAff = isl_pw_aff_add(LastDimAff, isl_pw_aff_from_aff(OneAff)); 1186 MaxPMA = isl_pw_multi_aff_set_pw_aff(MaxPMA, Pos, LastDimAff); 1187 1188 MinMaxAccesses->push_back(std::make_pair(MinPMA, MaxPMA)); 1189 1190 isl_set_free(Set); 1191 return 0; 1192 } 1193 1194 static __isl_give isl_set *getAccessDomain(MemoryAccess *MA) { 1195 isl_set *Domain = MA->getStatement()->getDomain(); 1196 Domain = isl_set_project_out(Domain, isl_dim_set, 0, isl_set_n_dim(Domain)); 1197 return isl_set_reset_tuple_id(Domain); 1198 } 1199 1200 bool Scop::buildAliasGroups(AliasAnalysis &AA) { 1201 // To create sound alias checks we perform the following steps: 1202 // o) Use the alias analysis and an alias set tracker to build alias sets 1203 // for all memory accesses inside the SCoP. 1204 // o) For each alias set we then map the aliasing pointers back to the 1205 // memory accesses we know, thus obtain groups of memory accesses which 1206 // might alias. 1207 // o) We divide each group based on the domains of the minimal/maximal 1208 // accesses. That means two minimal/maximal accesses are only in a group 1209 // if their access domains intersect, otherwise they are in different 1210 // ones. 1211 // o) We split groups such that they contain at most one read only base 1212 // address. 1213 // o) For each group with more than one base pointer we then compute minimal 1214 // and maximal accesses to each array in this group. 1215 using AliasGroupTy = SmallVector<MemoryAccess *, 4>; 1216 1217 AliasSetTracker AST(AA); 1218 1219 DenseMap<Value *, MemoryAccess *> PtrToAcc; 1220 DenseSet<Value *> HasWriteAccess; 1221 for (ScopStmt *Stmt : *this) { 1222 for (MemoryAccess *MA : *Stmt) { 1223 if (MA->isScalar()) 1224 continue; 1225 if (!MA->isRead()) 1226 HasWriteAccess.insert(MA->getBaseAddr()); 1227 Instruction *Acc = MA->getAccessInstruction(); 1228 PtrToAcc[getPointerOperand(*Acc)] = MA; 1229 AST.add(Acc); 1230 } 1231 } 1232 1233 SmallVector<AliasGroupTy, 4> AliasGroups; 1234 for (AliasSet &AS : AST) { 1235 if (AS.isMustAlias()) 1236 continue; 1237 AliasGroupTy AG; 1238 for (auto PR : AS) 1239 AG.push_back(PtrToAcc[PR.getValue()]); 1240 assert(AG.size() > 1 && 1241 "Alias groups should contain at least two accesses"); 1242 AliasGroups.push_back(std::move(AG)); 1243 } 1244 1245 // Split the alias groups based on their domain. 1246 for (unsigned u = 0; u < AliasGroups.size(); u++) { 1247 AliasGroupTy NewAG; 1248 AliasGroupTy &AG = AliasGroups[u]; 1249 AliasGroupTy::iterator AGI = AG.begin(); 1250 isl_set *AGDomain = getAccessDomain(*AGI); 1251 while (AGI != AG.end()) { 1252 MemoryAccess *MA = *AGI; 1253 isl_set *MADomain = getAccessDomain(MA); 1254 if (isl_set_is_disjoint(AGDomain, MADomain)) { 1255 NewAG.push_back(MA); 1256 AGI = AG.erase(AGI); 1257 isl_set_free(MADomain); 1258 } else { 1259 AGDomain = isl_set_union(AGDomain, MADomain); 1260 AGI++; 1261 } 1262 } 1263 if (NewAG.size() > 1) 1264 AliasGroups.push_back(std::move(NewAG)); 1265 isl_set_free(AGDomain); 1266 } 1267 1268 DenseMap<const Value *, SmallPtrSet<MemoryAccess *, 8>> ReadOnlyPairs; 1269 SmallPtrSet<const Value *, 4> NonReadOnlyBaseValues; 1270 for (AliasGroupTy &AG : AliasGroups) { 1271 NonReadOnlyBaseValues.clear(); 1272 ReadOnlyPairs.clear(); 1273 1274 if (AG.size() < 2) { 1275 AG.clear(); 1276 continue; 1277 } 1278 1279 for (auto II = AG.begin(); II != AG.end();) { 1280 Value *BaseAddr = (*II)->getBaseAddr(); 1281 if (HasWriteAccess.count(BaseAddr)) { 1282 NonReadOnlyBaseValues.insert(BaseAddr); 1283 II++; 1284 } else { 1285 ReadOnlyPairs[BaseAddr].insert(*II); 1286 II = AG.erase(II); 1287 } 1288 } 1289 1290 // If we don't have read only pointers check if there are at least two 1291 // non read only pointers, otherwise clear the alias group. 1292 if (ReadOnlyPairs.empty()) { 1293 if (NonReadOnlyBaseValues.size() <= 1) 1294 AG.clear(); 1295 continue; 1296 } 1297 1298 // If we don't have non read only pointers clear the alias group. 1299 if (NonReadOnlyBaseValues.empty()) { 1300 AG.clear(); 1301 continue; 1302 } 1303 1304 // If we have both read only and non read only base pointers we combine 1305 // the non read only ones with exactly one read only one at a time into a 1306 // new alias group and clear the old alias group in the end. 1307 for (const auto &ReadOnlyPair : ReadOnlyPairs) { 1308 AliasGroupTy AGNonReadOnly = AG; 1309 for (MemoryAccess *MA : ReadOnlyPair.second) 1310 AGNonReadOnly.push_back(MA); 1311 AliasGroups.push_back(std::move(AGNonReadOnly)); 1312 } 1313 AG.clear(); 1314 } 1315 1316 bool Valid = true; 1317 for (AliasGroupTy &AG : AliasGroups) { 1318 if (AG.empty()) 1319 continue; 1320 1321 MinMaxVectorTy *MinMaxAccesses = new MinMaxVectorTy(); 1322 MinMaxAccesses->reserve(AG.size()); 1323 1324 isl_union_map *Accesses = isl_union_map_empty(getParamSpace()); 1325 for (MemoryAccess *MA : AG) 1326 Accesses = isl_union_map_add_map(Accesses, MA->getAccessRelation()); 1327 Accesses = isl_union_map_intersect_domain(Accesses, getDomains()); 1328 1329 isl_union_set *Locations = isl_union_map_range(Accesses); 1330 Locations = isl_union_set_intersect_params(Locations, getAssumedContext()); 1331 Locations = isl_union_set_coalesce(Locations); 1332 Locations = isl_union_set_detect_equalities(Locations); 1333 Valid = (0 == isl_union_set_foreach_set(Locations, buildMinMaxAccess, 1334 MinMaxAccesses)); 1335 isl_union_set_free(Locations); 1336 MinMaxAliasGroups.push_back(MinMaxAccesses); 1337 1338 if (!Valid) 1339 break; 1340 } 1341 1342 return Valid; 1343 } 1344 1345 Scop::Scop(TempScop &tempScop, LoopInfo &LI, ScalarEvolution &ScalarEvolution, 1346 isl_ctx *Context) 1347 : SE(&ScalarEvolution), R(tempScop.getMaxRegion()), 1348 MaxLoopDepth(tempScop.getMaxLoopDepth()) { 1349 IslCtx = Context; 1350 buildContext(); 1351 1352 SmallVector<Loop *, 8> NestLoops; 1353 SmallVector<unsigned, 8> Scatter; 1354 1355 Scatter.assign(MaxLoopDepth + 1, 0); 1356 1357 // Build the iteration domain, access functions and scattering functions 1358 // traversing the region tree. 1359 buildScop(tempScop, getRegion(), NestLoops, Scatter, LI); 1360 1361 realignParams(); 1362 addParameterBounds(); 1363 simplifyAssumedContext(); 1364 1365 assert(NestLoops.empty() && "NestLoops not empty at top level!"); 1366 } 1367 1368 Scop::~Scop() { 1369 isl_set_free(Context); 1370 isl_set_free(AssumedContext); 1371 1372 // Free the statements; 1373 for (ScopStmt *Stmt : *this) 1374 delete Stmt; 1375 1376 // Free the alias groups 1377 for (MinMaxVectorTy *MinMaxAccesses : MinMaxAliasGroups) { 1378 for (MinMaxAccessTy &MMA : *MinMaxAccesses) { 1379 isl_pw_multi_aff_free(MMA.first); 1380 isl_pw_multi_aff_free(MMA.second); 1381 } 1382 delete MinMaxAccesses; 1383 } 1384 } 1385 1386 std::string Scop::getContextStr() const { return stringFromIslObj(Context); } 1387 std::string Scop::getAssumedContextStr() const { 1388 return stringFromIslObj(AssumedContext); 1389 } 1390 1391 std::string Scop::getNameStr() const { 1392 std::string ExitName, EntryName; 1393 raw_string_ostream ExitStr(ExitName); 1394 raw_string_ostream EntryStr(EntryName); 1395 1396 R.getEntry()->printAsOperand(EntryStr, false); 1397 EntryStr.str(); 1398 1399 if (R.getExit()) { 1400 R.getExit()->printAsOperand(ExitStr, false); 1401 ExitStr.str(); 1402 } else 1403 ExitName = "FunctionExit"; 1404 1405 return EntryName + "---" + ExitName; 1406 } 1407 1408 __isl_give isl_set *Scop::getContext() const { return isl_set_copy(Context); } 1409 __isl_give isl_space *Scop::getParamSpace() const { 1410 return isl_set_get_space(this->Context); 1411 } 1412 1413 __isl_give isl_set *Scop::getAssumedContext() const { 1414 return isl_set_copy(AssumedContext); 1415 } 1416 1417 void Scop::addAssumption(__isl_take isl_set *Set) { 1418 AssumedContext = isl_set_intersect(AssumedContext, Set); 1419 } 1420 1421 void Scop::printContext(raw_ostream &OS) const { 1422 OS << "Context:\n"; 1423 1424 if (!Context) { 1425 OS.indent(4) << "n/a\n\n"; 1426 return; 1427 } 1428 1429 OS.indent(4) << getContextStr() << "\n"; 1430 1431 OS.indent(4) << "Assumed Context:\n"; 1432 if (!AssumedContext) { 1433 OS.indent(4) << "n/a\n\n"; 1434 return; 1435 } 1436 1437 OS.indent(4) << getAssumedContextStr() << "\n"; 1438 1439 for (const SCEV *Parameter : Parameters) { 1440 int Dim = ParameterIds.find(Parameter)->second; 1441 OS.indent(4) << "p" << Dim << ": " << *Parameter << "\n"; 1442 } 1443 } 1444 1445 void Scop::printAliasAssumptions(raw_ostream &OS) const { 1446 OS.indent(4) << "Alias Groups (" << MinMaxAliasGroups.size() << "):\n"; 1447 if (MinMaxAliasGroups.empty()) { 1448 OS.indent(8) << "n/a\n"; 1449 return; 1450 } 1451 for (MinMaxVectorTy *MinMaxAccesses : MinMaxAliasGroups) { 1452 OS.indent(8) << "[["; 1453 for (MinMaxAccessTy &MinMacAccess : *MinMaxAccesses) 1454 OS << " <" << MinMacAccess.first << ", " << MinMacAccess.second << ">"; 1455 OS << " ]]\n"; 1456 } 1457 } 1458 1459 void Scop::printStatements(raw_ostream &OS) const { 1460 OS << "Statements {\n"; 1461 1462 for (ScopStmt *Stmt : *this) 1463 OS.indent(4) << *Stmt; 1464 1465 OS.indent(4) << "}\n"; 1466 } 1467 1468 void Scop::print(raw_ostream &OS) const { 1469 OS.indent(4) << "Function: " << getRegion().getEntry()->getParent()->getName() 1470 << "\n"; 1471 OS.indent(4) << "Region: " << getNameStr() << "\n"; 1472 printContext(OS.indent(4)); 1473 printAliasAssumptions(OS); 1474 printStatements(OS.indent(4)); 1475 } 1476 1477 void Scop::dump() const { print(dbgs()); } 1478 1479 isl_ctx *Scop::getIslCtx() const { return IslCtx; } 1480 1481 __isl_give isl_union_set *Scop::getDomains() { 1482 isl_union_set *Domain = isl_union_set_empty(getParamSpace()); 1483 1484 for (ScopStmt *Stmt : *this) 1485 Domain = isl_union_set_add_set(Domain, Stmt->getDomain()); 1486 1487 return Domain; 1488 } 1489 1490 __isl_give isl_union_map *Scop::getMustWrites() { 1491 isl_union_map *Write = isl_union_map_empty(this->getParamSpace()); 1492 1493 for (ScopStmt *Stmt : *this) { 1494 for (MemoryAccess *MA : *Stmt) { 1495 if (!MA->isMustWrite()) 1496 continue; 1497 1498 isl_set *Domain = Stmt->getDomain(); 1499 isl_map *AccessDomain = MA->getAccessRelation(); 1500 AccessDomain = isl_map_intersect_domain(AccessDomain, Domain); 1501 Write = isl_union_map_add_map(Write, AccessDomain); 1502 } 1503 } 1504 return isl_union_map_coalesce(Write); 1505 } 1506 1507 __isl_give isl_union_map *Scop::getMayWrites() { 1508 isl_union_map *Write = isl_union_map_empty(this->getParamSpace()); 1509 1510 for (ScopStmt *Stmt : *this) { 1511 for (MemoryAccess *MA : *Stmt) { 1512 if (!MA->isMayWrite()) 1513 continue; 1514 1515 isl_set *Domain = Stmt->getDomain(); 1516 isl_map *AccessDomain = MA->getAccessRelation(); 1517 AccessDomain = isl_map_intersect_domain(AccessDomain, Domain); 1518 Write = isl_union_map_add_map(Write, AccessDomain); 1519 } 1520 } 1521 return isl_union_map_coalesce(Write); 1522 } 1523 1524 __isl_give isl_union_map *Scop::getWrites() { 1525 isl_union_map *Write = isl_union_map_empty(this->getParamSpace()); 1526 1527 for (ScopStmt *Stmt : *this) { 1528 for (MemoryAccess *MA : *Stmt) { 1529 if (!MA->isWrite()) 1530 continue; 1531 1532 isl_set *Domain = Stmt->getDomain(); 1533 isl_map *AccessDomain = MA->getAccessRelation(); 1534 AccessDomain = isl_map_intersect_domain(AccessDomain, Domain); 1535 Write = isl_union_map_add_map(Write, AccessDomain); 1536 } 1537 } 1538 return isl_union_map_coalesce(Write); 1539 } 1540 1541 __isl_give isl_union_map *Scop::getReads() { 1542 isl_union_map *Read = isl_union_map_empty(getParamSpace()); 1543 1544 for (ScopStmt *Stmt : *this) { 1545 for (MemoryAccess *MA : *Stmt) { 1546 if (!MA->isRead()) 1547 continue; 1548 1549 isl_set *Domain = Stmt->getDomain(); 1550 isl_map *AccessDomain = MA->getAccessRelation(); 1551 1552 AccessDomain = isl_map_intersect_domain(AccessDomain, Domain); 1553 Read = isl_union_map_add_map(Read, AccessDomain); 1554 } 1555 } 1556 return isl_union_map_coalesce(Read); 1557 } 1558 1559 __isl_give isl_union_map *Scop::getSchedule() { 1560 isl_union_map *Schedule = isl_union_map_empty(getParamSpace()); 1561 1562 for (ScopStmt *Stmt : *this) 1563 Schedule = isl_union_map_add_map(Schedule, Stmt->getScattering()); 1564 1565 return isl_union_map_coalesce(Schedule); 1566 } 1567 1568 bool Scop::restrictDomains(__isl_take isl_union_set *Domain) { 1569 bool Changed = false; 1570 for (ScopStmt *Stmt : *this) { 1571 isl_union_set *StmtDomain = isl_union_set_from_set(Stmt->getDomain()); 1572 isl_union_set *NewStmtDomain = isl_union_set_intersect( 1573 isl_union_set_copy(StmtDomain), isl_union_set_copy(Domain)); 1574 1575 if (isl_union_set_is_subset(StmtDomain, NewStmtDomain)) { 1576 isl_union_set_free(StmtDomain); 1577 isl_union_set_free(NewStmtDomain); 1578 continue; 1579 } 1580 1581 Changed = true; 1582 1583 isl_union_set_free(StmtDomain); 1584 NewStmtDomain = isl_union_set_coalesce(NewStmtDomain); 1585 1586 if (isl_union_set_is_empty(NewStmtDomain)) { 1587 Stmt->restrictDomain(isl_set_empty(Stmt->getDomainSpace())); 1588 isl_union_set_free(NewStmtDomain); 1589 } else 1590 Stmt->restrictDomain(isl_set_from_union_set(NewStmtDomain)); 1591 } 1592 isl_union_set_free(Domain); 1593 return Changed; 1594 } 1595 1596 ScalarEvolution *Scop::getSE() const { return SE; } 1597 1598 bool Scop::isTrivialBB(BasicBlock *BB, TempScop &tempScop) { 1599 if (tempScop.getAccessFunctions(BB)) 1600 return false; 1601 1602 return true; 1603 } 1604 1605 void Scop::buildScop(TempScop &tempScop, const Region &CurRegion, 1606 SmallVectorImpl<Loop *> &NestLoops, 1607 SmallVectorImpl<unsigned> &Scatter, LoopInfo &LI) { 1608 Loop *L = castToLoop(CurRegion, LI); 1609 1610 if (L) 1611 NestLoops.push_back(L); 1612 1613 unsigned loopDepth = NestLoops.size(); 1614 assert(Scatter.size() > loopDepth && "Scatter not big enough!"); 1615 1616 for (Region::const_element_iterator I = CurRegion.element_begin(), 1617 E = CurRegion.element_end(); 1618 I != E; ++I) 1619 if (I->isSubRegion()) 1620 buildScop(tempScop, *(I->getNodeAs<Region>()), NestLoops, Scatter, LI); 1621 else { 1622 BasicBlock *BB = I->getNodeAs<BasicBlock>(); 1623 1624 if (isTrivialBB(BB, tempScop)) 1625 continue; 1626 1627 Stmts.push_back( 1628 new ScopStmt(*this, tempScop, CurRegion, *BB, NestLoops, Scatter)); 1629 1630 // Increasing the Scattering function is OK for the moment, because 1631 // we are using a depth first iterator and the program is well structured. 1632 ++Scatter[loopDepth]; 1633 } 1634 1635 if (!L) 1636 return; 1637 1638 // Exiting a loop region. 1639 Scatter[loopDepth] = 0; 1640 NestLoops.pop_back(); 1641 ++Scatter[loopDepth - 1]; 1642 } 1643 1644 //===----------------------------------------------------------------------===// 1645 ScopInfo::ScopInfo() : RegionPass(ID), scop(0) { 1646 ctx = isl_ctx_alloc(); 1647 isl_options_set_on_error(ctx, ISL_ON_ERROR_ABORT); 1648 } 1649 1650 ScopInfo::~ScopInfo() { 1651 clear(); 1652 isl_ctx_free(ctx); 1653 } 1654 1655 void ScopInfo::getAnalysisUsage(AnalysisUsage &AU) const { 1656 AU.addRequired<LoopInfo>(); 1657 AU.addRequired<RegionInfoPass>(); 1658 AU.addRequired<ScalarEvolution>(); 1659 AU.addRequired<TempScopInfo>(); 1660 AU.addRequired<AliasAnalysis>(); 1661 AU.setPreservesAll(); 1662 } 1663 1664 bool ScopInfo::runOnRegion(Region *R, RGPassManager &RGM) { 1665 LoopInfo &LI = getAnalysis<LoopInfo>(); 1666 AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); 1667 ScalarEvolution &SE = getAnalysis<ScalarEvolution>(); 1668 1669 TempScop *tempScop = getAnalysis<TempScopInfo>().getTempScop(R); 1670 1671 // This region is no Scop. 1672 if (!tempScop) { 1673 scop = 0; 1674 return false; 1675 } 1676 1677 // Statistics. 1678 ++ScopFound; 1679 if (tempScop->getMaxLoopDepth() > 0) 1680 ++RichScopFound; 1681 1682 scop = new Scop(*tempScop, LI, SE, ctx); 1683 1684 if (!PollyUseRuntimeAliasChecks) 1685 return false; 1686 1687 // If a problem occurs while building the alias groups we need to delete 1688 // this SCoP and pretend it wasn't valid in the first place. 1689 if (scop->buildAliasGroups(AA)) 1690 return false; 1691 1692 --ScopFound; 1693 if (tempScop->getMaxLoopDepth() > 0) 1694 --RichScopFound; 1695 1696 DEBUG(dbgs() 1697 << "\n\nNOTE: Run time checks for " << scop->getNameStr() 1698 << " could not be created as the number of parameters involved is too " 1699 "high. The SCoP will be " 1700 "dismissed.\nUse:\n\t--polly-rtc-max-parameters=X\nto adjust the " 1701 "maximal number of parameters but be advised that the compile time " 1702 "might increase exponentially.\n\n"); 1703 1704 delete scop; 1705 scop = nullptr; 1706 return false; 1707 } 1708 1709 char ScopInfo::ID = 0; 1710 1711 Pass *polly::createScopInfoPass() { return new ScopInfo(); } 1712 1713 INITIALIZE_PASS_BEGIN(ScopInfo, "polly-scops", 1714 "Polly - Create polyhedral description of Scops", false, 1715 false); 1716 INITIALIZE_AG_DEPENDENCY(AliasAnalysis); 1717 INITIALIZE_PASS_DEPENDENCY(LoopInfo); 1718 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass); 1719 INITIALIZE_PASS_DEPENDENCY(ScalarEvolution); 1720 INITIALIZE_PASS_DEPENDENCY(TempScopInfo); 1721 INITIALIZE_PASS_END(ScopInfo, "polly-scops", 1722 "Polly - Create polyhedral description of Scops", false, 1723 false) 1724