19#include "llvm/ADT/Statistic.h"
20#include "llvm/IR/Module.h"
21#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/JSON.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/Support/ToolOutputFile.h"
25#include "llvm/Support/raw_ostream.h"
30#include <system_error>
35#define DEBUG_TYPE "polly-import-jscop"
39 cl::desc(
"Polly - Print Scop import result"),
42STATISTIC(NewAccessMapFound,
"Number of updated access functions");
45static cl::opt<std::string>
46 ImportDir(
"polly-import-jscop-dir",
47 cl::desc(
"The directory to import the .jscop files from."),
48 cl::Hidden, cl::value_desc(
"Directory path"), cl::ValueRequired,
51static cl::opt<std::string>
52 ImportPostfix(
"polly-import-jscop-postfix",
53 cl::desc(
"Postfix to append to the import .jsop files."),
54 cl::Hidden, cl::value_desc(
"File postfix"), cl::ValueRequired,
59 std::string FunctionName =
S.getFunction().getName().str();
60 std::string FileName = FunctionName +
"___" +
S.getNameStr() +
".jscop";
63 FileName +=
"." + Suffix.str();
76 llvm::raw_string_ostream RawStringOstream(Buffer);
78 for (
auto &SAI :
S.arrays()) {
79 if (!SAI->isArrayKind())
84 Array[
"name"] = SAI->getName();
86 if (!SAI->getDimensionSize(i)) {
90 for (; i < SAI->getNumberOfDimensions(); i++) {
91 SAI->getDimensionSize(i)->print(RawStringOstream);
92 Sizes.push_back(Buffer);
95 Array[
"sizes"] = std::move(Sizes);
96 SAI->getElementType()->print(RawStringOstream);
97 Array[
"type"] = Buffer;
99 Arrays.push_back(std::move(
Array));
106 unsigned LineBegin, LineEnd;
107 std::string FileName;
110 std::string Location;
111 if (LineBegin != (
unsigned)-1)
112 Location = FileName +
":" + std::to_string(LineBegin) +
"-" +
113 std::to_string(LineEnd);
115 root[
"name"] =
S.getNameStr();
116 root[
"context"] =
S.getContextStr();
117 if (LineBegin != (
unsigned)-1)
118 root[
"location"] = Location;
124 json::Array Statements;
126 json::Object statement;
128 statement[
"name"] = Stmt.getBaseName();
129 statement[
"domain"] = Stmt.getDomainStr();
130 statement[
"schedule"] = Stmt.getScheduleStr();
132 json::Array Accesses;
136 access[
"kind"] = MA->isRead() ?
"read" :
"write";
137 access[
"relation"] = MA->getAccessRelationStr();
139 Accesses.push_back(std::move(access));
141 statement[
"accesses"] = std::move(Accesses);
143 Statements.push_back(std::move(statement));
146 root[
"statements"] = std::move(Statements);
147 return json::Value(std::move(root));
151 std::string FileName = ImportDir +
"/" +
getFileName(
S);
157 ToolOutputFile F(FileName, EC, llvm::sys::fs::OF_TextWithCRLF);
159 std::string FunctionName =
S.getFunction().getName().str();
160 errs() <<
"Writing JScop '" <<
S.getNameStr() <<
"' in function '"
161 << FunctionName <<
"' to '" << FileName <<
"'.\n";
164 F.os() << formatv(
"{0:3}", jscop);
166 if (!F.os().has_error()) {
173 errs() <<
" error opening file for writing!\n";
174 F.os().clear_error();
189 if (!JScop.get(
"context")) {
190 errs() <<
"JScop file has no key named 'context'.\n";
195 isl::set{
S.getIslCtx().get(), JScop.getString(
"context").value().str()};
199 errs() <<
"The context was not parsed successfully by ISL.\n";
205 errs() <<
"The isl_set is not a parameter set.\n";
213 if (OldContextDim != NewContextDim) {
214 errs() <<
"Imported context has the wrong number of parameters : "
215 <<
"Found " << NewContextDim <<
" Expected " << OldContextDim
220 for (
unsigned i = 0; i < OldContextDim; i++) {
225 S.setContext(NewContext);
244 if (!JScop.get(
"statements")) {
245 errs() <<
"JScop file has no key name 'statements'.\n";
249 const json::Array &statements = *JScop.getArray(
"statements");
252 if (statements.size() !=
S.getSize()) {
253 errs() <<
"The number of indices and the number of statements differ.\n";
260 if (!statements[Index].getAsObject()->get(
"schedule")) {
261 errs() <<
"Statement " << Index <<
" has no 'schedule' key.\n";
264 std::optional<StringRef> Schedule =
265 statements[Index].getAsObject()->getString(
"schedule");
266 assert(Schedule.has_value() &&
267 "Schedules that contain extension nodes require special handling.");
269 Schedule.value().str().c_str());
273 errs() <<
"The schedule was not parsed successfully (index = " << Index
278 isl_space *Space = Stmt.getDomainSpace().release();
295 errs() <<
"JScop file contains a schedule that changes the "
296 <<
"dependences. Use -disable-polly-legality to continue anyways\n";
302 if (NewSchedule.contains(&Stmt))
303 ScheduleMap = ScheduleMap.unite(NewSchedule[&Stmt]);
305 ScheduleMap = ScheduleMap.unite(Stmt.getSchedule());
308 S.setSchedule(ScheduleMap);
323 std::vector<std::string> *NewAccessStrings =
nullptr) {
324 int StatementIdx = 0;
327 if (!JScop.get(
"statements")) {
328 errs() <<
"JScop file has no key name 'statements'.\n";
331 const json::Array &statements = *JScop.getArray(
"statements");
334 if (statements.size() !=
S.getSize()) {
335 errs() <<
"The number of indices and the number of statements differ.\n";
340 int MemoryAccessIdx = 0;
341 const json::Object *Statement = statements[StatementIdx].getAsObject();
345 if (!Statement->get(
"accesses")) {
347 <<
"Statement from JScop file has no key name 'accesses' for index "
348 << StatementIdx <<
".\n";
351 const json::Array &JsonAccesses = *Statement->getArray(
"accesses");
355 if (Stmt.size() != JsonAccesses.size()) {
356 errs() <<
"The number of memory accesses in the JSop file and the number "
357 "of memory accesses differ for index "
358 << StatementIdx <<
".\n";
364 const json::Object *JsonMemoryAccess =
365 JsonAccesses[MemoryAccessIdx].getAsObject();
367 if (!JsonMemoryAccess->get(
"relation")) {
368 errs() <<
"Memory access number " << MemoryAccessIdx
369 <<
" has no key name 'relation' for statement number "
370 << StatementIdx <<
".\n";
373 StringRef Accesses = *JsonMemoryAccess->getString(
"relation");
379 errs() <<
"The access was not parsed successfully by ISL.\n";
382 isl_map *CurrentAccessMap = MA->getAccessRelation().release();
387 errs() <<
"JScop file changes the number of parameter dimensions.\n";
404 if (!SAI || SAI->getElementType() != OutSAI->getElementType()) {
405 errs() <<
"JScop file contains access function with undeclared "
413 NewOutId = SAI->getBasePtrId().release();
420 if (MA->isArrayKind()) {
424 bool SpecialAlignment =
true;
425 if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) {
427 DL.getABITypeAlign(LoadI->getType()) != LoadI->getAlign();
428 }
else if (StoreInst *StoreI =
429 dyn_cast<StoreInst>(MA->getAccessInstruction())) {
431 DL.getABITypeAlign(StoreI->getValueOperand()->getType()) !=
435 if (SpecialAlignment) {
445 errs() <<
"JScop file changes the accessed memory\n";
471 errs() <<
"JScop file contains access function with incompatible "
483 S.getContext().release());
484 CurrentAccessDomain =
490 errs() <<
"Mapping not defined for all iteration domain elements\n";
504 if (NewAccessStrings)
505 NewAccessStrings->push_back(Accesses.str());
506 MA->setNewAccessRelation(
isl::manage(NewAccessMap));
522 llvm::raw_string_ostream RawStringOstream(Buffer);
525 if (!
Array.get(
"type")) {
526 errs() <<
"Array has no key 'type'.\n";
531 if (!
Array.get(
"sizes")) {
532 errs() <<
"Array has no key 'sizes'.\n";
537 if (!
Array.get(
"name")) {
538 errs() <<
"Array has no key 'name'.\n";
548 for (
unsigned i = 1; i <
Array.getArray(
"sizes")->
size(); i++) {
550 const json::Array &SizesArray = *
Array.getArray(
"sizes");
551 if (Buffer != SizesArray[i].getAsString().value())
558 if (Buffer !=
Array.getString(
"type").value()) {
559 errs() <<
"Array has not a valid type.\n";
573 LLVMContext &LLVMContext) {
574 std::map<std::string, Type *> MapStrToType = {
575 {
"void", Type::getVoidTy(LLVMContext)},
576 {
"half", Type::getHalfTy(LLVMContext)},
577 {
"float", Type::getFloatTy(LLVMContext)},
578 {
"double", Type::getDoubleTy(LLVMContext)},
579 {
"x86_fp80", Type::getX86_FP80Ty(LLVMContext)},
580 {
"fp128", Type::getFP128Ty(LLVMContext)},
581 {
"ppc_fp128", Type::getPPC_FP128Ty(LLVMContext)},
582 {
"i1", Type::getInt1Ty(LLVMContext)},
583 {
"i8", Type::getInt8Ty(LLVMContext)},
584 {
"i16", Type::getInt16Ty(LLVMContext)},
585 {
"i32", Type::getInt32Ty(LLVMContext)},
586 {
"i64", Type::getInt64Ty(LLVMContext)},
587 {
"i128", Type::getInt128Ty(LLVMContext)}};
589 auto It = MapStrToType.find(TypeTextRepresentation);
590 if (It != MapStrToType.end())
593 errs() <<
"Textual representation can not be parsed: "
594 << TypeTextRepresentation <<
"\n";
605 if (!JScop.get(
"arrays"))
607 const json::Array &Arrays = *JScop.getArray(
"arrays");
608 if (Arrays.size() == 0)
611 unsigned ArrayIdx = 0;
612 for (
auto &SAI :
S.arrays()) {
613 if (!SAI->isArrayKind())
615 if (ArrayIdx + 1 > Arrays.size()) {
616 errs() <<
"Not enough array entries in JScop file.\n";
620 errs() <<
"No match for array '" << SAI->getName() <<
"' in JScop.\n";
626 for (; ArrayIdx < Arrays.size(); ArrayIdx++) {
627 const json::Object &
Array = *Arrays[ArrayIdx].getAsObject();
630 S.getSE()->getContext());
632 errs() <<
"Error while parsing element type for new array.\n";
635 const json::Array &SizesArray = *
Array.getArray(
"sizes");
636 std::vector<unsigned> DimSizes;
637 for (
unsigned i = 0; i < SizesArray.size(); i++) {
638 auto Size = std::stoi(SizesArray[i].getAsString()->
str());
642 errs() <<
"The size at index " << i <<
" is =< 0.\n";
646 DimSizes.push_back(Size);
649 auto NewSAI =
S.createScopArrayInfo(
650 ElementType,
Array.getString(
"name").value().str(), DimSizes);
652 if (
Array.get(
"allocation")) {
653 NewSAI->setIsOnHeap(
Array.getString(
"allocation").value() ==
"heap");
670 std::vector<std::string> *NewAccessStrings =
nullptr) {
671 std::string FileName = ImportDir +
"/" +
getFileName(
S, ImportPostfix);
673 std::string FunctionName =
S.getFunction().getName().str();
674 errs() <<
"Reading JScop '" <<
S.getNameStr() <<
"' in function '"
675 << FunctionName <<
"' from '" << FileName <<
"'.\n";
676 ErrorOr<std::unique_ptr<MemoryBuffer>> result =
677 MemoryBuffer::getFile(FileName);
678 std::error_code ec = result.getError();
681 errs() <<
"File could not be read: " << ec.message() <<
"\n";
685 Expected<json::Value> ParseResult =
686 json::parse(result.get().get()->getBuffer());
688 if (Error E = ParseResult.takeError()) {
689 errs() <<
"JSCoP file could not be parsed\n";
691 consumeError(std::move(E));
694 json::Object &jscop = *ParseResult.get().getAsObject();
720 const DataLayout &DL =
S.getFunction().getParent()->getDataLayout();
721 std::vector<std::string> NewAccessStrings;
723 report_fatal_error(
"Tried to import a malformed jscop file.");
727 <<
"Printing analysis 'Polly - Print Scop import result' for region: '"
728 <<
S.getRegion().getNameStr() <<
"' in function '"
729 <<
S.getFunction().getName() <<
"':\n";
731 for (std::vector<std::string>::const_iterator I = NewAccessStrings.begin(),
732 E = NewAccessStrings.end();
734 outs() <<
"New access function '" << *I <<
"' detected in JSCOP file\n";
static bool importAccesses(Scop &S, const json::Object &JScop, const DataLayout &DL, std::vector< std::string > *NewAccessStrings=nullptr)
Import new memory accesses from JScop.
static Type * parseTextType(const std::string &TypeTextRepresentation, LLVMContext &LLVMContext)
Get the accepted primitive type from its textual representation TypeTextRepresentation.
static bool importContext(Scop &S, const json::Object &JScop)
Import a new context from JScop.
static std::string getFileName(Scop &S, StringRef Suffix="")
static cl::opt< bool > PollyPrintImportJscop("polly-print-import-jscop", cl::desc("Polly - Print Scop import result"), cl::cat(PollyCategory))
Dependences::StatementToIslMapTy StatementToIslMapTy
static json::Array exportArrays(const Scop &S)
Export all arrays from the Scop.
STATISTIC(NewAccessMapFound, "Number of updated access functions")
static json::Value getJSON(Scop &S)
static void exportScop(Scop &S)
static bool importScop(Scop &S, const Dependences &D, const DataLayout &DL, std::vector< std::string > *NewAccessStrings=nullptr)
Import a Scop from a JSCOP file.
static bool importSchedule(Scop &S, const json::Object &JScop, const Dependences &D)
Import a new schedule from JScop.
static bool importArrays(Scop &S, const json::Object &JScop)
Import new arrays from JScop.
static bool areArraysEqual(ScopArrayInfo *SAI, const json::Object &Array)
Check whether SAI and Array represent the same array.
llvm::cl::OptionCategory PollyCategory
isl::set set_dim_id(isl::dim type, unsigned int pos, isl::id id) const
isl::id get_dim_id(isl::dim type, unsigned int pos) const
boolean is_params() const
class size dim(isl::dim type) const
static isl::union_map empty(isl::ctx ctx)
The accumulated dependence information for a SCoP.
DenseMap< ScopStmt *, isl::map > StatementToIslMapTy
Map type to associate statements with schedules.
bool isValidSchedule(Scop &S, const StatementToIslMapTy &NewSchedules) const
Check if a new schedule is valid.
Represent memory accesses in statements.
A class to store information about arrays in the SCoP.
const SCEV * getDimensionSize(unsigned Dim) const
Return the size of dimension dim as SCEV*.
static const ScopArrayInfo * getFromId(isl::id Id)
Access the ScopArrayInfo associated with an isl Id.
std::string getName() const
Get the name of this memory reference.
unsigned getNumberOfDimensions() const
Return the number of dimensions.
Type * getElementType() const
Get the canonical element type of this array.
__isl_export __isl_keep const char * isl_id_get_name(__isl_keep isl_id *id)
__isl_null isl_id * isl_id_free(__isl_take isl_id *id)
__isl_export __isl_give isl_set * isl_map_domain(__isl_take isl_map *bmap)
__isl_give isl_map * isl_map_copy(__isl_keep isl_map *map)
__isl_give isl_map * isl_map_set_dim_id(__isl_take isl_map *map, enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
__isl_export isl_bool isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
__isl_give isl_id * isl_map_get_dim_id(__isl_keep isl_map *map, enum isl_dim_type type, unsigned pos)
__isl_constructor __isl_give isl_map * isl_map_read_from_str(isl_ctx *ctx, const char *str)
isl_size isl_map_dim(__isl_keep isl_map *map, enum isl_dim_type type)
__isl_give isl_map * isl_map_set_tuple_id(__isl_take isl_map *map, enum isl_dim_type type, __isl_take isl_id *id)
__isl_null isl_map * isl_map_free(__isl_take isl_map *map)
__isl_export __isl_give isl_set * isl_map_range(__isl_take isl_map *map)
__isl_give isl_id * isl_map_get_tuple_id(__isl_keep isl_map *map, enum isl_dim_type type)
boolean manage(isl_bool val)
void runExportJSON(Scop &S)
This pass exports a scop to a jscop file.
void runImportJSON(Scop &S, DependenceAnalysis::Result &DA)
This pass imports a scop from a jscop file.
@ Array
MemoryKind::Array: Models a one or multi-dimensional array.
void getDebugLocation(const llvm::Region *R, unsigned &LineBegin, unsigned &LineEnd, std::string &FileName)
Get the location of a region from the debug info.
isl_bool isl_set_has_equal_space(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
__isl_export __isl_give isl_set * isl_set_intersect_params(__isl_take isl_set *set, __isl_take isl_set *params)
__isl_null isl_set * isl_set_free(__isl_take isl_set *set)
__isl_export isl_bool isl_set_is_subset(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
__isl_export __isl_give isl_set * isl_set_intersect(__isl_take isl_set *set1, __isl_take isl_set *set2)
__isl_null isl_space * isl_space_free(__isl_take isl_space *space)
__isl_give isl_id * isl_space_get_tuple_id(__isl_keep isl_space *space, enum isl_dim_type type)
__isl_give isl_id * isl_space_get_dim_id(__isl_keep isl_space *space, enum isl_dim_type type, unsigned pos)
isl_size isl_space_dim(__isl_keep isl_space *space, enum isl_dim_type type)
const Dependences & getDependences(Dependences::AnalysisLevel Level)
Return the dependence information for the current SCoP.