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>
37#define DEBUG_TYPE "polly-import-jscop"
39STATISTIC(NewAccessMapFound,
"Number of updated access functions");
42static 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,
48static 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,
54class JSONExporter :
public ScopPass {
57 explicit JSONExporter() :
ScopPass(ID) {}
69class JSONImporter :
public ScopPass {
72 std::vector<std::string> NewAccessStrings;
73 explicit JSONImporter() :
ScopPass(ID) {}
86 std::string FunctionName =
S.getFunction().getName().str();
87 std::string FileName = FunctionName +
"___" +
S.getNameStr() +
".jscop";
90 FileName +=
"." + Suffix.str();
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));
133 unsigned LineBegin, LineEnd;
134 std::string 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;
151 json::Array Statements;
153 json::Object statement;
155 statement[
"name"] = Stmt.getBaseName();
156 statement[
"domain"] = Stmt.getDomainStr();
157 statement[
"schedule"] = Stmt.getScheduleStr();
159 json::Array Accesses;
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));
178 std::string FileName = ImportDir +
"/" +
getFileName(
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();
216 if (!JScop.get(
"context")) {
217 errs() <<
"JScop file has no key named 'context'.\n";
222 isl::set{
S.getIslCtx().get(), JScop.getString(
"context").value().str()};
226 errs() <<
"The context was not parsed successfully by ISL.\n";
232 errs() <<
"The isl_set is not a parameter set.\n";
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++) {
252 S.setContext(NewContext);
271 if (!JScop.get(
"statements")) {
272 errs() <<
"JScop file has no key name 'statements'.\n";
276 const json::Array &statements = *JScop.getArray(
"statements");
279 if (statements.size() !=
S.getSize()) {
280 errs() <<
"The number of indices and the number of statements differ.\n";
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.");
296 Schedule.value().str().c_str());
300 errs() <<
"The schedule was not parsed successfully (index = " << Index
305 isl_space *Space = Stmt.getDomainSpace().release();
322 errs() <<
"JScop file contains a schedule that changes the "
323 <<
"dependences. Use -disable-polly-legality to continue anyways\n";
329 if (NewSchedule.contains(&Stmt))
330 ScheduleMap = ScheduleMap.unite(NewSchedule[&Stmt]);
332 ScheduleMap = ScheduleMap.unite(Stmt.getSchedule());
335 S.setSchedule(ScheduleMap);
350 std::vector<std::string> *NewAccessStrings =
nullptr) {
351 int StatementIdx = 0;
354 if (!JScop.get(
"statements")) {
355 errs() <<
"JScop file has no key name 'statements'.\n";
358 const json::Array &statements = *JScop.getArray(
"statements");
361 if (statements.size() !=
S.getSize()) {
362 errs() <<
"The number of indices and the number of statements differ.\n";
367 int MemoryAccessIdx = 0;
368 const json::Object *Statement = statements[StatementIdx].getAsObject();
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");
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";
391 const json::Object *JsonMemoryAccess =
392 JsonAccesses[MemoryAccessIdx].getAsObject();
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");
406 errs() <<
"The access was not parsed successfully by ISL.\n";
409 isl_map *CurrentAccessMap = MA->getAccessRelation().release();
414 errs() <<
"JScop file changes the number of parameter dimensions.\n";
431 if (!SAI || SAI->getElementType() != OutSAI->getElementType()) {
432 errs() <<
"JScop file contains access function with undeclared "
440 NewOutId = SAI->getBasePtrId().release();
447 if (MA->isArrayKind()) {
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) {
472 errs() <<
"JScop file changes the accessed memory\n";
498 errs() <<
"JScop file contains access function with incompatible "
510 S.getContext().release());
511 CurrentAccessDomain =
517 errs() <<
"Mapping not defined for all iteration domain elements\n";
531 if (NewAccessStrings)
532 NewAccessStrings->push_back(Accesses.str());
533 MA->setNewAccessRelation(
isl::manage(NewAccessMap));
549 llvm::raw_string_ostream RawStringOstream(Buffer);
552 if (!
Array.get(
"type")) {
553 errs() <<
"Array has no key 'type'.\n";
558 if (!
Array.get(
"sizes")) {
559 errs() <<
"Array has no key 'sizes'.\n";
564 if (!
Array.get(
"name")) {
565 errs() <<
"Array has no key 'name'.\n";
575 for (
unsigned i = 1; i <
Array.getArray(
"sizes")->
size(); i++) {
577 const json::Array &SizesArray = *
Array.getArray(
"sizes");
578 if (RawStringOstream.str() != SizesArray[i].getAsString().value())
585 if (RawStringOstream.str() !=
Array.getString(
"type").value()) {
586 errs() <<
"Array has not a valid type.\n";
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";
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";
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();
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());
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");
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();
745char JSONExporter::ID = 0;
746void JSONExporter::printScop(raw_ostream &OS,
Scop &
S)
const { OS <<
S; }
748bool JSONExporter::runOnScop(
Scop &
S) {
753void JSONExporter::getAnalysisUsage(AnalysisUsage &AU)
const {
754 AU.setPreservesAll();
764 return PreservedAnalyses::all();
767char JSONImporter::ID = 0;
769void 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";
777bool JSONImporter::runOnScop(
Scop &
S) {
780 const DataLayout &DL =
S.getFunction().getParent()->getDataLayout();
783 report_fatal_error(
"Tried to import a malformed jscop file.");
788void JSONImporter::getAnalysisUsage(AnalysisUsage &AU)
const {
804 const DataLayout &DL =
S.getFunction().getParent()->getDataLayout();
807 report_fatal_error(
"Tried to import a malformed jscop file.");
810 PreservedAnalyses PA;
811 PA.preserveSet<AllAnalysesOn<Module>>();
812 PA.preserveSet<AllAnalysesOn<Function>>();
813 PA.preserveSet<AllAnalysesOn<Loop>>();
818 "Polly - Export Scops as JSON"
819 " (Writes a .jscop file for each Scop)",
823 "Polly - Export Scops as
JSON"
828 "Polly - Import Scops from
JSON"
833 "Polly - Import Scops from
JSON"
841class JSONImporterPrinterLegacyPass final :
public ScopPass {
845 JSONImporterPrinterLegacyPass() : JSONImporterPrinterLegacyPass(outs()) {}
846 explicit JSONImporterPrinterLegacyPass(llvm::raw_ostream &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 {
862 AU.addRequired<JSONImporter>();
863 AU.setPreservesAll();
867 llvm::raw_ostream &OS;
870char JSONImporterPrinterLegacyPass::ID = 0;
874 return new JSONImporterPrinterLegacyPass(OS);
878 "Polly - Print Scop import result",
false,
false)
INITIALIZE_PASS_BEGIN(DependenceInfo, "polly-dependences", "Polly - Calculate dependences", false, false)
INITIALIZE_PASS_END(DependenceInfo, "polly-dependences", "Polly - Calculate dependences", false, false) namespace
INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass)
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="")
polly print import Polly Print Scop import result
Dependences::StatementToIslMapTy StatementToIslMapTy
static json::Array exportArrays(const Scop &S)
Export all arrays from the Scop.
polly import Polly Import Scops from JSON(Reads a .jscop file for each 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
for(int c0=1;c0< 3 *M - 1;c0+=3)
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.
isl::union_map getDependences(int Kinds) const
Get the dependences of type Kinds.
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.
The legacy pass manager's analysis pass to compute scop information for a region.
ScopPass - This class adapts the RegionPass interface to allow convenient creation of passes that ope...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnScop(Scop &S)=0
runOnScop - This method must be overloaded to perform the desired Polyhedral transformation or analys...
virtual void printScop(raw_ostream &OS, Scop &S) const
Print method for SCoPs.
__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)
void *GMPZAPI() export(void *rop, size_t *countp, int order, size_t size, int endian, size_t nails, mp_int op)
void GMPZAPI() import(mp_int rop, size_t count, int order, size_t size, int endian, size_t nails, const void *op)
__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)
This file contains the declaration of the PolyhedralInfo class, which will provide an interface to ex...
llvm::Pass * createJSONImporterPrinterLegacyPass(llvm::raw_ostream &OS)
llvm::Pass * createJSONImporterPass()
@ 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.
llvm::Pass * createJSONExporterPass()
AnalysisManager< Scop, ScopStandardAnalysisResults & > ScopAnalysisManager
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)
llvm::PreservedAnalyses run(Scop &, ScopAnalysisManager &, ScopStandardAnalysisResults &, SPMUpdater &)
llvm::PreservedAnalyses run(Scop &, ScopAnalysisManager &, ScopStandardAnalysisResults &, SPMUpdater &)
static std::vector< Signature > each