#include "../Utils/leak_detector.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "errors.h" #include "version.h" #include "../GraphLoop/graph_loops.h" #include "../Distribution/Array.h" #include "../Distribution/Arrays.h" #include "../DynamicAnalysis/gcov_info.h" #include "../ParallelizationRegions/ParRegions.h" #include "json.hpp" #if __SPF #include "acc_analyzer.h" #endif using std::map; using std::pair; using std::tuple; using std::set; using std::vector; using std::string; using std::wstring; using json = nlohmann::json; #if __cplusplus >= 201703L #include namespace fs = std::filesystem; #else #ifdef _WIN32 #include #else #include #endif #endif void createMapLoopGraph(map &sortedLoopGraph, const vector *loopGraph) { if (loopGraph) { for (int i = 0; i < (int)loopGraph->size(); ++i) { auto it = sortedLoopGraph.find((*loopGraph)[i]->lineNum); if (it != sortedLoopGraph.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); sortedLoopGraph[(*loopGraph)[i]->lineNum] = (*loopGraph)[i]; createMapLoopGraph(sortedLoopGraph, &((*loopGraph)[i]->children)); } } } string FullNameWithExt(const char* filename) { char* basename = new char[strlen(filename) + 1]; int i; strcpy(basename, filename); for (i = (int)strlen(filename) - 1; i >= 0; --i) { if (basename[i] == '.') { basename[i] = '_'; break; } } string retVal(basename); delete[] basename; return retVal; } string OnlyName(const char *filename) { char *basename = new char[strlen(filename) + 1]; int i; strcpy(basename, filename); for (i = (int)strlen(filename) - 1; i >= 0; --i) { if (basename[i] == '.') { basename[i] = '\0'; break; } } string retVal(basename); delete[] basename; return retVal; } string OnlyExt(const char *filename) { char *extname = new char[1024]; extname[0] = '\0'; int i; int len = (int)strlen(filename); for (i = len - 1; i >= 0; --i) { if (filename[i] == '.') { i++; int k; int bound = len - i; for (k = 0; k < bound; ++k, ++i) extname[k] = filename[i]; extname[k] = '\0'; break; } } string retVal(extname); delete[] extname; return retVal; } void printHelp(const char **passNames, const int lastPass) { printf("Help info for passes.\n\n"); printf(" -f90 free form\n"); printf(" -sh turn on static shadow analysis\n"); printf(" -shWidth maximum width of shadow in percent\n"); printf(" -ver/-Ver version of SAPFOR\n"); printf(" -priv turn on static private analysis\n"); printf(" -keep keep temporary files\n"); printf(" -keepSPF keep SPF directives\n"); printf(" -keepDVM keep DVM directives\n"); printf(" -allVars get all parallel versions\n"); printf(" -var N get specific parallel version, N=1,2,..\n"); printf(" -parse run parser with next option (-inl option allow to parse project for -inlineH/I regime)\n"); printf(" -pppa run performance statistic analyzer \n"); printf(" -fdvm run fdvm convertation\n"); printf(" -inlineH run hierarchical inlining for all functions called from 'funcName'\n"); printf(" -inlineI run incremental inlining for function 'funcName' on 'lineNum' of 'fileName'\n"); printf(" -passInfo print passes information\n"); printf(" -dumpIR print IR information (works only with BUILD_IR pass)\n"); printf(" -ignoreDistArray ingnore array distribution information (set to all arrays no distribution state\n"); printf(" -shared shared memory and mpi programs parallelization\n"); printf(" -printSymbTable print all symbol tables of project\n"); printf("\n"); printf(" -F output to folder\n"); printf(" -p \n"); printf(" -pass \n"); printf(" -passN \n"); for (int i = 0; i < lastPass; ++i) printf(" pass_num = %d: %s\n", i, passNames[i]); printf("\n"); printf(" -t \n"); printf(" analysis_num = 13: insert parallel directives\n"); throw(-1); } void printVersion(const string pref) { printf("%sSAPFOR version is %s, build date: %s %s, c++ version %d\n", pref.c_str(), VERSION_SPF, __DATE__, __TIME__, __cplusplus); } extern bool noLogo; extern int staticShadowAnalysis; extern int keepDvmDirectives; extern int ignoreIO; extern int keepSpfDirs; extern int maxShadowWidth; const string printVersionAsFortranComm() { if (noLogo) return ""; char buf[512]; sprintf(buf, "! *** generated by SAPFOR with version %s and build date: %s %s\n", VERSION_SPF, __DATE__, __TIME__); string ret = buf; ret += "! *** Enabled options ***:\n"; if (staticShadowAnalysis) ret += "! *** shadow optimization\n"; if (keepDvmDirectives) ret += "! *** consider DVMH directives\n"; if (keepSpfDirs) ret += "! *** save SPF directives\n"; if (sharedMemoryParallelization) ret += "! *** MPI program regime (shared memory parallelization)\n"; if (ignoreIO) ret += "! *** ignore I/O checker for arrays (DVM I/O limitations)\n"; if (maxShadowWidth > 0) ret += "! *** maximum shadow width is " + std::to_string(maxShadowWidth) + " percent\n"; ret += "! *** generated by SAPFOR\n"; return ret; } void convertToLower(string &str) { std::locale loc; for (int i = 0; i < str.length(); ++i) str[i] = std::tolower(str[i], loc); } void convertToUpper(string &str) { std::locale loc; for (int i = 0; i < str.length(); ++i) str[i] = std::toupper(str[i], loc); } void splitString(const string &strIn, const char delim, vector &result, bool withQuotes) { std::stringstream ss; ss.str(strIn); vector tmp_result; string item; while (std::getline(ss, item, delim)) tmp_result.push_back(item); if (withQuotes) { bool quStarted = false; item = ""; for (auto& elem : tmp_result) { if (elem.size()) { if (quStarted) { item += " " + elem; if (elem[elem.size() - 1] == '"') { quStarted = false; result.push_back(item.erase(item.size() - 1, 1)); } } else { if (elem[0] == '"') { quStarted = true; item = elem.erase(0, 1); if (item[item.size() - 1] == '"') { quStarted = false; result.push_back(item.erase(item.size() - 1, 1)); } } else result.push_back(elem); } } else if (quStarted) item += " "; } } else result = tmp_result; } void splitString(const wstring& strIn, const char delim, vector& result, bool withQuotes) { std::wstringstream ss; ss.str(strIn); vector tmp_result; wstring item; wchar_t buf[1024]; while (ss.good()) { ss.getline(buf, 1024, delim); tmp_result.push_back(buf); } if (withQuotes) { bool quStarted = false; item = L""; for (auto& elem : tmp_result) { if (elem.size()) { if (quStarted) { item += elem; if (elem[elem.size() - 1] == L'"') { quStarted = false; result.push_back(item.erase(item.size() - 1, 1)); } } else { if (elem[0] == '"') { quStarted = true; item = elem.erase(0, 1); if (item[item.size() - 1] == L'"') { quStarted = false; result.push_back(item.erase(item.size() - 1, 1)); } } else result.push_back(elem); } } else if (quStarted) item += L" "; } } else result = tmp_result; } void removeSubstrFromStr(string &str, const string &del) { string::size_type pos = str.find(del); while (pos != string::npos) { str.erase(pos, del.size()); pos = str.find(del, pos + 1); } } string convertFileName(const char *file) { string tmp(file); std::reverse(tmp.begin(), tmp.end()); int t = 0; while (tmp[t] != '\\' && tmp[t] != '/' && t < tmp.size()) t++; tmp.erase(tmp.begin() + t, tmp.end()); std::reverse(tmp.begin(), tmp.end()); return tmp; } void printBlanks(const int sizeOfBlank, const int countOfBlanks) { for (int k = 0; k < countOfBlanks; ++k) for (int m = 0; m < sizeOfBlank; ++m) { char buf[256]; sprintf(buf, " "); addToGlobalBufferAndPrint(buf); } } string globalOutputBuffer = ""; int consoleMode = 0; void addToGlobalBufferAndPrint(const string &toPrint) { globalOutputBuffer += toPrint; if (consoleMode) { printf("%s", toPrint.c_str()); fflush(NULL); } } void clearGlobalBuffer() { globalOutputBuffer = ""; } const string& getGlobalBuffer() { return globalOutputBuffer; } set allocated; set allocatedInt; static void convertGlobalBuffer(short *&result, int *&resultSize) { const unsigned len = (unsigned)globalOutputBuffer.size(); result = new short[len + 1]; allocated.insert(result); result[len] = '\0'; for (unsigned i = 0; i < len; ++i) result[i] = globalOutputBuffer[i]; resultSize = new int[1]; resultSize[0] = (int)len; } extern map> SPF_messages; //file ->messages void clearGlobalMessagesBuffer() { //clear allocated memory for (auto& elem : allocated) delete[]elem; for (auto& elem : allocatedInt) delete[]elem; allocated.clear(); allocatedInt.clear(); SPF_messages.clear(); } static map> removeCopies(map> in) { map> out; for (auto& byFile : in) { map, const Messages*> uniq; for (auto& message : byFile.second) { auto key = message.getUniqKey(); /*string tmp = ""; for (auto& s : message.toString()) tmp += (char)s; __spf_print(1, "%s\n", tmp.c_str());*/ uniq[key] = &message; } __spf_print(1, " messages filtering for file '%s': count before %d, count after %d\n", byFile.first.c_str(), byFile.second.size(), uniq.size()); vector uniqV; for (auto& elem : uniq) { /*string tmp = ""; for (auto& s : elem.second->toString()) tmp += (char)s; __spf_print(1, "%s\n", tmp.c_str());*/ uniqV.push_back(*elem.second); } out[byFile.first] = uniqV; } return out; } static void convertGlobalMessagesBuffer(short *&result, int *&resultSize) { auto copySPF_messages = removeCopies(SPF_messages); for (auto &byFile : copySPF_messages) { vector newVal; bool waschanged = false; for (auto &message : byFile.second) { if (message.getLine() > 0) newVal.push_back(message); else waschanged = true; } if (waschanged) byFile.second = newVal; } json allMessages = json::array(); for (auto& byFile : copySPF_messages) { json inFile; inFile["file"] = byFile.first; json array = json::array(); for (auto& message : byFile.second) { json msg = message.toJson(); array.push_back(msg); } inFile["messages"] = array; allMessages.push_back(inFile); } json all; all["allMessages"] = allMessages; const string str = all.dump(); const unsigned len = (unsigned)str.size(); copyStringToShort(result, str); allocated.insert(result); resultSize = new int[1]; resultSize[0] = (int)len; } void convertBuffers(short*& resultM, int*& resultSizeM, short*& result, int*& resultSize) { convertGlobalMessagesBuffer(resultM, resultSizeM); convertGlobalBuffer(result, resultSize); } bool isSPF_comment(const string &bufStr) { bool spfStart = false; if (bufStr.size() > 6) spfStart = (bufStr[0] == '!' || bufStr[0] == 'c') && bufStr[1] == '$' && bufStr[2] == 's' && bufStr[3] == 'p' && bufStr[4] == 'f'; return spfStart; } bool isDVM_comment(const string& bufStr) { bool dvmStart = false; if (bufStr.size() > 6) { dvmStart = (bufStr[0] == '!' || bufStr[0] == 'c') && bufStr[1] == 'd' && bufStr[2] == 'v' && bufStr[3] == 'm' && bufStr[4] == '$'; } return dvmStart; } static string renameExtension(const string& inc) { string ret = inc; if (ret.find(".") != string::npos) ret = OnlyName(ret.c_str()); ret += ".h"; return ret; } string renameInclude(const string& inc) { auto posStart = inc.find("'"); auto posEnd = inc.find("'", posStart + 1); if (posStart == string::npos || posEnd == string::npos) { posStart = inc.find("\""); posEnd = inc.find("\"", posStart + 1); if (posStart == string::npos || posEnd == string::npos) { __spf_print(1, "incorrect include string <%s>\n", inc.c_str()); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } } string substr = renameExtension(inc.substr(posStart + 1, posEnd - posStart - 1)); string ret = inc; ret.replace(posStart + 1, posEnd - posStart - 1, substr); return ret; } void copyIncludes(const set &allIncludeFiles, const map>> &commentsToInclude, const map>>& newCopyDeclToIncl, const char *folderName, bool keepSpfDirs, bool isFreeStyle, bool isRename, int removeDirs) { for (auto &include : allIncludeFiles) { if (commentsToInclude.find(include) != commentsToInclude.end()) continue; string newCurrFile = string(folderName) + "/" + (isRename ? renameExtension(include) : include); FILE *tryToOpen = fopen(newCurrFile.c_str(), "r"); if (tryToOpen == NULL) { __spf_print(1, " try to copy file '%s' to '%s'\n", include.c_str(), newCurrFile.c_str()); FILE *copyFile = fopen(newCurrFile.c_str(), "w"); FILE *oldFile = fopen(include.c_str(), "r"); if (!copyFile) { __spf_print(1, " can not open file '%s' for read\n", include.c_str()); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } if (!oldFile) { __spf_print(1, " can not open file '%s' for write\n", newCurrFile.c_str()); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } while (!feof(oldFile)) { char buf[8192]; char *res = fgets(buf, 16384, oldFile); if (res == NULL) break; const string orig(buf); string bufStr(buf); convertToLower(bufStr); if (!keepSpfDirs) { bool spfStart = isSPF_comment(bufStr); if (spfStart) bufStr = "\n"; } //remove DVM dirs or save DVM dirs as comment if (removeDirs == 1 || removeDirs == 2) { if (bufStr[0] == '!' || bufStr[0] == 'c') { if (bufStr[1] == 'd' && bufStr[2] == 'v' && bufStr[3] == 'm' && bufStr[4] == '$') { if (removeDirs == 1) bufStr = ""; else if (removeDirs == 2) bufStr.insert(1, " "); } } } //remove SPF dirs else if (removeDirs == 3) { if (bufStr[0] == '!' || bufStr[0] == 'c') if (bufStr[1] == '$' && bufStr[2] == 's' && bufStr[3] == 'p' && bufStr[4] == 'f') bufStr = ""; } // save original include name if (bufStr.find("include") != string::npos) fputs(orig.c_str(), copyFile); else { if (bufStr != "") fputs(bufStr.c_str(), copyFile); } } auto newDecls = newCopyDeclToIncl.find(include); if (newDecls != newCopyDeclToIncl.end()) for (auto& declByLine : newDecls->second) for (auto& decl : declByLine.second) fputs(decl.c_str(), copyFile); fclose(oldFile); fclose(copyFile); //TODO: read options /*string text = ""; copyFile = fopen(newCurrFile.c_str(), "r"); while (!feof(copyFile)) { char buf[8192]; char* res = fgets(buf, 16384, copyFile); if (res == NULL) break; text += res; } fclose(copyFile); FileInfo tmp; tmp.text = text; tmp.style = isFreeStyle ? 2 : 0; tmp.fileName = newCurrFile; convertStyle(&tmp);*/ fflush(NULL); } else fclose(tryToOpen); } } string splitDirective(const string &in_) { if (in_ == "") return ""; string in(in_); string lastEnd = ""; if (in[in.size() - 1] == '\n') { in.erase(in.begin() + in_.size() - 1); lastEnd = "\n"; } string out = ""; if (in.size() < 71) out = in; else { char buf[72]; int len = in.size() - 71; int idx = 71; buf[in.copy(buf, 71, 0)] = '\0'; out += buf; if (len > 0) out += "\n!DVM$&"; while (len > 65) { buf[in.copy(buf, 65, idx)] = '\0'; out += buf; len -= 65; idx += 65; if (len > 0) out += "\n!DVM$&"; } if (len > 0) { buf[in.copy(buf, 65, idx)] = '\0'; out += buf; } } return out + lastEnd; } string splitDirectiveFull(const string &in_) { if (in_ == "") return ""; string in(in_); string lastEnd = ""; if (in[in.size() - 1] == '\n') { in.erase(in.begin() + in_.size() - 1); lastEnd = "\n"; } string out = ""; vector splited; splitString(in_, '\n', splited); for (int z = 0; z < splited.size(); ++z) { if (z != 0) out += "\n"; out += splitDirective(splited[z]); } return out + lastEnd; } void ExitFromOmegaTest(const int c) { throw c; } extern "C" void ExitFromParser(const int c) { ExitFromOmegaTest(c); } void sortFilesBySize(const char *proj_name) { FILE *proj = fopen(proj_name, "r"); if (proj) { map, string> files; while (!feof(proj)) { char buf[512]; fgets(buf, 512, proj); string filename(buf); long size; FILE *fin = fopen(filename.c_str(), "rb"); FILE *p_fin = fin; if (fin) { fseek(p_fin, 0, SEEK_END); size = ftell(p_fin); fclose(fin); } else size = 0; files[make_pair(size, filename)] = filename; } fclose(proj); proj = fopen(proj_name, "w"); for (auto it = files.rbegin(); it != files.rend(); ++it) fwrite(it->second.c_str(), sizeof(char), it->second.size(), proj); fclose(proj); } else { __spf_print(1, "project file '%s' does not exist\n", proj_name); throw(-1); } } void uniteVectors(const vector, vector>>> &first, const vector, vector>>> &second, vector, vector>>> &result) { int *uniteF = new int[first.size()]; int *uniteS = new int[second.size()]; memset(uniteF, 0, sizeof(int) * first.size()); memset(uniteS, 0, sizeof(int) * second.size()); for (int i = 0; i < (int)first.size(); ++i) { const string &arrayName = first[i].first.second; int k; for (k = 0; k < (int)second.size(); ++k) { if (uniteS[k] == 0) { if (arrayName == second[k].first.second) { uniteS[k] = 1; break; } } } if (k != (int)second.size()) { uniteF[i] = 1; assert(first[i].second.size() == second[k].second.size()); result.push_back(make_pair(first[i].first, vector>(first[i].second.size()))); const vector> &boundsF = first[i].second; const vector> &boundsS = second[k].second; for (int z = 0; z < (int)boundsF.size(); ++z) { pair newBounds = std::make_pair(std::max(boundsF[z].first, boundsS[z].first), std::max(boundsF[z].second, boundsS[z].second)); result.back().second[z] = newBounds; } } } for (int i = 0; i < (int)first.size(); ++i) { if (uniteF[i] == 0) result.push_back(first[i]); } for (int i = 0; i < (int)second.size(); ++i) { if (uniteS[i] == 0) result.push_back(second[i]); } delete[]uniteF; delete[]uniteS; } #include #define FULL_ERROR_DUMP 1 // pointer -> type of alloc function #if FULL_ERROR_DUMP static std::unordered_map> pointerCollection; static std::unordered_map> pointerCollectionLocal; #else static std::unordered_map> pointerCollection; static std::unordered_map> pointerCollectionLocal; #endif static bool deleteInProgress = false; static void* currentPointer = NULL; static set deleted; static bool storeInLocal = false; // type == 0 -> free, type == 1 -> delete, type == 2 -> delete[] // acc_analyzer.h: ControlFlowItem = 3, doLoopItem = 4, doLoops = 5, LabelCFI = 6, CLAStatementItem = 7 // VarItem = 8, VarSet = 9, DoLoopDataItem = 10, DoLoopDataList = 11 // CVarEntryInfo = 12, CScalarVarEntryInfo = 13, CRecordVarEntryInfo = 14 // ArraySubscriptData = 15, CArrayVarEntryInfo = 16, BasicBlockItem = 17, // CallAnalysisLog = 18, CExprList = 19, SymbolKey = 20, CBasicBlock = 21 // CommonVarSet = 22, AnalysedCallsList = 23, CallData = 24, CommonVarInfo = 25 // CommonDataItem = 26, CommonData = 27, PrivateDelayedItem = 28, ActualDelayedData = 29 // ControlFlowGraph = 30 extern "C" void addToCollection(const int line, const char *file, void *pointer, int type) { #if FULL_ERROR_DUMP if (storeInLocal) pointerCollectionLocal.insert(std::make_pair(pointer, std::make_tuple(type, line, file))); pointerCollection.insert(std::make_pair(pointer, std::make_tuple(type, line, file))); #else if (storeInLocal) pointerCollectionLocal.insert(std::make_pair(pointer, std::make_tuple(type))); pointerCollection.insert(std::make_pair(pointer, std::make_tuple(type))); #endif } extern "C" void removeFromCollection(void *pointer) { if (deleteInProgress) { if (pointer != currentPointer) deleted.insert(pointer); } else { auto it = pointerCollection.find(pointer); if (it != pointerCollection.end()) pointerCollection.erase(it); if (storeInLocal) { auto it = pointerCollectionLocal.find(pointer); if (it != pointerCollectionLocal.end()) pointerCollectionLocal.erase(it); } } } void startLocalColletion() { storeInLocal = true; } void finishLocalColletion() { storeInLocal = false; } void deleteLeaks() { map places; auto copy = pointerCollection; for (auto& elem : copy) { string place = std::get<2>(elem.second); places[place]++; if (place.find("make_nodes.c") != string::npos) { free((char*)(elem.first)); auto it = pointerCollection.find(elem.first); if (it != pointerCollection.end()) pointerCollection.erase(it); } } } void deletePointerAllocatedData(bool delLocal) { int leaks = 0; int failed = 0; deleteInProgress = true; deleted.clear(); int maxS = -1; int z = -1; #if FULL_ERROR_DUMP std::unordered_map>* toDelCollection = delLocal ? &pointerCollectionLocal : &pointerCollection; #else std::unordered_map>* toDelCollection = delLocal ? &pointerCollectionLocal : &pointerCollection; #endif for (auto &elem : *toDelCollection) { ++z; maxS = std::max(maxS, (int)deleted.size()); auto itD = deleted.find(elem.first); if (deleted.find(elem.first) != deleted.end()) { deleted.erase(itD); continue; } const pair pointer = std::make_pair(elem.first, std::get<0>(elem.second)); currentPointer = pointer.first; //printf("[%d]: %d %s\n", z, std::get<1>(elem.second), std::get<2>(elem.second)); //fflush(NULL); if (pointer.second == 0) { if (pointer.first) { free((char*)(pointer.first)); leaks++; } else failed++; } else if (pointer.second == 1) { if (pointer.first) { delete (char*)(pointer.first); leaks++; } else failed++; } else if (pointer.second == 2) { if (pointer.first) { delete [](char*)(pointer.first); leaks++; } else failed++; } else if (pointer.second >= 3 && pointer.second <= 30) { if (pointer.first) { switch (pointer.second) { #if __SPF case 3: delete (ControlFlowItem*)pointer.first; break; case 4: delete (doLoopItem*)pointer.first; break; case 5: delete (doLoops*)pointer.first; break; case 6: delete (LabelCFI*)pointer.first; break; case 7: delete (CLAStatementItem*)pointer.first; break; case 8: delete (VarItem*)pointer.first; break; case 9: delete (VarSet*)pointer.first; break; case 10: delete (DoLoopDataItem*)pointer.first; break; case 11: delete (DoLoopDataList*)pointer.first; break; case 12: delete (CVarEntryInfo*)pointer.first; break; case 13: delete (CScalarVarEntryInfo*)pointer.first; break; case 14: delete (CRecordVarEntryInfo*)pointer.first; break; case 15: delete (ArraySubscriptData*)pointer.first; break; case 16: delete (CArrayVarEntryInfo*)pointer.first; break; case 17: delete (BasicBlockItem*)pointer.first; break; case 18: delete (CallAnalysisLog*)pointer.first; break; case 19: delete (CExprList*)pointer.first; break; case 20: delete (SymbolKey*)pointer.first; break; case 21: delete (CBasicBlock*)pointer.first; break; case 22: delete (CommonVarSet*)pointer.first; break; case 23: delete (AnalysedCallsList*)pointer.first; break; case 24: delete (CallData*)pointer.first; break; case 25: delete (CommonVarInfo*)pointer.first; break; case 26: delete (CommonDataItem*)pointer.first; break; case 27: delete (CommonData*)pointer.first; break; case 28: delete (PrivateDelayedItem*)pointer.first; break; case 29: delete (ActualDelayedData*)pointer.first; break; case 30: delete (ControlFlowGraph*)pointer.first; break; #endif default: break; } leaks++; } else failed++; } } if (leaks > 0) printf("SAPFOR: detected %d leaks of memory\n", leaks); if (failed > 0) printf("SAPFOR: detected failed %d leaks of memory\n", failed); printf("SAPFOR: deleted set size %d, maxS = %d\n", (int)deleted.size(), maxS); toDelCollection->clear(); deleted.clear(); deleteInProgress = false; currentPointer = NULL; } static unsigned arrayIdCounter = 0; unsigned getUniqArrayId() { return arrayIdCounter++; } static bool isAllRulesEqualWA_l(const vector>>> &rules) { if (rules.size() <= 1) return true; else { vector>> first = rules[0]; for (auto &elem : rules) { int z = 0; if (elem.size() != first.size()) return false; for (auto &item : elem) if (std::get<2>(item) != std::get<2>(first[z++])) return false; } return true; } } template static bool isAllRulesEqual_l(T rules) { if (rules.size() <= 1) return true; else { for (auto &elem : rules) if (elem != rules[0]) return false; return true; } } template static bool isAllRulesEqual_p(T rules) { if (rules.size() <= 1) return true; else { for (auto &elem : rules) if (elem != rules[0]) return false; return true; } } bool isAllRulesEqualWithoutArray(const vector>>> &allRules) { return isAllRulesEqualWA_l(allRules); } bool isAllRulesEqual(const vector>>> &allRules) { return isAllRulesEqual_l(allRules); } bool isAllRulesEqual(const vector> &allRules) { return isAllRulesEqual_l(allRules); } bool isAllRulesEqual(const vector>> &allRules) { return isAllRulesEqual_p(allRules); } static int newLineNumber = -2; // -1 is used for OMP int getNextNegativeLineNumber() { int ret = newLineNumber; newLineNumber--; return ret; } void findAndReplaceDimentions(vector>> &rule, const DIST::Arrays &allArrays) { for (int i = 0; i < rule.size(); ++i) { if (std::get<0>(rule[i]) == NULL) continue; int alignTo = -1; int ok = allArrays.GetDimNumber(std::get<0>(rule[i]), (std::get<1>(rule[i])), alignTo); if (ok != 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); (std::get<1>(rule[i])) = alignTo; } } vector findLinksBetweenArrays(DIST::Array *from, DIST::Array *to, const uint64_t regionId, bool withCheck) { vector retVal(from->GetDimSize()); std::fill(retVal.begin(), retVal.end(), -1); if (to->IsTemplate()) { if (to != from->GetTemplateArray(regionId, withCheck)) return retVal; else return from->GetLinksWithTemplate(regionId); } else { if (to->GetTemplateArray(regionId, withCheck) != from->GetTemplateArray(regionId, withCheck)) { string leftT = to->GetTemplateArray(regionId, withCheck) ? to->GetTemplateArray(regionId, withCheck)->GetShortName() : "nul"; string rightT = from->GetTemplateArray(regionId, withCheck) ? from->GetTemplateArray(regionId, withCheck)->GetShortName() : "nul"; __spf_print(1, "regionId = %lld: templates for array %s and %s not eq: %s != %s\n", regionId, from->GetName().c_str(), to->GetName().c_str(), leftT.c_str(), rightT.c_str()); } else { auto ruleL = from->GetLinksWithTemplate(regionId); auto ruleR = to->GetLinksWithTemplate(regionId); int currD = 0; for (auto &elem1 : ruleL) { int idx = 0; for (auto &elem2 : ruleR) { if (elem2 == elem1) { retVal[currD] = idx; break; } ++idx; } ++currD; } } return retVal; } } std::wstring to_wstring(const std::string str) { return std::wstring(str.begin(), str.end()); } template objT& getObjectForFileFromMap(const char *fileName, map &mapObject) { auto it = mapObject.find(fileName); if (it == mapObject.end()) it = mapObject.insert(it, std::make_pair(fileName, objT())); return it->second; } template vector& getObjectForFileFromMap(const char* fileName, map>&); template vector& getObjectForFileFromMap(const char *fileName, map>&); template vector& getObjectForFileFromMap(const char *fileName, map>&); template vector& getObjectForFileFromMap(const char *fileName, map>&); template map& getObjectForFileFromMap(const char *fileName, map>&); template map& getObjectForFileFromMap(const char *fileName, map>&); #if __SPF template map>& getObjectForFileFromMap(const char* fileName, map>>&); #endif static set mpiFunctions; bool isMpiFunction(const string& func) { if (mpiFunctions.size() == 0) { mpiFunctions.insert("mpi_abort"); mpiFunctions.insert("mpi_address"); mpiFunctions.insert("mpi_allgather"); mpiFunctions.insert("mpi_allgatherv"); mpiFunctions.insert("mpi_allreduce"); mpiFunctions.insert("mpi_alltoall"); mpiFunctions.insert("mpi_alltoallv"); mpiFunctions.insert("mpi_barrier"); mpiFunctions.insert("mpi_bcast"); mpiFunctions.insert("mpi_bsend"); mpiFunctions.insert("mpi_bsend_init"); mpiFunctions.insert("mpi_buffer_attach"); mpiFunctions.insert("mpi_buffer_detach"); mpiFunctions.insert("mpi_cart_coords"); mpiFunctions.insert("mpi_cart_create"); mpiFunctions.insert("mpi_cart_get"); mpiFunctions.insert("mpi_cart_rank"); mpiFunctions.insert("mpi_cart_shift"); mpiFunctions.insert("mpi_cart_sub"); mpiFunctions.insert("mpi_cartdim_get"); mpiFunctions.insert("mpi_comm_create"); mpiFunctions.insert("mpi_comm_dup"); mpiFunctions.insert("mpi_comm_free"); mpiFunctions.insert("mpi_comm_group"); mpiFunctions.insert("mpi_comm_rank"); mpiFunctions.insert("mpi_comm_size"); mpiFunctions.insert("mpi_comm_split"); mpiFunctions.insert("mpi_dims_create"); mpiFunctions.insert("mpi_finalize"); mpiFunctions.insert("mpi_gather"); mpiFunctions.insert("mpi_gatherv"); mpiFunctions.insert("mpi_get_count"); mpiFunctions.insert("mpi_get_processor_name"); mpiFunctions.insert("mpi_graph_create"); mpiFunctions.insert("mpi_graph_get"); mpiFunctions.insert("mpi_graph_neighbors"); mpiFunctions.insert("mpi_graph_neighbors_count"); mpiFunctions.insert("mpi_graphdims_get"); mpiFunctions.insert("mpi_group_compare"); mpiFunctions.insert("mpi_group_difference"); mpiFunctions.insert("mpi_group_excl"); mpiFunctions.insert("mpi_group_free"); mpiFunctions.insert("mpi_group_incl"); mpiFunctions.insert("mpi_group_intersection"); mpiFunctions.insert("mpi_group_rank"); mpiFunctions.insert("mpi_group_size"); mpiFunctions.insert("mpi_group_translate_ranks"); mpiFunctions.insert("mpi_group_union"); mpiFunctions.insert("mpi_ibsend"); mpiFunctions.insert("mpi_init"); mpiFunctions.insert("mpi_initialized"); mpiFunctions.insert("mpi_iprobe"); mpiFunctions.insert("mpi_irecv"); mpiFunctions.insert("mpi_irsend"); mpiFunctions.insert("mpi_isend"); mpiFunctions.insert("mpi_issend"); mpiFunctions.insert("mpi_op_create"); mpiFunctions.insert("mpi_op_free"); mpiFunctions.insert("mpi_pack"); mpiFunctions.insert("mpi_pack_size"); mpiFunctions.insert("mpi_probe"); mpiFunctions.insert("mpi_recv"); mpiFunctions.insert("mpi_recv_init"); mpiFunctions.insert("mpi_reduce"); mpiFunctions.insert("mpi_reduce_scatter"); mpiFunctions.insert("mpi_request_free"); mpiFunctions.insert("mpi_rsend"); mpiFunctions.insert("mpi_rsend_init"); mpiFunctions.insert("mpi_scan"); mpiFunctions.insert("mpi_scatter"); mpiFunctions.insert("mpi_scatterv"); mpiFunctions.insert("mpi_send"); mpiFunctions.insert("mpi_send_init"); mpiFunctions.insert("mpi_sendrecv"); mpiFunctions.insert("mpi_sendrecv_replace"); mpiFunctions.insert("mpi_ssend"); mpiFunctions.insert("mpi_ssend_init"); mpiFunctions.insert("mpi_start"); mpiFunctions.insert("mpi_startall"); mpiFunctions.insert("mpi_test"); mpiFunctions.insert("mpi_testall"); mpiFunctions.insert("mpi_testany"); mpiFunctions.insert("mpi_testsome"); mpiFunctions.insert("mpi_topo_test"); mpiFunctions.insert("mpi_type_commit"); mpiFunctions.insert("mpi_type_contiguous"); mpiFunctions.insert("mpi_type_extent"); mpiFunctions.insert("mpi_type_free"); mpiFunctions.insert("mpi_type_hindexed"); mpiFunctions.insert("mpi_type_hvector"); mpiFunctions.insert("mpi_type_indexed"); mpiFunctions.insert("mpi_type_lb"); mpiFunctions.insert("mpi_type_size"); mpiFunctions.insert("mpi_type_struct"); mpiFunctions.insert("mpi_type_ub"); mpiFunctions.insert("mpi_type_vector"); mpiFunctions.insert("mpi_unpack"); mpiFunctions.insert("mpi_wait"); mpiFunctions.insert("mpi_waitall"); mpiFunctions.insert("mpi_waitany"); mpiFunctions.insert("mpi_waitsome"); mpiFunctions.insert("mpi_wtick"); mpiFunctions.insert("mpi_wtime"); } return mpiFunctions.find(func) != mpiFunctions.end(); } map createMapOfArrayAccess(const map, pair> &declaredArrays) { map out; for (auto& elem : declaredArrays) out[elem.second.first] = elem.second.second; return out; } string readFileToStr(const string& name) { string sf; std::ifstream inf; inf.open(name); if (!inf) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); getline(inf, sf, '\0'); inf.close(); return sf; } void writeFileFromStr(const string& name, const string &data) { string sf; std::ofstream outf; outf.open(name); if (!outf) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); outf << data; outf.close(); } ParallelRegion* getRegionById(const vector& regions, const uint64_t regionId) { for (auto& region : regions) if (region->GetId() == regionId) return region; return NULL; } ParallelRegion* getRegionByName(const vector& regions, const string& regionName) { string test = regionName; convertToLower(test); for (auto& region : regions) if (region->GetName() == test) return region; return NULL; } ParallelRegion* getRegionByLine(const vector& regions, const string& file, const int line) { if (regions.size() == 1 && regions[0]->GetName() == "DEFAULT") // only default return regions[0]; else if (regions.size() > 0) { set regFound; for (int i = 0; i < regions.size(); ++i) if (regions[i]->HasThisLine(line, file)) regFound.insert(regions[i]); if (regFound.size() == 0) return NULL; else if (regFound.size() == 1) return *regFound.begin(); else { __spf_print(1, "WARN: this lines included in more than one region!!\n"); return NULL; } } else return NULL; return NULL; } set getAllRegionsByLine(const vector& regions, const string& file, const int line) { set regFound; if (regions.size() == 1 && regions[0]->GetName() == "DEFAULT") // only default regFound.insert(regions[0]); else if (regions.size() > 0) { for (int i = 0; i < regions.size(); ++i) if (regions[i]->HasThisLine(line, file)) regFound.insert(regions[i]); } return regFound; } static bool checkFormat(const string& toCheck, const string& given) { if (given == "" || given == "*") { if (toCheck == "for" || toCheck == "f90" || toCheck == "fdv" || toCheck == "ftn" || toCheck == "f95" || toCheck == "f03" || toCheck == "f") { return true; } } else if (toCheck == given) return true; return false; } pair, vector> splitCommandLineForParse(char** argv, int argc, bool& isInline) { #if __cplusplus >= 201703L vector filesInDir; for (const auto& entry : fs::directory_iterator(fs::current_path())) filesInDir.push_back(entry.path().filename()); #endif vector options; set files; //fdv|f|ftn|for|f90|f95|f03 for (int z = 0; z < argc; ++z) { string arg = argv[z]; string ext = OnlyExt(arg.c_str()); convertToLower(ext); if (arg.find("*") != string::npos || checkFormat(ext, "")) { if (arg.find("*") == string::npos) { if (checkFormat(ext, "")) files.insert(arg); else printf("skip file %s\n", arg.c_str()); } else { #if __cplusplus >= 201703L for (auto& file : filesInDir) { auto cmp_ext = file.extension().string(); convertToLower(cmp_ext); if (cmp_ext.size() && cmp_ext[0] == '.') cmp_ext.erase(cmp_ext.begin()); if (checkFormat(cmp_ext, ext)) files.insert(file.filename().string()); } #endif } } else { if (arg == "-inl") isInline = true; else if (arg.find("-") != string::npos) options.push_back(arg); else printf(" skip option %s\n", arg.c_str()); } } vector filesV; for (auto& elem : files) { FILE* check = fopen(elem.c_str(), "r"); if (check) { filesV.push_back(elem); printf(" parse file '%s'\n", elem.c_str()); fclose(check); } else printf(" skip not existing file '%s'\n", elem.c_str()); } printf(" options: "); for (auto& opt : options) printf("%s ", opt.c_str()); printf("\n"); return make_pair(options, filesV); } bool createDirectory(const string& name) { #if __cplusplus >= 201703L if (fs::exists(name)) return true; else return fs::create_directories(name); #else #ifdef _WIN32 if (_mkdir(name.c_str()) == 0) return true; #else if (mkdir(name.c_str(), 0777) == 0) return true; #endif return false; #endif } string getClearName(const string& in) { char fromChar; if (in.find('.') == string::npos) { if (in.find("::") == string::npos) return in; else fromChar = ':'; } else fromChar = '.'; string ret = in; auto it = ret.rfind(fromChar); if (it == string::npos) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); ret = ret.substr(it + 1); return ret; } wstring fixedLongFormat(const wchar_t* old_) { /*#if __SPF return old_ ? old_ : L""; #endif*/ if (old_ == NULL) return L""; wstring old(old_); //exclude russian codes if (old_[0] == L'R' && (old_[1] == L'R' || (old_[1] >= L'0' && old_[1] <= L'9'))) return old; wstring ret = L""; for (int z = 0; z < old.size(); ++z) { if (old[z] == L'%') { if (z + 1 < old.size()) { if (old[z + 1] == L's') { ret += L"%ls"; z++; continue; } } } ret += old[z]; } return ret; } const set getExcludedModules() { return { "omp_lib", "ifport" }; }; map sortArraysByName(const set& toSort) { map sorted; for (auto& array : toSort) sorted[array->GetName()] = array; if (sorted.size() != toSort.size()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return sorted; } vector splitAndArgvCreate(const string& options) { vector optSplited; optSplited.push_back(""); splitString(options, ' ', optSplited, true); vector optSplited1; for (auto& elem : optSplited) if (elem != "") optSplited1.push_back(elem); optSplited1.insert(optSplited1.begin(), ""); for (int z = 0; z < optSplited1.size(); ++z) { //printf("%s\n", optSplited1[z].c_str()); if (optSplited1[z][0] == '"' && optSplited1[z][optSplited1[z].size() - 1] == '"') optSplited1[z] = optSplited1[z].substr(1, optSplited1[z].size() - 2); } return optSplited1; } static bool isNotNullIntersection(const set& first, const set& second) { for (auto& elem1 : first) if (second.find(elem1) != second.end()) return true; return false; } set fillDistributedArraysD(const DataDirective& dataDirectives, const map>& tableOfUniqNamesByArray, const map>& arrayLinksByFuncCalls, bool onlyCommon) { set distrArrays; set distrArraysD; set distrArraysAdded; for (int z = 0; z < dataDirectives.distrRules.size(); ++z) distrArraysD.insert(dataDirectives.distrRules[z].first); for (int z = 0; z < dataDirectives.alignRules.size(); ++z) distrArraysD.insert(dataDirectives.alignRules[z].alignArray); for (auto& elem : tableOfUniqNamesByArray) { set realRefs; getRealArrayRefs(elem.first, elem.first, realRefs, arrayLinksByFuncCalls); if (isNotNullIntersection(realRefs, distrArraysD)) distrArraysAdded.insert(elem.first); } for (auto& elem : distrArraysD) { if (onlyCommon) { if (elem->GetLocation().first == DIST::l_COMMON) distrArrays.insert(elem); } else distrArrays.insert(elem); } for (auto& elem : distrArraysAdded) { if (onlyCommon) { if (elem->GetLocation().first == DIST::l_COMMON) distrArrays.insert(elem); } else distrArrays.insert(elem); } return distrArrays; } set fillDistributedArrays(const DataDirective& dataDirectives, const map>& tableOfUniqNamesByArray, const map>& arrayLinksByFuncCalls, bool onlyCommon, bool shortName) { set distrArrays; set ret = fillDistributedArraysD(dataDirectives, tableOfUniqNamesByArray, arrayLinksByFuncCalls, onlyCommon); for (auto& elem : ret) distrArrays.insert(shortName ? elem->GetShortName() : elem->GetName()); return distrArrays; } void copyStringToShort(short*& result, const string& resVal, bool withEnd) { result = new short[resVal.size() + 1]; allocated.insert(result); for (int i = 0; i < resVal.size(); ++i) result[i] = resVal[i]; if (withEnd) result[resVal.size()] = (short)'\0'; }