IslAst.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. //===- IslAst.cpp - isl code generator interface --------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // The isl code generator interface takes a Scop and generates an isl_ast. This
  10. // ist_ast can either be returned directly or it can be pretty printed to
  11. // stdout.
  12. //
  13. // A typical isl_ast output looks like this:
  14. //
  15. // for (c2 = max(0, ceild(n + m, 2); c2 <= min(511, floord(5 * n, 3)); c2++) {
  16. // bb2(c2);
  17. // }
  18. //
  19. // An in-depth discussion of our AST generation approach can be found in:
  20. //
  21. // Polyhedral AST generation is more than scanning polyhedra
  22. // Tobias Grosser, Sven Verdoolaege, Albert Cohen
  23. // ACM Transactions on Programming Languages and Systems (TOPLAS),
  24. // 37(4), July 2015
  25. // http://www.grosser.es/#pub-polyhedral-AST-generation
  26. //
  27. //===----------------------------------------------------------------------===//
  28. #include "polly/CodeGen/IslAst.h"
  29. #include "polly/CodeGen/CodeGeneration.h"
  30. #include "polly/DependenceInfo.h"
  31. #include "polly/LinkAllPasses.h"
  32. #include "polly/Options.h"
  33. #include "polly/ScopDetection.h"
  34. #include "polly/ScopInfo.h"
  35. #include "polly/ScopPass.h"
  36. #include "polly/Support/GICHelper.h"
  37. #include "llvm/ADT/Statistic.h"
  38. #include "llvm/IR/Function.h"
  39. #include "llvm/Support/Debug.h"
  40. #include "llvm/Support/raw_ostream.h"
  41. #include "isl/aff.h"
  42. #include "isl/ast.h"
  43. #include "isl/ast_build.h"
  44. #include "isl/id.h"
  45. #include "isl/isl-noexceptions.h"
  46. #include "isl/printer.h"
  47. #include "isl/schedule.h"
  48. #include "isl/set.h"
  49. #include "isl/union_map.h"
  50. #include "isl/val.h"
  51. #include <cassert>
  52. #include <cstdlib>
  53. #define DEBUG_TYPE "polly-ast"
  54. using namespace llvm;
  55. using namespace polly;
  56. using IslAstUserPayload = IslAstInfo::IslAstUserPayload;
  57. static cl::opt<bool>
  58. PollyParallel("polly-parallel",
  59. cl::desc("Generate thread parallel code (isl codegen only)"),
  60. cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
  61. static cl::opt<bool> PrintAccesses("polly-ast-print-accesses",
  62. cl::desc("Print memory access functions"),
  63. cl::init(false), cl::ZeroOrMore,
  64. cl::cat(PollyCategory));
  65. static cl::opt<bool> PollyParallelForce(
  66. "polly-parallel-force",
  67. cl::desc(
  68. "Force generation of thread parallel code ignoring any cost model"),
  69. cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
  70. static cl::opt<bool> UseContext("polly-ast-use-context",
  71. cl::desc("Use context"), cl::Hidden,
  72. cl::init(true), cl::ZeroOrMore,
  73. cl::cat(PollyCategory));
  74. static cl::opt<bool> DetectParallel("polly-ast-detect-parallel",
  75. cl::desc("Detect parallelism"), cl::Hidden,
  76. cl::init(false), cl::ZeroOrMore,
  77. cl::cat(PollyCategory));
  78. STATISTIC(ScopsProcessed, "Number of SCoPs processed");
  79. STATISTIC(ScopsBeneficial, "Number of beneficial SCoPs");
  80. STATISTIC(BeneficialAffineLoops, "Number of beneficial affine loops");
  81. STATISTIC(BeneficialBoxedLoops, "Number of beneficial boxed loops");
  82. STATISTIC(NumForLoops, "Number of for-loops");
  83. STATISTIC(NumParallel, "Number of parallel for-loops");
  84. STATISTIC(NumInnermostParallel, "Number of innermost parallel for-loops");
  85. STATISTIC(NumOutermostParallel, "Number of outermost parallel for-loops");
  86. STATISTIC(NumReductionParallel, "Number of reduction-parallel for-loops");
  87. STATISTIC(NumExecutedInParallel, "Number of for-loops executed in parallel");
  88. STATISTIC(NumIfConditions, "Number of if-conditions");
  89. namespace polly {
  90. /// Temporary information used when building the ast.
  91. struct AstBuildUserInfo {
  92. /// Construct and initialize the helper struct for AST creation.
  93. AstBuildUserInfo() = default;
  94. /// The dependence information used for the parallelism check.
  95. const Dependences *Deps = nullptr;
  96. /// Flag to indicate that we are inside a parallel for node.
  97. bool InParallelFor = false;
  98. /// Flag to indicate that we are inside an SIMD node.
  99. bool InSIMD = false;
  100. /// The last iterator id created for the current SCoP.
  101. isl_id *LastForNodeId = nullptr;
  102. };
  103. } // namespace polly
  104. /// Free an IslAstUserPayload object pointed to by @p Ptr.
  105. static void freeIslAstUserPayload(void *Ptr) {
  106. delete ((IslAstInfo::IslAstUserPayload *)Ptr);
  107. }
  108. /// Print a string @p str in a single line using @p Printer.
  109. static isl_printer *printLine(__isl_take isl_printer *Printer,
  110. const std::string &str,
  111. __isl_keep isl_pw_aff *PWA = nullptr) {
  112. Printer = isl_printer_start_line(Printer);
  113. Printer = isl_printer_print_str(Printer, str.c_str());
  114. if (PWA)
  115. Printer = isl_printer_print_pw_aff(Printer, PWA);
  116. return isl_printer_end_line(Printer);
  117. }
  118. /// Return all broken reductions as a string of clauses (OpenMP style).
  119. static const std::string getBrokenReductionsStr(const isl::ast_node &Node) {
  120. IslAstInfo::MemoryAccessSet *BrokenReductions;
  121. std::string str;
  122. BrokenReductions = IslAstInfo::getBrokenReductions(Node);
  123. if (!BrokenReductions || BrokenReductions->empty())
  124. return "";
  125. // Map each type of reduction to a comma separated list of the base addresses.
  126. std::map<MemoryAccess::ReductionType, std::string> Clauses;
  127. for (MemoryAccess *MA : *BrokenReductions)
  128. if (MA->isWrite())
  129. Clauses[MA->getReductionType()] +=
  130. ", " + MA->getScopArrayInfo()->getName();
  131. // Now print the reductions sorted by type. Each type will cause a clause
  132. // like: reduction (+ : sum0, sum1, sum2)
  133. for (const auto &ReductionClause : Clauses) {
  134. str += " reduction (";
  135. str += MemoryAccess::getReductionOperatorStr(ReductionClause.first);
  136. // Remove the first two symbols (", ") to make the output look pretty.
  137. str += " : " + ReductionClause.second.substr(2) + ")";
  138. }
  139. return str;
  140. }
  141. /// Callback executed for each for node in the ast in order to print it.
  142. static isl_printer *cbPrintFor(__isl_take isl_printer *Printer,
  143. __isl_take isl_ast_print_options *Options,
  144. __isl_keep isl_ast_node *Node, void *) {
  145. isl::pw_aff DD =
  146. IslAstInfo::getMinimalDependenceDistance(isl::manage_copy(Node));
  147. const std::string BrokenReductionsStr =
  148. getBrokenReductionsStr(isl::manage_copy(Node));
  149. const std::string KnownParallelStr = "#pragma known-parallel";
  150. const std::string DepDisPragmaStr = "#pragma minimal dependence distance: ";
  151. const std::string SimdPragmaStr = "#pragma simd";
  152. const std::string OmpPragmaStr = "#pragma omp parallel for";
  153. if (!DD.is_null())
  154. Printer = printLine(Printer, DepDisPragmaStr, DD.get());
  155. if (IslAstInfo::isInnermostParallel(isl::manage_copy(Node)))
  156. Printer = printLine(Printer, SimdPragmaStr + BrokenReductionsStr);
  157. if (IslAstInfo::isExecutedInParallel(isl::manage_copy(Node)))
  158. Printer = printLine(Printer, OmpPragmaStr);
  159. else if (IslAstInfo::isOutermostParallel(isl::manage_copy(Node)))
  160. Printer = printLine(Printer, KnownParallelStr + BrokenReductionsStr);
  161. return isl_ast_node_for_print(Node, Printer, Options);
  162. }
  163. /// Check if the current scheduling dimension is parallel.
  164. ///
  165. /// In case the dimension is parallel we also check if any reduction
  166. /// dependences is broken when we exploit this parallelism. If so,
  167. /// @p IsReductionParallel will be set to true. The reduction dependences we use
  168. /// to check are actually the union of the transitive closure of the initial
  169. /// reduction dependences together with their reversal. Even though these
  170. /// dependences connect all iterations with each other (thus they are cyclic)
  171. /// we can perform the parallelism check as we are only interested in a zero
  172. /// (or non-zero) dependence distance on the dimension in question.
  173. static bool astScheduleDimIsParallel(const isl::ast_build &Build,
  174. const Dependences *D,
  175. IslAstUserPayload *NodeInfo) {
  176. if (!D->hasValidDependences())
  177. return false;
  178. isl::union_map Schedule = Build.get_schedule();
  179. isl::union_map Dep = D->getDependences(
  180. Dependences::TYPE_RAW | Dependences::TYPE_WAW | Dependences::TYPE_WAR);
  181. if (!D->isParallel(Schedule.get(), Dep.release())) {
  182. isl::union_map DepsAll =
  183. D->getDependences(Dependences::TYPE_RAW | Dependences::TYPE_WAW |
  184. Dependences::TYPE_WAR | Dependences::TYPE_TC_RED);
  185. // TODO: We will need to change isParallel to stop the unwrapping
  186. isl_pw_aff *MinimalDependenceDistanceIsl = nullptr;
  187. D->isParallel(Schedule.get(), DepsAll.release(),
  188. &MinimalDependenceDistanceIsl);
  189. NodeInfo->MinimalDependenceDistance =
  190. isl::manage(MinimalDependenceDistanceIsl);
  191. return false;
  192. }
  193. isl::union_map RedDeps = D->getDependences(Dependences::TYPE_TC_RED);
  194. if (!D->isParallel(Schedule.get(), RedDeps.release()))
  195. NodeInfo->IsReductionParallel = true;
  196. if (!NodeInfo->IsReductionParallel)
  197. return true;
  198. for (const auto &MaRedPair : D->getReductionDependences()) {
  199. if (!MaRedPair.second)
  200. continue;
  201. isl::union_map MaRedDeps = isl::manage_copy(MaRedPair.second);
  202. if (!D->isParallel(Schedule.get(), MaRedDeps.release()))
  203. NodeInfo->BrokenReductions.insert(MaRedPair.first);
  204. }
  205. return true;
  206. }
  207. // This method is executed before the construction of a for node. It creates
  208. // an isl_id that is used to annotate the subsequently generated ast for nodes.
  209. //
  210. // In this function we also run the following analyses:
  211. //
  212. // - Detection of openmp parallel loops
  213. //
  214. static __isl_give isl_id *astBuildBeforeFor(__isl_keep isl_ast_build *Build,
  215. void *User) {
  216. AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User;
  217. IslAstUserPayload *Payload = new IslAstUserPayload();
  218. isl_id *Id = isl_id_alloc(isl_ast_build_get_ctx(Build), "", Payload);
  219. Id = isl_id_set_free_user(Id, freeIslAstUserPayload);
  220. BuildInfo->LastForNodeId = Id;
  221. Payload->IsParallel = astScheduleDimIsParallel(isl::manage_copy(Build),
  222. BuildInfo->Deps, Payload);
  223. // Test for parallelism only if we are not already inside a parallel loop
  224. if (!BuildInfo->InParallelFor && !BuildInfo->InSIMD)
  225. BuildInfo->InParallelFor = Payload->IsOutermostParallel =
  226. Payload->IsParallel;
  227. return Id;
  228. }
  229. // This method is executed after the construction of a for node.
  230. //
  231. // It performs the following actions:
  232. //
  233. // - Reset the 'InParallelFor' flag, as soon as we leave a for node,
  234. // that is marked as openmp parallel.
  235. //
  236. static __isl_give isl_ast_node *
  237. astBuildAfterFor(__isl_take isl_ast_node *Node, __isl_keep isl_ast_build *Build,
  238. void *User) {
  239. isl_id *Id = isl_ast_node_get_annotation(Node);
  240. assert(Id && "Post order visit assumes annotated for nodes");
  241. IslAstUserPayload *Payload = (IslAstUserPayload *)isl_id_get_user(Id);
  242. assert(Payload && "Post order visit assumes annotated for nodes");
  243. AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User;
  244. assert(Payload->Build.is_null() && "Build environment already set");
  245. Payload->Build = isl::manage_copy(Build);
  246. Payload->IsInnermost = (Id == BuildInfo->LastForNodeId);
  247. Payload->IsInnermostParallel =
  248. Payload->IsInnermost && (BuildInfo->InSIMD || Payload->IsParallel);
  249. if (Payload->IsOutermostParallel)
  250. BuildInfo->InParallelFor = false;
  251. isl_id_free(Id);
  252. return Node;
  253. }
  254. static isl_stat astBuildBeforeMark(__isl_keep isl_id *MarkId,
  255. __isl_keep isl_ast_build *Build,
  256. void *User) {
  257. if (!MarkId)
  258. return isl_stat_error;
  259. AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User;
  260. if (strcmp(isl_id_get_name(MarkId), "SIMD") == 0)
  261. BuildInfo->InSIMD = true;
  262. return isl_stat_ok;
  263. }
  264. static __isl_give isl_ast_node *
  265. astBuildAfterMark(__isl_take isl_ast_node *Node,
  266. __isl_keep isl_ast_build *Build, void *User) {
  267. assert(isl_ast_node_get_type(Node) == isl_ast_node_mark);
  268. AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User;
  269. auto *Id = isl_ast_node_mark_get_id(Node);
  270. if (strcmp(isl_id_get_name(Id), "SIMD") == 0)
  271. BuildInfo->InSIMD = false;
  272. isl_id_free(Id);
  273. return Node;
  274. }
  275. static __isl_give isl_ast_node *AtEachDomain(__isl_take isl_ast_node *Node,
  276. __isl_keep isl_ast_build *Build,
  277. void *User) {
  278. assert(!isl_ast_node_get_annotation(Node) && "Node already annotated");
  279. IslAstUserPayload *Payload = new IslAstUserPayload();
  280. isl_id *Id = isl_id_alloc(isl_ast_build_get_ctx(Build), "", Payload);
  281. Id = isl_id_set_free_user(Id, freeIslAstUserPayload);
  282. Payload->Build = isl::manage_copy(Build);
  283. return isl_ast_node_set_annotation(Node, Id);
  284. }
  285. // Build alias check condition given a pair of minimal/maximal access.
  286. static isl::ast_expr buildCondition(Scop &S, isl::ast_build Build,
  287. const Scop::MinMaxAccessTy *It0,
  288. const Scop::MinMaxAccessTy *It1) {
  289. isl::pw_multi_aff AFirst = It0->first;
  290. isl::pw_multi_aff ASecond = It0->second;
  291. isl::pw_multi_aff BFirst = It1->first;
  292. isl::pw_multi_aff BSecond = It1->second;
  293. isl::id Left = AFirst.get_tuple_id(isl::dim::set);
  294. isl::id Right = BFirst.get_tuple_id(isl::dim::set);
  295. isl::ast_expr True =
  296. isl::ast_expr::from_val(isl::val::int_from_ui(Build.ctx(), 1));
  297. isl::ast_expr False =
  298. isl::ast_expr::from_val(isl::val::int_from_ui(Build.ctx(), 0));
  299. const ScopArrayInfo *BaseLeft =
  300. ScopArrayInfo::getFromId(Left)->getBasePtrOriginSAI();
  301. const ScopArrayInfo *BaseRight =
  302. ScopArrayInfo::getFromId(Right)->getBasePtrOriginSAI();
  303. if (BaseLeft && BaseLeft == BaseRight)
  304. return True;
  305. isl::set Params = S.getContext();
  306. isl::ast_expr NonAliasGroup, MinExpr, MaxExpr;
  307. // In the following, we first check if any accesses will be empty under
  308. // the execution context of the scop and do not code generate them if this
  309. // is the case as isl will fail to derive valid AST expressions for such
  310. // accesses.
  311. if (!AFirst.intersect_params(Params).domain().is_empty() &&
  312. !BSecond.intersect_params(Params).domain().is_empty()) {
  313. MinExpr = Build.access_from(AFirst).address_of();
  314. MaxExpr = Build.access_from(BSecond).address_of();
  315. NonAliasGroup = MaxExpr.le(MinExpr);
  316. }
  317. if (!BFirst.intersect_params(Params).domain().is_empty() &&
  318. !ASecond.intersect_params(Params).domain().is_empty()) {
  319. MinExpr = Build.access_from(BFirst).address_of();
  320. MaxExpr = Build.access_from(ASecond).address_of();
  321. isl::ast_expr Result = MaxExpr.le(MinExpr);
  322. if (!NonAliasGroup.is_null())
  323. NonAliasGroup = isl::manage(
  324. isl_ast_expr_or(NonAliasGroup.release(), Result.release()));
  325. else
  326. NonAliasGroup = Result;
  327. }
  328. if (NonAliasGroup.is_null())
  329. NonAliasGroup = True;
  330. return NonAliasGroup;
  331. }
  332. isl::ast_expr IslAst::buildRunCondition(Scop &S, const isl::ast_build &Build) {
  333. isl::ast_expr RunCondition;
  334. // The conditions that need to be checked at run-time for this scop are
  335. // available as an isl_set in the runtime check context from which we can
  336. // directly derive a run-time condition.
  337. auto PosCond = Build.expr_from(S.getAssumedContext());
  338. if (S.hasTrivialInvalidContext()) {
  339. RunCondition = std::move(PosCond);
  340. } else {
  341. auto ZeroV = isl::val::zero(Build.ctx());
  342. auto NegCond = Build.expr_from(S.getInvalidContext());
  343. auto NotNegCond =
  344. isl::ast_expr::from_val(std::move(ZeroV)).eq(std::move(NegCond));
  345. RunCondition =
  346. isl::manage(isl_ast_expr_and(PosCond.release(), NotNegCond.release()));
  347. }
  348. // Create the alias checks from the minimal/maximal accesses in each alias
  349. // group which consists of read only and non read only (read write) accesses.
  350. // This operation is by construction quadratic in the read-write pointers and
  351. // linear in the read only pointers in each alias group.
  352. for (const Scop::MinMaxVectorPairTy &MinMaxAccessPair : S.getAliasGroups()) {
  353. auto &MinMaxReadWrite = MinMaxAccessPair.first;
  354. auto &MinMaxReadOnly = MinMaxAccessPair.second;
  355. auto RWAccEnd = MinMaxReadWrite.end();
  356. for (auto RWAccIt0 = MinMaxReadWrite.begin(); RWAccIt0 != RWAccEnd;
  357. ++RWAccIt0) {
  358. for (auto RWAccIt1 = RWAccIt0 + 1; RWAccIt1 != RWAccEnd; ++RWAccIt1)
  359. RunCondition = isl::manage(isl_ast_expr_and(
  360. RunCondition.release(),
  361. buildCondition(S, Build, RWAccIt0, RWAccIt1).release()));
  362. for (const Scop::MinMaxAccessTy &ROAccIt : MinMaxReadOnly)
  363. RunCondition = isl::manage(isl_ast_expr_and(
  364. RunCondition.release(),
  365. buildCondition(S, Build, RWAccIt0, &ROAccIt).release()));
  366. }
  367. }
  368. return RunCondition;
  369. }
  370. /// Simple cost analysis for a given SCoP.
  371. ///
  372. /// TODO: Improve this analysis and extract it to make it usable in other
  373. /// places too.
  374. /// In order to improve the cost model we could either keep track of
  375. /// performed optimizations (e.g., tiling) or compute properties on the
  376. /// original as well as optimized SCoP (e.g., #stride-one-accesses).
  377. static bool benefitsFromPolly(Scop &Scop, bool PerformParallelTest) {
  378. if (PollyProcessUnprofitable)
  379. return true;
  380. // Check if nothing interesting happened.
  381. if (!PerformParallelTest && !Scop.isOptimized() &&
  382. Scop.getAliasGroups().empty())
  383. return false;
  384. // The default assumption is that Polly improves the code.
  385. return true;
  386. }
  387. /// Collect statistics for the syntax tree rooted at @p Ast.
  388. static void walkAstForStatistics(const isl::ast_node &Ast) {
  389. assert(!Ast.is_null());
  390. isl_ast_node_foreach_descendant_top_down(
  391. Ast.get(),
  392. [](__isl_keep isl_ast_node *Node, void *User) -> isl_bool {
  393. switch (isl_ast_node_get_type(Node)) {
  394. case isl_ast_node_for:
  395. NumForLoops++;
  396. if (IslAstInfo::isParallel(isl::manage_copy(Node)))
  397. NumParallel++;
  398. if (IslAstInfo::isInnermostParallel(isl::manage_copy(Node)))
  399. NumInnermostParallel++;
  400. if (IslAstInfo::isOutermostParallel(isl::manage_copy(Node)))
  401. NumOutermostParallel++;
  402. if (IslAstInfo::isReductionParallel(isl::manage_copy(Node)))
  403. NumReductionParallel++;
  404. if (IslAstInfo::isExecutedInParallel(isl::manage_copy(Node)))
  405. NumExecutedInParallel++;
  406. break;
  407. case isl_ast_node_if:
  408. NumIfConditions++;
  409. break;
  410. default:
  411. break;
  412. }
  413. // Continue traversing subtrees.
  414. return isl_bool_true;
  415. },
  416. nullptr);
  417. }
  418. IslAst::IslAst(Scop &Scop) : S(Scop), Ctx(Scop.getSharedIslCtx()) {}
  419. IslAst::IslAst(IslAst &&O)
  420. : S(O.S), Ctx(O.Ctx), RunCondition(std::move(O.RunCondition)),
  421. Root(std::move(O.Root)) {}
  422. void IslAst::init(const Dependences &D) {
  423. bool PerformParallelTest = PollyParallel || DetectParallel ||
  424. PollyVectorizerChoice != VECTORIZER_NONE;
  425. auto ScheduleTree = S.getScheduleTree();
  426. // Skip AST and code generation if there was no benefit achieved.
  427. if (!benefitsFromPolly(S, PerformParallelTest))
  428. return;
  429. auto ScopStats = S.getStatistics();
  430. ScopsBeneficial++;
  431. BeneficialAffineLoops += ScopStats.NumAffineLoops;
  432. BeneficialBoxedLoops += ScopStats.NumBoxedLoops;
  433. auto Ctx = S.getIslCtx();
  434. isl_options_set_ast_build_atomic_upper_bound(Ctx.get(), true);
  435. isl_options_set_ast_build_detect_min_max(Ctx.get(), true);
  436. isl_ast_build *Build;
  437. AstBuildUserInfo BuildInfo;
  438. if (UseContext)
  439. Build = isl_ast_build_from_context(S.getContext().release());
  440. else
  441. Build = isl_ast_build_from_context(
  442. isl_set_universe(S.getParamSpace().release()));
  443. Build = isl_ast_build_set_at_each_domain(Build, AtEachDomain, nullptr);
  444. if (PerformParallelTest) {
  445. BuildInfo.Deps = &D;
  446. BuildInfo.InParallelFor = false;
  447. BuildInfo.InSIMD = false;
  448. Build = isl_ast_build_set_before_each_for(Build, &astBuildBeforeFor,
  449. &BuildInfo);
  450. Build =
  451. isl_ast_build_set_after_each_for(Build, &astBuildAfterFor, &BuildInfo);
  452. Build = isl_ast_build_set_before_each_mark(Build, &astBuildBeforeMark,
  453. &BuildInfo);
  454. Build = isl_ast_build_set_after_each_mark(Build, &astBuildAfterMark,
  455. &BuildInfo);
  456. }
  457. RunCondition = buildRunCondition(S, isl::manage_copy(Build));
  458. Root = isl::manage(
  459. isl_ast_build_node_from_schedule(Build, S.getScheduleTree().release()));
  460. walkAstForStatistics(Root);
  461. isl_ast_build_free(Build);
  462. }
  463. IslAst IslAst::create(Scop &Scop, const Dependences &D) {
  464. IslAst Ast{Scop};
  465. Ast.init(D);
  466. return Ast;
  467. }
  468. isl::ast_node IslAst::getAst() { return Root; }
  469. isl::ast_expr IslAst::getRunCondition() { return RunCondition; }
  470. isl::ast_node IslAstInfo::getAst() { return Ast.getAst(); }
  471. isl::ast_expr IslAstInfo::getRunCondition() { return Ast.getRunCondition(); }
  472. IslAstUserPayload *IslAstInfo::getNodePayload(const isl::ast_node &Node) {
  473. isl::id Id = Node.get_annotation();
  474. if (Id.is_null())
  475. return nullptr;
  476. IslAstUserPayload *Payload = (IslAstUserPayload *)Id.get_user();
  477. return Payload;
  478. }
  479. bool IslAstInfo::isInnermost(const isl::ast_node &Node) {
  480. IslAstUserPayload *Payload = getNodePayload(Node);
  481. return Payload && Payload->IsInnermost;
  482. }
  483. bool IslAstInfo::isParallel(const isl::ast_node &Node) {
  484. return IslAstInfo::isInnermostParallel(Node) ||
  485. IslAstInfo::isOutermostParallel(Node);
  486. }
  487. bool IslAstInfo::isInnermostParallel(const isl::ast_node &Node) {
  488. IslAstUserPayload *Payload = getNodePayload(Node);
  489. return Payload && Payload->IsInnermostParallel;
  490. }
  491. bool IslAstInfo::isOutermostParallel(const isl::ast_node &Node) {
  492. IslAstUserPayload *Payload = getNodePayload(Node);
  493. return Payload && Payload->IsOutermostParallel;
  494. }
  495. bool IslAstInfo::isReductionParallel(const isl::ast_node &Node) {
  496. IslAstUserPayload *Payload = getNodePayload(Node);
  497. return Payload && Payload->IsReductionParallel;
  498. }
  499. bool IslAstInfo::isExecutedInParallel(const isl::ast_node &Node) {
  500. if (!PollyParallel)
  501. return false;
  502. // Do not parallelize innermost loops.
  503. //
  504. // Parallelizing innermost loops is often not profitable, especially if
  505. // they have a low number of iterations.
  506. //
  507. // TODO: Decide this based on the number of loop iterations that will be
  508. // executed. This can possibly require run-time checks, which again
  509. // raises the question of both run-time check overhead and code size
  510. // costs.
  511. if (!PollyParallelForce && isInnermost(Node))
  512. return false;
  513. return isOutermostParallel(Node) && !isReductionParallel(Node);
  514. }
  515. isl::union_map IslAstInfo::getSchedule(const isl::ast_node &Node) {
  516. IslAstUserPayload *Payload = getNodePayload(Node);
  517. return Payload ? Payload->Build.get_schedule() : isl::union_map();
  518. }
  519. isl::pw_aff
  520. IslAstInfo::getMinimalDependenceDistance(const isl::ast_node &Node) {
  521. IslAstUserPayload *Payload = getNodePayload(Node);
  522. return Payload ? Payload->MinimalDependenceDistance : isl::pw_aff();
  523. }
  524. IslAstInfo::MemoryAccessSet *
  525. IslAstInfo::getBrokenReductions(const isl::ast_node &Node) {
  526. IslAstUserPayload *Payload = getNodePayload(Node);
  527. return Payload ? &Payload->BrokenReductions : nullptr;
  528. }
  529. isl::ast_build IslAstInfo::getBuild(const isl::ast_node &Node) {
  530. IslAstUserPayload *Payload = getNodePayload(Node);
  531. return Payload ? Payload->Build : isl::ast_build();
  532. }
  533. static std::unique_ptr<IslAstInfo> runIslAst(
  534. Scop &Scop,
  535. function_ref<const Dependences &(Dependences::AnalysisLevel)> GetDeps) {
  536. // Skip SCoPs in case they're already handled by PPCGCodeGeneration.
  537. if (Scop.isToBeSkipped())
  538. return {};
  539. ScopsProcessed++;
  540. const Dependences &D = GetDeps(Dependences::AL_Statement);
  541. if (D.getSharedIslCtx() != Scop.getSharedIslCtx()) {
  542. LLVM_DEBUG(
  543. dbgs() << "Got dependence analysis for different SCoP/isl_ctx\n");
  544. return {};
  545. }
  546. std::unique_ptr<IslAstInfo> Ast = std::make_unique<IslAstInfo>(Scop, D);
  547. LLVM_DEBUG({
  548. if (Ast)
  549. Ast->print(dbgs());
  550. });
  551. return Ast;
  552. }
  553. IslAstInfo IslAstAnalysis::run(Scop &S, ScopAnalysisManager &SAM,
  554. ScopStandardAnalysisResults &SAR) {
  555. auto GetDeps = [&](Dependences::AnalysisLevel Lvl) -> const Dependences & {
  556. return SAM.getResult<DependenceAnalysis>(S, SAR).getDependences(Lvl);
  557. };
  558. return std::move(*runIslAst(S, GetDeps));
  559. }
  560. static __isl_give isl_printer *cbPrintUser(__isl_take isl_printer *P,
  561. __isl_take isl_ast_print_options *O,
  562. __isl_keep isl_ast_node *Node,
  563. void *User) {
  564. isl::ast_node_user AstNode = isl::manage_copy(Node).as<isl::ast_node_user>();
  565. isl::ast_expr NodeExpr = AstNode.expr();
  566. isl::ast_expr CallExpr = NodeExpr.get_op_arg(0);
  567. isl::id CallExprId = CallExpr.get_id();
  568. ScopStmt *AccessStmt = (ScopStmt *)CallExprId.get_user();
  569. P = isl_printer_start_line(P);
  570. P = isl_printer_print_str(P, AccessStmt->getBaseName());
  571. P = isl_printer_print_str(P, "(");
  572. P = isl_printer_end_line(P);
  573. P = isl_printer_indent(P, 2);
  574. for (MemoryAccess *MemAcc : *AccessStmt) {
  575. P = isl_printer_start_line(P);
  576. if (MemAcc->isRead())
  577. P = isl_printer_print_str(P, "/* read */ &");
  578. else
  579. P = isl_printer_print_str(P, "/* write */ ");
  580. isl::ast_build Build = IslAstInfo::getBuild(isl::manage_copy(Node));
  581. if (MemAcc->isAffine()) {
  582. isl_pw_multi_aff *PwmaPtr =
  583. MemAcc->applyScheduleToAccessRelation(Build.get_schedule()).release();
  584. isl::pw_multi_aff Pwma = isl::manage(PwmaPtr);
  585. isl::ast_expr AccessExpr = Build.access_from(Pwma);
  586. P = isl_printer_print_ast_expr(P, AccessExpr.get());
  587. } else {
  588. P = isl_printer_print_str(
  589. P, MemAcc->getLatestScopArrayInfo()->getName().c_str());
  590. P = isl_printer_print_str(P, "[*]");
  591. }
  592. P = isl_printer_end_line(P);
  593. }
  594. P = isl_printer_indent(P, -2);
  595. P = isl_printer_start_line(P);
  596. P = isl_printer_print_str(P, ");");
  597. P = isl_printer_end_line(P);
  598. isl_ast_print_options_free(O);
  599. return P;
  600. }
  601. void IslAstInfo::print(raw_ostream &OS) {
  602. isl_ast_print_options *Options;
  603. isl::ast_node RootNode = Ast.getAst();
  604. Function &F = S.getFunction();
  605. OS << ":: isl ast :: " << F.getName() << " :: " << S.getNameStr() << "\n";
  606. if (RootNode.is_null()) {
  607. OS << ":: isl ast generation and code generation was skipped!\n\n";
  608. OS << ":: This is either because no useful optimizations could be applied "
  609. "(use -polly-process-unprofitable to enforce code generation) or "
  610. "because earlier passes such as dependence analysis timed out (use "
  611. "-polly-dependences-computeout=0 to set dependence analysis timeout "
  612. "to infinity)\n\n";
  613. return;
  614. }
  615. isl::ast_expr RunCondition = Ast.getRunCondition();
  616. char *RtCStr, *AstStr;
  617. Options = isl_ast_print_options_alloc(S.getIslCtx().get());
  618. if (PrintAccesses)
  619. Options =
  620. isl_ast_print_options_set_print_user(Options, cbPrintUser, nullptr);
  621. Options = isl_ast_print_options_set_print_for(Options, cbPrintFor, nullptr);
  622. isl_printer *P = isl_printer_to_str(S.getIslCtx().get());
  623. P = isl_printer_set_output_format(P, ISL_FORMAT_C);
  624. P = isl_printer_print_ast_expr(P, RunCondition.get());
  625. RtCStr = isl_printer_get_str(P);
  626. P = isl_printer_flush(P);
  627. P = isl_printer_indent(P, 4);
  628. P = isl_ast_node_print(RootNode.get(), P, Options);
  629. AstStr = isl_printer_get_str(P);
  630. LLVM_DEBUG({
  631. dbgs() << S.getContextStr() << "\n";
  632. dbgs() << stringFromIslObj(S.getScheduleTree(), "null");
  633. });
  634. OS << "\nif (" << RtCStr << ")\n\n";
  635. OS << AstStr << "\n";
  636. OS << "else\n";
  637. OS << " { /* original code */ }\n\n";
  638. free(RtCStr);
  639. free(AstStr);
  640. isl_printer_free(P);
  641. }
  642. AnalysisKey IslAstAnalysis::Key;
  643. PreservedAnalyses IslAstPrinterPass::run(Scop &S, ScopAnalysisManager &SAM,
  644. ScopStandardAnalysisResults &SAR,
  645. SPMUpdater &U) {
  646. auto &Ast = SAM.getResult<IslAstAnalysis>(S, SAR);
  647. Ast.print(OS);
  648. return PreservedAnalyses::all();
  649. }
  650. void IslAstInfoWrapperPass::releaseMemory() { Ast.reset(); }
  651. bool IslAstInfoWrapperPass::runOnScop(Scop &Scop) {
  652. auto GetDeps = [this](Dependences::AnalysisLevel Lvl) -> const Dependences & {
  653. return getAnalysis<DependenceInfo>().getDependences(Lvl);
  654. };
  655. Ast = runIslAst(Scop, GetDeps);
  656. return false;
  657. }
  658. void IslAstInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
  659. // Get the Common analysis usage of ScopPasses.
  660. ScopPass::getAnalysisUsage(AU);
  661. AU.addRequiredTransitive<ScopInfoRegionPass>();
  662. AU.addRequired<DependenceInfo>();
  663. AU.addPreserved<DependenceInfo>();
  664. }
  665. void IslAstInfoWrapperPass::printScop(raw_ostream &OS, Scop &S) const {
  666. OS << "Printing analysis 'Polly - Generate an AST of the SCoP (isl)'"
  667. << S.getName() << "' in function '" << S.getFunction().getName() << "':\n";
  668. if (Ast)
  669. Ast->print(OS);
  670. }
  671. char IslAstInfoWrapperPass::ID = 0;
  672. Pass *polly::createIslAstInfoWrapperPassPass() {
  673. return new IslAstInfoWrapperPass();
  674. }
  675. INITIALIZE_PASS_BEGIN(IslAstInfoWrapperPass, "polly-ast",
  676. "Polly - Generate an AST of the SCoP (isl)", false,
  677. false);
  678. INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass);
  679. INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
  680. INITIALIZE_PASS_END(IslAstInfoWrapperPass, "polly-ast",
  681. "Polly - Generate an AST from the SCoP (isl)", false, false)