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