From d7754a1245ea5462d50649252b10c21ec13c2fc2 Mon Sep 17 00:00:00 2001 From: Roman Gareev Date: Sat, 30 Jul 2016 09:25:51 +0000 Subject: [PATCH] Extend the jscop interface to allow the user to declare new arrays and to reference these arrays from access expressions Extend the jscop interface to allow the user to export arrays. It is required that already existing arrays of the list of arrays correspond to arrays of the SCoP. Each array that is appended to the list will be newly created. Furthermore, we allow the user to modify access expressions to reference any array in case it has the same element type. Reviewed-by: Tobias Grosser Differential Revision: https://reviews.llvm.org/D22828 llvm-svn: 277263 --- polly/include/polly/CodeGen/IslNodeBuilder.h | 3 + polly/include/polly/ScopInfo.h | 59 ++++-- polly/lib/Analysis/ScopInfo.cpp | 57 ++++-- polly/lib/CodeGen/BlockGenerators.cpp | 9 +- polly/lib/CodeGen/CodeGeneration.cpp | 1 + polly/lib/CodeGen/IslNodeBuilder.cpp | 26 +++ polly/lib/CodeGen/PPCGCodeGeneration.cpp | 11 +- polly/lib/Exchange/JSONExporter.cpp | 169 +++++++++++++++++- .../Isl/CodeGen/MemAccess/create_arrays.ll | 76 ++++++++ .../create_arrays___%bb9---%bb26.jscop | 37 ++++ ...te_arrays___%bb9---%bb26.jscop.transformed | 52 ++++++ 11 files changed, 458 insertions(+), 42 deletions(-) create mode 100644 polly/test/Isl/CodeGen/MemAccess/create_arrays.ll create mode 100644 polly/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop create mode 100644 polly/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop.transformed diff --git a/polly/include/polly/CodeGen/IslNodeBuilder.h b/polly/include/polly/CodeGen/IslNodeBuilder.h index edc14eeb4c6c..3c8ae652ab82 100644 --- a/polly/include/polly/CodeGen/IslNodeBuilder.h +++ b/polly/include/polly/CodeGen/IslNodeBuilder.h @@ -55,6 +55,9 @@ public: void addParameters(__isl_take isl_set *Context); void create(__isl_take isl_ast_node *Node); + /// @brief Allocate memory for all new arrays created by Polly. + void allocateNewArrays(); + /// @brief Preload all memory loads that are invariant. bool preloadInvariantLoads(); diff --git a/polly/include/polly/ScopInfo.h b/polly/include/polly/ScopInfo.h index f3680a4f565e..3fe7c72cbb2f 100644 --- a/polly/include/polly/ScopInfo.h +++ b/polly/include/polly/ScopInfo.h @@ -231,9 +231,10 @@ public: /// @param Kind The kind of the array object. /// @param DL The data layout of the module. /// @param S The scop this array object belongs to. + /// @param BaseName The optional name of this memory reference. ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *IslCtx, ArrayRef DimensionSizes, enum MemoryKind Kind, - const DataLayout &DL, Scop *S); + const DataLayout &DL, Scop *S, const char *BaseName = nullptr); /// @brief Update the element type of the ScopArrayInfo object. /// @@ -1398,9 +1399,14 @@ private: /// @brief The affinator used to translate SCEVs to isl expressions. SCEVAffinator Affinator; - typedef MapVector, int>, - std::unique_ptr> + typedef std::map, int>, + std::unique_ptr> ArrayInfoMapTy; + + typedef StringMap> ArrayNameMapTy; + + typedef SetVector ArrayInfoSetTy; + /// @brief A map to remember ScopArrayInfo objects for all base pointers. /// /// As PHI nodes may have two array info objects associated, we add a flag @@ -1408,6 +1414,14 @@ private: /// and the normal one. ArrayInfoMapTy ScopArrayInfoMap; + /// @brief A map to remember ScopArrayInfo objects for all names of memory + /// references. + ArrayNameMapTy ScopArrayNameMap; + + /// @brief A set to remember ScopArrayInfo objects. + /// @see Scop::ScopArrayInfoMap + ArrayInfoSetTy ScopArrayInfoSet; + /// @brief The assumptions under which this scop was built. /// /// When constructing a scop sometimes the exact representation of a statement @@ -1855,21 +1869,21 @@ public: /// could be executed. bool isEmpty() const { return Stmts.empty(); } - typedef ArrayInfoMapTy::iterator array_iterator; - typedef ArrayInfoMapTy::const_iterator const_array_iterator; - typedef iterator_range array_range; - typedef iterator_range const_array_range; + typedef ArrayInfoSetTy::iterator array_iterator; + typedef ArrayInfoSetTy::const_iterator const_array_iterator; + typedef iterator_range array_range; + typedef iterator_range const_array_range; - inline array_iterator array_begin() { return ScopArrayInfoMap.begin(); } + inline array_iterator array_begin() { return ScopArrayInfoSet.begin(); } - inline array_iterator array_end() { return ScopArrayInfoMap.end(); } + inline array_iterator array_end() { return ScopArrayInfoSet.end(); } inline const_array_iterator array_begin() const { - return ScopArrayInfoMap.begin(); + return ScopArrayInfoSet.begin(); } inline const_array_iterator array_end() const { - return ScopArrayInfoMap.end(); + return ScopArrayInfoSet.end(); } inline array_range arrays() { @@ -2148,10 +2162,21 @@ public: /// /// @param ElementType The type of the elements stored in this array. /// @param Kind The kind of the array info object. + /// @param BaseName The optional name of this memory reference. const ScopArrayInfo *getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType, ArrayRef Sizes, - ScopArrayInfo::MemoryKind Kind); + ScopArrayInfo::MemoryKind Kind, + const char *BaseName = nullptr); + + /// @brief Create an array and return the corresponding ScopArrayInfo object. + /// + /// @param ElementType The type of the elements stored in this array. + /// @param BaseName The name of this memory reference. + /// @param Sizes The sizes of dimensions. + const ScopArrayInfo *createScopArrayInfo(Type *ElementType, + const std::string &BaseName, + const std::vector &Sizes); /// @brief Return the cached ScopArrayInfo object for @p BasePtr. /// @@ -2165,7 +2190,11 @@ public: /// @param BasePtr The base pointer of the ScopArrayInfo object to invalidate. /// @param Kind The Kind of the ScopArrayInfo object. void invalidateScopArrayInfo(Value *BasePtr, ScopArrayInfo::MemoryKind Kind) { - ScopArrayInfoMap.erase(std::make_pair(BasePtr, Kind)); + auto It = ScopArrayInfoMap.find(std::make_pair(BasePtr, Kind)); + if (It == ScopArrayInfoMap.end()) + return; + ScopArrayInfoSet.remove(It->second.get()); + ScopArrayInfoMap.erase(It); } void setContext(isl_set *NewContext); @@ -2275,6 +2304,10 @@ public: /// >0 for other loops in the SCoP /// -1 if @p L is nullptr or there is no outermost loop in the SCoP int getRelativeLoopDepth(const Loop *L) const; + + /// @brief Find the ScopArrayInfo associated with an isl Id + /// that has name @p Name. + ScopArrayInfo *getArrayInfoByName(const std::string BaseName); }; /// @brief Print Scop scop to raw_ostream O. diff --git a/polly/lib/Analysis/ScopInfo.cpp b/polly/lib/Analysis/ScopInfo.cpp index a5693413ca0d..c8b61bb2a81e 100644 --- a/polly/lib/Analysis/ScopInfo.cpp +++ b/polly/lib/Analysis/ScopInfo.cpp @@ -169,13 +169,21 @@ static const ScopArrayInfo *identifyBasePtrOriginSAI(Scop *S, Value *BasePtr) { ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *Ctx, ArrayRef Sizes, enum MemoryKind Kind, - const DataLayout &DL, Scop *S) + const DataLayout &DL, Scop *S, + const char *BaseName) : BasePtr(BasePtr), ElementType(ElementType), Kind(Kind), DL(DL), S(*S) { std::string BasePtrName = - getIslCompatibleName("MemRef_", BasePtr, Kind == MK_PHI ? "__phi" : ""); + BaseName ? BaseName : getIslCompatibleName("MemRef_", BasePtr, + Kind == MK_PHI ? "__phi" : ""); Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this); updateSizes(Sizes); + + if (!BasePtr) { + BasePtrOriginSAI = nullptr; + return; + } + BasePtrOriginSAI = identifyBasePtrOriginSAI(S, BasePtr); if (BasePtrOriginSAI) const_cast(BasePtrOriginSAI)->addDerivedSAI(this); @@ -3133,7 +3141,9 @@ Scop::~Scop() { // Explicitly release all Scop objects and the underlying isl objects before // we relase the isl context. Stmts.clear(); + ScopArrayInfoSet.clear(); ScopArrayInfoMap.clear(); + ScopArrayNameMap.clear(); AccFuncMap.clear(); } @@ -3476,15 +3486,19 @@ void Scop::hoistInvariantLoads() { isl_union_map_free(Writes); } -const ScopArrayInfo * -Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType, - ArrayRef Sizes, - ScopArrayInfo::MemoryKind Kind) { - auto &SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)]; +const ScopArrayInfo *Scop::getOrCreateScopArrayInfo( + Value *BasePtr, Type *ElementType, ArrayRef Sizes, + ScopArrayInfo::MemoryKind Kind, const char *BaseName) { + assert((BasePtr || BaseName) && + "BasePtr and BaseName can not be nullptr at the same time."); + assert(!(BasePtr && BaseName) && "BaseName is redundant."); + auto &SAI = BasePtr ? ScopArrayInfoMap[std::make_pair(BasePtr, Kind)] + : ScopArrayNameMap[BaseName]; if (!SAI) { auto &DL = getFunction().getParent()->getDataLayout(); SAI.reset(new ScopArrayInfo(BasePtr, ElementType, getIslCtx(), Sizes, Kind, - DL, this)); + DL, this, BaseName)); + ScopArrayInfoSet.insert(SAI.get()); } else { SAI->updateElementType(ElementType); // In case of mismatching array sizes, we bail out by setting the run-time @@ -3495,6 +3509,21 @@ Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType, return SAI.get(); } +const ScopArrayInfo * +Scop::createScopArrayInfo(Type *ElementType, const std::string &BaseName, + const std::vector &Sizes) { + auto *DimSizeType = Type::getInt64Ty(getSE()->getContext()); + std::vector SCEVSizes; + + for (auto size : Sizes) + SCEVSizes.push_back(getSE()->getConstant(DimSizeType, size, false)); + + auto *SAI = + getOrCreateScopArrayInfo(nullptr, ElementType, SCEVSizes, + ScopArrayInfo::MK_Array, BaseName.c_str()); + return SAI; +} + const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, ScopArrayInfo::MemoryKind Kind) { auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)].get(); @@ -3781,14 +3810,14 @@ void Scop::printArrayInfo(raw_ostream &OS) const { OS << "Arrays {\n"; for (auto &Array : arrays()) - Array.second->print(OS); + Array->print(OS); OS.indent(4) << "}\n"; OS.indent(4) << "Arrays (Bounds as pw_affs) {\n"; for (auto &Array : arrays()) - Array.second->print(OS, /* SizeAsPwAff */ true); + Array->print(OS, /* SizeAsPwAff */ true); OS.indent(4) << "}\n"; } @@ -4187,6 +4216,14 @@ int Scop::getRelativeLoopDepth(const Loop *L) const { return L->getLoopDepth() - OuterLoop->getLoopDepth(); } +ScopArrayInfo *Scop::getArrayInfoByName(const std::string BaseName) { + for (auto &SAI : arrays()) { + if (SAI->getName() == BaseName) + return SAI; + } + return nullptr; +} + //===----------------------------------------------------------------------===// void ScopInfoRegionPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); diff --git a/polly/lib/CodeGen/BlockGenerators.cpp b/polly/lib/CodeGen/BlockGenerators.cpp index 9d0517d5fbb7..510dc8678d18 100644 --- a/polly/lib/CodeGen/BlockGenerators.cpp +++ b/polly/lib/CodeGen/BlockGenerators.cpp @@ -485,8 +485,7 @@ void BlockGenerator::createScalarInitialization(Scop &S) { Builder.SetInsertPoint(StartBB->getTerminator()); - for (auto &Pair : S.arrays()) { - auto &Array = Pair.second; + for (auto &Array : S.arrays()) { if (Array->getNumberOfDimensions() != 0) continue; if (Array->isPHIKind()) { @@ -576,8 +575,7 @@ void BlockGenerator::createScalarFinalization(Scop &S) { } void BlockGenerator::findOutsideUsers(Scop &S) { - for (auto &Pair : S.arrays()) { - auto &Array = Pair.second; + for (auto &Array : S.arrays()) { if (Array->getNumberOfDimensions() != 0) continue; @@ -613,8 +611,7 @@ void BlockGenerator::createExitPHINodeMerges(Scop &S) { Builder.SetInsertPoint(OptExitBB->getTerminator()); - for (auto &Pair : S.arrays()) { - auto &SAI = Pair.second; + for (auto &SAI : S.arrays()) { auto *Val = SAI->getBasePtr(); // Only Value-like scalars need a merge PHI. Exit block PHIs receive either diff --git a/polly/lib/CodeGen/CodeGeneration.cpp b/polly/lib/CodeGen/CodeGeneration.cpp index 709f3601a3a7..4550a0598aaa 100644 --- a/polly/lib/CodeGen/CodeGeneration.cpp +++ b/polly/lib/CodeGen/CodeGeneration.cpp @@ -189,6 +189,7 @@ public: isl_ast_node_free(AstRoot); } else { + NodeBuilder.allocateNewArrays(); NodeBuilder.addParameters(S.getContext()); diff --git a/polly/lib/CodeGen/IslNodeBuilder.cpp b/polly/lib/CodeGen/IslNodeBuilder.cpp index 6b1025893f4d..fa10d64dbb1f 100644 --- a/polly/lib/CodeGen/IslNodeBuilder.cpp +++ b/polly/lib/CodeGen/IslNodeBuilder.cpp @@ -1157,6 +1157,32 @@ bool IslNodeBuilder::preloadInvariantEquivClass( return true; } +void IslNodeBuilder::allocateNewArrays() { + for (auto &SAI : S.arrays()) { + if (SAI->getBasePtr()) + continue; + + Type *NewArrayType = nullptr; + for (unsigned i = SAI->getNumberOfDimensions() - 1; i >= 1; i--) { + auto *DimSize = SAI->getDimensionSize(i); + unsigned UnsignedDimSize = static_cast(DimSize) + ->getAPInt() + .getLimitedValue(); + + if (!NewArrayType) + NewArrayType = SAI->getElementType(); + + NewArrayType = ArrayType::get(NewArrayType, UnsignedDimSize); + } + + auto InstIt = + Builder.GetInsertBlock()->getParent()->getEntryBlock().getTerminator(); + Value *CreatedArray = + new AllocaInst(NewArrayType, SAI->getName(), &*InstIt); + SAI->setBasePtr(CreatedArray); + } +} + bool IslNodeBuilder::preloadInvariantLoads() { auto &InvariantEquivClasses = S.getInvariantAccesses(); diff --git a/polly/lib/CodeGen/PPCGCodeGeneration.cpp b/polly/lib/CodeGen/PPCGCodeGeneration.cpp index 955aaac08b4f..db32ad40f8a4 100644 --- a/polly/lib/CodeGen/PPCGCodeGeneration.cpp +++ b/polly/lib/CodeGen/PPCGCodeGeneration.cpp @@ -794,7 +794,7 @@ SetVector GPUNodeBuilder::getReferencesInKernel(ppcg_kernel *Kernel) { findValues(Expr, SE, SubtreeValues); for (auto &SAI : S.arrays()) - SubtreeValues.remove(SAI.second->getBasePtr()); + SubtreeValues.remove(SAI->getBasePtr()); isl_space *Space = S.getParamSpace(); for (long i = 0; i < isl_space_dim(Space, isl_dim_param); i++) { @@ -1379,7 +1379,7 @@ public: } for (auto &Array : S->arrays()) { - auto Id = Array.second->getBasePtrId(); + auto Id = Array->getBasePtrId(); Names = isl_id_to_ast_expr_set(Names, Id, isl_ast_expr_copy(Zero)); } @@ -1550,9 +1550,7 @@ public: /// @param PPCGProg The program to compute the arrays for. void createArrays(gpu_prog *PPCGProg) { int i = 0; - for (auto &Element : S->arrays()) { - ScopArrayInfo *Array = Element.second.get(); - + for (auto &Array : S->arrays()) { std::string TypeName; raw_string_ostream OS(TypeName); @@ -1595,8 +1593,7 @@ public: isl_union_map *getArrayIdentity() { isl_union_map *Maps = isl_union_map_empty(S->getParamSpace()); - for (auto &Item : S->arrays()) { - ScopArrayInfo *Array = Item.second.get(); + for (auto &Array : S->arrays()) { isl_space *Space = Array->getSpace(); Space = isl_space_map_from_set(Space); isl_map *Identity = isl_map_identity(Space); diff --git a/polly/lib/Exchange/JSONExporter.cpp b/polly/lib/Exchange/JSONExporter.cpp index 73177ce757d2..299687029039 100644 --- a/polly/lib/Exchange/JSONExporter.cpp +++ b/polly/lib/Exchange/JSONExporter.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/raw_ostream.h" #include "isl/constraint.h" #include "isl/map.h" #include "isl/printer.h" @@ -96,6 +97,14 @@ struct JSONImporter : public ScopPass { /// @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. @@ -127,6 +136,35 @@ std::string JSONExporter::getFileName(Scop &S) const { void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { S.print(OS); } +/// 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) { + Json::Value Arrays; + std::string Buffer; + llvm::raw_string_ostream RawStringOstream(Buffer); + + for (auto &SAI : S.arrays()) { + if (!SAI->isArrayKind()) + continue; + + Json::Value Array; + Array["name"] = SAI->getName(); + for (unsigned i = 1; i < SAI->getNumberOfDimensions(); i++) { + SAI->getDimensionSize(i)->print(RawStringOstream); + Array["sizes"].append(RawStringOstream.str()); + Buffer.clear(); + } + SAI->getElementType()->print(RawStringOstream); + Array["type"] = RawStringOstream.str(); + Buffer.clear(); + Arrays.append(Array); + } + return Arrays; +} + Json::Value JSONExporter::getJSON(Scop &S) const { Json::Value root; unsigned LineBegin, LineEnd; @@ -142,6 +180,9 @@ Json::Value JSONExporter::getJSON(Scop &S) const { root["context"] = S.getContextStr(); if (LineBegin != (unsigned)-1) root["location"] = Location; + + root["arrays"] = exportArrays(S); + root["statements"]; for (ScopStmt &Stmt : S) { @@ -305,8 +346,28 @@ bool JSONImporter::importAccesses(Scop &S, Json::Value &JScop, return false; } - isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out); - NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, OutId); + isl_id *NewOutId; + + if (MA->isArrayKind()) { + NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out); + auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId)); + isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out); + auto *OutSAI = ScopArrayInfo::getFromId(OutId); + if (!SAI || SAI->getElementType() != OutSAI->getElementType()) { + errs() << "JScop file contains access function with undeclared " + "ScopArrayInfo\n"; + isl_map_free(CurrentAccessMap); + isl_map_free(NewAccessMap); + isl_id_free(NewOutId); + return false; + } + isl_id_free(NewOutId); + NewOutId = SAI->getBasePtrId(); + } else { + NewOutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out); + } + + NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, NewOutId); if (MA->isArrayKind()) { // We keep the old alignment, thus we cannot allow accesses to memory @@ -354,17 +415,19 @@ bool JSONImporter::importAccesses(Scop &S, Json::Value &JScop, isl_id *Id = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_in); NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_in, Id); - if (!isl_map_has_equal_space(CurrentAccessMap, NewAccessMap)) { + auto NewAccessDomain = isl_map_domain(isl_map_copy(NewAccessMap)); + auto CurrentAccessDomain = isl_map_domain(isl_map_copy(CurrentAccessMap)); + + if (!isl_set_has_equal_space(NewAccessDomain, CurrentAccessDomain)) { errs() << "JScop file contains access function with incompatible " << "dimensions\n"; isl_map_free(CurrentAccessMap); isl_map_free(NewAccessMap); + isl_set_free(NewAccessDomain); + isl_set_free(CurrentAccessDomain); return false; } - auto NewAccessDomain = isl_map_domain(isl_map_copy(NewAccessMap)); - auto CurrentAccessDomain = isl_map_domain(isl_map_copy(CurrentAccessMap)); - NewAccessDomain = isl_set_intersect_params(NewAccessDomain, S.getContext()); CurrentAccessDomain = @@ -400,6 +463,95 @@ bool JSONImporter::importAccesses(Scop &S, Json::Value &JScop, return true; } +/// @brief Check whether @p SAI and @p Array represent the same array. +bool areArraysEqual(ScopArrayInfo *SAI, Json::Value Array) { + std::string Buffer; + llvm::raw_string_ostream RawStringOstream(Buffer); + + if (SAI->getName() != Array["name"].asCString()) + return false; + + if (SAI->getNumberOfDimensions() != Array["sizes"].size() + 1) + return false; + + for (unsigned i = 0; i < Array["sizes"].size(); i++) { + SAI->getDimensionSize(i + 1)->print(RawStringOstream); + if (RawStringOstream.str() != Array["sizes"][i].asCString()) + return false; + Buffer.clear(); + } + + SAI->getElementType()->print(RawStringOstream); + if (RawStringOstream.str() != Array["type"].asCString()) + return false; + + return true; +} + +/// @brief Get the accepted primitive type from its textual representation +/// @p TypeTextRepresentation. +/// +/// @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) { + std::map MapStrToType = { + {"void", Type::getVoidTy(LLVMContext)}, + {"half", Type::getHalfTy(LLVMContext)}, + {"float", Type::getFloatTy(LLVMContext)}, + {"double", Type::getDoubleTy(LLVMContext)}, + {"x86_fp80", Type::getX86_FP80Ty(LLVMContext)}, + {"fp128", Type::getFP128Ty(LLVMContext)}, + {"ppc_fp128", Type::getPPC_FP128Ty(LLVMContext)}, + {"i1", Type::getInt1Ty(LLVMContext)}, + {"i8", Type::getInt8Ty(LLVMContext)}, + {"i16", Type::getInt16Ty(LLVMContext)}, + {"i32", Type::getInt32Ty(LLVMContext)}, + {"i64", Type::getInt64Ty(LLVMContext)}, + {"i128", Type::getInt128Ty(LLVMContext)}}; + + auto It = MapStrToType.find(TypeTextRepresentation); + if (It != MapStrToType.end()) + return It->second; + + errs() << "Textual representation can not be parsed: " + << TypeTextRepresentation << "\n"; + return nullptr; +} + +bool JSONImporter::importArrays(Scop &S, Json::Value &JScop) { + Json::Value Arrays = JScop["arrays"]; + + if (Arrays.size() == 0) + return true; + + unsigned ArrayIdx = 0; + for (auto &SAI : S.arrays()) { + if (!SAI->isArrayKind()) + continue; + if (ArrayIdx + 1 > Arrays.size()) + return false; + if (!areArraysEqual(SAI, Arrays[ArrayIdx])) + return false; + ArrayIdx++; + } + + for (; ArrayIdx < Arrays.size(); ArrayIdx++) { + auto *ElementType = parseTextType(Arrays[ArrayIdx]["type"].asCString(), + S.getSE()->getContext()); + if (!ElementType) + return false; + std::vector DimSizes; + for (unsigned i = 0; i < Arrays[ArrayIdx]["sizes"].size(); i++) + DimSizes.push_back(std::stoi(Arrays[ArrayIdx]["sizes"][i].asCString())); + S.createScopArrayInfo(ElementType, Arrays[ArrayIdx]["name"].asCString(), + DimSizes); + } + + return true; +} + bool JSONImporter::runOnScop(Scop &S) { const Dependences &D = getAnalysis().getDependences(Dependences::AL_Statement); @@ -436,6 +588,11 @@ bool JSONImporter::runOnScop(Scop &S) { Success = importSchedule(S, jscop, D); + if (!Success) + return false; + + Success = importArrays(S, jscop); + if (!Success) return false; diff --git a/polly/test/Isl/CodeGen/MemAccess/create_arrays.ll b/polly/test/Isl/CodeGen/MemAccess/create_arrays.ll new file mode 100644 index 000000000000..d10d6c94bfa7 --- /dev/null +++ b/polly/test/Isl/CodeGen/MemAccess/create_arrays.ll @@ -0,0 +1,76 @@ +; RUN: opt %loadPolly -polly-scops -analyze -polly-import-jscop-dir=%S -polly-import-jscop -polly-import-jscop-postfix=transformed < %s 2>&1 | FileCheck %s +; RUN: opt %loadPolly -polly-import-jscop-dir=%S -polly-import-jscop -polly-import-jscop-postfix=transformed -polly-codegen -S < %s 2>&1 | FileCheck %s --check-prefix=CODEGEN +; +; for (i = 0; i < _PB_NI; i++) +; for (j = 0; j < _PB_NJ; j++) +; for (k = 0; k < _PB_NK; ++k) +; B[i][j] = beta * A[i][k]; +; +; +; CHECK: Arrays { +; CHECK: double MemRef_B[*][1024]; // Element size 8 +; CHECK: double MemRef_beta; // Element size 8 +; CHECK: double MemRef_A[*][1056]; // Element size 8 +; CHECK: double D[*][270336]; // Element size 8 +; CHECK: double E[*][270336][200000]; // Element size 8 +; CHECK: i64 F[*][270336]; // Element size 8 +; +; CHECK:New access function '{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }'detected in JSCOP file +; +;define internal void @create_arrays(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 { +;bb: +; %beta.s2a = alloca double +; %D = alloca [270336 x double] +; %E = alloca [270336 x [200000 x double]] +; %F = alloca [270336 x i64] +; br label %bb8 +; +; CODEGEN: %polly.access.cast.E = bitcast [270336 x [200000 x double]]* %E to double* +; CODEGEN: %polly.access.mul.E = mul nsw i64 %polly.indvar33, 270336 +; CODEGEN: %polly.access.add.E = add nsw i64 %polly.access.mul.E, %polly.indvar +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-unknown" + +; Function Attrs: nounwind uwtable +define internal void @create_arrays(i32 %arg, i32 %arg1, i32 %arg2, double %arg3, double %beta, [1056 x double]* %A, [1024 x double]* %B, [1056 x double]* %arg7) #0 { +bb: + br label %bb8 + +bb8: ; preds = %bb + br label %bb9 + +bb9: ; preds = %bb23, %bb8 + %tmp = phi i64 [ 0, %bb8 ], [ %tmp24, %bb23 ] + br label %bb10 + +bb10: ; preds = %bb20, %bb9 + %tmp11 = phi i64 [ 0, %bb9 ], [ %tmp21, %bb20 ] + br label %bb12 + +bb12: ; preds = %bb12, %bb10 + %tmp13 = phi i64 [ 0, %bb10 ], [ %tmp18, %bb12 ] + %tmp14 = getelementptr inbounds [1024 x double], [1024 x double]* %B, i64 %tmp, i64 %tmp13 + %tmp15 = load double, double* %tmp14, align 8 + %tmp16 = fmul double %tmp15, %beta + %tmp17 = getelementptr inbounds [1056 x double], [1056 x double]* %A, i64 %tmp, i64 %tmp11 + store double %tmp16, double* %tmp17, align 8 + %tmp18 = add nuw nsw i64 %tmp13, 1 + %tmp19 = icmp ne i64 %tmp18, 1024 + br i1 %tmp19, label %bb12, label %bb20 + +bb20: ; preds = %bb12 + %tmp21 = add nuw nsw i64 %tmp11, 1 + %tmp22 = icmp ne i64 %tmp21, 1056 + br i1 %tmp22, label %bb10, label %bb23 + +bb23: ; preds = %bb20 + %tmp24 = add nuw nsw i64 %tmp, 1 + %tmp25 = icmp ne i64 %tmp24, 1056 + br i1 %tmp25, label %bb9, label %bb26 + +bb26: ; preds = %bb23 + ret void +} + +attributes #0 = { nounwind uwtable "target-cpu"="x86-64" "target-features"="+aes,+avx,+cmov,+cx16,+fxsr,+mmx,+pclmul,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt" } diff --git a/polly/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop b/polly/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop new file mode 100644 index 000000000000..4ceaa41d4cb4 --- /dev/null +++ b/polly/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop @@ -0,0 +1,37 @@ +{ + "arrays" : [ + { + "name" : "MemRef_B", + "sizes" : [ "1024" ], + "type" : "double" + }, + { + "name" : "MemRef_A", + "sizes" : [ "1056" ], + "type" : "double" + } + ], + "context" : "{ : }", + "name" : "%bb9---%bb26", + "statements" : [ + { + "accesses" : [ + { + "kind" : "read", + "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_B[i0, i2] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }" + }, + { + "kind" : "write", + "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }" + } + ], + "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }", + "name" : "Stmt_bb12", + "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }" + } + ] +} diff --git a/polly/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop.transformed b/polly/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop.transformed new file mode 100644 index 000000000000..67a126478d86 --- /dev/null +++ b/polly/test/Isl/CodeGen/MemAccess/create_arrays___%bb9---%bb26.jscop.transformed @@ -0,0 +1,52 @@ +{ + "arrays" : [ + { + "name" : "MemRef_B", + "sizes" : [ "1024" ], + "type" : "double" + }, + { + "name" : "MemRef_A", + "sizes" : [ "1056" ], + "type" : "double" + }, + { + "name" : "D", + "sizes" : [ "270336" ], + "type" : "double" + }, + { + "name" : "E", + "sizes" : [ "270336", "200000" ], + "type" : "double" + }, + { + "name" : "F", + "sizes" : [ "270336" ], + "type" : "i64" + } + ], + "context" : "{ : }", + "name" : "%bb9---%bb26", + "statements" : [ + { + "accesses" : [ + { + "kind" : "read", + "relation" : "{ Stmt_bb12[i0, i1, i2] -> E[i2, i0] }" + }, + { + "kind" : "read", + "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_beta[] }" + }, + { + "kind" : "write", + "relation" : "{ Stmt_bb12[i0, i1, i2] -> MemRef_A[i0, i1] }" + } + ], + "domain" : "{ Stmt_bb12[i0, i1, i2] : 0 <= i0 <= 1055 and 0 <= i1 <= 1055 and 0 <= i2 <= 1023 }", + "name" : "Stmt_bb12", + "schedule" : "{ Stmt_bb12[i0, i1, i2] -> [i0, i1, i2] }" + } + ] +}