JSONExporter.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  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. struct JSONExporter : public ScopPass {
  48. static char ID;
  49. explicit JSONExporter() : ScopPass(ID) {}
  50. /// Export the SCoP @p S to a JSON file.
  51. bool runOnScop(Scop &S) override;
  52. /// Print the SCoP @p S as it is exported.
  53. void printScop(raw_ostream &OS, Scop &S) const override;
  54. /// Register all analyses and transformation required.
  55. void getAnalysisUsage(AnalysisUsage &AU) const override;
  56. };
  57. struct JSONImporter : public ScopPass {
  58. static char ID;
  59. std::vector<std::string> NewAccessStrings;
  60. explicit JSONImporter() : ScopPass(ID) {}
  61. /// Import new access functions for SCoP @p S from a JSON file.
  62. bool runOnScop(Scop &S) override;
  63. /// Print the SCoP @p S and the imported access functions.
  64. void printScop(raw_ostream &OS, Scop &S) const override;
  65. /// Register all analyses and transformation required.
  66. void getAnalysisUsage(AnalysisUsage &AU) const override;
  67. };
  68. } // namespace
  69. static std::string getFileName(Scop &S, StringRef Suffix = "") {
  70. std::string FunctionName = S.getFunction().getName().str();
  71. std::string FileName = FunctionName + "___" + S.getNameStr() + ".jscop";
  72. if (Suffix != "")
  73. FileName += "." + Suffix.str();
  74. return FileName;
  75. }
  76. /// Export all arrays from the Scop.
  77. ///
  78. /// @param S The Scop containing the arrays.
  79. ///
  80. /// @returns Json::Value containing the arrays.
  81. static json::Array exportArrays(const Scop &S) {
  82. json::Array Arrays;
  83. std::string Buffer;
  84. llvm::raw_string_ostream RawStringOstream(Buffer);
  85. for (auto &SAI : S.arrays()) {
  86. if (!SAI->isArrayKind())
  87. continue;
  88. json::Object Array;
  89. json::Array Sizes;
  90. Array["name"] = SAI->getName();
  91. unsigned i = 0;
  92. if (!SAI->getDimensionSize(i)) {
  93. Sizes.push_back("*");
  94. i++;
  95. }
  96. for (; i < SAI->getNumberOfDimensions(); i++) {
  97. SAI->getDimensionSize(i)->print(RawStringOstream);
  98. Sizes.push_back(RawStringOstream.str());
  99. Buffer.clear();
  100. }
  101. Array["sizes"] = std::move(Sizes);
  102. SAI->getElementType()->print(RawStringOstream);
  103. Array["type"] = RawStringOstream.str();
  104. Buffer.clear();
  105. Arrays.push_back(std::move(Array));
  106. }
  107. return Arrays;
  108. }
  109. static json::Value getJSON(Scop &S) {
  110. json::Object root;
  111. unsigned LineBegin, LineEnd;
  112. std::string FileName;
  113. getDebugLocation(&S.getRegion(), LineBegin, LineEnd, FileName);
  114. std::string Location;
  115. if (LineBegin != (unsigned)-1)
  116. Location = FileName + ":" + std::to_string(LineBegin) + "-" +
  117. std::to_string(LineEnd);
  118. root["name"] = S.getNameStr();
  119. root["context"] = S.getContextStr();
  120. if (LineBegin != (unsigned)-1)
  121. root["location"] = Location;
  122. root["arrays"] = exportArrays(S);
  123. root["statements"];
  124. json::Array Statements;
  125. for (ScopStmt &Stmt : S) {
  126. json::Object statement;
  127. statement["name"] = Stmt.getBaseName();
  128. statement["domain"] = Stmt.getDomainStr();
  129. statement["schedule"] = Stmt.getScheduleStr();
  130. json::Array Accesses;
  131. for (MemoryAccess *MA : Stmt) {
  132. json::Object access;
  133. access["kind"] = MA->isRead() ? "read" : "write";
  134. access["relation"] = MA->getAccessRelationStr();
  135. Accesses.push_back(std::move(access));
  136. }
  137. statement["accesses"] = std::move(Accesses);
  138. Statements.push_back(std::move(statement));
  139. }
  140. root["statements"] = std::move(Statements);
  141. return json::Value(std::move(root));
  142. }
  143. static void exportScop(Scop &S) {
  144. std::string FileName = ImportDir + "/" + getFileName(S);
  145. json::Value jscop = getJSON(S);
  146. // Write to file.
  147. std::error_code EC;
  148. ToolOutputFile F(FileName, EC, llvm::sys::fs::OF_TextWithCRLF);
  149. std::string FunctionName = S.getFunction().getName().str();
  150. errs() << "Writing JScop '" << S.getNameStr() << "' in function '"
  151. << FunctionName << "' to '" << FileName << "'.\n";
  152. if (!EC) {
  153. F.os() << formatv("{0:3}", jscop);
  154. F.os().close();
  155. if (!F.os().has_error()) {
  156. errs() << "\n";
  157. F.keep();
  158. return;
  159. }
  160. }
  161. errs() << " error opening file for writing!\n";
  162. F.os().clear_error();
  163. }
  164. typedef Dependences::StatementToIslMapTy StatementToIslMapTy;
  165. /// Import a new context from JScop.
  166. ///
  167. /// @param S The scop to update.
  168. /// @param JScop The JScop file describing the new schedule.
  169. ///
  170. /// @returns True if the import succeeded, otherwise False.
  171. static bool importContext(Scop &S, const json::Object &JScop) {
  172. isl::set OldContext = S.getContext();
  173. // Check if key 'context' is present.
  174. if (!JScop.get("context")) {
  175. errs() << "JScop file has no key named 'context'.\n";
  176. return false;
  177. }
  178. isl::set NewContext = isl::set{S.getIslCtx().get(),
  179. JScop.getString("context").getValue().str()};
  180. // Check whether the context was parsed successfully.
  181. if (NewContext.is_null()) {
  182. errs() << "The context was not parsed successfully by ISL.\n";
  183. return false;
  184. }
  185. // Check if the isl_set is a parameter set.
  186. if (!NewContext.is_params()) {
  187. errs() << "The isl_set is not a parameter set.\n";
  188. return false;
  189. }
  190. unsigned OldContextDim = unsignedFromIslSize(OldContext.dim(isl::dim::param));
  191. unsigned NewContextDim = unsignedFromIslSize(NewContext.dim(isl::dim::param));
  192. // Check if the imported context has the right number of parameters.
  193. if (OldContextDim != NewContextDim) {
  194. errs() << "Imported context has the wrong number of parameters : "
  195. << "Found " << NewContextDim << " Expected " << OldContextDim
  196. << "\n";
  197. return false;
  198. }
  199. for (unsigned i = 0; i < OldContextDim; i++) {
  200. isl::id Id = OldContext.get_dim_id(isl::dim::param, i);
  201. NewContext = NewContext.set_dim_id(isl::dim::param, i, Id);
  202. }
  203. S.setContext(NewContext);
  204. return true;
  205. }
  206. /// Import a new schedule from JScop.
  207. ///
  208. /// ... and verify that the new schedule does preserve existing data
  209. /// dependences.
  210. ///
  211. /// @param S The scop to update.
  212. /// @param JScop The JScop file describing the new schedule.
  213. /// @param D The data dependences of the @p S.
  214. ///
  215. /// @returns True if the import succeeded, otherwise False.
  216. static bool importSchedule(Scop &S, const json::Object &JScop,
  217. const Dependences &D) {
  218. StatementToIslMapTy NewSchedule;
  219. // Check if key 'statements' is present.
  220. if (!JScop.get("statements")) {
  221. errs() << "JScop file has no key name 'statements'.\n";
  222. return false;
  223. }
  224. const json::Array &statements = *JScop.getArray("statements");
  225. // Check whether the number of indices equals the number of statements
  226. if (statements.size() != S.getSize()) {
  227. errs() << "The number of indices and the number of statements differ.\n";
  228. return false;
  229. }
  230. int Index = 0;
  231. for (ScopStmt &Stmt : S) {
  232. // Check if key 'schedule' is present.
  233. if (!statements[Index].getAsObject()->get("schedule")) {
  234. errs() << "Statement " << Index << " has no 'schedule' key.\n";
  235. return false;
  236. }
  237. Optional<StringRef> Schedule =
  238. statements[Index].getAsObject()->getString("schedule");
  239. assert(Schedule.hasValue() &&
  240. "Schedules that contain extension nodes require special handling.");
  241. isl_map *Map = isl_map_read_from_str(S.getIslCtx().get(),
  242. Schedule.getValue().str().c_str());
  243. // Check whether the schedule was parsed successfully
  244. if (!Map) {
  245. errs() << "The schedule was not parsed successfully (index = " << Index
  246. << ").\n";
  247. return false;
  248. }
  249. isl_space *Space = Stmt.getDomainSpace().release();
  250. // Copy the old tuple id. This is necessary to retain the user pointer,
  251. // that stores the reference to the ScopStmt this schedule belongs to.
  252. Map = isl_map_set_tuple_id(Map, isl_dim_in,
  253. isl_space_get_tuple_id(Space, isl_dim_set));
  254. for (isl_size i = 0; i < isl_space_dim(Space, isl_dim_param); i++) {
  255. isl_id *Id = isl_space_get_dim_id(Space, isl_dim_param, i);
  256. Map = isl_map_set_dim_id(Map, isl_dim_param, i, Id);
  257. }
  258. isl_space_free(Space);
  259. NewSchedule[&Stmt] = isl::manage(Map);
  260. Index++;
  261. }
  262. // Check whether the new schedule is valid or not.
  263. if (!D.isValidSchedule(S, NewSchedule)) {
  264. errs() << "JScop file contains a schedule that changes the "
  265. << "dependences. Use -disable-polly-legality to continue anyways\n";
  266. return false;
  267. }
  268. auto ScheduleMap = isl::union_map::empty(S.getIslCtx());
  269. for (ScopStmt &Stmt : S) {
  270. if (NewSchedule.find(&Stmt) != NewSchedule.end())
  271. ScheduleMap = ScheduleMap.unite(NewSchedule[&Stmt]);
  272. else
  273. ScheduleMap = ScheduleMap.unite(Stmt.getSchedule());
  274. }
  275. S.setSchedule(ScheduleMap);
  276. return true;
  277. }
  278. /// Import new memory accesses from JScop.
  279. ///
  280. /// @param S The scop to update.
  281. /// @param JScop The JScop file describing the new schedule.
  282. /// @param DL The data layout to assume.
  283. /// @param NewAccessStrings optionally record the imported access strings
  284. ///
  285. /// @returns True if the import succeeded, otherwise False.
  286. static bool
  287. importAccesses(Scop &S, const json::Object &JScop, const DataLayout &DL,
  288. std::vector<std::string> *NewAccessStrings = nullptr) {
  289. int StatementIdx = 0;
  290. // Check if key 'statements' is present.
  291. if (!JScop.get("statements")) {
  292. errs() << "JScop file has no key name 'statements'.\n";
  293. return false;
  294. }
  295. const json::Array &statements = *JScop.getArray("statements");
  296. // Check whether the number of indices equals the number of statements
  297. if (statements.size() != S.getSize()) {
  298. errs() << "The number of indices and the number of statements differ.\n";
  299. return false;
  300. }
  301. for (ScopStmt &Stmt : S) {
  302. int MemoryAccessIdx = 0;
  303. const json::Object *Statement = statements[StatementIdx].getAsObject();
  304. assert(Statement);
  305. // Check if key 'accesses' is present.
  306. if (!Statement->get("accesses")) {
  307. errs()
  308. << "Statement from JScop file has no key name 'accesses' for index "
  309. << StatementIdx << ".\n";
  310. return false;
  311. }
  312. const json::Array &JsonAccesses = *Statement->getArray("accesses");
  313. // Check whether the number of indices equals the number of memory
  314. // accesses
  315. if (Stmt.size() != JsonAccesses.size()) {
  316. errs() << "The number of memory accesses in the JSop file and the number "
  317. "of memory accesses differ for index "
  318. << StatementIdx << ".\n";
  319. return false;
  320. }
  321. for (MemoryAccess *MA : Stmt) {
  322. // Check if key 'relation' is present.
  323. const json::Object *JsonMemoryAccess =
  324. JsonAccesses[MemoryAccessIdx].getAsObject();
  325. assert(JsonMemoryAccess);
  326. if (!JsonMemoryAccess->get("relation")) {
  327. errs() << "Memory access number " << MemoryAccessIdx
  328. << " has no key name 'relation' for statement number "
  329. << StatementIdx << ".\n";
  330. return false;
  331. }
  332. StringRef Accesses = JsonMemoryAccess->getString("relation").getValue();
  333. isl_map *NewAccessMap =
  334. isl_map_read_from_str(S.getIslCtx().get(), Accesses.str().c_str());
  335. // Check whether the access was parsed successfully
  336. if (!NewAccessMap) {
  337. errs() << "The access was not parsed successfully by ISL.\n";
  338. return false;
  339. }
  340. isl_map *CurrentAccessMap = MA->getAccessRelation().release();
  341. // Check if the number of parameter change
  342. if (isl_map_dim(NewAccessMap, isl_dim_param) !=
  343. isl_map_dim(CurrentAccessMap, isl_dim_param)) {
  344. errs() << "JScop file changes the number of parameter dimensions.\n";
  345. isl_map_free(CurrentAccessMap);
  346. isl_map_free(NewAccessMap);
  347. return false;
  348. }
  349. isl_id *NewOutId;
  350. // If the NewAccessMap has zero dimensions, it is the scalar access; it
  351. // must be the same as before.
  352. // If it has at least one dimension, it's an array access; search for
  353. // its ScopArrayInfo.
  354. if (isl_map_dim(NewAccessMap, isl_dim_out) >= 1) {
  355. NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out);
  356. auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId));
  357. isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
  358. auto *OutSAI = ScopArrayInfo::getFromId(isl::manage(OutId));
  359. if (!SAI || SAI->getElementType() != OutSAI->getElementType()) {
  360. errs() << "JScop file contains access function with undeclared "
  361. "ScopArrayInfo\n";
  362. isl_map_free(CurrentAccessMap);
  363. isl_map_free(NewAccessMap);
  364. isl_id_free(NewOutId);
  365. return false;
  366. }
  367. isl_id_free(NewOutId);
  368. NewOutId = SAI->getBasePtrId().release();
  369. } else {
  370. NewOutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
  371. }
  372. NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, NewOutId);
  373. if (MA->isArrayKind()) {
  374. // We keep the old alignment, thus we cannot allow accesses to memory
  375. // locations that were not accessed before if the alignment of the
  376. // access is not the default alignment.
  377. bool SpecialAlignment = true;
  378. if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) {
  379. SpecialAlignment =
  380. LoadI->getAlignment() &&
  381. DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment();
  382. } else if (StoreInst *StoreI =
  383. dyn_cast<StoreInst>(MA->getAccessInstruction())) {
  384. SpecialAlignment =
  385. StoreI->getAlignment() &&
  386. DL.getABITypeAlignment(StoreI->getValueOperand()->getType()) !=
  387. StoreI->getAlignment();
  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").getValue())
  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().getValue())
  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").getValue()) {
  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().getValue().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().getValue().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").getValue().str(), DimSizes);
  577. if (Array.get("allocation")) {
  578. NewSAI->setIsOnHeap(Array.getString("allocation").getValue() == "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)