#include "leak_detector.h" #include #include #include #include #include #include #include #include #include "dvm.h" #include "../Sapfor.h" #include "graph_calls_func.h" #include "../ParallelizationRegions/ParRegions_func.h" #include "expr_transform.h" #include "../Distribution/GraphCSR.h" #include "../Distribution/Arrays.h" #include "../Distribution/Distribution.h" #include "graph_loops.h" #include "utils.h" #include "SgUtils.h" #include "errors.h" #include "AstWrapper.h" #include "json.hpp" #include "../DirectiveProcessing/directive_parser.h" #include "../DynamicAnalysis/gCov_parser_func.h" #include "../Transformations/VectorAssignToLoop/array_assign_to_loop.h" using std::vector; using std::map; using std::set; using std::string; using std::wstring; using std::pair; using json = nlohmann::json; #define DEBUG 0 static inline void insertLabels(SgExpression *lb, map> &gotoLabels, const int line) { while (lb) { SgLabel *lab = ((SgLabelRefExp *)(lb->lhs()))->label(); gotoLabels[lab->getLabNumber()].push_back(line); lb = lb->rhs(); } } static bool recVariantFind(SgExpression *ex, const int var) { bool ret = false; if (ex) { if (ex->variant() == var) return true; ret = ret || recVariantFind(ex->lhs(), var); ret = ret || recVariantFind(ex->rhs(), var); } return ret; } static void recInderectFind(SgExpression *ex, set &usedArrays) { if (ex) { if (ex->variant() == ARRAY_REF) { DIST::Array *arrayRef = NULL; SgSymbol *symbS = OriginalSymbol(ex->symbol()); const string symb = symbS->identifier(); if (symbS) arrayRef = getArrayFromDeclarated(declaratedInStmt(symbS), symb); else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); // only distributed arrays were added if (arrayRef) if (arrayRef->IsNotDistribute() == false) usedArrays.insert(arrayRef); } recInderectFind(ex->lhs(), usedArrays); recInderectFind(ex->rhs(), usedArrays); } } bool recSymbolFind(SgExpression *ex, const string &symb, const int var) { bool ret = false; if (ex) { if (ex->variant() == var) { if (ex->symbol()) if (ex->symbol()->identifier() == symb) return true; } ret = ret || recSymbolFind(ex->lhs(), symb, var); ret = ret || recSymbolFind(ex->rhs(), symb, var); } return ret; } static inline void processIOlist(SgExpression *spec, const int line, map>& labelsList) { while (spec) { if (spec->lhs()) { SgExpression* specL = spec->lhs(); if (specL->lhs() && specL->rhs()) { if (specL->lhs()->variant() == KEYWORD_VAL) { SgKeywordValExp* keyVal = (SgKeywordValExp*)specL->lhs(); if (keyVal->value() != string("fmt")) { if (specL->rhs()->variant() == LABEL_REF) { SgLabelRefExp* labRef = (SgLabelRefExp*)specL->rhs(); if (labRef->label()) labelsList[labRef->label()->getLabNumber()].push_back(line); } } } } } spec = spec->rhs(); } } static inline void processLables(SgStatement *curr, map> &labelsList, bool includeWrite = true) { const int var = curr->variant(); if (var == GOTO_NODE) { SgGotoStmt *gotoS = (SgGotoStmt *)curr; labelsList[gotoS->branchLabel()->getLabNumber()].push_back(curr->lineNumber()); } else if (var == ARITHIF_NODE) { SgExpression *lb = curr->expr(1); insertLabels(lb, labelsList, curr->lineNumber()); } else if (var == COMGOTO_NODE) { SgExpression *lb = ((SgComputedGotoStmt*)curr)->labelList(); insertLabels(lb, labelsList, curr->lineNumber()); } else if ((var == PRINT_STAT || var == WRITE_STAT) && includeWrite) { SgInputOutputStmt *ioStat = (SgInputOutputStmt*)curr; SgExpression *spec = ioStat->specList(); processIOlist(spec, curr->lineNumber(), labelsList); } } static SgStatement *getLoopControlParent(SgStatement *inSt) { SgStatement *cp = inSt->controlParent(); while (!isSgForStmt(cp) && cp) cp = cp->controlParent(); return cp; } static inline bool hasGoto(SgStatement *begin, SgStatement *end, vector &linesOfIntGoTo, vector &linesOfExtGoTo, const map> &labelsRef, vector& cycleStmts) { bool has = false; SgStatement *curr = begin->lexNext(); map> gotoLabels; map> inFragLabels; while (curr != end) { if (curr->hasLabel()) inFragLabels[curr->label()->getLabNumber()].push_back(curr->lineNumber()); for (int i = 0; i < 3; ++i) { if (curr->expr(i)) { if (recVariantFind(curr->expr(i), EXIT_STMT) && getLoopControlParent(curr) == begin) { linesOfIntGoTo.push_back(curr->lineNumber()); has = true; } } } processLables(curr, gotoLabels); if (curr->variant() == EXIT_STMT && getLoopControlParent(curr) == begin) { linesOfIntGoTo.push_back(curr->lineNumber()); has = true; } if (curr->variant() == RETURN_STAT) { linesOfIntGoTo.push_back(curr->lineNumber()); has = true; } if (curr->variant() == CYCLE_STMT) cycleStmts.push_back(curr->lineNumber()); curr = curr->lexNext(); } // if loop has no labels from goto for (auto it = gotoLabels.begin(); it != gotoLabels.end(); ++it) { if (inFragLabels.find(it->first) == inFragLabels.end()) { has = true; for (int z = 0; z < it->second.size(); ++z) linesOfIntGoTo.push_back(it->second[z]); } } // if loop has labels with extern goto for (auto it = inFragLabels.begin(); it != inFragLabels.end(); ++it) { auto labRef = labelsRef.find(it->first); if (labRef != labelsRef.end()) { for (auto &line : labRef->second) { if (!(line > begin->lineNumber() && line <= end->lineNumber())) { has = true; linesOfExtGoTo.push_back(line); } } } } return has; } bool checkRegionEntries(SgStatement *begin, SgStatement *end, const map &funcMap, const vector ¶llelRegions, map> &SPF_messages) { bool noError = true; SgStatement *st = begin; SgSymbol *regIdent = begin->symbol(); // get func statement while (st->variant() != PROG_HEDR && st->variant() != PROC_HEDR && st->variant() != FUNC_HEDR) st = st->controlParent(); // check GOTO map> labelsRef; findAllRefsToLables(st, labelsRef); vector linesOfIntGoTo; vector linesOfExtGoTo; vector tmp; hasGoto(begin, end, linesOfIntGoTo, linesOfExtGoTo, labelsRef, tmp); if (linesOfExtGoTo.size()) { __spf_print(1, "wrong parallel region position: there are several entries in fragment '%s' caused by GOTO on line %d\n", regIdent->identifier(), begin->lineNumber()); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"wrong parallel region position: there are several entries in fragment '%s' caused by GOTO", to_wstring(regIdent->identifier()).c_str()); __spf_printToLongBuf(messageR, R11, to_wstring(regIdent->identifier()).c_str()); getObjectForFileFromMap(begin->fileName(), SPF_messages).push_back(Messages(ERROR, begin->lineNumber(), messageR, messageE, 1001)); noError = false; } // check ENTRY auto oldFile = current_file->filename(); for (auto &funcPair : funcMap) { auto func = funcPair.second; if (SgFile::switchToFile(func->fileName) != -1) { SgStatement *funcSt = func->funcPointer->GetOriginal(); ParallelRegion *reg = NULL; if (funcSt->variant() == ENTRY_STAT && func->callsTo.size() && (reg = getRegionByLine(parallelRegions, func->fileName, funcSt->lineNumber()))) { __spf_print(1, "wrong parallel region position: there are several entries in fragment '%s' caused by ENTRY on line %d\n", reg->GetName().c_str(), funcSt->lineNumber()); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"wrong parallel region position: there are several entries in fragment '%s' caused by ENTRY", to_wstring(reg->GetName()).c_str()); __spf_printToLongBuf(messageR, R10, to_wstring(reg->GetName()).c_str()); getObjectForFileFromMap(func->fileName.c_str(), SPF_messages).push_back(Messages(ERROR, funcSt->lineNumber(), messageR, messageE, 1001)); noError = false; } } else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } if (SgFile::switchToFile(oldFile) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return noError; } bool hasThisIds(SgStatement *start, set &lines, const set &IDs, const set* activeOps) { bool has = false; SgStatement *end = start->lastNodeOfStmt(); SgStatement *curr = start; for ( ; curr != end; curr = curr->lexNext()) { const int var = curr->variant(); if (var == CONTAINS_STMT) break; if (var == ENTRY_STAT) continue; if (activeOps && activeOps->size() && activeOps->find(curr) == activeOps->end() && isSgExecutableStatement(curr)) { curr = curr->lastNodeOfStmt(); continue; } if (IDs.find(var) != IDs.end()) { has = true; lines.insert(curr->lineNumber()); } } return has; } static inline void findFuncCalls(SgExpression *ex, set &funcCalls) { if (ex) { if (ex->variant() == FUNC_CALL) funcCalls.insert(ex->symbol()->identifier()); findFuncCalls(ex->lhs(), funcCalls); findFuncCalls(ex->rhs(), funcCalls); } } static inline int tryCalculate(SgExpression *expr, int &res) { SgExpression *copyExp = expr->copyPtr(); replaceConstantRec(copyExp); calculate(copyExp); if (CalculateInteger(copyExp, res) == -1) return -1; return 0; } int calculateLoopIters(SgExpression *start, SgExpression *end, SgExpression *step, std::tuple &result) { if (!start && !end) return 0; int startV; int endV; int stepV; if (!step) stepV = 1; else { if (tryCalculate(step, stepV) == -1) return 0; } if (tryCalculate(start, startV) == -1) return 0; if (tryCalculate(end, endV) == -1) return 0; if (startV > endV && stepV > 0) return 0; if (startV < endV && stepV < 0) return 0; int count = (endV - startV + stepV) / stepV; if (count > 0) { std::get<0>(result) = startV; std::get<1>(result) = endV; std::get<2>(result) = stepV; return count; } else return 0; } void findAllRefsToLables(SgStatement *st, map> &labelsRef, bool includeWrite) { SgStatement *last = st->lastNodeOfStmt(); for ( ; st != last; st = st->lexNext()) processLables(st, labelsRef, includeWrite); } static bool hasNonRect(SgForStmt *st, const vector &parentLoops, vector &messages) { bool has = false; SgExpression* start = st->start(); SgExpression* end = st->end(); SgExpression* step = st->step(); if (sharedMemoryParallelization == 0) { set usedArrays; bool has1 = recVariantFind(start, FUNC_CALL) || recVariantFind(end, FUNC_CALL) || recVariantFind(step, FUNC_CALL); //TODO: corect recInderectFind! //TODO: need to add more checking of start,end and step recInderectFind(start, usedArrays); recInderectFind(end, usedArrays); recInderectFind(step, usedArrays); //has = has1 || (usedArrays.size() > 0); for (auto& array : usedArrays) { wstring bufE, bufR; __spf_printToLongBuf(bufE, L"Array '%s' can not be distributed", to_wstring(array->GetShortName()).c_str()); __spf_printToLongBuf(bufR, R91, to_wstring(array->GetShortName()).c_str()); messages.push_back(Messages(NOTE, st->lineNumber(), bufR, bufE, 1047)); array->SetDistributeFlag(DIST::SPF_PRIV); } } if (has == false) { for (auto &upLoop : parentLoops) { SgForStmt *up = (SgForStmt*)upLoop->loop; SgSymbol *symb = up->symbol(); if (symb) { const string strSymb = symb->identifier(); has = has || recSymbolFind(start, strSymb, VAR_REF); has = has || recSymbolFind(end, strSymb, VAR_REF); has = has || recSymbolFind(step, strSymb, VAR_REF); if (has) break; } } } return has; } static void addLoopVariablesToPrivateList(SgForStmt *currLoopRef) { if (currLoopRef == NULL) return; SgStatement *spfStat = new SgStatement(SPF_ANALYSIS_DIR); spfStat->setlineNumber(currLoopRef->lineNumber()); spfStat->setFileName(currLoopRef->fileName()); SgExpression *toAdd = new SgExpression(EXPR_LIST, new SgExpression(ACC_PRIVATE_OP), NULL, NULL); set privateDoSymbs = { currLoopRef->symbol() }; SgStatement *end = currLoopRef->lastNodeOfStmt(); for (SgStatement *st = currLoopRef->lexNext(); st != end; st = st->lexNext()) { SgForStmt *currFor = isSgForStmt(st); if (currFor) privateDoSymbs.insert(currFor->symbol()); } spfStat->setExpression(0, *toAdd); toAdd = toAdd->lhs(); bool first = true; for (auto &elem : privateDoSymbs) { if (first) { toAdd->setLhs(new SgExpression(EXPR_LIST)); toAdd = toAdd->lhs(); first = false; } else { toAdd->setRhs(new SgExpression(EXPR_LIST)); toAdd = toAdd->rhs(); } toAdd->setLhs(new SgVarRefExp(elem)); } currLoopRef->addAttribute(SPF_ANALYSIS_DIR, spfStat, sizeof(SgStatement)); } static void findArrayRef(SgExpression *exp, bool isWirte, set& usedArrays, set& usedArraysWrite, set& allUsedArrays, set& allUsedArraysWrite) { if (exp) { if (isArrayRef(exp)) { DIST::Array *arrayRef = NULL; SgSymbol *symbS = OriginalSymbol(exp->symbol()); const string symb = symbS->identifier(); if (symbS) arrayRef = getArrayFromDeclarated(declaratedInStmt(symbS), symb); else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); // only distributed arrays were added if (arrayRef) { if (arrayRef->IsNotDistribute() == false) { usedArrays.insert(arrayRef); if (isWirte) usedArraysWrite.insert(arrayRef); } allUsedArrays.insert(arrayRef); if (isWirte) allUsedArraysWrite.insert(arrayRef); } } findArrayRef(exp->lhs(), false, usedArrays, usedArraysWrite, allUsedArrays, allUsedArraysWrite); findArrayRef(exp->rhs(), false, usedArrays, usedArraysWrite, allUsedArrays, allUsedArraysWrite); } } static void findArrayRefs(LoopGraph *loop) { for (SgStatement *st = loop->loop->lexNext(); st != loop->loop->lastNodeOfStmt(); st = st->lexNext()) { if (isSgExecutableStatement(st) && !isDVM_stat(st) && !isSPF_stat(st)) { for (int z = 0; z < 3; ++z) { bool isWrite = false; if (z == 0 && st->variant() == ASSIGN_STAT) isWrite = true; findArrayRef(st->expr(z), isWrite, loop->usedArrays, loop->usedArraysWrite, loop->usedArraysAll, loop->usedArraysWriteAll); } } } } static bool isLoopStat(SgStatement* st) { const int var = st->variant(); return (var == FOR_NODE || var == WHILE_NODE); } static bool hasSubstringRef(SgExpression* ex) { bool res = false; if (ex) { if (ex->variant() == ARRAY_OP) return true; if (ex->variant() == ARRAY_REF && !isArrayRef(ex)) return true; if (ex->lhs()) res |= hasSubstringRef(ex->lhs()); if (ex->rhs()) res |= hasSubstringRef(ex->rhs()); } return res; } static bool hasSubstringRef(SgStatement* loop) { for (SgStatement* st = loop->lexNext(); st != loop->lastNodeOfStmt(); st = st->lexNext()) { if (isSgExecutableStatement(st) && !isDVM_stat(st) && !isSPF_stat(st)) { for (int z = 0; z < 3; ++z) { bool res = hasSubstringRef(st->expr(z)); if (res) return true; } } } return false; } void loopGraphAnalyzer(SgFile *file, vector &loopGraph, const vector &intervalTree, vector &messages, int sharedMemoryParallelization) { map mapIntervals; createMapOfinterval(mapIntervals, intervalTree); int funcNum = file->numberOfFunctions(); __spf_print(DEBUG, "functions num in file = %d\n", funcNum); for (int i = 0; i < funcNum; ++i) { map> labelsRef; SgStatement *st = file->functions(i); findAllRefsToLables(st, labelsRef); if (st->variant() == PROG_HEDR) { SgProgHedrStmt *progH = (SgProgHedrStmt*)st; __spf_print(DEBUG, "*** Program <%s> started at line %d / %s\n", progH->symbol()->identifier(), st->lineNumber(), st->fileName()); } else if (st->variant() == PROC_HEDR) { SgProcHedrStmt *procH = (SgProcHedrStmt*)st; __spf_print(DEBUG, "*** Function <%s> started at line %d / %s\n", procH->symbol()->identifier(), st->lineNumber(), st->fileName()); } else if (st->variant() == FUNC_HEDR) { SgFuncHedrStmt *funcH = (SgFuncHedrStmt*)st; __spf_print(DEBUG, "*** Function <%s> started at line %d / %s\n", funcH->symbol()->identifier(), st->lineNumber(), st->fileName()); } SgStatement *lastNode = st->lastNodeOfStmt(); vector parentLoops; LoopGraph *currLoop = NULL; while (st != lastNode) { if (st == NULL) { __spf_print(1, "internal error in analysis, parallel directives will not be generated for this file!\n"); break; } if (st->variant() == CONTAINS_STMT) break; if (!__gcov_doesThisLineExecuted(st->fileName(), st->lineNumber())) { st = st->lexNext(); continue; } //printf("new st with var = %d, on line %d\n", st->variant(), st->lineNumber()); if (isLoopStat(st)) { LoopGraph *newLoop = new LoopGraph(); newLoop->lineNum = st->lineNumber(); if (newLoop->lineNum < 0) { if (st->localLineNumber() > 0) { SgStatement* copied = SgStatement::getStatementByFileAndLine(st->fileName(), st->localLineNumber()); checkNull(copied, convertFileName(__FILE__).c_str(), __LINE__); if (notDeletedVectorAssign(copied)) newLoop->altLineNum = st->localLineNumber(); } } SgStatement *afterLoop = st->lastNodeOfStmt()->lexNext(); //< 0 was appear after CONVERT_ASSIGN_TO_LOOP pass while (afterLoop->lineNumber() < 0 || (isDVM_stat(afterLoop) && afterLoop->variant() != DVM_INTERVAL_DIR && afterLoop->variant() != DVM_ENDINTERVAL_DIR)) { afterLoop = afterLoop->lastNodeOfStmt(); afterLoop = afterLoop->lexNext(); } newLoop->lineNumAfterLoop = afterLoop->lineNumber(); set tmpLines; newLoop->fileName = st->fileName(); newLoop->perfectLoop = countPerfectLoopNest(st); newLoop->hasGoto = hasGoto(st, st->lastNodeOfStmt(), newLoop->linesOfInternalGoTo, newLoop->linesOfExternalGoTo, labelsRef, newLoop->linesOfCycle); newLoop->hasPrints = hasThisIds(st, newLoop->linesOfIO, { WRITE_STAT, READ_STAT, OPEN_STAT, CLOSE_STAT, PRINT_STAT } ); // FORMAT_STAT newLoop->hasStops = hasThisIds(st, newLoop->linesOfStop, { STOP_STAT, PAUSE_NODE }); newLoop->hasDvmIntervals = hasThisIds(st, tmpLines, { DVM_INTERVAL_DIR, DVM_ENDINTERVAL_DIR, DVM_EXIT_INTERVAL_DIR }); newLoop->isFor = isSgForStmt(st) ? true : false; newLoop->inCanonicalFrom = isSgForStmt(st) ? true : false; newLoop->hasSubstringRefs = hasSubstringRef(st); if (isSgForStmt(st)) newLoop->hasNonRectangularBounds = hasNonRect(((SgForStmt*)st), parentLoops, messages); auto itTime = mapIntervals.find(newLoop->lineNum); if (itTime != mapIntervals.end() && itTime->second->exec_time != 0) newLoop->executionTimeInSec = itTime->second->exec_time / itTime->second->exec_count; else if (mapIntervals.size()) { //messages.push_back(Messages(NOTE, newLoop->lineNum, R137, L"Can not find execution time in statistic", 3016)); } SgForStmt *currLoopRef = isSgForStmt(st); if (currLoopRef) { std::tuple loopInfoSES; newLoop->countOfIters = calculateLoopIters(currLoopRef->start(), currLoopRef->end(), currLoopRef->step(), loopInfoSES); Expression* startExpr = currLoopRef->start() ? new Expression(currLoopRef->start()) : NULL; Expression* endExpr = currLoopRef->end() ? new Expression(currLoopRef->end()) : NULL; Expression* stepExpr = currLoopRef->step() ? new Expression(currLoopRef->step()) : NULL; newLoop->startEndStepVals = std::make_tuple(startExpr, endExpr, stepExpr); newLoop->startVal = newLoop->endVal = newLoop->stepVal = 0; if (newLoop->countOfIters != 0) { newLoop->calculatedCountOfIters = newLoop->countOfIters; newLoop->startVal = std::get<0>(loopInfoSES); newLoop->endVal = std::get<1>(loopInfoSES); newLoop->stepVal = std::get<2>(loopInfoSES); } else { SgExpression* start = currLoopRef->start(); SgExpression* end = currLoopRef->end(); SgExpression* step = currLoopRef->step(); if (start == NULL || end == NULL) newLoop->inCanonicalFrom = false; Expression* endE = NULL; Expression* startE = NULL; if (step == NULL) { startE = new Expression(start); endE = new Expression(end); newLoop->stepVal = 1; } else { int res = -1; int err = CalculateInteger(step, res); if (err == 0 && res != 0) { newLoop->stepVal = res; if (res > 0) { startE = new Expression(start); endE = new Expression(&((*end - *start + *step) / *step)); } else { endE = new Expression(end); endE = new Expression(&((*start - *end + *step) / *step)); } } } newLoop->startEndExpr = std::make_pair(startE, endE); } } else newLoop->startEndExpr = std::make_pair((Expression*)NULL, (Expression*)NULL); newLoop->loop = new Statement(st); newLoop->loopSymbol = st->symbol() ? st->symbol()->identifier() : "unknown"; findArrayRefs(newLoop); SgStatement *lexPrev = st->lexPrev(); if (lexPrev->variant() == DVM_PARALLEL_ON_DIR) newLoop->userDvmDirective = new Statement(lexPrev); if (parentLoops.size() == 0) loopGraph.push_back(newLoop); else { currLoop->children.push_back(newLoop); currLoop->children.back()->parent = parentLoops.back(); } parentLoops.push_back(newLoop); currLoop = newLoop; addLoopVariablesToPrivateList(currLoopRef); } else if (st->variant() == CONTROL_END) { if (isLoopStat(st->controlParent())) { parentLoops.pop_back(); if (parentLoops.size() != 0) currLoop = parentLoops.back(); else currLoop = NULL; } } else if (currLoop && (st->variant() == PROC_STAT || st->variant() == FUNC_STAT)) { string pureNameOfCallFunc = removeString("call ", st->symbol()->identifier()); for (auto &loop : parentLoops) loop->calls.push_back(make_pair(pureNameOfCallFunc, st->lineNumber())); } else if (currLoop) { for (int i = 0; i < 3; ++i) { set funcCalls; findFuncCalls(st->expr(i), funcCalls); for (auto &loop : parentLoops) for (auto k = funcCalls.begin(); k != funcCalls.end(); ++k) loop->calls.push_back(make_pair(*k, st->lineNumber())); } } st = st->lexNext(); } __spf_print(DEBUG, "Function ended\n"); } for (auto &loop : loopGraph) loop->propagateUserDvmDir(); } void LoopGraph::recalculatePerfect() { auto loopRef = loop->GetOriginal(); perfectLoop = isSgForStmt(loopRef) ? countPerfectLoopNest(loop->GetOriginal()) : perfectLoop; for (auto &loop : children) loop->recalculatePerfect(); } void LoopGraph::clearUserDirectives() { if (userDvmDirective) { //move comment to next statement if (userDvmDirective->comments()) { char* comms = userDvmDirective->comments(); string comments(comms); userDvmDirective->delComments(); SgStatement* next = userDvmDirective->lexNext(); if (next) next->addComment(comments.c_str()); } userDvmDirective->GetOriginal()->deleteStmt(); userDvmDirective = NULL; } for (auto& ch : children) ch->clearUserDirectives(); } bool LoopGraph::hasParallelLoopsInChList() { bool result = (directive != NULL); for (auto& ch : children) result |= ch->hasParallelLoopsInChList(); return result; } bool LoopGraph::hasParalleDirectiveBefore() { return loop->GetOriginal()->lexPrev()->variant() == DVM_PARALLEL_ON_DIR; } void LoopGraph::analyzeParallelDirs() { if (hasParalleDirectiveBefore()) { if (directive == NULL) { SgExprListExp* loops = isSgExprListExp(loop->GetOriginal()->lexPrev()->expr(2)); int deep = loops->length(); LoopGraph* withDir = this; for (int z = 0; z < deep; ++z) { if (withDir == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (withDir->directive == NULL) // TODO: may be need to fill it correctly withDir->directive = new ParallelDirective(); if (withDir->children.size() == 0 && z != deep - 1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (z != deep - 1) withDir = withDir->children[0]; } } } for (auto& ch : children) ch->analyzeParallelDirs(); } void* LoopGraph::getRealStat(const char* file) const { SgStatement* local = SgStatement::getStatementByFileAndLine(file, lineNum); if (local == NULL) local = SgStatement::getStatementByFileAndLine(file, altLineNum); checkNull(local, convertFileName(__FILE__).c_str(), __LINE__); return local; } extern int PASSES_DONE[EMPTY_PASS]; static int getLoopState(const LoopGraph* currLoop) { int loopState = 0; // 0 - unknown, 1 - good, 2 - bad if (PASSES_DONE[CREATE_TEMPLATE_LINKS] || PASSES_DONE[LOOP_ANALYZER_NODIST]) { if (currLoop->hasLimitsToParallel()) loopState = 2; else loopState = 1; } else { if (currLoop->hasLimitsToParallel()) loopState = 2; } return loopState; } static json convertToJson(const LoopGraph* currLoop) { json loop; if (currLoop && currLoop->lineNum > 0) { loop["file"] = currLoop->fileName; loop["line"] = currLoop->lineNum; loop["lineNumAfterLoop"] = currLoop->lineNumAfterLoop; loop["perfectLoop"] = currLoop->perfectLoop; loop["loopState"] = getLoopState(currLoop); loop["hasNonRectangularBounds"] = (int)currLoop->hasNonRectangularBounds; json calls = json::array(); for (auto& [func, line] : currLoop->calls) { json call; call["line"] = line; call["funcName"] = func; calls.push_back(call); } loop["funcCalls"] = calls; json e_gotos = json::array(); for (auto& line : currLoop->linesOfExternalGoTo) e_gotos.push_back(line); loop["extGotos"] = e_gotos; json i_gotos = json::array(); for (auto& line : currLoop->linesOfInternalGoTo) i_gotos.push_back(line); loop["intGotos"] = i_gotos; json ios = json::array(); for (auto& line : currLoop->linesOfIO) ios.push_back(line); loop["ios"] = ios; json stops = json::array(); for (auto& line : currLoop->linesOfStop) stops.push_back(line); loop["stops"] = stops; json children = json::array(); for (const auto& ch : currLoop->children) { auto conv = convertToJson(ch); if (!conv.empty()) children.push_back(conv); } loop["children"] = children; } return loop; } json convertToJson(const map>& loopsByFileMap) { json loopsByFile = json::array(); for (auto& byFile : loopsByFileMap) { json loop; const string& file = byFile.first; json loops_array = json::array(); for (auto& loop : byFile.second) { auto conv = convertToJson(loop); if (!conv.empty()) loops_array.push_back(conv); } loop["file"] = file; loop["loops"] = loops_array; loopsByFile.push_back(loop); } json allLoops; allLoops["allLoops"] = loopsByFile; return allLoops; } void createMapLoopGraph(const vector &loops, map &mapGraph) { for (auto &elem : loops) { if (mapGraph.find(elem->lineNum) != mapGraph.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); mapGraph[elem->lineNum] = elem; } for (auto &elem : loops) createMapLoopGraph(elem->children, mapGraph); } map findAllDirectives(SgFile *file, const vector &loops, const uint64_t regId) { if (loops.size() == 0) return map(); map retVal; map mapGraph; createMapLoopGraph(loops, mapGraph); for (SgStatement *st = file->firstStatement(); st; st = st->lexNext()) { if (st->variant() == DVM_PARALLEL_ON_DIR) { auto next = st->lexNext(); if (next->variant() != FOR_NODE) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto it = mapGraph.find(next->lineNumber()); if (it == mapGraph.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (it->second->region && it->second->region->GetId() == regId) retVal[it->second] = it->second->directive; } } return retVal; } static void fillFromList(SgExpression *list, vector &coords, DIST::Array *currArr) { if (list) { int idx = 0; while (list) { if (list->lhs()) { const int var = list->lhs()->variant(); if (var == DDOT || var == KEYWORD_VAL) coords[currArr->GetDimSize() - 1 - idx] = -1; else coords[currArr->GetDimSize() - 1 - idx] = 0; } else coords[currArr->GetDimSize() - 1 - idx] = -1; idx++; list = list->rhs(); } } else // full std::fill(coords.begin(), coords.end(), -1); } map> fillRemoteInParallel(Statement *loop) { map> toRet; if (!loop->switchToFile()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgStatement *st = loop->lexPrev(); if (st->variant() == DVM_PARALLEL_ON_DIR) { map, Expression*> remotes; fillRemoteFromComment(new Statement(st), remotes, false, DVM_PARALLEL_ON_DIR); for (auto &newRem : remotes) { auto key = make_pair(string(newRem.first.first->GetOriginal()->symbol()->identifier()), newRem.first.second); DIST::Array *currArr = getArrayFromDeclarated(declaratedInStmt(newRem.first.first->GetOriginal()->symbol()), key.first); newRem.first.first->GetOriginal()->addAttribute(ARRAY_REF, currArr, sizeof(DIST::Array)); if (toRet.find(currArr) != toRet.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); vector coords(currArr->GetDimSize()); SgExpression *list = newRem.second->GetOriginal(); fillFromList(list, coords, currArr); toRet[currArr] = coords; } } return toRet; } vector, pair>> findAllSingleRemotes(SgFile *file, const uint64_t regId, vector ®ions) { vector, pair>> retVal; for (SgStatement *st = file->firstStatement(); st; st = st->lexNext()) { if (st->variant() == DVM_REMOTE_ACCESS_DIR) { ParallelRegion *currReg = getRegionByLine(regions, st->fileName(), st->lineNumber()); if (currReg) { map, Expression*> remotes; fillRemoteFromComment(new Statement(st), remotes, false, DVM_REMOTE_ACCESS_DIR); for (auto &array : remotes) { auto arrName = array.first.first->GetOriginal(); DIST::Array *currArr = getArrayFromDeclarated(declaratedInStmt(arrName), arrName->identifier()); checkNull(currArr, convertFileName(__FILE__).c_str(), __LINE__); vector coords(currArr->GetDimSize()); SgExpression *list = array.second->GetOriginal(); fillFromList(list, coords, currArr); retVal.push_back(std::make_tuple(currArr, coords, std::make_pair(st->lexNext()->fileName(), st->lexNext()->lineNumber()))); } } } } return retVal; } static void processFuncParameters(LoopGraph *loop, SgExpression *list, const FuncInfo* func) { int parNum = 0; while (list) { if (list->lhs() && isArrayRef(list->lhs())) { SgSymbol* arrayS = OriginalSymbol(list->lhs()->symbol()); if (arrayS->type()->variant() != T_STRING) { DIST::Array* array = getArrayFromDeclarated(declaratedInStmt(arrayS), arrayS->identifier()); checkNull(array, convertFileName(__FILE__).c_str(), __LINE__); if (array->IsNotDistribute() == false) if (func->funcParams.isArgOut(parNum)) loop->usedArraysWrite.insert(array); } } ++parNum; list = list->rhs(); } } static void processExpression(SgExpression *ex, LoopGraph* loop, const map &funcByName) { if (ex) { if (ex->variant() == FUNC_CALL) { const string funcName = ex->symbol()->identifier(); auto itF = funcByName.find(funcName); if (itF != funcByName.end()) processFuncParameters(loop, ex->lhs(), itF->second); } processExpression(ex->lhs(), loop, funcByName); processExpression(ex->rhs(), loop, funcByName); } } void completeFillOfArrayUsageBetweenProc(const map>& loopGraph, const map>& allFuncInfo) { map funcByName; createMapOfFunc(allFuncInfo, funcByName); for (auto& byFile : loopGraph) { map loopsMap; createMapLoopGraph(byFile.second, loopsMap); if (SgFile::switchToFile(byFile.first) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto& loop : loopsMap) { SgStatement* start = loop.second->loop->GetOriginal(); SgStatement* end = start->lastNodeOfStmt(); for (SgStatement* st = start; st != end; st = st->lexNext()) { if (st->variant() == PROC_STAT) { const string funcName = st->symbol()->identifier(); auto itF = funcByName.find(funcName); if (itF != funcByName.end()) processFuncParameters(loop.second, st->expr(0), itF->second); } for (int z = 0; z < 3; ++z) processExpression(st->expr(z), loop.second, funcByName); } } } } bool detectMpiCalls(SgProject* proj, map>& SPF_messages) { bool retVal = false; int n = proj->numberOfFiles(); for (int i = n - 1; i >= 0; --i) { SgFile* file = &(proj->file(i)); string fileName = file->filename(); SgStatement* st = file->firstStatement(); while (st) { if (st->variant() == PROC_STAT) { if (isMpiFunction(st->symbol()->identifier())) { retVal = true; wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Detected mpi call, turn on special regime of paralyzing"); __spf_printToLongBuf(messageR, R148); SPF_messages[fileName].push_back(Messages(NOTE, st->lineNumber(), messageR, messageE, 1051)); } } st = st->lexNext(); } } return retVal; } void swapLoopsForParallel(map>& loopGraph, map>& SPF_messages, const int reverse) { for (auto& byFile : loopGraph) { map> loopHeadr; if (SgFile::switchToFile(byFile.first) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); map mapGraph; createMapLoopGraph(byFile.second, mapGraph); for (auto& byLoop : mapGraph) { auto forSwap = byLoop.second->getForSwap(); if (forSwap) loopHeadr[reverse * byLoop.second->lineNum] = std::make_pair(byLoop.second, forSwap); } for (auto& loopPair : loopHeadr) ((SgForStmt*)loopPair.second.first->loop)->interchangeNestedLoops((SgForStmt*)loopPair.second.second->loop); } } static bool isVectorAssign(SgStatement *st) { bool ifVector = false; if (!st) return ifVector; auto prev = st->lexPrev(); if (prev && prev->variant() == CONTROL_END) { auto cp = prev->controlParent(); if (cp->variant() == FOR_NODE) ifVector = cp->lineNumber() < 0 && cp->localLineNumber() > 0; } return ifVector; } int countPerfectLoopNest(SgStatement* st) { int perfect = 1; if (st->variant() != FOR_NODE) return perfect; perfect = 0; SgStatement* next = st; SgStatement* last = st->lastNodeOfStmt(); do { vector attrSpfPar; bool ifVector; do { next = next->lexNext(); attrSpfPar.clear(); if (next) attrSpfPar = getAttributes(next, set{ SPF_PARAMETER_OP }); ifVector = isVectorAssign(next); } while (next && (ifVector && notDeletedVectorAssign(next) || attrSpfPar.size() != 0)); do { last = last->lexPrev(); attrSpfPar.clear(); if (last) attrSpfPar = getAttributes(last, set{ SPF_PARAMETER_OP }); ifVector = isVectorAssign(last); } while (last && (ifVector && notDeletedVectorAssign(last) || attrSpfPar.size() != 0)); ++perfect; if (next == NULL || last == NULL) break; } while (next->variant() == FOR_NODE && last->variant() == CONTROL_END && next->lastNodeOfStmt() == last); return perfect; } #undef DEBUG