#include "leak_detector.h" #include #include #include #include "loop_transform.h" #include "../DirectiveProcessing/directive_parser.h" #include "../SageAnalysisTool/OmegaForSage/include/lang-interf.h" #include "../SageAnalysisTool/definesValues.h" #include "../Utils/SgUtils.h" #include "../SageAnalysisTool/depGraph.h" #include "../GraphCall/graph_calls_func.h" using std::pair; using std::map; using std::tuple; using std::stack; using std::string; using std::vector; using std::set; using std::make_pair; static void buildTopParentLoop(LoopGraph *current, LoopGraph *top, map &loopTopMap) { loopTopMap[current] = top; for (int i = 0; i < current->children.size(); ++i) buildTopParentLoop(current->children[i], top, loopTopMap); } static void buildLoopMap(LoopGraph *current, map &loopMap) { loopMap[current->loop->thebif] = current; for (int i = 0; i < current->children.size(); ++i) buildLoopMap(current->children[i], loopMap); } void reverseCreatedNestedLoops(const string &file, vector &loopsInFile) { map loopMap; map loopTopMap; for (auto &elem : loopsInFile) { buildLoopMap(elem, loopMap); buildTopParentLoop(elem, elem, loopTopMap); } //TODO: need to rewrite /* auto *launches = SageTransform::LoopTransformTighten::getLaunches(); if (launches->count(file) == 0) { __spf_print(1, " nothing to revert in %s\n", file.c_str()); return; } stack> &backOrder = launches->at(file); set topLoopsToRecalaulate; while (backOrder.size()) { auto &elem = backOrder.top(); auto it = loopMap.find(elem.first->thebif); if (it == loopMap.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto reorder = elem.second.buildReverse(); SageTransform::LineReorderer::apply(elem.first, reorder); topLoopsToRecalaulate.insert(loopTopMap[it->second]); backOrder.pop(); } for (auto &elem : topLoopsToRecalaulate) { elem->recalculatePerfect(); elem->restoreDirective(); }*/ } static void fillPrivateAndReductionFromComment(SgStatement *st, set &privates, map> &reduction, map>> &reduction_loc) { for (auto &data : getAttributes(st, set{ SPF_ANALYSIS_DIR })) { fillPrivatesFromComment(new Statement(data), privates); fillReductionsFromComment(new Statement(data), reduction); fillReductionsFromComment(new Statement(data), reduction_loc); } } static pair getDepGraph(LoopGraph *loopGraph, const map &depInfoForLoopGraph) { SgForStmt *sgForStmt = NULL; depGraph *dg = NULL; if (depInfoForLoopGraph.count(loopGraph) == 0) __spf_print(1, "getDepGraph for loop at %d. No depGraph found\n", loopGraph->lineNum); else { dg = depInfoForLoopGraph.at(loopGraph); sgForStmt = isSgForStmt(dg->loop); if (sgForStmt == NULL) __spf_print(1, "getDepGraph for loop at %d. SgForStmt missing for depGraph\n", loopGraph->lineNum); } return make_pair(sgForStmt, dg); } static ddnature fromDepNode(depNode *node) { if (node->typedep == SCALARDEP || node->typedep == PRIVATEDEP) { ddnature nature = (ddnature) node->kinddep; switch (nature) { case ddflow: case ddanti: case ddoutput: return nature; default: break; } } return dd_unknown; } static void displayDep(const depNode *dn) { SgExpression *ex1, *ex2; int i; ddnature nature; ex1 = dn->varin; ex2 = dn->varout; if (!dn->typedep) { __spf_print(1, "UNKNOWN DATA DEPENDENCE\n"); return; } if (dn->typedep == ARRAYDEP) { nature = (ddnature)dn->kinddep; __spf_print(1, "------> "); switch (nature) { case ddflow: __spf_print(1, "FLOW dependence between "); break; case ddanti: __spf_print(1, "ANTI dependence between "); break; case ddoutput: __spf_print(1, "OUTPUT dependence between "); break; case ddreduce: __spf_print(1, "REDUCE dependence between "); break; } __spf_print(1, "%s", ex1->unparse()); __spf_print(1, " (line %d) and ", dn->stmtin->lineNumber()); __spf_print(1, "%s", ex2->unparse()); __spf_print(1, " (line %d) with vector (", dn->stmtout->lineNumber()); for (i = 1; i <= dn->lenghtvect; i++) { if (dn->knowndist[i]) __spf_print(1, "%d", dn->distance[i]); else { if (dn->distance[i] & DEPZERO) __spf_print(1, "0"); if (dn->distance[i] & DEPGREATER) __spf_print(1, "+"); if (dn->distance[i] & DEPLESS) __spf_print(1, "-"); } if (i < dn->lenghtvect) __spf_print(1, ", "); } __spf_print(1, ")\n"); } else { __spf_print(1, "------> "); __spf_print(1, "This is a Scalar Dep on "); __spf_print(1, "%s", ex1->unparse()); if (dn->typedep == PRIVATEDEP) __spf_print(1, " and variable can be PRIVATE"); if (dn->typedep == REDUCTIONDEP) __spf_print(1, " and variable can be REDUCTION with kind %d", dn->kinddep); __spf_print(1, "\n"); } } static void printDepGraph(depGraph *dg) { if(dg == NULL) return; for (depNode *dn : dg->getNodes()) { displayDep(dn); /*int out = dn->stmtout != NULL ? dn->stmtout->lineNumber() : -1; int in = dn->stmtin != NULL ? dn->stmtin->lineNumber() : -1; __spf_print(1, "dep from %d --> %d\n", out, in);*/ } } static void addToMap(SgStatement *stmt, depGraph *depGraph, map &depMap) { depNode *node = NULL; for (auto &dn : depGraph->getNodes()) { //TODO: process ARRAYDEP! if (dn->typedep > ARRAYDEP && dn->stmtin == stmt) { node = dn; break; } } if (node != NULL) { ddnature type = fromDepNode(node); if (node->typedep == SCALARDEP) type = ddoutput; SgSymbol *symbol = node->varin->symbol(); auto it = depMap.find(symbol); if(it != depMap.end()) depMap[symbol] = (it->second < type ? type : it->second); else depMap.insert(make_pair(symbol, type)); } } static map buildTransformerDependencyMap(SgForStmt *outerLoop, depGraph *outerDepGraph, SgForStmt *innerLoop, depGraph *innerDepGraph) { __spf_print(1, "Print outer depgraph START\n"); printDepGraph(outerDepGraph); __spf_print(1, "Print outer depgraph END\n"); __spf_print(1, "Print inner depgraph START\n"); printDepGraph(innerDepGraph); __spf_print(1, "Print inner depgraph END\n"); map depMap; for (SgStatement *stmt = outerLoop->lexNext(); stmt != outerLoop->lastNodeOfStmt(); stmt = stmt->lexNext()) { addToMap(stmt, innerDepGraph, depMap); addToMap(stmt, outerDepGraph, depMap); } return depMap; } static SgForStmt* lexNextLoop(SgStatement* pStmt, SgStatement* end) { SgStatement* pClosestDo = pStmt; while (!isSgForStmt(pClosestDo) && pClosestDo != end) pClosestDo = pClosestDo->lexNext(); return isSgForStmt(pClosestDo); } static ddnature getOrDefault(const map &inMap, SgSymbol *key, ddnature defaultValue) { //implementation must be visible to compiler auto it = inMap.find(key); if (it == inMap.end()) return defaultValue; else return it->second; }; static void processArgs(SgExpression *ex, set &assignToScalars, bool &allAssignmentOrIf, int numArg, const FuncInfo *currF) { if (ex) { bool onlyIn = false; if (currF) if (currF->funcParams.isArgIn(numArg) && !currF->funcParams.isArgOut(numArg)) onlyIn = true; if (ex->variant() == ARRAY_REF) { if (!onlyIn) allAssignmentOrIf = false; } else if (ex->variant() == VAR_REF) { if (!onlyIn) assignToScalars.insert(OriginalSymbol(ex->symbol())); } } } static void findfuncCalls(SgExpression *ex, set& assignToScalars, bool& allAssignmentOrIf, const map& mapFuncInfo) { if (ex) { if (ex->variant() == FUNC_CALL) { SgFunctionCallExp* funcExp = (SgFunctionCallExp*)ex; const string fName = funcExp->funName()->identifier(); if (!isIntrinsicFunctionName(fName.c_str())) { auto itF = mapFuncInfo.find(fName); FuncInfo* currF = NULL; if (itF != mapFuncInfo.end()) currF = itF->second; for (int z = 0; z < funcExp->numberOfArgs(); ++z) processArgs(funcExp->arg(z), assignToScalars, allAssignmentOrIf, z, currF); } } findfuncCalls(ex->lhs(), assignToScalars, allAssignmentOrIf, mapFuncInfo); findfuncCalls(ex->rhs(), assignToScalars, allAssignmentOrIf, mapFuncInfo); } } static bool processInterval(SgStatement* invBegin, SgStatement* invEnd, set& assignToScalars, const map& mapFuncInfo) { bool allAssignmentOrIf = true; SgStatement* stmt = invBegin; while (stmt != invEnd) { allAssignmentOrIf = allAssignmentOrIf && (isSgAssignStmt(stmt) || isSgIfStmt(stmt) || isSgLogIfStmt(stmt) || isSgControlEndStmt(stmt)); if (stmt->variant() == ASSIGN_STAT) { if (stmt->expr(0)->variant() == ARRAY_REF) allAssignmentOrIf = false; else assignToScalars.insert(OriginalSymbol(stmt->expr(0)->symbol())); } else if (stmt->variant() == PROC_STAT) { if (!isIntrinsicFunctionName(stmt->symbol()->identifier())) { auto itF = mapFuncInfo.find(stmt->symbol()->identifier()); FuncInfo* currF = NULL; if (itF != mapFuncInfo.end()) currF = itF->second; int num = 0; for (SgExpression* ex = stmt->expr(0); ex; ex = ex->rhs(), ++num) processArgs(ex->lhs(), assignToScalars, allAssignmentOrIf, num, currF); } } for (int z = 0; z < 3; ++z) findfuncCalls(stmt->expr(z), assignToScalars, allAssignmentOrIf, mapFuncInfo); stmt = stmt->lexNext(); } return allAssignmentOrIf; } static bool validateInvariantStatement(SgStatement* invBegin, SgStatement* invEnd, const map &dependencies, const map& mapFuncInfo) { //by type check SgStatement* stmt = invBegin; set assignToScalarsOuter; set assignToScalarsInner; bool allAssignmentOrIf = processInterval(invBegin, invEnd, assignToScalarsOuter, mapFuncInfo); processInterval(invEnd, invEnd->lastNodeOfStmt(), assignToScalarsInner, mapFuncInfo); if (allAssignmentOrIf) { //TODO: use CFG graph for this analysis //TODO: improve it for (auto& elem : assignToScalarsInner) if (assignToScalarsOuter.find(elem) != assignToScalarsOuter.end()) return false; bool hasFlowDep = false; stmt = invBegin; while (stmt != invEnd && !hasFlowDep) { SgAssignStmt* assignStmt = isSgAssignStmt(stmt); if(assignStmt) { SgSymbol* symbol = assignStmt->lhs()->symbol(); auto dependency = getOrDefault(dependencies, symbol, ddnovalue); hasFlowDep = hasFlowDep || dependency == ddflow || dependency == dd_unknown; } stmt = stmt->lexNext(); } if (hasFlowDep) { bool hasAntiOrOutputDep = false; stmt = invBegin; while (stmt != invEnd && !hasAntiOrOutputDep) { SgAssignStmt* assignStmt = isSgAssignStmt(stmt); if(assignStmt) { SgSymbol* symbol = assignStmt->lhs()->symbol(); auto dependency = getOrDefault(dependencies, symbol, ddnovalue); hasAntiOrOutputDep = hasAntiOrOutputDep || dependency == ddanti || dependency == ddoutput || dependency == dd_unknown; } stmt = stmt->lexNext(); } if (!hasAntiOrOutputDep) { __spf_print(1, "%d : Only flow dependencies present, can tighten.\n", invBegin->lineNumber()); return true; } } else { __spf_print(1, "%d : Invariant value not used in loop, can tighten.\n", invBegin->lineNumber()); return true; } } __spf_print(1, "%d : Invariant cannot be moved into loop.\n", invBegin->lineNumber()); return false; } static bool canTightenSingleLevel(SgForStmt* outerLoop, const map &dependencies, const map& mapFuncInfo) { SgStatement* outerEnddo = outerLoop->lastNodeOfStmt(); SgForStmt* innerLoop = lexNextLoop(outerLoop->lexNext(), outerEnddo); if (innerLoop != NULL) { bool beforeValid = validateInvariantStatement(outerLoop->lexNext(), innerLoop, dependencies, mapFuncInfo); //TODO: //validateInvariantStatement(innerLoop->lastNodeOfStmt()->lexNext(), outerEnddo, dependencies); bool afterValid = (outerLoop->lastNodeOfStmt() == innerLoop->lastNodeOfStmt()->lexNext()); return beforeValid && afterValid; } else return false; } static int canTighten(SgForStmt* pForLoop, const map &dependencies, const map& mapFuncInfo) { int nestDepth = 1; SgForStmt* processedLoop = pForLoop; while (canTightenSingleLevel(processedLoop, dependencies, mapFuncInfo)) { processedLoop = lexNextLoop(processedLoop->lexNext(), NULL); nestDepth++; } if (nestDepth == 1) return 0; else return nestDepth; } static int canTighten(SgForStmt* pForLoop) { int nestnessLevel = 1; SgForStmt* nextOuterLoop = pForLoop; while (nextOuterLoop) { SgStatement* outerLoopControlEnd = nextOuterLoop->lastNodeOfStmt(); SgStatement* nextInnerLoop = nextOuterLoop->lexNext(); while (!isSgForStmt(nextInnerLoop) && nextInnerLoop != outerLoopControlEnd) nextInnerLoop = nextInnerLoop->lexNext(); if (nextInnerLoop == outerLoopControlEnd) //no for loops found in outerloop nextOuterLoop = NULL; else //inner for loop found { nestnessLevel++; nextOuterLoop = isSgForStmt(nextInnerLoop); } } if (nestnessLevel == 1) return 0; else return nestnessLevel; } static SgStatement* sinkIntoNextNearestLoop(SgStatement* pStmt, SgStatement* nextLoop) { __spf_print(1, "%d : SinkIntoNextNearestLoop\n", pStmt->lineNumber()); if(!isSgIfStmt(pStmt->controlParent())) { SgStatement *extr = pStmt->extractStmt(); nextLoop->insertStmtAfter(*extr, *nextLoop); } return pStmt; } static SgStatement* sinkIntoPreviousNearestLoop(SgStatement* pStmt, SgStatement* prevLoop, SgStatement* afterStmt) { __spf_print(1, "%d : sinkIntoPreviousNearestLoop\n", pStmt->lineNumber()); if(!isSgIfStmt(pStmt->controlParent())) { SgStatement *extr = pStmt->extractStmt(); afterStmt->insertStmtAfter(*extr, *prevLoop); } return pStmt; } static void tightenSingleLevel(SgForStmt* outerLoop, SgForStmt* topLevelForLoop) { SgForStmt* innerLoop = lexNextLoop(outerLoop->lexNext(), NULL); { //move statements after given loop before the inner loop //moving these statements is done in reverse order, // because insertion is always after the inner loop header //begin := statement before closest inner loop header SgStatement* begin = innerLoop->lexPrev(); SgStatement* end = outerLoop; SgStatement* stmt = begin; SgStatement* next; while (stmt != end) { next = stmt->lexPrev(); sinkIntoNextNearestLoop(stmt, innerLoop); stmt = next; } } { SgStatement* begin = outerLoop->lastNodeOfStmt()->lexPrev(); SgStatement* end = innerLoop->lastNodeOfStmt(); SgStatement* afterStmt = end->lexPrev(); SgStatement* stmt = begin; SgStatement* next; while (stmt != end) { next = stmt->lexPrev(); sinkIntoPreviousNearestLoop(stmt, innerLoop, afterStmt); stmt = next; } } } static bool tighten(SgForStmt* pForLoop, int level) { if (level > canTighten(pForLoop)) //cannot do that return false; int processing = 2; SgForStmt* processedLoop = pForLoop; while (processing <= level) { tightenSingleLevel(processedLoop, pForLoop); processedLoop = lexNextLoop(processedLoop->lexNext(), NULL); processing++; } return true; } bool createNestedLoops(LoopGraph *current, const map &depInfoForLoopGraphV, const map& mapFuncInfo, vector &messages) { map depInfoForLoopGraph; for (auto& elem : depInfoForLoopGraphV) depInfoForLoopGraph[elem.first] = (depGraph*)elem.second; bool wasTightened = false; // has non nested child loop __spf_print(1, " createNestedLoops for loop at %d. Start\n", current->lineNum); bool outerTightened = false; bool loopCondition = current->children.size() == 1 && current->perfectLoop == 1 && !current->hasLimitsToParallel(); if (loopCondition) { pair outerLoopDependencies = getDepGraph(current, depInfoForLoopGraph); pair innerLoopDependencies = getDepGraph(current->children.at(0), depInfoForLoopGraph); if (outerLoopDependencies.first && outerLoopDependencies.second && innerLoopDependencies.first && innerLoopDependencies.second) { SgForStmt *outerLoop = outerLoopDependencies.first; map depMap = buildTransformerDependencyMap(outerLoop, outerLoopDependencies.second, innerLoopDependencies.first, innerLoopDependencies.second); if (canTighten(outerLoop, depMap, mapFuncInfo) >= 2) { outerTightened = tighten(outerLoop, 2); LoopGraph *firstChild = current->children.at(0); if (outerTightened) firstChild->perfectLoop = countPerfectLoopNest(firstChild->loop); __spf_print(1, " createNestedLoops for loop at %d. Tighten success: %d\n", current->lineNum, outerTightened); wchar_t buf[256]; std::wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Loops on lines %d and %d were combined", current->lineNum, firstChild->lineNum); __spf_printToLongBuf(messageR, R100, current->lineNum, firstChild->lineNum); messages.push_back(Messages(NOTE, current->lineNum, messageR, messageE, 2005)); } } } wasTightened = outerTightened; for (int i = 0; i < current->children.size(); ++i) { __spf_print(1, " createNestedLoops for loop at %d. Transform child %d\n", current->lineNum, i); bool result = createNestedLoops(current->children[i], depInfoForLoopGraphV, mapFuncInfo, messages); wasTightened = wasTightened || result; } //update perfect loop current->recalculatePerfect(); __spf_print(1, " createNestedLoops for loop at %d. End\n", current->lineNum); return wasTightened; }