1 //===-- JSONExporter.cpp - Export Scops as JSON -------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Export the Scops build by ScopInfo pass as a JSON file.
11 //===----------------------------------------------------------------------===//
13 #include "polly/JSONExporter.h"
14 #include "polly/DependenceInfo.h"
15 #include "polly/LinkAllPasses.h"
16 #include "polly/Options.h"
17 #include "polly/ScopInfo.h"
18 #include "polly/ScopPass.h"
19 #include "polly/Support/ISLTools.h"
20 #include "polly/Support/ScopLocation.h"
21 #include "llvm/ADT/Statistic.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/Support/FileSystem.h"
24 #include "llvm/Support/JSON.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 #include "llvm/Support/ToolOutputFile.h"
27 #include "llvm/Support/raw_ostream.h"
32 #include <system_error>
35 using namespace polly
;
37 #define DEBUG_TYPE "polly-import-jscop"
39 STATISTIC(NewAccessMapFound
, "Number of updated access functions");
42 static cl::opt
<std::string
>
43 ImportDir("polly-import-jscop-dir",
44 cl::desc("The directory to import the .jscop files from."),
45 cl::Hidden
, cl::value_desc("Directory path"), cl::ValueRequired
,
46 cl::init("."), cl::cat(PollyCategory
));
48 static cl::opt
<std::string
>
49 ImportPostfix("polly-import-jscop-postfix",
50 cl::desc("Postfix to append to the import .jsop files."),
51 cl::Hidden
, cl::value_desc("File postfix"), cl::ValueRequired
,
52 cl::init(""), cl::cat(PollyCategory
));
54 class JSONExporter
: public ScopPass
{
57 explicit JSONExporter() : ScopPass(ID
) {}
59 /// Export the SCoP @p S to a JSON file.
60 bool runOnScop(Scop
&S
) override
;
62 /// Print the SCoP @p S as it is exported.
63 void printScop(raw_ostream
&OS
, Scop
&S
) const override
;
65 /// Register all analyses and transformation required.
66 void getAnalysisUsage(AnalysisUsage
&AU
) const override
;
69 class JSONImporter
: public ScopPass
{
72 std::vector
<std::string
> NewAccessStrings
;
73 explicit JSONImporter() : ScopPass(ID
) {}
74 /// Import new access functions for SCoP @p S from a JSON file.
75 bool runOnScop(Scop
&S
) override
;
77 /// Print the SCoP @p S and the imported access functions.
78 void printScop(raw_ostream
&OS
, Scop
&S
) const override
;
80 /// Register all analyses and transformation required.
81 void getAnalysisUsage(AnalysisUsage
&AU
) const override
;
85 static std::string
getFileName(Scop
&S
, StringRef Suffix
= "") {
86 std::string FunctionName
= S
.getFunction().getName().str();
87 std::string FileName
= FunctionName
+ "___" + S
.getNameStr() + ".jscop";
90 FileName
+= "." + Suffix
.str();
95 /// Export all arrays from the Scop.
97 /// @param S The Scop containing the arrays.
99 /// @returns Json::Value containing the arrays.
100 static json::Array
exportArrays(const Scop
&S
) {
103 llvm::raw_string_ostream
RawStringOstream(Buffer
);
105 for (auto &SAI
: S
.arrays()) {
106 if (!SAI
->isArrayKind())
111 Array
["name"] = SAI
->getName();
113 if (!SAI
->getDimensionSize(i
)) {
114 Sizes
.push_back("*");
117 for (; i
< SAI
->getNumberOfDimensions(); i
++) {
118 SAI
->getDimensionSize(i
)->print(RawStringOstream
);
119 Sizes
.push_back(RawStringOstream
.str());
122 Array
["sizes"] = std::move(Sizes
);
123 SAI
->getElementType()->print(RawStringOstream
);
124 Array
["type"] = RawStringOstream
.str();
126 Arrays
.push_back(std::move(Array
));
131 static json::Value
getJSON(Scop
&S
) {
133 unsigned LineBegin
, LineEnd
;
134 std::string FileName
;
136 getDebugLocation(&S
.getRegion(), LineBegin
, LineEnd
, FileName
);
137 std::string Location
;
138 if (LineBegin
!= (unsigned)-1)
139 Location
= FileName
+ ":" + std::to_string(LineBegin
) + "-" +
140 std::to_string(LineEnd
);
142 root
["name"] = S
.getNameStr();
143 root
["context"] = S
.getContextStr();
144 if (LineBegin
!= (unsigned)-1)
145 root
["location"] = Location
;
147 root
["arrays"] = exportArrays(S
);
151 json::Array Statements
;
152 for (ScopStmt
&Stmt
: S
) {
153 json::Object statement
;
155 statement
["name"] = Stmt
.getBaseName();
156 statement
["domain"] = Stmt
.getDomainStr();
157 statement
["schedule"] = Stmt
.getScheduleStr();
159 json::Array Accesses
;
160 for (MemoryAccess
*MA
: Stmt
) {
163 access
["kind"] = MA
->isRead() ? "read" : "write";
164 access
["relation"] = MA
->getAccessRelationStr();
166 Accesses
.push_back(std::move(access
));
168 statement
["accesses"] = std::move(Accesses
);
170 Statements
.push_back(std::move(statement
));
173 root
["statements"] = std::move(Statements
);
174 return json::Value(std::move(root
));
177 static void exportScop(Scop
&S
) {
178 std::string FileName
= ImportDir
+ "/" + getFileName(S
);
180 json::Value jscop
= getJSON(S
);
184 ToolOutputFile
F(FileName
, EC
, llvm::sys::fs::OF_TextWithCRLF
);
186 std::string FunctionName
= S
.getFunction().getName().str();
187 errs() << "Writing JScop '" << S
.getNameStr() << "' in function '"
188 << FunctionName
<< "' to '" << FileName
<< "'.\n";
191 F
.os() << formatv("{0:3}", jscop
);
193 if (!F
.os().has_error()) {
200 errs() << " error opening file for writing!\n";
201 F
.os().clear_error();
204 typedef Dependences::StatementToIslMapTy StatementToIslMapTy
;
206 /// Import a new context from JScop.
208 /// @param S The scop to update.
209 /// @param JScop The JScop file describing the new schedule.
211 /// @returns True if the import succeeded, otherwise False.
212 static bool importContext(Scop
&S
, const json::Object
&JScop
) {
213 isl::set OldContext
= S
.getContext();
215 // Check if key 'context' is present.
216 if (!JScop
.get("context")) {
217 errs() << "JScop file has no key named 'context'.\n";
221 isl::set NewContext
=
222 isl::set
{S
.getIslCtx().get(), JScop
.getString("context").value().str()};
224 // Check whether the context was parsed successfully.
225 if (NewContext
.is_null()) {
226 errs() << "The context was not parsed successfully by ISL.\n";
230 // Check if the isl_set is a parameter set.
231 if (!NewContext
.is_params()) {
232 errs() << "The isl_set is not a parameter set.\n";
236 unsigned OldContextDim
= unsignedFromIslSize(OldContext
.dim(isl::dim::param
));
237 unsigned NewContextDim
= unsignedFromIslSize(NewContext
.dim(isl::dim::param
));
239 // Check if the imported context has the right number of parameters.
240 if (OldContextDim
!= NewContextDim
) {
241 errs() << "Imported context has the wrong number of parameters : "
242 << "Found " << NewContextDim
<< " Expected " << OldContextDim
247 for (unsigned i
= 0; i
< OldContextDim
; i
++) {
248 isl::id Id
= OldContext
.get_dim_id(isl::dim::param
, i
);
249 NewContext
= NewContext
.set_dim_id(isl::dim::param
, i
, Id
);
252 S
.setContext(NewContext
);
256 /// Import a new schedule from JScop.
258 /// ... and verify that the new schedule does preserve existing data
261 /// @param S The scop to update.
262 /// @param JScop The JScop file describing the new schedule.
263 /// @param D The data dependences of the @p S.
265 /// @returns True if the import succeeded, otherwise False.
266 static bool importSchedule(Scop
&S
, const json::Object
&JScop
,
267 const Dependences
&D
) {
268 StatementToIslMapTy NewSchedule
;
270 // Check if key 'statements' is present.
271 if (!JScop
.get("statements")) {
272 errs() << "JScop file has no key name 'statements'.\n";
276 const json::Array
&statements
= *JScop
.getArray("statements");
278 // Check whether the number of indices equals the number of statements
279 if (statements
.size() != S
.getSize()) {
280 errs() << "The number of indices and the number of statements differ.\n";
285 for (ScopStmt
&Stmt
: S
) {
286 // Check if key 'schedule' is present.
287 if (!statements
[Index
].getAsObject()->get("schedule")) {
288 errs() << "Statement " << Index
<< " has no 'schedule' key.\n";
291 std::optional
<StringRef
> Schedule
=
292 statements
[Index
].getAsObject()->getString("schedule");
293 assert(Schedule
.has_value() &&
294 "Schedules that contain extension nodes require special handling.");
295 isl_map
*Map
= isl_map_read_from_str(S
.getIslCtx().get(),
296 Schedule
.value().str().c_str());
298 // Check whether the schedule was parsed successfully
300 errs() << "The schedule was not parsed successfully (index = " << Index
305 isl_space
*Space
= Stmt
.getDomainSpace().release();
307 // Copy the old tuple id. This is necessary to retain the user pointer,
308 // that stores the reference to the ScopStmt this schedule belongs to.
309 Map
= isl_map_set_tuple_id(Map
, isl_dim_in
,
310 isl_space_get_tuple_id(Space
, isl_dim_set
));
311 for (isl_size i
= 0; i
< isl_space_dim(Space
, isl_dim_param
); i
++) {
312 isl_id
*Id
= isl_space_get_dim_id(Space
, isl_dim_param
, i
);
313 Map
= isl_map_set_dim_id(Map
, isl_dim_param
, i
, Id
);
315 isl_space_free(Space
);
316 NewSchedule
[&Stmt
] = isl::manage(Map
);
320 // Check whether the new schedule is valid or not.
321 if (!D
.isValidSchedule(S
, NewSchedule
)) {
322 errs() << "JScop file contains a schedule that changes the "
323 << "dependences. Use -disable-polly-legality to continue anyways\n";
327 auto ScheduleMap
= isl::union_map::empty(S
.getIslCtx());
328 for (ScopStmt
&Stmt
: S
) {
329 if (NewSchedule
.contains(&Stmt
))
330 ScheduleMap
= ScheduleMap
.unite(NewSchedule
[&Stmt
]);
332 ScheduleMap
= ScheduleMap
.unite(Stmt
.getSchedule());
335 S
.setSchedule(ScheduleMap
);
340 /// Import new memory accesses from JScop.
342 /// @param S The scop to update.
343 /// @param JScop The JScop file describing the new schedule.
344 /// @param DL The data layout to assume.
345 /// @param NewAccessStrings optionally record the imported access strings
347 /// @returns True if the import succeeded, otherwise False.
349 importAccesses(Scop
&S
, const json::Object
&JScop
, const DataLayout
&DL
,
350 std::vector
<std::string
> *NewAccessStrings
= nullptr) {
351 int StatementIdx
= 0;
353 // Check if key 'statements' is present.
354 if (!JScop
.get("statements")) {
355 errs() << "JScop file has no key name 'statements'.\n";
358 const json::Array
&statements
= *JScop
.getArray("statements");
360 // Check whether the number of indices equals the number of statements
361 if (statements
.size() != S
.getSize()) {
362 errs() << "The number of indices and the number of statements differ.\n";
366 for (ScopStmt
&Stmt
: S
) {
367 int MemoryAccessIdx
= 0;
368 const json::Object
*Statement
= statements
[StatementIdx
].getAsObject();
371 // Check if key 'accesses' is present.
372 if (!Statement
->get("accesses")) {
374 << "Statement from JScop file has no key name 'accesses' for index "
375 << StatementIdx
<< ".\n";
378 const json::Array
&JsonAccesses
= *Statement
->getArray("accesses");
380 // Check whether the number of indices equals the number of memory
382 if (Stmt
.size() != JsonAccesses
.size()) {
383 errs() << "The number of memory accesses in the JSop file and the number "
384 "of memory accesses differ for index "
385 << StatementIdx
<< ".\n";
389 for (MemoryAccess
*MA
: Stmt
) {
390 // Check if key 'relation' is present.
391 const json::Object
*JsonMemoryAccess
=
392 JsonAccesses
[MemoryAccessIdx
].getAsObject();
393 assert(JsonMemoryAccess
);
394 if (!JsonMemoryAccess
->get("relation")) {
395 errs() << "Memory access number " << MemoryAccessIdx
396 << " has no key name 'relation' for statement number "
397 << StatementIdx
<< ".\n";
400 StringRef Accesses
= *JsonMemoryAccess
->getString("relation");
401 isl_map
*NewAccessMap
=
402 isl_map_read_from_str(S
.getIslCtx().get(), Accesses
.str().c_str());
404 // Check whether the access was parsed successfully
406 errs() << "The access was not parsed successfully by ISL.\n";
409 isl_map
*CurrentAccessMap
= MA
->getAccessRelation().release();
411 // Check if the number of parameter change
412 if (isl_map_dim(NewAccessMap
, isl_dim_param
) !=
413 isl_map_dim(CurrentAccessMap
, isl_dim_param
)) {
414 errs() << "JScop file changes the number of parameter dimensions.\n";
415 isl_map_free(CurrentAccessMap
);
416 isl_map_free(NewAccessMap
);
422 // If the NewAccessMap has zero dimensions, it is the scalar access; it
423 // must be the same as before.
424 // If it has at least one dimension, it's an array access; search for
425 // its ScopArrayInfo.
426 if (isl_map_dim(NewAccessMap
, isl_dim_out
) >= 1) {
427 NewOutId
= isl_map_get_tuple_id(NewAccessMap
, isl_dim_out
);
428 auto *SAI
= S
.getArrayInfoByName(isl_id_get_name(NewOutId
));
429 isl_id
*OutId
= isl_map_get_tuple_id(CurrentAccessMap
, isl_dim_out
);
430 auto *OutSAI
= ScopArrayInfo::getFromId(isl::manage(OutId
));
431 if (!SAI
|| SAI
->getElementType() != OutSAI
->getElementType()) {
432 errs() << "JScop file contains access function with undeclared "
434 isl_map_free(CurrentAccessMap
);
435 isl_map_free(NewAccessMap
);
436 isl_id_free(NewOutId
);
439 isl_id_free(NewOutId
);
440 NewOutId
= SAI
->getBasePtrId().release();
442 NewOutId
= isl_map_get_tuple_id(CurrentAccessMap
, isl_dim_out
);
445 NewAccessMap
= isl_map_set_tuple_id(NewAccessMap
, isl_dim_out
, NewOutId
);
447 if (MA
->isArrayKind()) {
448 // We keep the old alignment, thus we cannot allow accesses to memory
449 // locations that were not accessed before if the alignment of the
450 // access is not the default alignment.
451 bool SpecialAlignment
= true;
452 if (LoadInst
*LoadI
= dyn_cast
<LoadInst
>(MA
->getAccessInstruction())) {
454 DL
.getABITypeAlign(LoadI
->getType()) != LoadI
->getAlign();
455 } else if (StoreInst
*StoreI
=
456 dyn_cast
<StoreInst
>(MA
->getAccessInstruction())) {
458 DL
.getABITypeAlign(StoreI
->getValueOperand()->getType()) !=
462 if (SpecialAlignment
) {
463 isl_set
*NewAccessSet
= isl_map_range(isl_map_copy(NewAccessMap
));
464 isl_set
*CurrentAccessSet
=
465 isl_map_range(isl_map_copy(CurrentAccessMap
));
466 bool IsSubset
= isl_set_is_subset(NewAccessSet
, CurrentAccessSet
);
467 isl_set_free(NewAccessSet
);
468 isl_set_free(CurrentAccessSet
);
470 // Check if the JScop file changes the accessed memory.
472 errs() << "JScop file changes the accessed memory\n";
473 isl_map_free(CurrentAccessMap
);
474 isl_map_free(NewAccessMap
);
480 // We need to copy the isl_ids for the parameter dimensions to the new
481 // map. Without doing this the current map would have different
482 // ids then the new one, even though both are named identically.
483 for (isl_size i
= 0; i
< isl_map_dim(CurrentAccessMap
, isl_dim_param
);
485 isl_id
*Id
= isl_map_get_dim_id(CurrentAccessMap
, isl_dim_param
, i
);
486 NewAccessMap
= isl_map_set_dim_id(NewAccessMap
, isl_dim_param
, i
, Id
);
489 // Copy the old tuple id. This is necessary to retain the user pointer,
490 // that stores the reference to the ScopStmt this access belongs to.
491 isl_id
*Id
= isl_map_get_tuple_id(CurrentAccessMap
, isl_dim_in
);
492 NewAccessMap
= isl_map_set_tuple_id(NewAccessMap
, isl_dim_in
, Id
);
494 auto NewAccessDomain
= isl_map_domain(isl_map_copy(NewAccessMap
));
495 auto CurrentAccessDomain
= isl_map_domain(isl_map_copy(CurrentAccessMap
));
497 if (!isl_set_has_equal_space(NewAccessDomain
, CurrentAccessDomain
)) {
498 errs() << "JScop file contains access function with incompatible "
500 isl_map_free(CurrentAccessMap
);
501 isl_map_free(NewAccessMap
);
502 isl_set_free(NewAccessDomain
);
503 isl_set_free(CurrentAccessDomain
);
508 isl_set_intersect_params(NewAccessDomain
, S
.getContext().release());
509 CurrentAccessDomain
= isl_set_intersect_params(CurrentAccessDomain
,
510 S
.getContext().release());
511 CurrentAccessDomain
=
512 isl_set_intersect(CurrentAccessDomain
, Stmt
.getDomain().release());
515 isl_set_is_subset(CurrentAccessDomain
, NewAccessDomain
) ==
517 errs() << "Mapping not defined for all iteration domain elements\n";
518 isl_set_free(CurrentAccessDomain
);
519 isl_set_free(NewAccessDomain
);
520 isl_map_free(CurrentAccessMap
);
521 isl_map_free(NewAccessMap
);
525 isl_set_free(CurrentAccessDomain
);
526 isl_set_free(NewAccessDomain
);
528 if (!isl_map_is_equal(NewAccessMap
, CurrentAccessMap
)) {
531 if (NewAccessStrings
)
532 NewAccessStrings
->push_back(Accesses
.str());
533 MA
->setNewAccessRelation(isl::manage(NewAccessMap
));
535 isl_map_free(NewAccessMap
);
537 isl_map_free(CurrentAccessMap
);
546 /// Check whether @p SAI and @p Array represent the same array.
547 static bool areArraysEqual(ScopArrayInfo
*SAI
, const json::Object
&Array
) {
549 llvm::raw_string_ostream
RawStringOstream(Buffer
);
551 // Check if key 'type' is present.
552 if (!Array
.get("type")) {
553 errs() << "Array has no key 'type'.\n";
557 // Check if key 'sizes' is present.
558 if (!Array
.get("sizes")) {
559 errs() << "Array has no key 'sizes'.\n";
563 // Check if key 'name' is present.
564 if (!Array
.get("name")) {
565 errs() << "Array has no key 'name'.\n";
569 if (SAI
->getName() != *Array
.getString("name"))
572 if (SAI
->getNumberOfDimensions() != Array
.getArray("sizes")->size())
575 for (unsigned i
= 1; i
< Array
.getArray("sizes")->size(); i
++) {
576 SAI
->getDimensionSize(i
)->print(RawStringOstream
);
577 const json::Array
&SizesArray
= *Array
.getArray("sizes");
578 if (RawStringOstream
.str() != SizesArray
[i
].getAsString().value())
583 // Check if key 'type' differs from the current one or is not valid.
584 SAI
->getElementType()->print(RawStringOstream
);
585 if (RawStringOstream
.str() != Array
.getString("type").value()) {
586 errs() << "Array has not a valid type.\n";
593 /// Get the accepted primitive type from its textual representation
594 /// @p TypeTextRepresentation.
596 /// @param TypeTextRepresentation The textual representation of the type.
597 /// @return The pointer to the primitive type, if this type is accepted
598 /// or nullptr otherwise.
599 static Type
*parseTextType(const std::string
&TypeTextRepresentation
,
600 LLVMContext
&LLVMContext
) {
601 std::map
<std::string
, Type
*> MapStrToType
= {
602 {"void", Type::getVoidTy(LLVMContext
)},
603 {"half", Type::getHalfTy(LLVMContext
)},
604 {"float", Type::getFloatTy(LLVMContext
)},
605 {"double", Type::getDoubleTy(LLVMContext
)},
606 {"x86_fp80", Type::getX86_FP80Ty(LLVMContext
)},
607 {"fp128", Type::getFP128Ty(LLVMContext
)},
608 {"ppc_fp128", Type::getPPC_FP128Ty(LLVMContext
)},
609 {"i1", Type::getInt1Ty(LLVMContext
)},
610 {"i8", Type::getInt8Ty(LLVMContext
)},
611 {"i16", Type::getInt16Ty(LLVMContext
)},
612 {"i32", Type::getInt32Ty(LLVMContext
)},
613 {"i64", Type::getInt64Ty(LLVMContext
)},
614 {"i128", Type::getInt128Ty(LLVMContext
)}};
616 auto It
= MapStrToType
.find(TypeTextRepresentation
);
617 if (It
!= MapStrToType
.end())
620 errs() << "Textual representation can not be parsed: "
621 << TypeTextRepresentation
<< "\n";
625 /// Import new arrays from JScop.
627 /// @param S The scop to update.
628 /// @param JScop The JScop file describing new arrays.
630 /// @returns True if the import succeeded, otherwise False.
631 static bool importArrays(Scop
&S
, const json::Object
&JScop
) {
632 if (!JScop
.get("arrays"))
634 const json::Array
&Arrays
= *JScop
.getArray("arrays");
635 if (Arrays
.size() == 0)
638 unsigned ArrayIdx
= 0;
639 for (auto &SAI
: S
.arrays()) {
640 if (!SAI
->isArrayKind())
642 if (ArrayIdx
+ 1 > Arrays
.size()) {
643 errs() << "Not enough array entries in JScop file.\n";
646 if (!areArraysEqual(SAI
, *Arrays
[ArrayIdx
].getAsObject())) {
647 errs() << "No match for array '" << SAI
->getName() << "' in JScop.\n";
653 for (; ArrayIdx
< Arrays
.size(); ArrayIdx
++) {
654 const json::Object
&Array
= *Arrays
[ArrayIdx
].getAsObject();
656 parseTextType(Array
.get("type")->getAsString().value().str(),
657 S
.getSE()->getContext());
659 errs() << "Error while parsing element type for new array.\n";
662 const json::Array
&SizesArray
= *Array
.getArray("sizes");
663 std::vector
<unsigned> DimSizes
;
664 for (unsigned i
= 0; i
< SizesArray
.size(); i
++) {
665 auto Size
= std::stoi(SizesArray
[i
].getAsString()->str());
667 // Check if the size if positive.
669 errs() << "The size at index " << i
<< " is =< 0.\n";
673 DimSizes
.push_back(Size
);
676 auto NewSAI
= S
.createScopArrayInfo(
677 ElementType
, Array
.getString("name").value().str(), DimSizes
);
679 if (Array
.get("allocation")) {
680 NewSAI
->setIsOnHeap(Array
.getString("allocation").value() == "heap");
687 /// Import a Scop from a JSCOP file
688 /// @param S The scop to be modified
689 /// @param D Dependence Info
690 /// @param DL The DataLayout of the function
691 /// @param NewAccessStrings Optionally record the imported access strings
693 /// @returns true on success, false otherwise. Beware that if this returns
694 /// false, the Scop may still have been modified. In this case the Scop contains
695 /// invalid information.
696 static bool importScop(Scop
&S
, const Dependences
&D
, const DataLayout
&DL
,
697 std::vector
<std::string
> *NewAccessStrings
= nullptr) {
698 std::string FileName
= ImportDir
+ "/" + getFileName(S
, ImportPostfix
);
700 std::string FunctionName
= S
.getFunction().getName().str();
701 errs() << "Reading JScop '" << S
.getNameStr() << "' in function '"
702 << FunctionName
<< "' from '" << FileName
<< "'.\n";
703 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> result
=
704 MemoryBuffer::getFile(FileName
);
705 std::error_code ec
= result
.getError();
708 errs() << "File could not be read: " << ec
.message() << "\n";
712 Expected
<json::Value
> ParseResult
=
713 json::parse(result
.get().get()->getBuffer());
715 if (Error E
= ParseResult
.takeError()) {
716 errs() << "JSCoP file could not be parsed\n";
718 consumeError(std::move(E
));
721 json::Object
&jscop
= *ParseResult
.get().getAsObject();
723 bool Success
= importContext(S
, jscop
);
728 Success
= importSchedule(S
, jscop
, D
);
733 Success
= importArrays(S
, jscop
);
738 Success
= importAccesses(S
, jscop
, DL
, NewAccessStrings
);
745 char JSONExporter::ID
= 0;
746 void JSONExporter::printScop(raw_ostream
&OS
, Scop
&S
) const { OS
<< S
; }
748 bool JSONExporter::runOnScop(Scop
&S
) {
753 void JSONExporter::getAnalysisUsage(AnalysisUsage
&AU
) const {
754 AU
.setPreservesAll();
755 AU
.addRequired
<ScopInfoRegionPass
>();
758 Pass
*polly::createJSONExporterPass() { return new JSONExporter(); }
760 PreservedAnalyses
JSONExportPass::run(Scop
&S
, ScopAnalysisManager
&SAM
,
761 ScopStandardAnalysisResults
&SAR
,
764 return PreservedAnalyses::all();
767 char JSONImporter::ID
= 0;
769 void JSONImporter::printScop(raw_ostream
&OS
, Scop
&S
) const {
771 for (std::vector
<std::string
>::const_iterator I
= NewAccessStrings
.begin(),
772 E
= NewAccessStrings
.end();
774 OS
<< "New access function '" << *I
<< "' detected in JSCOP file\n";
777 bool JSONImporter::runOnScop(Scop
&S
) {
778 const Dependences
&D
=
779 getAnalysis
<DependenceInfo
>().getDependences(Dependences::AL_Statement
);
780 const DataLayout
&DL
= S
.getFunction().getParent()->getDataLayout();
782 if (!importScop(S
, D
, DL
, &NewAccessStrings
))
783 report_fatal_error("Tried to import a malformed jscop file.");
788 void JSONImporter::getAnalysisUsage(AnalysisUsage
&AU
) const {
789 ScopPass::getAnalysisUsage(AU
);
790 AU
.addRequired
<DependenceInfo
>();
792 // TODO: JSONImporter should throw away DependenceInfo.
793 AU
.addPreserved
<DependenceInfo
>();
796 Pass
*polly::createJSONImporterPass() { return new JSONImporter(); }
798 PreservedAnalyses
JSONImportPass::run(Scop
&S
, ScopAnalysisManager
&SAM
,
799 ScopStandardAnalysisResults
&SAR
,
801 const Dependences
&D
=
802 SAM
.getResult
<DependenceAnalysis
>(S
, SAR
).getDependences(
803 Dependences::AL_Statement
);
804 const DataLayout
&DL
= S
.getFunction().getParent()->getDataLayout();
806 if (!importScop(S
, D
, DL
))
807 report_fatal_error("Tried to import a malformed jscop file.");
809 // This invalidates all analyses on Scop.
810 PreservedAnalyses PA
;
811 PA
.preserveSet
<AllAnalysesOn
<Module
>>();
812 PA
.preserveSet
<AllAnalysesOn
<Function
>>();
813 PA
.preserveSet
<AllAnalysesOn
<Loop
>>();
817 INITIALIZE_PASS_BEGIN(JSONExporter
, "polly-export-jscop",
818 "Polly - Export Scops as JSON"
819 " (Writes a .jscop file for each Scop)",
821 INITIALIZE_PASS_DEPENDENCY(DependenceInfo
)
822 INITIALIZE_PASS_END(JSONExporter
, "polly-export-jscop",
823 "Polly - Export Scops as JSON"
824 " (Writes a .jscop file for each Scop)",
827 INITIALIZE_PASS_BEGIN(JSONImporter
, "polly-import-jscop",
828 "Polly - Import Scops from JSON"
829 " (Reads a .jscop file for each Scop)",
831 INITIALIZE_PASS_DEPENDENCY(DependenceInfo
)
832 INITIALIZE_PASS_END(JSONImporter
, "polly-import-jscop",
833 "Polly - Import Scops from JSON"
834 " (Reads a .jscop file for each Scop)",
837 //===----------------------------------------------------------------------===//
840 /// Print result from JSONImporter.
841 class JSONImporterPrinterLegacyPass final
: public ScopPass
{
845 JSONImporterPrinterLegacyPass() : JSONImporterPrinterLegacyPass(outs()) {}
846 explicit JSONImporterPrinterLegacyPass(llvm::raw_ostream
&OS
)
847 : ScopPass(ID
), OS(OS
) {}
849 bool runOnScop(Scop
&S
) override
{
850 JSONImporter
&P
= getAnalysis
<JSONImporter
>();
852 OS
<< "Printing analysis '" << P
.getPassName() << "' for region: '"
853 << S
.getRegion().getNameStr() << "' in function '"
854 << S
.getFunction().getName() << "':\n";
860 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
861 ScopPass::getAnalysisUsage(AU
);
862 AU
.addRequired
<JSONImporter
>();
863 AU
.setPreservesAll();
867 llvm::raw_ostream
&OS
;
870 char JSONImporterPrinterLegacyPass::ID
= 0;
873 Pass
*polly::createJSONImporterPrinterLegacyPass(llvm::raw_ostream
&OS
) {
874 return new JSONImporterPrinterLegacyPass(OS
);
877 INITIALIZE_PASS_BEGIN(JSONImporterPrinterLegacyPass
, "polly-print-import-jscop",
878 "Polly - Print Scop import result", false, false)
879 INITIALIZE_PASS_DEPENDENCY(JSONImporter
)
880 INITIALIZE_PASS_END(JSONImporterPrinterLegacyPass
, "polly-print-import-jscop",
881 "Polly - Print Scop import result", false, false)