Index: polly/trunk/include/polly/JSONExporter.h =================================================================== --- polly/trunk/include/polly/JSONExporter.h +++ polly/trunk/include/polly/JSONExporter.h @@ -0,0 +1,23 @@ +#ifndef POLLY_JSONEXPORTER_H +#define POLLY_JSONEXPORTER_H + +#include "polly/ScopPass.h" +#include "llvm/IR/PassManager.h" + +namespace polly { +/// This pass exports a scop to a jscop file. The filename is generated from the +/// concatenation of the function and scop name. +struct JSONExportPass : public llvm::PassInfoMixin { + llvm::PreservedAnalyses run(Scop &, ScopAnalysisManager &, + ScopStandardAnalysisResults &, SPMUpdater &); +}; + +/// This pass imports a scop from a jscop file. The filename is deduced from the +/// concatenation of the function and scop name. +struct JSONImportPass : public llvm::PassInfoMixin { + llvm::PreservedAnalyses run(Scop &, ScopAnalysisManager &, + ScopStandardAnalysisResults &, SPMUpdater &); +}; +} // namespace polly + +#endif /* POLLY_JSONEXPORTER_H */ Index: polly/trunk/lib/Exchange/JSONExporter.cpp =================================================================== --- polly/trunk/lib/Exchange/JSONExporter.cpp +++ polly/trunk/lib/Exchange/JSONExporter.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "polly/JSONExporter.h" #include "polly/DependenceInfo.h" #include "polly/LinkAllPasses.h" #include "polly/Options.h" @@ -59,9 +60,6 @@ static char ID; explicit JSONExporter() : ScopPass(ID) {} - std::string getFileName(Scop &S) const; - Json::Value getJSON(Scop &S) const; - /// Export the SCoP @p S to a JSON file. bool runOnScop(Scop &S) override; @@ -76,46 +74,6 @@ static char ID; std::vector NewAccessStrings; explicit JSONImporter() : ScopPass(ID) {} - - /// Import a new context from JScop. - /// - /// @param S The scop to update. - /// @param JScop The JScop file describing the new schedule. - /// - /// @returns True if the import succeeded, otherwise False. - bool importContext(Scop &S, Json::Value &JScop); - - /// Import a new schedule from JScop. - /// - /// ... and verify that the new schedule does preserve existing data - /// dependences. - /// - /// @param S The scop to update. - /// @param JScop The JScop file describing the new schedule. - /// @param D The data dependences of the @p S. - /// - /// @returns True if the import succeeded, otherwise False. - bool importSchedule(Scop &S, Json::Value &JScop, const Dependences &D); - - /// Import new arrays from JScop. - /// - /// @param S The scop to update. - /// @param JScop The JScop file describing new arrays. - /// - /// @returns True if the import succeeded, otherwise False. - bool importArrays(Scop &S, Json::Value &JScop); - - /// Import new memory accesses from JScop. - /// - /// @param S The scop to update. - /// @param JScop The JScop file describing the new schedule. - /// @param DL The data layout to assume. - /// - /// @returns True if the import succeeded, otherwise False. - bool importAccesses(Scop &S, Json::Value &JScop, const DataLayout &DL); - - std::string getFileName(Scop &S) const; - /// Import new access functions for SCoP @p S from a JSON file. bool runOnScop(Scop &S) override; @@ -127,21 +85,22 @@ }; } // namespace -char JSONExporter::ID = 0; -std::string JSONExporter::getFileName(Scop &S) const { +static std::string getFileName(Scop &S, StringRef Suffix = "") { std::string FunctionName = S.getFunction().getName(); std::string FileName = FunctionName + "___" + S.getNameStr() + ".jscop"; + + if (Suffix != "") + FileName += "." + Suffix.str(); + return FileName; } -void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { OS << S; } - /// Export all arrays from the Scop. /// /// @param S The Scop containing the arrays. /// /// @returns Json::Value containing the arrays. -Json::Value exportArrays(const Scop &S) { +static Json::Value exportArrays(const Scop &S) { Json::Value Arrays; std::string Buffer; llvm::raw_string_ostream RawStringOstream(Buffer); @@ -170,7 +129,7 @@ return Arrays; } -Json::Value JSONExporter::getJSON(Scop &S) const { +static Json::Value getJSON(Scop &S) { Json::Value root; unsigned LineBegin, LineEnd; std::string FileName; @@ -213,7 +172,7 @@ return root; } -bool JSONExporter::runOnScop(Scop &S) { +static void exportScop(Scop &S) { std::string FileName = ImportDir + "/" + getFileName(S); Json::Value jscop = getJSON(S); @@ -234,45 +193,23 @@ if (!F.os().has_error()) { errs() << "\n"; F.keep(); - return false; + return; } } errs() << " error opening file for writing!\n"; F.os().clear_error(); - - return false; -} - -void JSONExporter::getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - AU.addRequired(); -} - -Pass *polly::createJSONExporterPass() { return new JSONExporter(); } - -char JSONImporter::ID = 0; -std::string JSONImporter::getFileName(Scop &S) const { - std::string FunctionName = S.getFunction().getName(); - std::string FileName = FunctionName + "___" + S.getNameStr() + ".jscop"; - - if (ImportPostfix != "") - FileName += "." + ImportPostfix; - - return FileName; -} - -void JSONImporter::printScop(raw_ostream &OS, Scop &S) const { - OS << S; - for (std::vector::const_iterator I = NewAccessStrings.begin(), - E = NewAccessStrings.end(); - I != E; I++) - OS << "New access function '" << *I << "' detected in JSCOP file\n"; } typedef Dependences::StatementToIslMapTy StatementToIslMapTy; -bool JSONImporter::importContext(Scop &S, Json::Value &JScop) { +/// Import a new context from JScop. +/// +/// @param S The scop to update. +/// @param JScop The JScop file describing the new schedule. +/// +/// @returns True if the import succeeded, otherwise False. +static bool importContext(Scop &S, Json::Value &JScop) { isl_set *OldContext = S.getContext().release(); // Check if key 'context' is present. @@ -324,8 +261,17 @@ return true; } -bool JSONImporter::importSchedule(Scop &S, Json::Value &JScop, - const Dependences &D) { +/// Import a new schedule from JScop. +/// +/// ... and verify that the new schedule does preserve existing data +/// dependences. +/// +/// @param S The scop to update. +/// @param JScop The JScop file describing the new schedule. +/// @param D The data dependences of the @p S. +/// +/// @returns True if the import succeeded, otherwise False. +static bool importSchedule(Scop &S, Json::Value &JScop, const Dependences &D) { StatementToIslMapTy NewSchedule; // Check if key 'statements' is present. @@ -405,8 +351,17 @@ return true; } -bool JSONImporter::importAccesses(Scop &S, Json::Value &JScop, - const DataLayout &DL) { +/// Import new memory accesses from JScop. +/// +/// @param S The scop to update. +/// @param JScop The JScop file describing the new schedule. +/// @param DL The data layout to assume. +/// @param NewAccessStrings optionally record the imported access strings +/// +/// @returns True if the import succeeded, otherwise False. +static bool +importAccesses(Scop &S, Json::Value &JScop, const DataLayout &DL, + std::vector *NewAccessStrings = nullptr) { int StatementIdx = 0; // Check if key 'statements' is present. @@ -582,7 +537,8 @@ if (!isl_map_is_equal(NewAccessMap, CurrentAccessMap)) { // Statistics. ++NewAccessMapFound; - NewAccessStrings.push_back(Accesses.asCString()); + if (NewAccessStrings) + NewAccessStrings->push_back(Accesses.asCString()); MA->setNewAccessRelation(isl::manage(NewAccessMap)); } else { isl_map_free(NewAccessMap); @@ -597,7 +553,7 @@ } /// Check whether @p SAI and @p Array represent the same array. -bool areArraysEqual(ScopArrayInfo *SAI, Json::Value Array) { +static bool areArraysEqual(ScopArrayInfo *SAI, Json::Value Array) { std::string Buffer; llvm::raw_string_ostream RawStringOstream(Buffer); @@ -648,8 +604,8 @@ /// @param TypeTextRepresentation The textual representation of the type. /// @return The pointer to the primitive type, if this type is accepted /// or nullptr otherwise. -Type *parseTextType(const std::string &TypeTextRepresentation, - LLVMContext &LLVMContext) { +static Type *parseTextType(const std::string &TypeTextRepresentation, + LLVMContext &LLVMContext) { std::map MapStrToType = { {"void", Type::getVoidTy(LLVMContext)}, {"half", Type::getHalfTy(LLVMContext)}, @@ -674,7 +630,13 @@ return nullptr; } -bool JSONImporter::importArrays(Scop &S, Json::Value &JScop) { +/// Import new arrays from JScop. +/// +/// @param S The scop to update. +/// @param JScop The JScop file describing new arrays. +/// +/// @returns True if the import succeeded, otherwise False. +static bool importArrays(Scop &S, Json::Value &JScop) { Json::Value Arrays = JScop["arrays"]; if (Arrays.size() == 0) return true; @@ -726,12 +688,18 @@ return true; } -bool JSONImporter::runOnScop(Scop &S) { - const Dependences &D = - getAnalysis().getDependences(Dependences::AL_Statement); - const DataLayout &DL = S.getFunction().getParent()->getDataLayout(); - - std::string FileName = ImportDir + "/" + getFileName(S); +/// Import a Scop from a JSCOP file +/// @param S The scop to be modified +/// @param D Dependence Info +/// @param DL The DataLayout of the function +/// @param NewAccessStrings Optionally record the imported access strings +/// +/// @returns true on success, false otherwise. Beware that if this returns +/// false, the Scop may still have been modified. In this case the Scop contains +/// invalid information. +static bool importScop(Scop &S, const Dependences &D, const DataLayout &DL, + std::vector *NewAccessStrings = nullptr) { + std::string FileName = ImportDir + "/" + getFileName(S, ImportPostfix); std::string FunctionName = S.getFunction().getName(); errs() << "Reading JScop '" << S.getNameStr() << "' in function '" @@ -770,11 +738,50 @@ if (!Success) return false; - Success = importAccesses(S, jscop, DL); + Success = importAccesses(S, jscop, DL, NewAccessStrings); if (!Success) return false; + return true; +} + +char JSONExporter::ID = 0; +void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { OS << S; } +bool JSONExporter::runOnScop(Scop &S) { + exportScop(S); + return false; +} + +void JSONExporter::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); +} + +Pass *polly::createJSONExporterPass() { return new JSONExporter(); } + +PreservedAnalyses JSONExportPass::run(Scop &S, ScopAnalysisManager &SAM, + ScopStandardAnalysisResults &SAR, + SPMUpdater &) { + exportScop(S); + return PreservedAnalyses::all(); +} + +char JSONImporter::ID = 0; + +void JSONImporter::printScop(raw_ostream &OS, Scop &S) const { + OS << S; + for (std::vector::const_iterator I = NewAccessStrings.begin(), + E = NewAccessStrings.end(); + I != E; I++) + OS << "New access function '" << *I << "' detected in JSCOP file\n"; +} + +bool JSONImporter::runOnScop(Scop &S) { + const Dependences &D = + getAnalysis().getDependences(Dependences::AL_Statement); + const DataLayout &DL = S.getFunction().getParent()->getDataLayout(); + importScop(S, D, DL, &NewAccessStrings); return false; } @@ -785,6 +792,24 @@ Pass *polly::createJSONImporterPass() { return new JSONImporter(); } +PreservedAnalyses JSONImportPass::run(Scop &S, ScopAnalysisManager &SAM, + ScopStandardAnalysisResults &SAR, + SPMUpdater &) { + const Dependences &D = + SAM.getResult(S, SAR).getDependences( + Dependences::AL_Statement); + const DataLayout &DL = S.getFunction().getParent()->getDataLayout(); + + importScop(S, D, DL); + + // This invalidates all analyses on Scop. + PreservedAnalyses PA; + PA.preserveSet>(); + PA.preserveSet>(); + PA.preserveSet>(); + return PA; +} + INITIALIZE_PASS_BEGIN(JSONExporter, "polly-export-jscop", "Polly - Export Scops as JSON" " (Writes a .jscop file for each Scop)", Index: polly/trunk/lib/Support/PollyPasses.def =================================================================== --- polly/trunk/lib/Support/PollyPasses.def +++ polly/trunk/lib/Support/PollyPasses.def @@ -23,6 +23,8 @@ #ifndef SCOP_PASS #define SCOP_PASS(NAME, CREATE_PASS) #endif +SCOP_PASS("polly-export-jscop", JSONExportPass()) +SCOP_PASS("polly-import-jscop", JSONImportPass()) SCOP_PASS("print", IslAstPrinterPass(outs())) SCOP_PASS("print", DependenceInfoPrinterPass(outs())) SCOP_PASS("polly-codegen", CodeGenerationPass()) Index: polly/trunk/lib/Support/RegisterPasses.cpp =================================================================== --- polly/trunk/lib/Support/RegisterPasses.cpp +++ polly/trunk/lib/Support/RegisterPasses.cpp @@ -30,6 +30,7 @@ #include "polly/DependenceInfo.h" #include "polly/FlattenSchedule.h" #include "polly/ForwardOpTree.h" +#include "polly/JSONExporter.h" #include "polly/LinkAllPasses.h" #include "polly/Options.h" #include "polly/PolyhedralInfo.h" @@ -473,7 +474,8 @@ assert(!EnablePolyhedralInfo && "This option is not implemented"); assert(!EnableDeLICM && "This option is not implemented"); assert(!EnableSimplify && "This option is not implemented"); - assert(!ImportJScop && "This option is not implemented"); + if (ImportJScop) + SPM.addPass(JSONImportPass()); assert(!DeadCodeElim && "This option is not implemented"); assert(!EnablePruneUnprofitable && "This option is not implemented"); if (Target == TARGET_CPU || Target == TARGET_HYBRID)