diff --git a/.gitignore b/.gitignore index 0000101..d9bf98a 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,7 @@ Sapfor/Sapc++/Sapc++/x64/ Sapfor/Sapc++/x64/ /build +/cmake-build-debug Sapfor/out/ Sapfor/_bin/* diff --git a/CMakeLists.txt b/CMakeLists.txt index 4332009..6eada33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,13 @@ set(OMEGA src/SageAnalysisTool/OmegaForSage/add-assert.cpp src/SageAnalysisTool/set.cpp) set(PRIV src/PrivateAnalyzer/private_analyzer.cpp - src/PrivateAnalyzer/private_analyzer.h) + src/PrivateAnalyzer/private_analyzer.h + src/PrivateAnalyzer/private_arrays_search.cpp + src/PrivateAnalyzer/private_arrays_search.h + src/PrivateAnalyzer/range_structures.cpp + src/PrivateAnalyzer/range_structures.h + src/PrivateAnalyzer/region.cpp + src/PrivateAnalyzer/region.h) set(FDVM ${fdvm_sources}/acc.cpp ${fdvm_sources}/acc_across.cpp diff --git a/src/CFGraph/IR.cpp b/src/CFGraph/IR.cpp index 76de087..4b24610 100644 --- a/src/CFGraph/IR.cpp +++ b/src/CFGraph/IR.cpp @@ -395,7 +395,7 @@ static SAPFOR::Argument* processExpression(SgExpression* ex, vector& if (ex) { const int var = ex->variant(); - if ((var == VAR_REF || var == CONST_REF || var == LABEL_REF) && !ex->lhs() && !ex->rhs()) // обращение к переменной + if ((var == VAR_REF || var == CONST_REF || var == LABEL_REF) && !ex->lhs() && !ex->rhs()) // variable reference { if (var == CONST_REF) { @@ -450,7 +450,7 @@ static SAPFOR::Argument* processExpression(SgExpression* ex, vector& return arg1; auto reg = isLeft ? NULL : createRegister(); - Instruction* instr = new Instruction(isLeft ? CFG_OP::STORE : CFG_OP::LOAD, arg1, createConstArg(numArgs), isLeft ? isLeft : reg); + Instruction* instr = new Instruction(isLeft ? CFG_OP::STORE : CFG_OP::LOAD, arg1, createConstArg(numArgs), isLeft ? isLeft : reg, NULL, ex); blocks.push_back(new IR_Block(instr)); return reg; } @@ -485,7 +485,7 @@ static SAPFOR::Argument* processExpression(SgExpression* ex, vector& auto arg1 = arrayRef ? arrayRef : createArrayArg(ref, blocks, func, numArgs, commonVars); auto reg = isLeft ? NULL : createRegister(); - instr = new Instruction(isLeft ? CFG_OP::STORE : CFG_OP::LOAD, arg1, createConstArg(1), isLeft ? isLeft : reg); + instr = new Instruction(isLeft ? CFG_OP::STORE : CFG_OP::LOAD, arg1, createConstArg(1), isLeft ? isLeft : reg, NULL, ex); blocks.push_back(new IR_Block(instr)); return reg; } @@ -602,7 +602,7 @@ static SAPFOR::Argument* processExpression(SgExpression* ex, vector& { if (returnReg == NULL) { - Instruction* instr = new Instruction(CFG_OP::LOAD, arg, NULL, reg); + Instruction* instr = new Instruction(CFG_OP::LOAD, arg, NULL, reg, NULL, ex); blocks.push_back(new IR_Block(instr)); } else @@ -1572,7 +1572,7 @@ vector buildIR(SgStatement* function, const FuncInfo* func, const vec else findReturn(0, blocks.size(), blocks, blocks.back()->getNumber()); - // добавление связей по GOTO и переходам + // adding links by GOTO and jumps for (int z = 0; z < blocks.size(); ++z) { auto op = blocks[z]->getInstruction()->getOperation(); @@ -1592,7 +1592,7 @@ vector buildIR(SgStatement* function, const FuncInfo* func, const vec blocks[z]->setJump(it->second); - // заменим метку на номер инструкции + // replacing the label with the instruction number arg->setValue(to_string(it->second->getNumber())); arg->setType(CFG_ARG_TYPE::INSTR); } diff --git a/src/Distribution/Array.h b/src/Distribution/Array.h index 8f77faf..74a8a08 100644 --- a/src/Distribution/Array.h +++ b/src/Distribution/Array.h @@ -827,4 +827,4 @@ namespace Distribution #undef PAIR #undef MAP #undef SET -#undef TO_STR \ No newline at end of file +#undef TO_STR diff --git a/src/LoopAnalyzer/loop_analyzer.cpp b/src/LoopAnalyzer/loop_analyzer.cpp index 4088a5c..a544fca 100644 --- a/src/LoopAnalyzer/loop_analyzer.cpp +++ b/src/LoopAnalyzer/loop_analyzer.cpp @@ -1635,9 +1635,9 @@ void loopAnalyzer(SgFile *file, vector ®ions, mapfunctions(i)->symbol()->identifier(); #if _WIN32 if (file->functions(i)->variant() != MODULE_STMT) - sendMessage_2lvl(wstring(L"��������� ������� '") + wstring(fName.begin(), fName.end()) + L"'"); + sendMessage_2lvl(wstring(L"обработка функции '") + wstring(fName.begin(), fName.end()) + L"'"); else - sendMessage_2lvl(wstring(L"��������� ������ '") + wstring(fName.begin(), fName.end()) + L"'"); + sendMessage_2lvl(wstring(L"обработка модуля '") + wstring(fName.begin(), fName.end()) + L"'"); #else if (file->functions(i)->variant() != MODULE_STMT) sendMessage_2lvl(wstring(L"processing function '") + wstring(fName.begin(), fName.end()) + L"'"); @@ -1710,7 +1710,10 @@ void loopAnalyzer(SgFile *file, vector ®ions, map> notMappedDistributedArrays; set mappedDistrbutedArrays; + const ParallelRegionLines* prevParLines = NULL; + double prevLinesWeight = 1.0; double currentWeight = 1.0; + while (st != lastNode) { createNeededException(); @@ -1733,13 +1736,31 @@ void loopAnalyzer(SgFile *file, vector ®ions, maplineNumber() < -1 ? st->localLineNumber() : st->lineNumber(); - ParallelRegion *currReg = getRegionByLine(regions, st->fileName(), currentLine); + auto regAndLines = getRegionAndLinesByLine(regions, st->fileName(), currentLine); + + auto *currReg = regAndLines.first; + auto *parLines = regAndLines.second; if (currReg == NULL) { st = st->lexNext(); continue; } + if (parLines != prevParLines) + { + prevParLines = parLines; + auto newParLinesWeight = parLines ? parLines->weight : 1.0; + + if (prevParLines) + currentWeight /= prevLinesWeight; + + if (parLines) + currentWeight *= newParLinesWeight; + + prevLinesWeight = newParLinesWeight; + prevParLines = parLines; + } + if (isSgExecutableStatement(st) == NULL) delcsStatViewed.insert(st); else if (!sharedMemoryParallelization && @@ -2168,7 +2189,7 @@ void loopAnalyzer(SgFile *file, vector ®ions, mapfunctions(i)->symbol()->identifier(); #ifdef _WIN32 - sendMessage_2lvl(wstring(L"��������� ����� ") + std::to_wstring(idx) + L"/" + std::to_wstring(convertedLoopInfo.size())); + sendMessage_2lvl(wstring(L"обработка цикла ") + std::to_wstring(idx) + L"/" + std::to_wstring(convertedLoopInfo.size())); #else sendMessage_2lvl(wstring(L"processing loop ") + std::to_wstring(idx) + L"/" + std::to_wstring(convertedLoopInfo.size())); #endif diff --git a/src/ParallelizationRegions/ParRegions.cpp b/src/ParallelizationRegions/ParRegions.cpp index 85d1953..f01be39 100644 --- a/src/ParallelizationRegions/ParRegions.cpp +++ b/src/ParallelizationRegions/ParRegions.cpp @@ -93,8 +93,10 @@ static inline SgStatement* getParentStat(SgStatement *st) return iterator; } -static void updateRegionInfo(SgStatement *st, map> &startEnd, map> &lines_, - set &funcCallFromReg, const map &mapFuncs) +static void updateRegionInfo(SgStatement *st, map> &startEnd, + map> &lines_, + map>> &funcCallFromReg, + const map &mapFuncs) { string containsPrefix = ""; SgStatement *st_ps = getParentStat(st); @@ -103,17 +105,26 @@ static void updateRegionInfo(SgStatement *st, mapsymbol()->identifier() + string("."); extendRegionInfo(st, startEnd, lines_); + + set callsFromStatement; + if (st->variant() == PROC_STAT) { string fullName = st->symbol()->identifier(); //check contains if (mapFuncs.find(containsPrefix + fullName) != mapFuncs.end()) fullName = containsPrefix + fullName; - funcCallFromReg.insert(fullName); + callsFromStatement.insert(fullName); } for (int z = 0; z < 3; ++z) - findFuncCalls(st->expr(z), funcCallFromReg, containsPrefix, mapFuncs); + findFuncCalls(st->expr(z), callsFromStatement, containsPrefix, mapFuncs); + + string filename = st->fileName(); + int line = st->lineNumber(); + + for (const auto &func_name : callsFromStatement) + funcCallFromReg[func_name][filename].insert(line); } static void fillArrayNamesInReg(set &usedArrayInRegion, SgExpression *exp) @@ -318,8 +329,9 @@ void fillRegionLines(SgFile *file, vector ®ions, vector> startEnd; map> lines_; - set funcCallFromReg; + map>> funcCallFromReg; bool regionStarted = false; + double fragmentWeight = 1.0; vector toDel; for (int i = 0; i < funcNum; ++i) @@ -368,6 +380,33 @@ void fillRegionLines(SgFile *file, vector ®ions, vectorsecond->callRegions.insert(0); } } + + // parse SPF_APPLY_FRAGMENT clause + auto *apply_fragment = data->expr(1); + fragmentWeight = 1.0; + + while (apply_fragment) + { + auto *curr = apply_fragment->lhs(); + if (curr) + { + __spf_print(1, "%s %d\n", curr->unparse(), curr->variant()); + + if (curr->variant() == SPF_WEIGHT_OP) + { + if (curr->lhs() && + isSgValueExp(curr->lhs()) && + isSgValueExp(curr->lhs())->doubleValue()) + { + fragmentWeight = strtod(isSgValueExp(curr->lhs())->doubleValue(), NULL); + __spf_print(1, "->> %lf\n", fragmentWeight); + } + else + __spf_print(1, "WEIGHT clause without double argument\n"); + } + } + apply_fragment = apply_fragment->rhs(); + } } if (next && next->variant() == SPF_END_PARALLEL_REG_DIR) @@ -400,10 +439,12 @@ void fillRegionLines(SgFile *file, vector ®ions, vectorAddLines(lines_[itRegInfo->first], itRegInfo->first, &itRegInfo->second); + currReg->AddLines(lines_[itRegInfo->first], itRegInfo->first, &itRegInfo->second, fragmentWeight); - for (auto &func : funcCallFromReg) - currReg->AddFuncCalls(func); + for (auto &by_func : funcCallFromReg) + for (auto &by_file : by_func.second) + for(auto &by_line : by_file.second) + currReg->AddFuncCalls(by_func.first, by_file.first, by_line); filterUserDirectives(currReg, usedArrayInRegion, userDvmRedistrDirs, userDvmRealignDirs, userDvmShadowDirs); currReg->AddUserDirectives(userDvmRealignDirs, DVM_REALIGN_DIR); @@ -496,34 +537,48 @@ void fillRegionLinesStep2(vector ®ions, const mapGetName() != "DEFAULT") for (auto &func : regions[i]->GetFuncCalls()) - setExplicitFlag(func, funcMap); + setExplicitFlag(func.first, funcMap); } for (int i = 0; i < regions.size(); ++i) { if (regions[i]->GetName() != "DEFAULT") { - set uniqFuncCalls; - for (auto &elem : regions[i]->GetFuncCalls()) - uniqFuncCalls.insert(elem); + map uniqFuncCalls; + map>> callPlaces; + + for (auto &elem : regions[i]->GetFuncCalls()) + { + double max_weight = 0; + for (auto* fragment : elem.second) + if (fragment->weight > max_weight) + max_weight = fragment->weight; + + uniqFuncCalls[elem.first] = max_weight; + } + + bool wasChanged = true; + auto funcsBefore = uniqFuncCalls; - bool wasChanged = 1; while (wasChanged) { - wasChanged = 0; + wasChanged = false; + auto updated = uniqFuncCalls; + for (auto &uniqF : uniqFuncCalls) { - auto func = funcMap.find(uniqF); + auto func = funcMap.find(uniqF.first); if (func != funcMap.end()) { - for (auto &calls : func->second->callsFrom) + for (auto &call : func->second->callsFromDetailed) { - auto it = uniqFuncCalls.find(calls); - if (it == uniqFuncCalls.end()) - { - uniqFuncCalls.insert(it, calls); - wasChanged = 1; - } + auto it = updated.find(call.detailCallsFrom.first); + if (it == updated.end()) + updated.insert({call.detailCallsFrom.first, uniqF.second}); + else + it->second = std::max(it->second, uniqF.second); + + callPlaces[call.detailCallsFrom.first][func->second->fileName].insert(call.detailCallsFrom.second); } } } @@ -532,21 +587,27 @@ void fillRegionLinesStep2(vector ®ions, const mapAddLines(it->second->linesNum, it->second->fileName); - regions[i]->AddFuncCallsToAllCalls(it->second); + regions[i]->AddLines(it->second->linesNum, it->second->fileName, NULL, elem.second); if (it->second->inRegion == 0) it->second->inRegion = 2; it->second->callRegions.insert(i); - toPrint += elem + " "; + toPrint += elem.first + " "; } } + for (auto &elem : callPlaces) + { + for (const auto &byFile : elem.second) + for (auto byLine : byFile.second) + regions[i]->AddFuncCalls(elem.first, byFile.first, byLine); + } + if (toPrint != "") __spf_print(1, "[%s]: funcs: %s\n", regions[i]->GetName().c_str(), toPrint.c_str()); } diff --git a/src/ParallelizationRegions/ParRegions.h b/src/ParallelizationRegions/ParRegions.h index fc72c3d..d613d31 100644 --- a/src/ParallelizationRegions/ParRegions.h +++ b/src/ParallelizationRegions/ParRegions.h @@ -19,7 +19,7 @@ struct ParallelRegionLines { - ParallelRegionLines() + ParallelRegionLines(double weight = 1.0) : weight(weight) { lines = std::make_pair(-1, -1); stats = std::make_pair(NULL, NULL); @@ -27,14 +27,15 @@ struct ParallelRegionLines intervalAfter = std::make_pair(NULL, NULL); } - ParallelRegionLines(const std::pair &lines) : lines(lines) + ParallelRegionLines(const std::pair &lines, double weight = 1.0) : lines(lines), weight(weight) { stats = std::make_pair(NULL, NULL); intervalBefore = std::make_pair(NULL, NULL); intervalAfter = std::make_pair(NULL, NULL); } - ParallelRegionLines(const std::pair &lines, const std::pair stats) : lines(lines), stats(stats) + ParallelRegionLines(const std::pair &lines, const std::pair stats, double weight = 1.0) + : lines(lines), stats(stats), weight(weight) { intervalBefore = std::make_pair(NULL, NULL); intervalAfter = std::make_pair(NULL, NULL); @@ -62,6 +63,8 @@ struct ParallelRegionLines // interval std::pair intervalBefore; std::pair intervalAfter; + + double weight; // weight of the fragment among all fragments of this region }; #if __SPF @@ -116,7 +119,7 @@ public: currentVariant = copy.currentVariant; } - int AddLines(const std::pair &linesToAdd, const std::string &file, const std::pair *startEnd = NULL) + int AddLines(const std::pair &linesToAdd, const std::string &file, const std::pair *startEnd = NULL, double weight = 1.0) { if (linesToAdd.first > linesToAdd.second) return -1; @@ -126,17 +129,29 @@ public: it = lines.insert(it, make_pair(file, std::vector())); if (startEnd) - it->second.push_back(ParallelRegionLines(linesToAdd, *startEnd)); + it->second.push_back(ParallelRegionLines(linesToAdd, *startEnd, weight)); else - it->second.push_back(ParallelRegionLines(linesToAdd)); + it->second.push_back(ParallelRegionLines(linesToAdd, weight)); return 0; } - void AddFuncCalls(const std::string &func) { functionsCall.insert(func); } + void AddFuncCalls(const std::string &func, const std::string &file, const int line) + { + auto *found_lines = GetLinesByLine(file, line); + + if (found_lines) + functionsCall[func].insert(found_lines); + } #if __SPF - void AddFuncCallsToAllCalls(FuncInfo *func) { allFunctionsCall.insert(func); } + void AddFuncCallsToAllCalls(FuncInfo *func, const std::string &file, const int line) + { + auto *found_lines = GetLinesByLine(file, line); + + if (found_lines) + allFunctionsCall[func].insert(found_lines); + } #endif uint64_t GetId() const { return regionId; } @@ -176,10 +191,10 @@ public: const DataDirective& GetDataDir() const { return dataDirectives; } DataDirective& GetDataDirToModify() { return dataDirectives; } - const std::set& GetFuncCalls() const { return functionsCall; } + const std::map>& GetFuncCalls() const { return functionsCall; } #if __SPF - const std::set& GetAllFuncCalls() const { return allFunctionsCall; } + const std::map>& GetAllFuncCalls() const { return allFunctionsCall; } const std::map>>& GetUsedLocalArrays() const { return usedLocalArrays; } const std::map>>& GetUsedCommonArrays() const { return usedCommonArrays; } @@ -218,7 +233,7 @@ public: } #endif - bool HasThisLine(const int line, const std::string &file) const + bool HasThisLine(const int line, const std::string &file, const ParallelRegionLines** found = nullptr) const { bool retVal = false; auto it = lines.find(file); @@ -229,6 +244,9 @@ public: if (it->second[i].lines.first <= line && it->second[i].lines.second >= line) { retVal = true; + if (found) + *found = &(it->second[i]); + break; } } @@ -292,7 +310,7 @@ public: fprintf(fileOut, " originalName '%s'\n", originalName.c_str()); fprintf(fileOut, " functions call from %d:\n", (int)functionsCall.size()); for (auto &func : functionsCall) - fprintf(fileOut, " '%s'\n", func.c_str()); + fprintf(fileOut, " '%s'\n", func.first.c_str()); fprintf(fileOut, " total lines %d:\n", (int)lines.size()); for (auto &line : lines) { @@ -362,11 +380,11 @@ private: std::string originalName; // file -> lines info std::map> lines; - std::set functionsCall; + std::map> functionsCall; // func name -> fragments with calls #if __SPF // for RESOLVE_PAR_REGIONS - std::set allFunctionsCall; + std::map> allFunctionsCall; // function -> fragments with calls std::map>> usedLocalArrays; // func -> array -> lines std::map>> usedCommonArrays; // func -> array -> lines // @@ -408,4 +426,5 @@ private: ParallelRegion* getRegionById(const std::vector& regions, const uint64_t regionId); ParallelRegion* getRegionByName(const std::vector& regions, const std::string& regionName); ParallelRegion* getRegionByLine(const std::vector& regions, const std::string& file, const int line); +std::pair getRegionAndLinesByLine(const std::vector& regions, const std::string& file, const int line); std::set getAllRegionsByLine(const std::vector& regions, const std::string& file, const int line); \ No newline at end of file diff --git a/src/PrivateAnalyzer/private_arrays_search.cpp b/src/PrivateAnalyzer/private_arrays_search.cpp new file mode 100644 index 0000000..985baf6 --- /dev/null +++ b/src/PrivateAnalyzer/private_arrays_search.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "private_arrays_search.h" +#include "range_structures.h" +#include "region.h" +#include "../Utils/SgUtils.h" +#include "../GraphLoop/graph_loops.h" +#include "../CFGraph/CFGraph.h" + +using namespace std; + +void Collapse(Region* region) +{ + if (region->getBasickBlocks().empty()) + return; + + for (auto& [arrayName, arrayRanges] : region->getHeader()->array_out) + { + for (Region* byBlock : region->getBasickBlocks()) + { + AccessingSet intersection = byBlock->array_def[arrayName].Intersect(arrayRanges); + region->array_def[arrayName] = region->array_def[arrayName].Union(intersection); + } + } + + for (auto& byBlock : region->getBasickBlocks()) + { + for (auto& [arrayName, arrayRanges] : byBlock->array_use) + { + AccessingSet diff = byBlock->array_use[arrayName].Diff(byBlock->array_in[arrayName]); + region->array_use[arrayName] = region->array_use[arrayName].Union(diff); + } + } + ArrayAccessingIndexes useUnion; + for (auto& byBlock : region->getBasickBlocks()) + for (auto& [arrayName, arrayRanges] : byBlock->array_use) + useUnion[arrayName] = useUnion[arrayName].Union(byBlock->array_use[arrayName]); + + for (auto& [arrayName, arrayRanges] : useUnion) + region->array_priv[arrayName] = useUnion[arrayName].Diff(region->array_use[arrayName]); + + for (Region* prevBlock : region->getHeader()->getPrevRegions()) + prevBlock->replaceInNextRegions(region, region->getHeader()); + + for (Region* nextBlock : region->getHeader()->getNextRegions()) + nextBlock->replaceInPrevRegions(region, region->getHeader()); +} + +static void SolveDataFlowIteratively(Region* DFG) +{ + unordered_set worklist(DFG->getBasickBlocks()); + do + { + Region* b = *worklist.begin(); + ArrayAccessingIndexes newIn; + bool flagFirst = true; + for (Region* prevBlock : b->getPrevRegions()) + { + if (flagFirst) + { + newIn = prevBlock->array_out; + flagFirst = false; + } + else + { + if (prevBlock->array_out.empty()) + { + newIn.clear(); + continue; + } + for (const auto& [arrayName, accessSet] : prevBlock->array_out) + { + if (newIn.find(arrayName) != newIn.end()) + newIn[arrayName] = newIn[arrayName].Intersect(accessSet); + else + newIn[arrayName] = AccessingSet(); + } + } + } + + b->array_in = move(newIn); + ArrayAccessingIndexes newOut; + if (b->array_def.empty()) + newOut = b->array_in; + else if (b->array_in.empty()) + newOut = b->array_def; + else + { + for (auto& [arrayName, accessSet] : b->array_def) + { + if (newOut.find(arrayName) != newOut.end()) + newOut[arrayName] = b->array_def[arrayName].Union(b->array_in[arrayName]); + else + newOut[arrayName] = accessSet; + } + } + + /* can not differ */ + if (newOut != b->array_out) + b->array_out = newOut; + else + worklist.erase(b); + } + while (!worklist.empty()); +} + +static void SolveDataFlow(Region* DFG) +{ + if (!DFG) + return; + + SolveDataFlowIteratively(DFG); + for (Region* subRegion : DFG->getSubRegions()) + SolveDataFlow(subRegion); + Collapse(DFG); +} + +map FindPrivateArrays(map> &loopGraph, map>& FullIR) +{ + map result; + for (const auto& [loopName, loops] : loopGraph) + { + for (const auto& loop : loops) + { + for (const auto& [funcInfo, blocks]: FullIR) + { + Region* loopRegion = new Region(loop, blocks); + SolveDataFlow(loopRegion); + result[loop] = loopRegion->array_priv; + delete(loopRegion); + } + } + } + return result; +} diff --git a/src/PrivateAnalyzer/private_arrays_search.h b/src/PrivateAnalyzer/private_arrays_search.h new file mode 100644 index 0000000..2faaa27 --- /dev/null +++ b/src/PrivateAnalyzer/private_arrays_search.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +#include + +#include "range_structures.h" +#include "region.h" +#include "../GraphLoop/graph_loops.h" +#include "../CFGraph/CFGraph.h" + +void Collapse(Region* region); +std::map FindPrivateArrays(std::map>& loopGraph, std::map>& FullIR); +std::pair> GetBasicBlocksForLoop(const LoopGraph* loop, const std::vector blocks); diff --git a/src/PrivateAnalyzer/range_structures.cpp b/src/PrivateAnalyzer/range_structures.cpp new file mode 100644 index 0000000..9a2f437 --- /dev/null +++ b/src/PrivateAnalyzer/range_structures.cpp @@ -0,0 +1,292 @@ +#include +#include +#include +#include +#include + +#include "range_structures.h" + +using namespace std; + +static vector FindParticularSolution(const ArrayDimension& dim1, const ArrayDimension& dim2) +{ + for (uint64_t i = 0; i < dim1.tripCount; i++) + { + uint64_t leftPart = dim1.start + i * dim1.step; + for (uint64_t j = 0; j < dim2.tripCount; j++) + { + uint64_t rightPart = dim2.start + j * dim2.step; + if (leftPart == rightPart) + return { i, j }; + } + } + return {}; +} + +/* dim1 /\ dim2 */ +static ArrayDimension* DimensionIntersection(const ArrayDimension& dim1, const ArrayDimension& dim2) +{ + vector partSolution = FindParticularSolution(dim1, dim2); + if (partSolution.empty()) + return NULL; + + int64_t x0 = partSolution[0], y0 = partSolution[1]; + /* x = x_0 + c * t */ + /* y = y_0 + d * t */ + int64_t c = dim2.step / gcd(dim1.step, dim2.step); + int64_t d = dim1.step / gcd(dim1.step, dim2.step); + int64_t tXMin, tXMax, tYMin, tYMax; + tXMin = -x0 / c; + tXMax = (dim1.tripCount - 1 - x0) / c; + tYMin = -y0 / d; + tYMax = (dim2.tripCount - 1 - y0) / d; + int64_t tMin = max(tXMin, tYMin); + uint64_t tMax = min(tXMax, tYMax); + if (tMin > tMax) + return NULL; + + uint64_t start3 = dim1.start + x0 * dim1.step; + uint64_t step3 = c * dim1.step; + ArrayDimension* result = new(ArrayDimension){ start3, step3, tMax + 1 }; + return result; +} + +/* dim1 / dim2 */ +static vector DimensionDifference(const ArrayDimension& dim1, const ArrayDimension& dim2) +{ + ArrayDimension* intersection = DimensionIntersection(dim1, dim2); + if (!intersection) + return { dim1 }; + + vector result; + /* add the part before intersection */ + if (dim1.start < intersection->start) + result.push_back({ dim1.start, dim1.step, (intersection->start - dim1.start) / dim1.step }); + + /* add the parts between intersection steps */ + uint64_t start = (intersection->start - dim1.start) / dim1.step; + uint64_t interValue = intersection->start; + for (int64_t i = start; dim1.start + i * dim1.step <= intersection->start + intersection->step * (intersection->tripCount - 1); i++) + { + uint64_t centerValue = dim1.start + i * dim1.step; + if (centerValue == interValue) + { + if (i - start > 1) + { + result.push_back({ dim1.start + (start + 1) * dim1.step, dim1.step, i - start - 1 }); + start = i; + } + interValue += intersection->step; + } + } + /* add the part after intersection */ + if (intersection->start + intersection->step * (intersection->tripCount - 1) < dim1.start + dim1.step * (dim1.tripCount - 1)) + { + /* first value after intersection */ + uint64_t right_start = intersection->start + intersection->step * (intersection->tripCount - 1) + dim1.step; + uint64_t tripCount = (dim1.start + dim1.step * dim1.tripCount - right_start) / dim1.step; + result.push_back({ right_start, dim1.step, tripCount }); + } + delete(intersection); + return result; +} + + +static vector DimensionUnion(const ArrayDimension& dim1, const ArrayDimension& dim2) +{ + vector res; + ArrayDimension* inter = DimensionIntersection(dim1, dim2); + if (!inter) + return { dim1, dim2 }; + + res.push_back(*inter); + delete(inter); + + vector diff1, diff2; + diff1 = DimensionDifference(dim1, dim2); + diff2 = DimensionDifference(dim2, dim1); + res.insert(res.end(), diff1.begin(), diff1.end()); + res.insert(res.end(), diff2.begin(), diff2.end()); + return res; +} + +static vector ElementsIntersection(const vector& firstElement, const vector& secondElement) +{ + if (firstElement.empty() || secondElement.empty()) + return {}; + + size_t dimAmount = firstElement.size(); + /* check if there is no intersecction */ + for (size_t i = 0; i < dimAmount; i++) + if (FindParticularSolution(firstElement[i], secondElement[i]).empty()) + return {}; + + vector result(dimAmount); + for (size_t i = 0; i < dimAmount; i++) + { + ArrayDimension* resPtr = DimensionIntersection(firstElement[i], secondElement[i]); + if (resPtr) + result[i] = *resPtr; + else + return {}; + + } + return result; +} + +static vector> ElementsDifference(const vector& firstElement, + const vector& secondElement) +{ + if (firstElement.empty() || secondElement.empty()) + return {}; + + vector intersection = ElementsIntersection(firstElement, secondElement); + vector> result; + if (intersection.empty()) + return { firstElement }; + + for (int i = 0; i < firstElement.size(); i++) + { + auto dimDiff = DimensionDifference(firstElement[i], secondElement[i]); + if (!dimDiff.empty()) + { + vector firstCopy = firstElement; + for (const auto& range : dimDiff) + { + firstCopy[i] = range; + result.push_back(firstCopy); + } + } + } + return result; +} + +static void ElementsUnion(const vector& firstElement, const vector& secondElement, + vector>& lc, vector>& rc, + vector& intersection) +{ + /* lc(rc) is a set of ranges, which only exist in first(second) element*/ + intersection = ElementsIntersection(firstElement, secondElement); + lc = ElementsDifference(firstElement, intersection); + rc = ElementsDifference(secondElement, intersection); +} + +void AccessingSet::FindUncovered(const vector& element, vector>& result) const { + vector> newTails; + result.push_back(element); + for (const auto& currentElement : allElements) + { + for (const auto& tailLoc : result) + { + auto intersection = ElementsIntersection(tailLoc, currentElement); + auto diff = ElementsDifference(tailLoc, intersection); + if (!diff.empty()) { + newTails.insert(newTails.end(), diff.begin(), diff.end()); + } + } + result = move(newTails); + } +} + +bool AccessingSet::ContainsElement(const vector& element) const +{ + vector> tails; + FindUncovered(element, tails); + return !tails.empty(); +} + +void AccessingSet::FindCoveredBy(const vector& element, vector>& result) const +{ + for (const auto& currentElement : allElements) + { + auto intersection = ElementsIntersection(element, currentElement); + if (!intersection.empty()) + result.push_back(intersection); + } +} + +vector> AccessingSet::GetElements() const { return allElements; } + +void AccessingSet::Insert(const vector& element) +{ + vector> tails; + FindUncovered(element, tails); + allElements.insert(allElements.end(), tails.begin(), tails.end()); +} + +AccessingSet AccessingSet::Union(const AccessingSet& source) { + AccessingSet result; + for (auto& element : source.GetElements()) + result.Insert(element); + + for (auto& element : allElements) + result.Insert(element); + return result; +} + +AccessingSet AccessingSet::Intersect(const AccessingSet& secondSet) const +{ + vector> result; + if (secondSet.GetElements().empty() || this->allElements.empty()) + return AccessingSet(result); + + for (const auto& element : allElements) + { + if (secondSet.ContainsElement(element)) + result.push_back(element); + else + { + vector> coveredBy; + secondSet.FindCoveredBy(element, coveredBy); + if (!coveredBy.empty()) + result.insert(result.end(), coveredBy.begin(), coveredBy.end()); + } + } + + return AccessingSet(result); +} + +AccessingSet AccessingSet::Diff(const AccessingSet& secondSet) const +{ + if (secondSet.GetElements().empty() || allElements.empty()) + return *this; + + AccessingSet intersection = this->Intersect(secondSet); + AccessingSet uncovered = *this; + vector> result; + for (const auto& element : intersection.GetElements()) + { + vector> current_uncovered; + uncovered.FindUncovered(element, current_uncovered); + uncovered = AccessingSet(current_uncovered); + } + return uncovered; +} + +bool operator!=(const ArrayDimension& lhs, const ArrayDimension& rhs) +{ + return !(lhs.start == rhs.start && lhs.step == rhs.step && lhs.tripCount == rhs.tripCount); +} + + +bool operator!=(const AccessingSet& lhs, const AccessingSet& rhs) +{ + for (size_t i = 0; i < lhs.allElements.size(); i++) + for (size_t j = 0; j < lhs.allElements[i].size(); j++) + if (lhs.allElements[i][j] != rhs.allElements[i][j]) + return true; + + return false; +} + +bool operator!=(const ArrayAccessingIndexes& lhs, const ArrayAccessingIndexes& rhs) +{ + if (lhs.size() != rhs.size()) + return true; + + for (auto& [key, value] : lhs) + if (rhs.find(key) == rhs.end()) + return true; + + return false; +} diff --git a/src/PrivateAnalyzer/range_structures.h b/src/PrivateAnalyzer/range_structures.h new file mode 100644 index 0000000..4b52f97 --- /dev/null +++ b/src/PrivateAnalyzer/range_structures.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include +#include + +struct ArrayDimension +{ + uint64_t start, step, tripCount; +}; + +class AccessingSet { +private: + std::vector> allElements; + +public: + AccessingSet(std::vector> input) : allElements(input) {}; + AccessingSet() {}; + AccessingSet(const AccessingSet& a) { allElements = a.GetElements(); }; + std::vector> GetElements() const; + void Insert(const std::vector& element); + AccessingSet Union(const AccessingSet& source); + AccessingSet Intersect(const AccessingSet& secondSet) const; + AccessingSet Diff(const AccessingSet& secondSet) const; + bool ContainsElement(const std::vector& element) const; + void FindCoveredBy(const std::vector& element, std::vector>& result) const; + void FindUncovered(const std::vector& element, std::vector>& result) const; + friend bool operator!=(const AccessingSet& lhs, const AccessingSet& rhs); +}; + +using ArrayAccessingIndexes = std::map; + +bool operator!=(const ArrayDimension& lhs, const ArrayDimension& rhs); +bool operator!=(const AccessingSet& lhs, const AccessingSet& rhs); +bool operator!=(const ArrayAccessingIndexes& lhs, const ArrayAccessingIndexes& rhs); \ No newline at end of file diff --git a/src/PrivateAnalyzer/region.cpp b/src/PrivateAnalyzer/region.cpp new file mode 100644 index 0000000..dfe30b1 --- /dev/null +++ b/src/PrivateAnalyzer/region.cpp @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include +#include + +#include "range_structures.h" +#include "region.h" + +#include "../Utils/SgUtils.h" + +using namespace std; + +static bool isParentStmt(SgStatement* stmt, SgStatement* parent) +{ + for (; stmt; stmt = stmt->controlParent()) + if (stmt == parent) + return true; + + return false; +} + +/*returns head block and loop*/ +pair> GetBasicBlocksForLoop(const LoopGraph* loop, const vector blocks) +{ + unordered_set block_loop; + SAPFOR::BasicBlock* head_block = nullptr; + auto loop_operator = loop->loop->GetOriginal(); + for (const auto& block : blocks) + { + if (!block || (block->getInstructions().size() == 0)) + continue; + + SgStatement* first = block->getInstructions().front()->getInstruction()->getOperator(); + SgStatement* last = block->getInstructions().back()->getInstruction()->getOperator(); + if (isParentStmt(first, loop_operator) && isParentStmt(last, loop_operator)) + { + block_loop.insert(block); + + if ((!head_block) && (first == loop_operator) && (last == loop_operator) && + (block->getInstructions().size() == 2) && + (block->getInstructions().back()->getInstruction()->getOperation() == SAPFOR::CFG_OP::JUMP_IF)) + { + head_block = block; + } + + } + } + return { head_block, block_loop }; +} + +static void BuildLoopIndex(map& loopForIndex, LoopGraph* loop) { + string index = loop->loopSymbol; + loopForIndex[index] = loop; + + for (const auto& childLoop : loop->children) + BuildLoopIndex(loopForIndex, childLoop); +} + +static string FindIndexName(int pos, SAPFOR::BasicBlock* block, map& loopForIndex) { + unordered_set args = { block->getInstructions()[pos]->getInstruction()->getArg1() }; + + for (int i = pos - 1; i >= 0; i--) + { + SAPFOR::Argument* res = block->getInstructions()[i]->getInstruction()->getResult(); + if (res && args.find(res) != args.end()) + { + SAPFOR::Argument* arg1 = block->getInstructions()[i]->getInstruction()->getArg1(); + SAPFOR::Argument* arg2 = block->getInstructions()[i]->getInstruction()->getArg2(); + if (arg1) + { + string name = arg1->getValue(); + int idx = name.find('%'); + if (idx != -1 && loopForIndex.find(name.substr(idx + 1)) != loopForIndex.end()) + return name.substr(idx + 1); + else + args.insert(arg1); + } + + if (arg2) + { + string name = arg2->getValue(); + int idx = name.find('%'); + if (idx != -1 && loopForIndex.find(name.substr(idx + 1)) != loopForIndex.end()) + return name.substr(idx + 1); + else + args.insert(arg2); + } + } + } + return ""; +} + +static int GetDefUseArray(SAPFOR::BasicBlock* block, LoopGraph* loop, ArrayAccessingIndexes& def, ArrayAccessingIndexes& use) { + auto instructions = block->getInstructions(); + map loopForIndex; + BuildLoopIndex(loopForIndex, loop); + for (int i = 0; i < instructions.size(); i++) + { + auto instruction = instructions[i]; + if (!instruction->getInstruction()->getArg1()) + continue; + + auto operation = instruction->getInstruction()->getOperation(); + auto type = instruction->getInstruction()->getArg1()->getType(); + if ((operation == SAPFOR::CFG_OP::STORE || operation == SAPFOR::CFG_OP::LOAD) && type == SAPFOR::CFG_ARG_TYPE::ARRAY) + { + vector index_vars; + vector refPos; + string array_name; + if (operation == SAPFOR::CFG_OP::STORE) + array_name = instruction->getInstruction()->getArg1()->getValue(); + else + array_name = instruction->getInstruction()->getArg2()->getValue(); + + int j = i - 1; + while (j >= 0 && instructions[j]->getInstruction()->getOperation() == SAPFOR::CFG_OP::REF) + { + index_vars.push_back(instructions[j]->getInstruction()->getArg1()); + refPos.push_back(j); + j--; + } + + /*to choose correct dimension*/ + int n = index_vars.size(); + vector accessPoint(n); + + auto* ref = isSgArrayRefExp(instruction->getInstruction()->getExpression()); + vector> coefsForDims; + for (int i = 0; ref && i < ref->numberOfSubscripts(); ++i) + { + const vector& coefs = getAttributes(ref->subscript(i), set{ INT_VAL }); + if (coefs.size() == 1) + { + const pair coef(coefs[0][0], coefs[0][1]); + coefsForDims.push_back(coef); + } + + } + + while (!index_vars.empty()) + { + auto var = index_vars.back(); + int currentVarPos = refPos.back(); + pair currentCoefs = coefsForDims.back(); + ArrayDimension current_dim; + if (var->getType() == SAPFOR::CFG_ARG_TYPE::CONST) + current_dim = { stoul(var->getValue()), 1, 1 }; + else + { + string name, full_name = var->getValue(); + int pos = full_name.find('%'); + LoopGraph* currentLoop; + if (pos != -1) + { + name = full_name.substr(pos + 1); + if (loopForIndex.find(name) != loopForIndex.end()) + currentLoop = loopForIndex[name]; + else + return -1; + } + else + { + name = FindIndexName(currentVarPos, block, loopForIndex); + if (name == "") + return -1; + + if (loopForIndex.find(name) != loopForIndex.end()) + currentLoop = loopForIndex[name]; + else + return -1; + } + + uint64_t start = currentLoop->startVal * currentCoefs.first + currentCoefs.second; + uint64_t step = currentCoefs.first; + current_dim = { start, step, (uint64_t)currentLoop->calculatedCountOfIters }; + } + + accessPoint[n - index_vars.size()] = current_dim; + index_vars.pop_back(); + refPos.pop_back(); + coefsForDims.pop_back(); + } + + if (operation == SAPFOR::CFG_OP::STORE) + def[array_name].Insert(accessPoint); + else + use[array_name].Insert(accessPoint); + } + } + return 0; + +} + +static void SetConnections(unordered_map& bbToRegion, const unordered_set& blockSet) +{ + for (SAPFOR::BasicBlock* block : blockSet) + { + for (SAPFOR::BasicBlock* nextBlock : block->getNext()) + if (bbToRegion.find(nextBlock) != bbToRegion.end()) + bbToRegion[block]->addNextRegion(bbToRegion[nextBlock]); + + for (SAPFOR::BasicBlock* prevBlock : block->getPrev()) + if (bbToRegion.find(prevBlock) != bbToRegion.end()) + bbToRegion[block]->addPrevRegion(bbToRegion[prevBlock]); + } +} + +static Region* CreateSubRegion(LoopGraph* loop, const vector& Blocks, const unordered_map& bbToRegion) +{ + Region* region = new Region; + auto [header, blockSet] = GetBasicBlocksForLoop(loop, Blocks); + if (bbToRegion.find(header) != bbToRegion.end()) + region->setHeader(bbToRegion.at(header)); + else + return NULL; + + for (SAPFOR::BasicBlock* block : blockSet) + if (bbToRegion.find(block) != bbToRegion.end()) + region->addBasickBlocks(bbToRegion.at(block)); + + for (LoopGraph* childLoop : loop->children) + region->addSubRegions(CreateSubRegion(childLoop, Blocks, bbToRegion)); + + cout << header << endl; + return region; +} + +Region::Region(LoopGraph* loop, const vector& Blocks) +{ + auto [header, blockSet] = GetBasicBlocksForLoop(loop, Blocks); + unordered_map bbToRegion; + for (auto poiner : blockSet) + { + bbToRegion[poiner] = new Region(*poiner); + this->basickBlocks.insert(bbToRegion[poiner]); + GetDefUseArray(poiner, loop, bbToRegion[poiner]->array_def, bbToRegion[poiner]->array_use); + + } + this->header = bbToRegion[header]; + SetConnections(bbToRegion, blockSet); + //create subRegions + for (LoopGraph* childLoop : loop->children) + subRegions.insert(CreateSubRegion(childLoop, Blocks, bbToRegion)); +} diff --git a/src/PrivateAnalyzer/region.h b/src/PrivateAnalyzer/region.h new file mode 100644 index 0000000..5e85900 --- /dev/null +++ b/src/PrivateAnalyzer/region.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include + +#include "../GraphLoop/graph_loops.h" +#include "../CFGraph/CFGraph.h" + +class Region : public SAPFOR::BasicBlock { +public: + Region() { header = nullptr; } + + Region(SAPFOR::BasicBlock block) : SAPFOR::BasicBlock::BasicBlock(block) { header = nullptr; } + + Region(LoopGraph* loop, const std::vector& Blocks); + + Region* getHeader() { return header; } + + void setHeader(Region* region) { header = region; } + + std::unordered_set& getBasickBlocks() { return basickBlocks; } + + void addBasickBlocks(Region* region) { basickBlocks.insert(region); } + + const std::unordered_set& getPrevRegions() { return prevRegions; } + + std::unordered_set getNextRegions() { return nextRegions; } + + void addPrevRegion(Region* region) { prevRegions.insert(region); } + + void addNextRegion(Region* region) { nextRegions.insert(region); } + + void replaceInPrevRegions(Region* source, Region* destination) + { + prevRegions.erase(destination); + prevRegions.insert(source); + } + + void replaceInNextRegions(Region* source, Region* destination) + { + nextRegions.erase(destination); + nextRegions.insert(source); + } + + std::unordered_set getSubRegions() { return subRegions; } + + void addSubRegions(Region* region) { subRegions.insert(region); } + + ArrayAccessingIndexes array_def, array_use, array_out, array_in, array_priv; + +private: + std::unordered_set subRegions, basickBlocks; + /*next Region which is BB for current BB Region*/ + std::unordered_set nextRegions; + /*prev Regions which is BBs for current BB Region*/ + std::unordered_set prevRegions; + Region* header; +}; diff --git a/src/Sapfor.cpp b/src/Sapfor.cpp index f39cb03..86d66ee 100644 --- a/src/Sapfor.cpp +++ b/src/Sapfor.cpp @@ -55,6 +55,7 @@ #include "VerificationCode/verifications.h" #include "Distribution/CreateDistributionDirs.h" #include "PrivateAnalyzer/private_analyzer.h" +#include "PrivateAnalyzer/private_arrays_search.h" #include "ExpressionTransform/expr_transform.h" #include "Predictor/PredictScheme.h" @@ -1031,15 +1032,13 @@ static bool runAnalysis(SgProject &project, const int curr_regime, const bool ne } else if (curr_regime == BUILD_IR_SSA_FORM) { - if (ssaFormIR.size() == 0) { + if (ssaFormIR.size() == 0) buildIRSSAForm(fullIR, &ssaFormIR); - } } - else if (curr_regime == EXPLORE_IR_LOOPS) - { - exploreLoops(&ssaFormIR, file_name); - } - + else if (curr_regime == EXPLORE_IR_LOOPS) + exploreLoops(&ssaFormIR, file_name); + else if (curr_regime == FIND_PRIVATE_ARRAYS) + FindPrivateArrays(loopGraph, fullIR); else if (curr_regime == TEST_PASS) { //test pass diff --git a/src/Sapfor.h b/src/Sapfor.h index bc77cd9..188921a 100644 --- a/src/Sapfor.h +++ b/src/Sapfor.h @@ -185,6 +185,8 @@ enum passes { EXPLORE_IR_LOOPS, BUILD_IR_SSA_FORM, + FIND_PRIVATE_ARRAYS, + TEST_PASS, EMPTY_PASS }; @@ -371,6 +373,7 @@ static void setPassValues() passNames[INSERT_NO_DISTR_FLAGS_FROM_GUI] = "INSERT_NO_DISTR_FLAGS_FROM_GUI"; passNames[EXPLORE_IR_LOOPS] = "EXPLORE_IR_LOOPS"; passNames[BUILD_IR_SSA_FORM] = "BUILD_IR_SSA_FORM"; + passNames[FIND_PRIVATE_ARRAYS] = "FIND_PRIVATE_ARRAYS"; passNames[TEST_PASS] = "TEST_PASS"; } diff --git a/src/Utils/PassManager.h b/src/Utils/PassManager.h index 542570b..b0fe453 100644 --- a/src/Utils/PassManager.h +++ b/src/Utils/PassManager.h @@ -316,8 +316,9 @@ void InitPassesDependencies(map> &passDepsIn, set list({ VERIFY_INCLUDES, CORRECT_VAR_DECL }) <= Pass(SET_IMPLICIT_NONE); - list({ CALL_GRAPH, LOOP_GRAPH, CALL_GRAPH2 }) <= Pass(BUILD_IR_SSA_FORM); - Pass(BUILD_IR_SSA_FORM) <= Pass(EXPLORE_IR_LOOPS); + list({ CALL_GRAPH, LOOP_GRAPH, CALL_GRAPH2 }) <= Pass(BUILD_IR_SSA_FORM) <= Pass(EXPLORE_IR_LOOPS); + + list({ CALL_GRAPH2, CALL_GRAPH, BUILD_IR, LOOP_GRAPH, LOOP_ANALYZER_DATA_DIST_S2 }) <= Pass(FIND_PRIVATE_ARRAYS); passesIgnoreStateDone.insert({ CREATE_PARALLEL_DIRS, INSERT_PARALLEL_DIRS, INSERT_SHADOW_DIRS, EXTRACT_PARALLEL_DIRS, EXTRACT_SHADOW_DIRS, CREATE_REMOTES, UNPARSE_FILE, REMOVE_AND_CALC_SHADOW, diff --git a/src/Utils/utils.cpp b/src/Utils/utils.cpp index ea9f073..2ee26d1 100644 --- a/src/Utils/utils.cpp +++ b/src/Utils/utils.cpp @@ -1415,6 +1415,35 @@ ParallelRegion* getRegionByLine(const vector& regions, const st return NULL; } +std::pair getRegionAndLinesByLine(const vector& regions, const string& file, const int line) +{ + if (regions.size() == 1 && regions[0]->GetName() == "DEFAULT") // only default + return { regions[0], NULL }; + else if (regions.size() > 0) + { + map regFound; + const ParallelRegionLines* foundLines = NULL; + + for (int i = 0; i < regions.size(); ++i) + if (regions[i]->HasThisLine(line, file, &foundLines)) + regFound[regions[i]] = foundLines; + + if (regFound.size() == 0) + return { NULL, 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, NULL }; + } + } + else + return { NULL, NULL }; + + return { NULL, NULL }; +} + set getAllRegionsByLine(const vector& regions, const string& file, const int line) { set regFound;