JSONExporter.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. //===-- JSONExporter.cpp - Export Scops as JSON -------------------------===//
  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. // Export the Scops build by ScopInfo pass as a JSON file.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "polly/JSONExporter.h"
  13. #include "polly/DependenceInfo.h"
  14. #include "polly/LinkAllPasses.h"
  15. #include "polly/Options.h"
  16. #include "polly/ScopInfo.h"
  17. #include "polly/ScopPass.h"
  18. #include "polly/Support/ISLTools.h"
  19. #include "polly/Support/ScopLocation.h"
  20. #include "llvm/ADT/Statistic.h"
  21. #include "llvm/IR/Module.h"
  22. #include "llvm/Support/FileSystem.h"
  23. #include "llvm/Support/JSON.h"
  24. #include "llvm/Support/MemoryBuffer.h"
  25. #include "llvm/Support/ToolOutputFile.h"
  26. #include "llvm/Support/raw_ostream.h"
  27. #include "isl/map.h"
  28. #include "isl/set.h"
  29. #include <memory>
  30. #include <string>
  31. #include <system_error>
  32. using namespace llvm;
  33. using namespace polly;
  34. #define DEBUG_TYPE "polly-import-jscop"
  35. STATISTIC(NewAccessMapFound, "Number of updated access functions");
  36. namespace {
  37. static cl::opt<std::string>
  38. ImportDir("polly-import-jscop-dir",
  39. cl::desc("The directory to import the .jscop files from."),
  40. cl::Hidden, cl::value_desc("Directory path"), cl::ValueRequired,
  41. cl::init("."), cl::cat(PollyCategory));
  42. static cl::opt<std::string>
  43. ImportPostfix("polly-import-jscop-postfix",
  44. cl::desc("Postfix to append to the import .jsop files."),
  45. cl::Hidden, cl::value_desc("File postfix"), cl::ValueRequired,
  46. cl::init(""), cl::cat(PollyCategory));
  47. class JSONExporter : public ScopPass {
  48. public:
  49. static char ID;
  50. explicit JSONExporter() : ScopPass(ID) {}
  51. /// Export the SCoP @p S to a JSON file.
  52. bool runOnScop(Scop &S) override;
  53. /// Print the SCoP @p S as it is exported.
  54. void printScop(raw_ostream &OS, Scop &S) const override;
  55. /// Register all analyses and transformation required.
  56. void getAnalysisUsage(AnalysisUsage &AU) const override;
  57. };
  58. class JSONImporter : public ScopPass {
  59. public:
  60. static char ID;
  61. std::vector<std::string> NewAccessStrings;
  62. explicit JSONImporter() : ScopPass(ID) {}
  63. /// Import new access functions for SCoP @p S from a JSON file.
  64. bool runOnScop(Scop &S) override;
  65. /// Print the SCoP @p S and the imported access functions.
  66. void printScop(raw_ostream &OS, Scop &S) const override;
  67. /// Register all analyses and transformation required.
  68. void getAnalysisUsage(AnalysisUsage &AU) const override;
  69. };
  70. } // namespace
  71. static std::string getFileName(Scop &S, StringRef Suffix = "") {
  72. std::string FunctionName = S.getFunction().getName().str();
  73. std::string FileName = FunctionName + "___" + S.getNameStr() + ".jscop";
  74. if (Suffix != "")
  75. FileName += "." + Suffix.str();
  76. return FileName;
  77. }
  78. /// Export all arrays from the Scop.
  79. ///
  80. /// @param S The Scop containing the arrays.
  81. ///
  82. /// @returns Json::Value containing the arrays.
  83. static json::Array exportArrays(const Scop &S) {
  84. json::Array Arrays;
  85. std::string Buffer;
  86. llvm::raw_string_ostream RawStringOstream(Buffer);
  87. for (auto &SAI : S.arrays()) {
  88. if (!SAI->isArrayKind())
  89. continue;
  90. json::Object Array;
  91. json::Array Sizes;
  92. Array["name"] = SAI->getName();
  93. unsigned i = 0;
  94. if (!SAI->getDimensionSize(i)) {
  95. Sizes.push_back("*");
  96. i++;
  97. }
  98. for (; i < SAI->getNumberOfDimensions(); i++) {
  99. SAI->getDimensionSize(i)->print(RawStringOstream);
  100. Sizes.push_back(RawStringOstream.str());
  101. Buffer.clear();
  102. }
  103. Array["sizes"] = std::move(Sizes);
  104. SAI->getElementType()->print(RawStringOstream);
  105. Array["type"] = RawStringOstream.str();
  106. Buffer.clear();
  107. Arrays.push_back(std::move(Array));
  108. }
  109. return Arrays;
  110. }
  111. static json::Value getJSON(Scop &S) {
  112. json::Object root;
  113. unsigned LineBegin, LineEnd;
  114. std::string FileName;
  115. getDebugLocation(&S.getRegion(), LineBegin, LineEnd, FileName);
  116. std::string Location;
  117. if (LineBegin != (unsigned)-1)
  118. Location = FileName + ":" + std::to_string(LineBegin) + "-" +
  119. std::to_string(LineEnd);
  120. root["name"] = S.getNameStr();
  121. root["context"] = S.getContextStr();
  122. if (LineBegin != (unsigned)-1)
  123. root["location"] = Location;
  124. root["arrays"] = exportArrays(S);
  125. root["statements"];
  126. json::Array Statements;
  127. for (ScopStmt &Stmt : S) {
  128. json::Object statement;
  129. statement["name"] = Stmt.getBaseName();
  130. statement["domain"] = Stmt.getDomainStr();
  131. statement["schedule"] = Stmt.getScheduleStr();
  132. json::Array Accesses;
  133. for (MemoryAccess *MA : Stmt) {
  134. json::Object access;
  135. access["kind"] = MA->isRead() ? "read" : "write";
  136. access["relation"] = MA->getAccessRelationStr();
  137. Accesses.push_back(std::move(access));
  138. }
  139. statement["accesses"] = std::move(Accesses);
  140. Statements.push_back(std::move(statement));
  141. }
  142. root["statements"] = std::move(Statements);
  143. return json::Value(std::move(root));
  144. }
  145. static void exportScop(Scop &S) {
  146. std::string FileName = ImportDir + "/" + getFileName(S);
  147. json::Value jscop = getJSON(S);
  148. // Write to file.
  149. std::error_code EC;
  150. ToolOutputFile F(FileName, EC, llvm::sys::fs::OF_TextWithCRLF);
  151. std::string FunctionName = S.getFunction().getName().str();
  152. errs() << "Writing JScop '" << S.getNameStr() << "' in function '"
  153. << FunctionName << "' to '" << FileName << "'.\n";
  154. if (!EC) {
  155. F.os() << formatv("{0:3}", jscop);
  156. F.os().close();
  157. if (!F.os().has_error()) {
  158. errs() << "\n";
  159. F.keep();
  160. return;
  161. }
  162. }
  163. errs() << " error opening file for writing!\n";
  164. F.os().clear_error();
  165. }
  166. typedef Dependences::StatementToIslMapTy StatementToIslMapTy;
  167. /// Import a new context from JScop.
  168. ///
  169. /// @param S The scop to update.
  170. /// @param JScop The JScop file describing the new schedule.
  171. ///
  172. /// @returns True if the import succeeded, otherwise False.
  173. static bool importContext(Scop &S, const json::Object &JScop) {
  174. isl::set OldContext = S.getContext();
  175. // Check if key 'context' is present.
  176. if (!JScop.get("context")) {
  177. errs() << "JScop file has no key named 'context'.\n";
  178. return false;
  179. }
  180. isl::set NewContext =
  181. isl::set{S.getIslCtx().get(), JScop.getString("context").value().str()};
  182. // Check whether the context was parsed successfully.
  183. if (NewContext.is_null()) {
  184. errs() << "The context was not parsed successfully by ISL.\n";
  185. return false;
  186. }
  187. // Check if the isl_set is a parameter set.
  188. if (!NewContext.is_params()) {
  189. errs() << "The isl_set is not a parameter set.\n";
  190. return false;
  191. }
  192. unsigned OldContextDim = unsignedFromIslSize(OldContext.dim(isl::dim::param));
  193. unsigned NewContextDim = unsignedFromIslSize(NewContext.dim(isl::dim::param));
  194. // Check if the imported context has the right number of parameters.
  195. if (OldContextDim != NewContextDim) {
  196. errs() << "Imported context has the wrong number of parameters : "
  197. << "Found " << NewContextDim << " Expected " << OldContextDim
  198. << "\n";
  199. return false;
  200. }
  201. for (unsigned i = 0; i < OldContextDim; i++) {
  202. isl::id Id = OldContext.get_dim_id(isl::dim::param, i);
  203. NewContext = NewContext.set_dim_id(isl::dim::param, i, Id);
  204. }
  205. S.setContext(NewContext);
  206. return true;
  207. }
  208. /// Import a new schedule from JScop.
  209. ///
  210. /// ... and verify that the new schedule does preserve existing data
  211. /// dependences.
  212. ///
  213. /// @param S The scop to update.
  214. /// @param JScop The JScop file describing the new schedule.
  215. /// @param D The data dependences of the @p S.
  216. ///
  217. /// @returns True if the import succeeded, otherwise False.
  218. static bool importSchedule(Scop &S, const json::Object &JScop,
  219. const Dependences &D) {
  220. StatementToIslMapTy NewSchedule;
  221. // Check if key 'statements' is present.
  222. if (!JScop.get("statements")) {
  223. errs() << "JScop file has no key name 'statements'.\n";
  224. return false;
  225. }
  226. const json::Array &statements = *JScop.getArray("statements");
  227. // Check whether the number of indices equals the number of statements
  228. if (statements.size() != S.getSize()) {
  229. errs() << "The number of indices and the number of statements differ.\n";
  230. return false;
  231. }
  232. int Index = 0;
  233. for (ScopStmt &Stmt : S) {
  234. // Check if key 'schedule' is present.
  235. if (!statements[Index].getAsObject()->get("schedule")) {
  236. errs() << "Statement " << Index << " has no 'schedule' key.\n";
  237. return false;
  238. }
  239. std::optional<StringRef> Schedule =
  240. statements[Index].getAsObject()->getString("schedule");
  241. assert(Schedule.has_value() &&
  242. "Schedules that contain extension nodes require special handling.");
  243. isl_map *Map = isl_map_read_from_str(S.getIslCtx().get(),
  244. Schedule.value().str().c_str());
  245. // Check whether the schedule was parsed successfully
  246. if (!Map) {
  247. errs() << "The schedule was not parsed successfully (index = " << Index
  248. << ").\n";
  249. return false;
  250. }
  251. isl_space *Space = Stmt.getDomainSpace().release();
  252. // Copy the old tuple id. This is necessary to retain the user pointer,
  253. // that stores the reference to the ScopStmt this schedule belongs to.
  254. Map = isl_map_set_tuple_id(Map, isl_dim_in,
  255. isl_space_get_tuple_id(Space, isl_dim_set));
  256. for (isl_size i = 0; i < isl_space_dim(Space, isl_dim_param); i++) {
  257. isl_id *Id = isl_space_get_dim_id(Space, isl_dim_param, i);
  258. Map = isl_map_set_dim_id(Map, isl_dim_param, i, Id);
  259. }
  260. isl_space_free(Space);
  261. NewSchedule[&Stmt] = isl::manage(Map);
  262. Index++;
  263. }
  264. // Check whether the new schedule is valid or not.
  265. if (!D.isValidSchedule(S, NewSchedule)) {
  266. errs() << "JScop file contains a schedule that changes the "
  267. << "dependences. Use -disable-polly-legality to continue anyways\n";
  268. return false;
  269. }
  270. auto ScheduleMap = isl::union_map::empty(S.getIslCtx());
  271. for (ScopStmt &Stmt : S) {
  272. if (NewSchedule.find(&Stmt) != NewSchedule.end())
  273. ScheduleMap = ScheduleMap.unite(NewSchedule[&Stmt]);
  274. else
  275. ScheduleMap = ScheduleMap.unite(Stmt.getSchedule());
  276. }
  277. S.setSchedule(ScheduleMap);
  278. return true;
  279. }
  280. /// Import new memory accesses from JScop.
  281. ///
  282. /// @param S The scop to update.
  283. /// @param JScop The JScop file describing the new schedule.
  284. /// @param DL The data layout to assume.
  285. /// @param NewAccessStrings optionally record the imported access strings
  286. ///
  287. /// @returns True if the import succeeded, otherwise False.
  288. static bool
  289. importAccesses(Scop &S, const json::Object &JScop, const DataLayout &DL,
  290. std::vector<std::string> *NewAccessStrings = nullptr) {
  291. int StatementIdx = 0;
  292. // Check if key 'statements' is present.
  293. if (!JScop.get("statements")) {
  294. errs() << "JScop file has no key name 'statements'.\n";
  295. return false;
  296. }
  297. const json::Array &statements = *JScop.getArray("statements");
  298. // Check whether the number of indices equals the number of statements
  299. if (statements.size() != S.getSize()) {
  300. errs() << "The number of indices and the number of statements differ.\n";
  301. return false;
  302. }
  303. for (ScopStmt &Stmt : S) {
  304. int MemoryAccessIdx = 0;
  305. const json::Object *Statement = statements[StatementIdx].getAsObject();
  306. assert(Statement);
  307. // Check if key 'accesses' is present.
  308. if (!Statement->get("accesses")) {
  309. errs()
  310. << "Statement from JScop file has no key name 'accesses' for index "
  311. << StatementIdx << ".\n";
  312. return false;
  313. }
  314. const json::Array &JsonAccesses = *Statement->getArray("accesses");
  315. // Check whether the number of indices equals the number of memory
  316. // accesses
  317. if (Stmt.size() != JsonAccesses.size()) {
  318. errs() << "The number of memory accesses in the JSop file and the number "
  319. "of memory accesses differ for index "
  320. << StatementIdx << ".\n";
  321. return false;
  322. }
  323. for (MemoryAccess *MA : Stmt) {
  324. // Check if key 'relation' is present.
  325. const json::Object *JsonMemoryAccess =
  326. JsonAccesses[MemoryAccessIdx].getAsObject();
  327. assert(JsonMemoryAccess);
  328. if (!JsonMemoryAccess->get("relation")) {
  329. errs() << "Memory access number " << MemoryAccessIdx
  330. << " has no key name 'relation' for statement number "
  331. << StatementIdx << ".\n";
  332. return false;
  333. }
  334. StringRef Accesses = *JsonMemoryAccess->getString("relation");
  335. isl_map *NewAccessMap =
  336. isl_map_read_from_str(S.getIslCtx().get(), Accesses.str().c_str());
  337. // Check whether the access was parsed successfully
  338. if (!NewAccessMap) {
  339. errs() << "The access was not parsed successfully by ISL.\n";
  340. return false;
  341. }
  342. isl_map *CurrentAccessMap = MA->getAccessRelation().release();
  343. // Check if the number of parameter change
  344. if (isl_map_dim(NewAccessMap, isl_dim_param) !=
  345. isl_map_dim(CurrentAccessMap, isl_dim_param)) {
  346. errs() << "JScop file changes the number of parameter dimensions.\n";
  347. isl_map_free(CurrentAccessMap);
  348. isl_map_free(NewAccessMap);
  349. return false;
  350. }
  351. isl_id *NewOutId;
  352. // If the NewAccessMap has zero dimensions, it is the scalar access; it
  353. // must be the same as before.
  354. // If it has at least one dimension, it's an array access; search for
  355. // its ScopArrayInfo.
  356. if (isl_map_dim(NewAccessMap, isl_dim_out) >= 1) {
  357. NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out);
  358. auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId));
  359. isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
  360. auto *OutSAI = ScopArrayInfo::getFromId(isl::manage(OutId));
  361. if (!SAI || SAI->getElementType() != OutSAI->getElementType()) {
  362. errs() << "JScop file contains access function with undeclared "
  363. "ScopArrayInfo\n";
  364. isl_map_free(CurrentAccessMap);
  365. isl_map_free(NewAccessMap);
  366. isl_id_free(NewOutId);
  367. return false;
  368. }
  369. isl_id_free(NewOutId);
  370. NewOutId = SAI->getBasePtrId().release();
  371. } else {
  372. NewOutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
  373. }
  374. NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, NewOutId);
  375. if (MA->isArrayKind()) {
  376. // We keep the old alignment, thus we cannot allow accesses to memory
  377. // locations that were not accessed before if the alignment of the
  378. // access is not the default alignment.
  379. bool SpecialAlignment = true;
  380. if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) {
  381. SpecialAlignment =
  382. DL.getABITypeAlign(LoadI->getType()) != LoadI->getAlign();
  383. } else if (StoreInst *StoreI =
  384. dyn_cast<StoreInst>(MA->getAccessInstruction())) {
  385. SpecialAlignment =
  386. DL.getABITypeAlign(StoreI->getValueOperand()->getType()) !=
  387. StoreI->getAlign();
  388. }
  389. if (SpecialAlignment) {
  390. isl_set *NewAccessSet = isl_map_range(isl_map_copy(NewAccessMap));
  391. isl_set *CurrentAccessSet =
  392. isl_map_range(isl_map_copy(CurrentAccessMap));
  393. bool IsSubset = isl_set_is_subset(NewAccessSet, CurrentAccessSet);
  394. isl_set_free(NewAccessSet);
  395. isl_set_free(CurrentAccessSet);
  396. // Check if the JScop file changes the accessed memory.
  397. if (!IsSubset) {
  398. errs() << "JScop file changes the accessed memory\n";
  399. isl_map_free(CurrentAccessMap);
  400. isl_map_free(NewAccessMap);
  401. return false;
  402. }
  403. }
  404. }
  405. // We need to copy the isl_ids for the parameter dimensions to the new
  406. // map. Without doing this the current map would have different
  407. // ids then the new one, even though both are named identically.
  408. for (isl_size i = 0; i < isl_map_dim(CurrentAccessMap, isl_dim_param);
  409. i++) {
  410. isl_id *Id = isl_map_get_dim_id(CurrentAccessMap, isl_dim_param, i);
  411. NewAccessMap = isl_map_set_dim_id(NewAccessMap, isl_dim_param, i, Id);
  412. }
  413. // Copy the old tuple id. This is necessary to retain the user pointer,
  414. // that stores the reference to the ScopStmt this access belongs to.
  415. isl_id *Id = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_in);
  416. NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_in, Id);
  417. auto NewAccessDomain = isl_map_domain(isl_map_copy(NewAccessMap));
  418. auto CurrentAccessDomain = isl_map_domain(isl_map_copy(CurrentAccessMap));
  419. if (!isl_set_has_equal_space(NewAccessDomain, CurrentAccessDomain)) {
  420. errs() << "JScop file contains access function with incompatible "
  421. << "dimensions\n";
  422. isl_map_free(CurrentAccessMap);
  423. isl_map_free(NewAccessMap);
  424. isl_set_free(NewAccessDomain);
  425. isl_set_free(CurrentAccessDomain);
  426. return false;
  427. }
  428. NewAccessDomain =
  429. isl_set_intersect_params(NewAccessDomain, S.getContext().release());
  430. CurrentAccessDomain = isl_set_intersect_params(CurrentAccessDomain,
  431. S.getContext().release());
  432. CurrentAccessDomain =
  433. isl_set_intersect(CurrentAccessDomain, Stmt.getDomain().release());
  434. if (MA->isRead() &&
  435. isl_set_is_subset(CurrentAccessDomain, NewAccessDomain) ==
  436. isl_bool_false) {
  437. errs() << "Mapping not defined for all iteration domain elements\n";
  438. isl_set_free(CurrentAccessDomain);
  439. isl_set_free(NewAccessDomain);
  440. isl_map_free(CurrentAccessMap);
  441. isl_map_free(NewAccessMap);
  442. return false;
  443. }
  444. isl_set_free(CurrentAccessDomain);
  445. isl_set_free(NewAccessDomain);
  446. if (!isl_map_is_equal(NewAccessMap, CurrentAccessMap)) {
  447. // Statistics.
  448. ++NewAccessMapFound;
  449. if (NewAccessStrings)
  450. NewAccessStrings->push_back(Accesses.str());
  451. MA->setNewAccessRelation(isl::manage(NewAccessMap));
  452. } else {
  453. isl_map_free(NewAccessMap);
  454. }
  455. isl_map_free(CurrentAccessMap);
  456. MemoryAccessIdx++;
  457. }
  458. StatementIdx++;
  459. }
  460. return true;
  461. }
  462. /// Check whether @p SAI and @p Array represent the same array.
  463. static bool areArraysEqual(ScopArrayInfo *SAI, const json::Object &Array) {
  464. std::string Buffer;
  465. llvm::raw_string_ostream RawStringOstream(Buffer);
  466. // Check if key 'type' is present.
  467. if (!Array.get("type")) {
  468. errs() << "Array has no key 'type'.\n";
  469. return false;
  470. }
  471. // Check if key 'sizes' is present.
  472. if (!Array.get("sizes")) {
  473. errs() << "Array has no key 'sizes'.\n";
  474. return false;
  475. }
  476. // Check if key 'name' is present.
  477. if (!Array.get("name")) {
  478. errs() << "Array has no key 'name'.\n";
  479. return false;
  480. }
  481. if (SAI->getName() != *Array.getString("name"))
  482. return false;
  483. if (SAI->getNumberOfDimensions() != Array.getArray("sizes")->size())
  484. return false;
  485. for (unsigned i = 1; i < Array.getArray("sizes")->size(); i++) {
  486. SAI->getDimensionSize(i)->print(RawStringOstream);
  487. const json::Array &SizesArray = *Array.getArray("sizes");
  488. if (RawStringOstream.str() != SizesArray[i].getAsString().value())
  489. return false;
  490. Buffer.clear();
  491. }
  492. // Check if key 'type' differs from the current one or is not valid.
  493. SAI->getElementType()->print(RawStringOstream);
  494. if (RawStringOstream.str() != Array.getString("type").value()) {
  495. errs() << "Array has not a valid type.\n";
  496. return false;
  497. }
  498. return true;
  499. }
  500. /// Get the accepted primitive type from its textual representation
  501. /// @p TypeTextRepresentation.
  502. ///
  503. /// @param TypeTextRepresentation The textual representation of the type.
  504. /// @return The pointer to the primitive type, if this type is accepted
  505. /// or nullptr otherwise.
  506. static Type *parseTextType(const std::string &TypeTextRepresentation,
  507. LLVMContext &LLVMContext) {
  508. std::map<std::string, Type *> MapStrToType = {
  509. {"void", Type::getVoidTy(LLVMContext)},
  510. {"half", Type::getHalfTy(LLVMContext)},
  511. {"float", Type::getFloatTy(LLVMContext)},
  512. {"double", Type::getDoubleTy(LLVMContext)},
  513. {"x86_fp80", Type::getX86_FP80Ty(LLVMContext)},
  514. {"fp128", Type::getFP128Ty(LLVMContext)},
  515. {"ppc_fp128", Type::getPPC_FP128Ty(LLVMContext)},
  516. {"i1", Type::getInt1Ty(LLVMContext)},
  517. {"i8", Type::getInt8Ty(LLVMContext)},
  518. {"i16", Type::getInt16Ty(LLVMContext)},
  519. {"i32", Type::getInt32Ty(LLVMContext)},
  520. {"i64", Type::getInt64Ty(LLVMContext)},
  521. {"i128", Type::getInt128Ty(LLVMContext)}};
  522. auto It = MapStrToType.find(TypeTextRepresentation);
  523. if (It != MapStrToType.end())
  524. return It->second;
  525. errs() << "Textual representation can not be parsed: "
  526. << TypeTextRepresentation << "\n";
  527. return nullptr;
  528. }
  529. /// Import new arrays from JScop.
  530. ///
  531. /// @param S The scop to update.
  532. /// @param JScop The JScop file describing new arrays.
  533. ///
  534. /// @returns True if the import succeeded, otherwise False.
  535. static bool importArrays(Scop &S, const json::Object &JScop) {
  536. if (!JScop.get("arrays"))
  537. return true;
  538. const json::Array &Arrays = *JScop.getArray("arrays");
  539. if (Arrays.size() == 0)
  540. return true;
  541. unsigned ArrayIdx = 0;
  542. for (auto &SAI : S.arrays()) {
  543. if (!SAI->isArrayKind())
  544. continue;
  545. if (ArrayIdx + 1 > Arrays.size()) {
  546. errs() << "Not enough array entries in JScop file.\n";
  547. return false;
  548. }
  549. if (!areArraysEqual(SAI, *Arrays[ArrayIdx].getAsObject())) {
  550. errs() << "No match for array '" << SAI->getName() << "' in JScop.\n";
  551. return false;
  552. }
  553. ArrayIdx++;
  554. }
  555. for (; ArrayIdx < Arrays.size(); ArrayIdx++) {
  556. const json::Object &Array = *Arrays[ArrayIdx].getAsObject();
  557. auto *ElementType =
  558. parseTextType(Array.get("type")->getAsString().value().str(),
  559. S.getSE()->getContext());
  560. if (!ElementType) {
  561. errs() << "Error while parsing element type for new array.\n";
  562. return false;
  563. }
  564. const json::Array &SizesArray = *Array.getArray("sizes");
  565. std::vector<unsigned> DimSizes;
  566. for (unsigned i = 0; i < SizesArray.size(); i++) {
  567. auto Size = std::stoi(SizesArray[i].getAsString()->str());
  568. // Check if the size if positive.
  569. if (Size <= 0) {
  570. errs() << "The size at index " << i << " is =< 0.\n";
  571. return false;
  572. }
  573. DimSizes.push_back(Size);
  574. }
  575. auto NewSAI = S.createScopArrayInfo(
  576. ElementType, Array.getString("name").value().str(), DimSizes);
  577. if (Array.get("allocation")) {
  578. NewSAI->setIsOnHeap(Array.getString("allocation").value() == "heap");
  579. }
  580. }
  581. return true;
  582. }
  583. /// Import a Scop from a JSCOP file
  584. /// @param S The scop to be modified
  585. /// @param D Dependence Info
  586. /// @param DL The DataLayout of the function
  587. /// @param NewAccessStrings Optionally record the imported access strings
  588. ///
  589. /// @returns true on success, false otherwise. Beware that if this returns
  590. /// false, the Scop may still have been modified. In this case the Scop contains
  591. /// invalid information.
  592. static bool importScop(Scop &S, const Dependences &D, const DataLayout &DL,
  593. std::vector<std::string> *NewAccessStrings = nullptr) {
  594. std::string FileName = ImportDir + "/" + getFileName(S, ImportPostfix);
  595. std::string FunctionName = S.getFunction().getName().str();
  596. errs() << "Reading JScop '" << S.getNameStr() << "' in function '"
  597. << FunctionName << "' from '" << FileName << "'.\n";
  598. ErrorOr<std::unique_ptr<MemoryBuffer>> result =
  599. MemoryBuffer::getFile(FileName);
  600. std::error_code ec = result.getError();
  601. if (ec) {
  602. errs() << "File could not be read: " << ec.message() << "\n";
  603. return false;
  604. }
  605. Expected<json::Value> ParseResult =
  606. json::parse(result.get().get()->getBuffer());
  607. if (Error E = ParseResult.takeError()) {
  608. errs() << "JSCoP file could not be parsed\n";
  609. errs() << E << "\n";
  610. consumeError(std::move(E));
  611. return false;
  612. }
  613. json::Object &jscop = *ParseResult.get().getAsObject();
  614. bool Success = importContext(S, jscop);
  615. if (!Success)
  616. return false;
  617. Success = importSchedule(S, jscop, D);
  618. if (!Success)
  619. return false;
  620. Success = importArrays(S, jscop);
  621. if (!Success)
  622. return false;
  623. Success = importAccesses(S, jscop, DL, NewAccessStrings);
  624. if (!Success)
  625. return false;
  626. return true;
  627. }
  628. char JSONExporter::ID = 0;
  629. void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { OS << S; }
  630. bool JSONExporter::runOnScop(Scop &S) {
  631. exportScop(S);
  632. return false;
  633. }
  634. void JSONExporter::getAnalysisUsage(AnalysisUsage &AU) const {
  635. AU.setPreservesAll();
  636. AU.addRequired<ScopInfoRegionPass>();
  637. }
  638. Pass *polly::createJSONExporterPass() { return new JSONExporter(); }
  639. PreservedAnalyses JSONExportPass::run(Scop &S, ScopAnalysisManager &SAM,
  640. ScopStandardAnalysisResults &SAR,
  641. SPMUpdater &) {
  642. exportScop(S);
  643. return PreservedAnalyses::all();
  644. }
  645. char JSONImporter::ID = 0;
  646. void JSONImporter::printScop(raw_ostream &OS, Scop &S) const {
  647. OS << S;
  648. for (std::vector<std::string>::const_iterator I = NewAccessStrings.begin(),
  649. E = NewAccessStrings.end();
  650. I != E; I++)
  651. OS << "New access function '" << *I << "' detected in JSCOP file\n";
  652. }
  653. bool JSONImporter::runOnScop(Scop &S) {
  654. const Dependences &D =
  655. getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement);
  656. const DataLayout &DL = S.getFunction().getParent()->getDataLayout();
  657. if (!importScop(S, D, DL, &NewAccessStrings))
  658. report_fatal_error("Tried to import a malformed jscop file.");
  659. return false;
  660. }
  661. void JSONImporter::getAnalysisUsage(AnalysisUsage &AU) const {
  662. ScopPass::getAnalysisUsage(AU);
  663. AU.addRequired<DependenceInfo>();
  664. // TODO: JSONImporter should throw away DependenceInfo.
  665. AU.addPreserved<DependenceInfo>();
  666. }
  667. Pass *polly::createJSONImporterPass() { return new JSONImporter(); }
  668. PreservedAnalyses JSONImportPass::run(Scop &S, ScopAnalysisManager &SAM,
  669. ScopStandardAnalysisResults &SAR,
  670. SPMUpdater &) {
  671. const Dependences &D =
  672. SAM.getResult<DependenceAnalysis>(S, SAR).getDependences(
  673. Dependences::AL_Statement);
  674. const DataLayout &DL = S.getFunction().getParent()->getDataLayout();
  675. if (!importScop(S, D, DL))
  676. report_fatal_error("Tried to import a malformed jscop file.");
  677. // This invalidates all analyses on Scop.
  678. PreservedAnalyses PA;
  679. PA.preserveSet<AllAnalysesOn<Module>>();
  680. PA.preserveSet<AllAnalysesOn<Function>>();
  681. PA.preserveSet<AllAnalysesOn<Loop>>();
  682. return PA;
  683. }
  684. INITIALIZE_PASS_BEGIN(JSONExporter, "polly-export-jscop",
  685. "Polly - Export Scops as JSON"
  686. " (Writes a .jscop file for each Scop)",
  687. false, false);
  688. INITIALIZE_PASS_DEPENDENCY(DependenceInfo)
  689. INITIALIZE_PASS_END(JSONExporter, "polly-export-jscop",
  690. "Polly - Export Scops as JSON"
  691. " (Writes a .jscop file for each Scop)",
  692. false, false)
  693. INITIALIZE_PASS_BEGIN(JSONImporter, "polly-import-jscop",
  694. "Polly - Import Scops from JSON"
  695. " (Reads a .jscop file for each Scop)",
  696. false, false);
  697. INITIALIZE_PASS_DEPENDENCY(DependenceInfo)
  698. INITIALIZE_PASS_END(JSONImporter, "polly-import-jscop",
  699. "Polly - Import Scops from JSON"
  700. " (Reads a .jscop file for each Scop)",
  701. false, false)
  702. //===----------------------------------------------------------------------===//
  703. namespace {
  704. /// Print result from JSONImporter.
  705. class JSONImporterPrinterLegacyPass final : public ScopPass {
  706. public:
  707. static char ID;
  708. JSONImporterPrinterLegacyPass() : JSONImporterPrinterLegacyPass(outs()){};
  709. explicit JSONImporterPrinterLegacyPass(llvm::raw_ostream &OS)
  710. : ScopPass(ID), OS(OS) {}
  711. bool runOnScop(Scop &S) override {
  712. JSONImporter &P = getAnalysis<JSONImporter>();
  713. OS << "Printing analysis '" << P.getPassName() << "' for region: '"
  714. << S.getRegion().getNameStr() << "' in function '"
  715. << S.getFunction().getName() << "':\n";
  716. P.printScop(OS, S);
  717. return false;
  718. }
  719. void getAnalysisUsage(AnalysisUsage &AU) const override {
  720. ScopPass::getAnalysisUsage(AU);
  721. AU.addRequired<JSONImporter>();
  722. AU.setPreservesAll();
  723. }
  724. private:
  725. llvm::raw_ostream &OS;
  726. };
  727. char JSONImporterPrinterLegacyPass::ID = 0;
  728. } // namespace
  729. Pass *polly::createJSONImporterPrinterLegacyPass(llvm::raw_ostream &OS) {
  730. return new JSONImporterPrinterLegacyPass(OS);
  731. }
  732. INITIALIZE_PASS_BEGIN(JSONImporterPrinterLegacyPass, "polly-print-import-jscop",
  733. "Polly - Print Scop import result", false, false)
  734. INITIALIZE_PASS_DEPENDENCY(JSONImporter)
  735. INITIALIZE_PASS_END(JSONImporterPrinterLegacyPass, "polly-print-import-jscop",
  736. "Polly - Print Scop import result", false, false)