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