#include "errors.h" #include "private_variables_analysis.h" #include "graph_loops.h" #include "../LoopAnalyzer/loop_analyzer.h" #include "../SageAnalysisTool/depGraph.h" #include "../DirectiveProcessing/directive_parser.h" #include "live_variable_analysis.h" #include "RD_subst.h" #include #include #include #include #include #include #include using std::string; using std::wstring; using std::pair; using std::vector; using std::map; using std::set; using std::unordered_set; using std::unordered_map; using std::list; static map, set>> outForFunc; static unordered_map global_cache, local_cache; static unordered_map argumentToSymbol; #define DEBUG_PRINT_PRIVATE 0 #define PRINT_PRIVATES 1 #define PRINT_WARNINGS 1 // print privates and lastprivates for loop void printLoopInfo(const LoopGraph* loop) { SgForStmt* loop_stmt = isSgForStmt(loop->loop); const set& priv = loop->privateScalars; const set& lastpriv = loop->lastprivateScalars; if(!loop_stmt) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); __spf_print(PRINT_PRIVATES, " loop in file '%s' at line %d\n", loop->fileName.c_str(), loop->lineNum); __spf_print(PRINT_PRIVATES, " privates:"); for(const auto& ident : priv) __spf_print(PRINT_PRIVATES, " %s", ident.c_str()); __spf_print(PRINT_PRIVATES, "\n lastprivates:"); for (const auto& ident : lastpriv) __spf_print(PRINT_PRIVATES, " %s", ident.c_str()); __spf_print(PRINT_PRIVATES, "\n"); if (PRINT_WARNINGS) { set added; for (auto& data : getAttributes(loop_stmt, set{ SPF_ANALYSIS_DIR })) fillPrivatesFromComment(new Statement(data), added); set extra_old; std::set_difference(added.begin(), added.end(), priv.begin(), priv.end(), std::inserter(extra_old, extra_old.begin())); if (extra_old.size() != 0) { __spf_print(PRINT_WARNINGS, " [WARNING] extra private variables:"); for (const auto& ident : extra_old) __spf_print(PRINT_WARNINGS, " %s", ident.c_str()); __spf_print(PRINT_WARNINGS, "\n"); } } } // check if parent statement contains stmt static bool isParentStmt(SgStatement* stmt, SgStatement* parent) { for (; stmt; stmt = stmt->controlParent()) if (stmt == parent) return true; return false; } // iterate over expr tree and find SgSymbol that matches arg (by name) static SgSymbol* findSymbolByArgInExpression(const vector>& commonVars, const FuncInfo* func, const SAPFOR::Argument* arg, SgExpression* expr) { if (!expr) return NULL; if (expr->symbol() && expr->symbol()->identifier() && getArgNameBySymbol(commonVars, func, expr->symbol(), global_cache, local_cache) == arg->getValue()) return expr->symbol(); SgSymbol* left; if (left = findSymbolByArgInExpression(commonVars, func, arg, expr->lhs())) return left; return findSymbolByArgInExpression(commonVars, func, arg, expr->rhs()); } // find SgSymbol that matches arg (by name) in stmt static SgSymbol* findSymbolByArgInStatement(const vector>& commonVars, const FuncInfo* func, const SAPFOR::Argument* arg, SgStatement* stmt) { if (!stmt) return NULL; if (stmt->hasSymbol() && stmt->symbol() && getArgNameBySymbol(commonVars, func, stmt->symbol(), global_cache, local_cache) == arg->getValue()) { return stmt->symbol(); } for (int i = 0; i < 3; i++) { SgSymbol* found = findSymbolByArgInExpression(commonVars, func, arg, stmt->expr(i)); if (found) return found; } return NULL; } // find SgSymbol for arg in instr's operator and fill argumentToSymbol // do nothing if arg already has found symbol static void addPlaceWithDef(const vector>& commonVars, const FuncInfo* func, SAPFOR::Argument* arg, SAPFOR::Instruction* instr) { if (argumentToSymbol.find(arg) != argumentToSymbol.end()) return; SgStatement* stmt_with_decl = instr->getOperator(); if (!stmt_with_decl) return; SgSymbol* found = findSymbolByArgInStatement(commonVars, func, arg, stmt_with_decl); if (found) argumentToSymbol[arg] = found; } static void getDefined(const string& func, const vector& params, set& result) { if (!joinGlobalsWithParameters(params, outForFunc, func, result)) { if (func == string("_WRITE") || isIntrinsic(func.c_str())) return; else //READ or else insertIfVar(params.begin(), params.end(), result); } } static void fillOutForFunc(const FuncInfo* func, const vector& blocks) { if (blocks.size() == 0) return; set exits = {}; for (auto block : blocks) { if (block->getNext().size() == 0) exits.insert(block); } set defined; set common_defined; for (auto byExit : exits) { for (const auto& byRd : byExit->getRD_Out()) { auto out_arg = byRd.first; if (!(byRd.second.size() == 1 && *(byRd.second.begin()) < 0)) { switch (out_arg->getMemType()) { case SAPFOR::CFG_MEM_TYPE::COMMON_: case SAPFOR::CFG_MEM_TYPE::MODULE_: common_defined.insert(out_arg); break; case SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_: { int num = getParamIndex(out_arg, func->funcParams.countOfPars); if(func->funcParams.isArgOut(num)) defined.insert(num); break; } } } } } outForFunc[func->funcName] = { defined, common_defined }; } static void getDefsFromBlock(SAPFOR::BasicBlock* block, set& res, const vector>& commonVars, const FuncInfo* func) { vector lastParamRef; for (auto ir_block : block->getInstructions()) { SAPFOR::Instruction* instr = ir_block->getInstruction(); SAPFOR::CFG_OP instr_operation = instr->getOperation(); if (instr_operation == SAPFOR::CFG_OP::PARAM) { SAPFOR::Argument* arg = instr->getArg1(); if(arg->getType() == SAPFOR::CFG_ARG_TYPE::VAR) addPlaceWithDef(commonVars, func, arg, instr); lastParamRef.push_back(arg); } else if (instr_operation == SAPFOR::CFG_OP::F_CALL) { int count = stoi(instr->getArg2()->getValue()); if (lastParamRef.size() != count) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); const string& fName = instr->getArg1()->getValue(); getDefined(fName, lastParamRef, res); lastParamRef.clear(); } } int first_instr_num = block->getInstructions().front()->getNumber(); int last_instr_num = block->getInstructions().back()->getNumber(); for (const auto& def : block->getRD_Out()) for (int place : def.second) if (place >= first_instr_num && place <= last_instr_num && def.first->getType() == SAPFOR::CFG_ARG_TYPE::VAR) { res.insert(def.first); addPlaceWithDef(commonVars, func, def.first, block->getInstructions()[place - first_instr_num]->getInstruction()); } } // recursively analyze FOR loops static set analyzeLoop(LoopGraph* loop, const set& blocks, const vector>& commonVars, const map& commonArgs, FuncInfo* func, map>& messages) { if (!loop->isFor()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //should be called only with FOR loops SgStatement* loop_operator = loop->loop->GetOriginal(); // find blocks related to the current loop set currentLoop = { }; /* service block that looks like _reg = _reg < _reg IF_FALSE _reg then goto ... */ SAPFOR::BasicBlock* head_block = NULL; int loop_start = loop->lineNum, loop_end = loop->lineNumAfterLoop; for (auto bb : blocks) { if (!bb || (bb->getInstructions().size() == 0)) continue; SgStatement* first = bb->getInstructions().front()->getInstruction()->getOperator(); SgStatement* last = bb->getInstructions().back()->getInstruction()->getOperator(); if (isParentStmt(first, loop_operator) && isParentStmt(last, loop_operator)) { currentLoop.insert(bb); if ((!head_block) && (first == loop_operator) && (last == loop_operator) && (bb->getInstructions().size() == 2) && (bb->getInstructions().back()->getInstruction()->getOperation() == SAPFOR::CFG_OP::JUMP_IF)) { head_block = bb; } } } if (!head_block) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); // find blocks inside loop wich can lead to head_block list search_stack = { head_block }; set cycleBody = { }; while (search_stack.size() > 0) { SAPFOR::BasicBlock* curr = search_stack.front(); search_stack.pop_front(); if (cycleBody.insert(curr).second) for (auto next : curr->getPrev()) if (currentLoop.count(next)) search_stack.push_back(next); } set useValueInLoop = {}; for (const auto& use : head_block->getLiveIn()) { for (SAPFOR::BasicBlock* place : use.second) { if (currentLoop.count(place)) { useValueInLoop.insert(use.first); break; } } } set changeValueInLoop = { }; set changeValueOnExit = { }; set LiveWhenLoopEnds = { }; auto loop_it = currentLoop.begin(); auto loop_end_it = currentLoop.end(); auto body_it = cycleBody.begin(); auto body_end = cycleBody.end(); while ((loop_it != loop_end_it) && (body_it != body_end)) { if (*loop_it == *body_it) { getDefsFromBlock(*loop_it, changeValueInLoop, commonVars, func); body_it++; } else getDefsFromBlock(*loop_it, changeValueOnExit, commonVars, func); loop_it++; } if (body_it != body_end) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (; loop_it != loop_end_it; loop_it++) getDefsFromBlock(*loop_it, changeValueOnExit, commonVars, func); for (auto bb : currentLoop) { //fill LiveWhenLoopEnds bool has_next_outside_body = false; for (const auto& next : bb->getNext()) { if (cycleBody.find(next) == cycleBody.end()) { has_next_outside_body = true; break; } } if (has_next_outside_body) { for (const auto& use : bb->getLiveOut()) for (SAPFOR::BasicBlock* place : use.second) if (currentLoop.count(place) == 0) { LiveWhenLoopEnds.insert(use.first); break; } } } set arg_private = {}, arg_lastprivate = {}; std::set_difference(changeValueInLoop.begin(), changeValueInLoop.end(), useValueInLoop.begin(), useValueInLoop.end(), std::inserter(arg_private, arg_private.begin())); arg_private.insert(changeValueOnExit.begin(), changeValueOnExit.end()); std::set_intersection(arg_private.begin(), arg_private.end(), LiveWhenLoopEnds.begin(), LiveWhenLoopEnds.end(), std::inserter(arg_lastprivate, arg_lastprivate.begin())); changeValueInLoop.clear(); LiveWhenLoopEnds.clear(); useValueInLoop.clear(); vector sym_private; for (auto e : arg_private) { SgSymbol* arg_sym = NULL; auto it = argumentToSymbol.find(e); if (it != argumentToSymbol.end()) arg_sym = it->second; else if (e->getMemType() == SAPFOR::CFG_MEM_TYPE::COMMON_ || e->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_) continue; if (arg_sym && arg_sym->identifier()) { if (arg_lastprivate.find(e) != arg_lastprivate.end()) { loop->lastprivateScalars.insert(arg_sym->identifier()); const char* identifier = arg_sym->identifier(); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"add lastprivate scalar '%s' to loop on line %d", to_wstring(identifier).c_str(), loop->lineNum); __spf_printToLongBuf(messageR, R200, to_wstring(identifier).c_str(), loop->lineNum); messages[loop->fileName].push_back(Messages(NOTE, loop->lineNum, messageR, messageE, 3002)); } else { SgStatement* s = new SgStatement(0); s->setlineNumber(loop_start); SgExpression* exp = new SgExpression(VAR_REF); exp->setSymbol(arg_sym); sym_private.push_back(new depNode(s, s, exp, exp, 0, 0, NULL, NULL, 0)); loop->privateScalars.insert(arg_sym->identifier()); } } else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } addPrivatesToLoops(loop, sym_private, { {loop_start, isSgForStmt(loop_operator)} }, messages[loop->fileName]); for (const depNode* node : sym_private) { delete node->stmtin; delete node; } arg_private.clear(); arg_lastprivate.clear(); printLoopInfo(loop); return currentLoop; } static void recAnalyzeLoop(LoopGraph* loop, const set& blocks, const vector>& commonVars, const map& commonArgs, FuncInfo* func, map>& messages) { const auto& loop_body = loop->isFor() ? analyzeLoop(loop, blocks, commonVars, commonArgs, func, messages) : blocks; for (const auto& inner_loop : loop->children) recAnalyzeLoop(inner_loop, loop_body, commonVars, commonArgs, func, messages); } void runPrivateVariableAnalysis(const map>& loopGraph, const map>& CFGraph_for_project, const map& commonBlocks, map>& messages) { map funcByName; for (const auto& byFunc : CFGraph_for_project) if (byFunc.first) funcByName[byFunc.first->funcName] = byFunc.first; //fill outForFunc for (const auto& byLoopFunc : loopGraph) { for (const auto& byLoop : byLoopFunc.second) { for (const auto& byFuncCall : byLoop->calls) { const string& fname = byFuncCall.first; if (outForFunc.find(fname) == outForFunc.end()) { auto func_it = funcByName.find(fname); if (func_it != funcByName.end()) { FuncInfo* func = func_it->second; auto cfg_it = CFGraph_for_project.find(func); if (cfg_it == CFGraph_for_project.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); fillOutForFunc(cfg_it->first, cfg_it->second); } } } } } map> commonArgsByFunc = { }; for (const auto& byFile : loopGraph) { SgFile::switchToFile(byFile.first); for (auto loop : byFile.second) { int loop_start = loop->lineNum, loop_end = loop->lineNumAfterLoop; SgStatement* search_func = loop->loop->GetOriginal(); while (search_func && (!isSgProgHedrStmt(search_func))) search_func = search_func->controlParent(); if(!search_func) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //loop statement outside any function statement bool loop_analyzed = false; for (const auto& byFunc : CFGraph_for_project) { if (byFunc.first->fileName == byFile.first && byFunc.first->funcPointer->GetOriginal() == search_func) { const auto& commonVars = getCommonsByFunction(current_file, byFunc.first->funcPointer, commonBlocks); const auto& commonArgs = getCommonArgsByFunc(byFunc.first, commonArgsByFunc, commonVars, global_cache, local_cache); set loop_ir; loop_ir.insert(byFunc.second.begin(), byFunc.second.end()); recAnalyzeLoop(loop, loop_ir, commonVars, commonArgs, byFunc.first, messages); argumentToSymbol.clear(); //clear cache loop_analyzed = true; break; } } if(!loop_analyzed) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //no func found for loop } local_cache.clear(); commonArgsByFunc.clear(); } outForFunc.clear(); global_cache.clear(); }