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