#include "leak_detector.h" #include #include #include #include #include #include #include #include #include #include "dvm.h" #include "graph_calls_func.h" #include "../CFGraph/CFGraph.h" #include "graph_loops_func.h" #include "../DirectiveProcessing/directive_parser.h" #include "SgUtils.h" #include "json.hpp" #include "../ParallelizationRegions/ParRegions_func.h" #include "../DynamicAnalysis/gCov_parser_func.h" #include "expr_transform.h" #include "../LoopAnalyzer/loop_analyzer.h" #include "../VerificationCode/verifications.h" using std::vector; using std::map; using std::set; using std::pair; using std::tuple; using std::string; using std::wstring; using std::make_pair; using std::to_string; using std::cout; using std::endl; using std::stack; using json = nlohmann::json; #define DEBUG 0 //TODO: improve parameter checking void correctNameIfContains(SgStatement *call, SgExpression *exCall, string &name, const vector &containsFunctions, const string &prefix) { if (containsFunctions.size() <= 0) return; if (call == NULL && exCall == NULL) return; for (auto &func : containsFunctions) { if (func->symbol()->identifier() == name) { int numPar = 0; if (call && call->variant() == PROC_STAT) numPar = isSgCallStmt(call)->numberOfArgs(); else if (exCall && exCall->variant() == FUNC_CALL) numPar = isSgFunctionCallExp(exCall)->numberOfArgs(); else return; SgProgHedrStmt *f = (SgProgHedrStmt*)func; //XXX if (f->numberOfParameters() == numPar) name = prefix + name; break; } } } extern map, pair> declaredArrays; extern map>> declaratedArraysSt; extern int getIntrinsicFunctionType(const char* name); static parF detectType(SgType *type) { parF retT = UNKNOWN_T; int len = getSizeOfType(type); int var = type->variant(); switch (var) { case DEFAULT: break; case T_INT: if (len == 0 || len == 4) retT = SCALAR_INT_T; else if (len == 8) retT = SCALAR_LONG_INT_T; else if (len == 2) retT = SCALAR_SHORT_T; break; case T_FLOAT: if (len == 0 || len == 4) retT = SCALAR_FLOAT_T; else if (len == 8) retT = SCALAR_DOUBLE_T; break; case T_DOUBLE: if (len == 0 || len == 8) retT = SCALAR_DOUBLE_T; break; case T_CHAR: if (len == 0 || len == 4) retT = SCALAR_CHAR_T; break; case T_BOOL: if (len == 0 || len == 4) retT = SCALAR_BOOL_T; break; case T_STRING: retT = STRING_T; break; case T_COMPLEX: if (len == 0 || len == 4) retT = SCALAR_CMPLX_FLOAT_T; else if (len == 8) retT = SCALAR_CMPLX_DOUBLE_T; break; case T_DCOMPLEX: if (len == 0 || len == 8) retT = SCALAR_CMPLX_DOUBLE_T; break; } return retT; } static void fillParam(const int i, SgSymbol *parIn, FuncParam& currParams, const map> &commonBlocks, bool isArrayRef, bool isExternal = false) { SgSymbol *par = OriginalSymbol(parIn); currParams.parametersT[i] = UNKNOWN_T; if ((par->attributes() & OPTIONAL_BIT) != 0) currParams.inout_types[i] |= OPTIONAL_BIT; if ((par->attributes() & EXTERNAL_BIT) || isExternal) { currParams.parametersT[i] = EXTERNAL_T; return; } if (par->variant() == FUNCTION_NAME) { if (isIntrinsicFunctionName(par->identifier())) { const int type = getIntrinsicFunctionType(par->identifier()); if (type == T_DOUBLE) currParams.parametersT[i] = SCALAR_DOUBLE_T; else if (type == T_FLOAT) currParams.parametersT[i] = SCALAR_FLOAT_T; } else { SgType* type = par->type(); currParams.parametersT[i] = detectType(type); } return; } SgType *type = par->type(); if (type) { const int varT = type->variant(); if (isArrayType(type)) { currParams.parametersT[i] = ARRAY_T; SgStatement* decl = declaratedInStmt(par); auto uniqKey = getUniqName(commonBlocks, decl, par); auto itArray = declaredArrays.find(uniqKey); if (itArray == declaredArrays.end()) { __spf_print(1, "array was not in declared list: '%s'\n", par->identifier()); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } currParams.parameters[i] = itArray->second.first; } else if (isStringArrayType(type)) { if (isArrayRef) currParams.parametersT[i] = STRING_T; else currParams.parametersT[i] = STRING_ARRAY_T; } else currParams.parametersT[i] = detectType(type); } else { //printf("var = %d %s\n", par->variant(), tag[par->variant()]); currParams.parametersT[i] = UNKNOWN_T; } } static void fillFuncParams(FuncInfo *currInfo, const map> &commonBlocks, SgProgHedrStmt *procHeader) { int numOfParams = procHeader->numberOfParameters(); FuncParam& currParams = currInfo->funcParams; currParams.init(numOfParams); if (numOfParams > 0) { for (int i = 0; i < numOfParams; ++i) fillParam(i, procHeader->parameter(i), currParams, commonBlocks, false); for (int i = 0; i < procHeader->numberOfParameters(); ++i) { currInfo->funcParams.identificators.push_back((procHeader->parameter(i))->identifier()); currInfo->isParamUsedAsIndex.push_back(false); } } } static void fillFuncParams(FuncInfo *currInfo, const map> &commonBlocks, SgStatement *entryHeader) { SgExpression *parList = entryHeader->expr(0); int numOfParams = 0; for (SgExpression *p = parList; p; p = p->rhs()) numOfParams++; FuncParam& currParams = currInfo->funcParams; currParams.init(numOfParams); if (numOfParams > 0) { SgExpression *p = parList; for (int i = 0; i < numOfParams; ++i, p = p->rhs()) { fillParam(i, p->lhs()->symbol(), currParams, commonBlocks, (p->lhs()->lhs() || p->lhs()->rhs())); currInfo->funcParams.identificators.push_back(p->lhs()->symbol()->identifier()); currInfo->isParamUsedAsIndex.push_back(false); } } } static parF detectMaxTypeOfExpression(SgExpression *ex) { if (!ex) return UNKNOWN_T; parF res = UNKNOWN_T; if (ex->variant() == VAR_REF) { if (ex->symbol() && ex->symbol()->type()) res = detectType(ex->symbol()->type()); } else if (isArrayRef(ex)) { if (ex->symbol() && ex->symbol()->type()->baseType()) res = detectType(ex->symbol()->type()->baseType()); } else if (ex->variant() == CONST_REF) { if (ex->type()) res = detectType(ex->type()); } else if (ex->variant() >= INT_VAL && ex->variant() <= STRING_VAL || ex->variant() == COMPLEX_VAL) { if (ex->type()) res = detectType(ex->type()); } else { parF lF = UNKNOWN_T, rF = UNKNOWN_T; if (ex->lhs()) lF = detectMaxTypeOfExpression(ex->lhs()); if (ex->rhs()) rF = detectMaxTypeOfExpression(ex->rhs()); res = MAX(res, lF); res = MAX(res, rF); } return res; } parF detectExpressionType(SgExpression *exp) { const int var = exp->variant(); if (var == INT_VAL) return SCALAR_INT_T; else if (var == FLOAT_VAL) return SCALAR_FLOAT_T; else if (var == DOUBLE_VAL) return SCALAR_DOUBLE_T; else if (var == CHAR_VAL) return SCALAR_CHAR_T; else if (var == BOOL_VAL) return SCALAR_BOOL_T; else if (exp->variant() == VAR_REF && exp->symbol() && (exp->symbol()->attributes() & EXTERNAL_BIT)) return EXTERNAL_T; else { SgType* type = exp->type(); if (type) { if (type->variant() == DEFAULT) return detectMaxTypeOfExpression(exp); else return detectType(type); } else return UNKNOWN_T; } } //TODO:: add values static void processActualParams(SgExpression *parList, const map> &commonBlocks, FuncParam& currParams, const set& externalCall) { int numOfPar = 0; for (SgExpression *ex = parList; ex != NULL; ex = ex->rhs()) numOfPar++; currParams.init(numOfPar); if (numOfPar > 0) { int num = 0; for (SgExpression *ex = parList; ex != NULL; ex = ex->rhs(), ++num) { if (ex->lhs() && ex->lhs()->lhs() == NULL && ex->lhs()->rhs() == NULL) currParams.identificators.push_back(string(ex->lhs()->unparse())); else currParams.identificators.push_back(""); if (ex->lhs()->symbol()) fillParam(num, ex->lhs()->symbol(), currParams, commonBlocks, (ex->lhs()->lhs() || ex->lhs()->rhs()), externalCall.find(ex->lhs()->symbol()->identifier()) != externalCall.end()); else { parF parf = detectExpressionType(ex->lhs()); currParams.parametersT[num] = parf; if (parf == SCALAR_INT_T) { SgExpression* result = CalculateInteger(ex->lhs()->copyPtr()); if (result != ex->lhs()) { currParams.parameters[num] = new int[1]; addToCollection(__LINE__, __FILE__, currParams.parameters[num], 2); ((int*)currParams.parameters[num])[0] = result->valueInteger(); } } } } } } static void findFuncCalls(SgStatement *parent, SgExpression *curr, FuncInfo* procInfo, const int line, const map> &commonBlocks, const set ¯oNames, const vector &containsFunctions, const string &prefix) { if (curr->variant() == FUNC_CALL && macroNames.find(curr->symbol()->identifier()) == macroNames.end()) { vector nameOfCallFunc; nameOfCallFunc.push_back(curr->symbol()->identifier()); nameOfCallFunc.push_back(OriginalSymbol(curr->symbol())->identifier()); for (auto& elem : nameOfCallFunc) correctNameIfContains(NULL, curr, elem, containsFunctions, prefix); procInfo->callsFrom.insert(nameOfCallFunc.begin(), nameOfCallFunc.end()); FuncInfoCallFrom newCall; newCall.detailCallsFrom = make_pair(nameOfCallFunc[1], line); // original name of call newCall.pointerDetailCallsFrom = make_pair(curr, FUNC_CALL); newCall.parentForPointer = parent; newCall.actualParams = FuncParam(); processActualParams(curr->lhs(), commonBlocks, newCall.actualParams, procInfo->externalCalls); procInfo->callsFromDetailed.push_back(newCall); } if (curr->lhs()) findFuncCalls(parent, curr->lhs(), procInfo, line, commonBlocks, macroNames, containsFunctions, prefix); if (curr->rhs()) findFuncCalls(parent, curr->rhs(), procInfo, line, commonBlocks, macroNames, containsFunctions, prefix); } static void findReplaceSymbolByExpression(SgExpression *parentEx, SgExpression *findIn, int pos, const string &symbol, SgExpression *replace, vector> &replaces) { if (findIn) { if (findIn->symbol()) if (findIn->symbol()->identifier() == symbol) replaces.push_back(std::make_tuple(parentEx, pos, replace->copyPtr())); findReplaceSymbolByExpression(findIn, findIn->lhs(), 0, symbol, replace, replaces); findReplaceSymbolByExpression(findIn, findIn->rhs(), 1, symbol, replace, replaces); } } static void doMacroExpand(SgStatement *parent, SgExpression *parentEx, SgExpression *findIn, int pos, const map ¯oStats, const set ¯oNames, bool &needToIterate, vector &messages) { if (findIn) { if(findIn->variant() == FUNC_CALL && macroNames.find(string(findIn->symbol()->identifier())) != macroNames.end()) { const string funcName = string(findIn->symbol()->identifier()); auto it = macroStats.find(funcName); SgStatement *macroStat = it->second; vector parameters; for (SgExpression *list = findIn->lhs(); list; list = list->rhs()) parameters.push_back(list->lhs()->copyPtr()); SgExpression *toInsert = macroStat->expr(0)->lhs()->copyPtr(); if (parentEx == NULL) parent->setExpression(pos, *toInsert); else { if (pos == 0) parentEx->setLhs(*toInsert); else if (pos == 1) parentEx->setRhs(*toInsert); } SgSymbol *declSymb = macroStat->expr(0)->symbol(); int parN = lenghtOfParamList(declSymb->thesymb); vector> replaces; for (int z = 0; z < parN; ++z) { SgSymbol *toExpand = SymbMapping(GetThParam(declSymb->thesymb, z)); findReplaceSymbolByExpression(toInsert, toInsert->lhs(), 0, toExpand->identifier(), parameters[z], replaces); findReplaceSymbolByExpression(toInsert, toInsert->rhs(), 1, toExpand->identifier(), parameters[z], replaces); } for (auto &repl : replaces) { if (std::get<1>(repl) == 0) std::get<0>(repl)->setLhs(std::get<2>(repl)); else if (std::get<1>(repl) == 1) std::get<0>(repl)->setRhs(std::get<2>(repl)); } needToIterate = true; wstring messageE, messageR; __spf_printToLongBuf(messageE, L"substitute statement function with name '%s'", to_wstring(funcName).c_str()); __spf_printToLongBuf(messageR, R101, to_wstring(funcName).c_str()); messages.push_back(Messages(NOTE, parent->lineNumber(), messageR, messageE, 2006)); } doMacroExpand(parent, findIn, findIn->lhs(), 0, macroStats, macroNames, needToIterate, messages); doMacroExpand(parent, findIn, findIn->rhs(), 1, macroStats, macroNames, needToIterate, messages); } } void doMacroExpand(SgFile *file, vector &messages) { for (int i = 0; i < file->numberOfFunctions(); ++i) { SgStatement *st = file->functions(i); SgStatement *lastNode = st->lastNodeOfStmt(); map macroStats; set macroNames; 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 (!isSgExecutableStatement(st)) { if (st->variant() == STMTFN_STAT) { macroStats.insert(make_pair(st->expr(0)->symbol()->identifier(), st)); macroNames.insert(st->expr(0)->symbol()->identifier()); } } else break; st = st->lexNext(); } if (macroStats.size() > 0) { bool needToIterate = true; while (needToIterate) { needToIterate = false; for (SgStatement *stat = st; stat != lastNode; stat = stat->lexNext()) for (int i = 1; i < 3; ++i) if (stat->expr(i)) doMacroExpand(stat, NULL, stat->expr(i), i, macroStats, macroNames, needToIterate, messages); } } } } static void findIdxRef(SgExpression *exp, FuncInfo &currInfo) { if (exp) { if (exp->variant() == VAR_REF) { for (int i = 0; i < currInfo.funcParams.identificators.size(); i++) { if (exp->symbol()->identifier() == currInfo.funcParams.identificators[i]) currInfo.isParamUsedAsIndex[i] = true; } } findIdxRef(exp->lhs(), currInfo); findIdxRef(exp->rhs(), currInfo); } } static void findArrayRef(SgExpression *exp, FuncInfo &currInfo, bool isWrite) { 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__); if (arrayRef) { // only distributed arrays were added if (arrayRef->IsNotDistribute() == false) { // Through all indexes for (SgExpression *ex = exp; ex != NULL; ex = ex->rhs()) findIdxRef(exp->lhs(), currInfo); currInfo.allUsedArrays.insert(arrayRef); if (isWrite) currInfo.usedArraysWrite.insert(arrayRef); } } } else { findArrayRef(exp->lhs(), currInfo, isWrite); findArrayRef(exp->rhs(), currInfo, isWrite); } } } static void findParamInParam(SgExpression *exp, FuncInfo &currInfo) { // Searching through expression, which parameter presented with if (exp) { if (exp->variant() == VAR_REF || isArrayRef(exp)) { // check for matching with one of param of func which called this //cout << "Checking " << exp->symbol()->identifier() << " for match.." << endl; for (int i = 0; i < currInfo.funcParams.identificators.size(); i++) { const string &parName = currInfo.funcParams.identificators[i]; //cout << " with " << parName << ".. "; if (exp->symbol()->identifier() == parName) { //cout << "Success." << endl; NestedFuncCall &currNestedFuncCall = currInfo.funcsCalledFromThis.back(); currNestedFuncCall.NoOfParamUsedForCall.back().push_back(i); break; } } } // do not search further if found, cause VAR_REF is always a leaf else { findParamInParam(exp->lhs(), currInfo); findParamInParam(exp->rhs(), currInfo); } } } static bool hasRecCall(const FuncInfo* proc, const vector& newNames) { bool has = false; for (auto& toAdd : newNames) if (proc->funcName == toAdd) has = true; return has; } static void findParamUsedInFuncCalls(SgExpression *exp, FuncInfo &currInfo, const vector& containsFunctions, const string& prefix); static void throughParams(SgExpression *pars, FuncInfo &currInfo, const vector& containsFunctions, const string& prefix) { for (SgExpression *par = pars; par != NULL; par = par->rhs()) { // initialize vector representing parameter #parNo NestedFuncCall &currNestedFuncCall = currInfo.funcsCalledFromThis.back(); currNestedFuncCall.NoOfParamUsedForCall.push_back(vector()); findParamInParam(par->lhs(), currInfo); } // search another func call, possibly used in parameter for (SgExpression *par = pars; par != NULL; par = par->rhs()) findParamUsedInFuncCalls(pars->lhs(), currInfo, containsFunctions, prefix); } // Takes random expression, finds there func calls and check their parameters // for using parameters of func where first is called from static void findParamUsedInFuncCalls(SgExpression *exp, FuncInfo &currInfo, const vector& containsFunctions, const string& prefix) { if (exp) { if (exp->variant() == FUNC_CALL) { vector nameOfCallFunc; nameOfCallFunc.push_back(exp->symbol()->identifier()); nameOfCallFunc.push_back(OriginalSymbol(exp->symbol())->identifier()); for (auto& elem : nameOfCallFunc) correctNameIfContains(NULL, exp, elem, containsFunctions, prefix); if (!hasRecCall(&currInfo, nameOfCallFunc)) { // Add func call which we've just found currInfo.funcsCalledFromThis.push_back(NestedFuncCall(nameOfCallFunc[1])); // For every found func call iterate through pars //cout << "Through params of the call of " << exp->symbol()->identifier() << endl; throughParams(exp->lhs(), currInfo, containsFunctions, prefix); } } else { // If we've not found func call, search further in all branches findParamUsedInFuncCalls(exp->rhs(), currInfo, containsFunctions, prefix); findParamUsedInFuncCalls(exp->lhs(), currInfo, containsFunctions, prefix); } } } static void printParInfo(const map> &allFuncInfo) { cout << "*********Which parameters of current function are used in func calls inside it*********" << endl; for (auto &file1 : allFuncInfo) { for (auto &currInfo : file1.second) { cout << currInfo->funcName << " calls to:" << endl; for (auto &calledFunc : currInfo->funcsCalledFromThis) { cout << " " << calledFunc.CalledFuncName << " with params:" << endl; int parNo = 0; for (auto ¶mOfCalled : calledFunc.NoOfParamUsedForCall) { cout << " " << parNo << ": "; for (auto ¶mOfCalling : paramOfCalled) cout << currInfo->funcParams.identificators[paramOfCalling] << " "; parNo++; cout << endl; } } } } cout << endl; cout << "*********Which parameters of current function are used as indices for arrays*********" << endl; for (auto &file1 : allFuncInfo) { for (auto &currInfo : file1.second) { cout << currInfo->funcName << endl; for (size_t i = 0; i < currInfo->isParamUsedAsIndex.size(); i++) { cout << currInfo->funcParams.identificators[i] << ": "; if (currInfo->isParamUsedAsIndex[i]) cout << "used" << endl; else cout << "not used" << endl; } } } cout << endl; } void findContainsFunctions(SgStatement *st, vector &found, const bool searchAll) { SgStatement *end = st->lastNodeOfStmt(); bool containsStarted = false; for (; st != end; st = st->lexNext()) { if (containsStarted) { if (st->variant() == PROC_HEDR || st->variant() == FUNC_HEDR) { found.push_back(st); st = searchAll? st : st->lastNodeOfStmt(); } else if (!searchAll && st->variant() == CONTAINS_STMT) break; } if (st->variant() == CONTAINS_STMT) containsStarted = true; } } static void fillIn(FuncInfo *currF, SgExpression *ex, const map &parNames, bool isInFuncPar) { if (ex) { if (!isInFuncPar && (ex->variant() == VAR_REF || isArrayRef(ex))) { const char *name = ex->symbol()->identifier(); if (name && name != string("")) { auto it = parNames.find(name); if (it != parNames.end()) currF->funcParams.inout_types[it->second] |= IN_BIT; } } if (ex->variant() == FUNC_CALL) { SgFunctionCallExp* call = (SgFunctionCallExp*)ex; for (int z = 0; z < call->numberOfArgs(); ++z) fillIn(currF, call->arg(z), parNames, true); } else { fillIn(currF, ex->lhs(), parNames, false); fillIn(currF, ex->rhs(), parNames, false); } } } static void fillType(FuncInfo* currF, const string& symb, const map& parNames, const int type) { if (symb != "") { auto it = parNames.find(symb); if (it != parNames.end()) currF->funcParams.inout_types[it->second] |= type; } } static void checkSpecList(SgExpression* pair, FuncInfo* currF, const map& parNames, int) { auto valExp = isSgKeywordValExp(pair->lhs()); if (valExp->value() == string("unit")) if (pair->rhs() && pair->rhs()->symbol()) fillType(currF, pair->rhs()->symbol()->identifier(), parNames, INOUT_BIT); } static void checkSpecList(SgExpression *spec, FuncInfo* currF, const map& parNames) { if (spec->variant() == SPEC_PAIR) checkSpecList(spec, currF, parNames, 0); else { while (spec) { if (spec->lhs()->variant() == SPEC_PAIR) checkSpecList(spec->lhs(), currF, parNames, 0); spec = spec->rhs(); } } } static void fillInOut(FuncInfo *currF, SgStatement *start, SgStatement *last, const set& activeOps) { if (currF->funcParams.countOfPars == 0) return; static map> supportedKeyWordArg = { {"system_clock", { OUT_BIT, OUT_BIT, OUT_BIT } } }; map parNames; for (int i = 0; i < currF->funcParams.identificators.size(); ++i) parNames[currF->funcParams.identificators[i]] = i; for (auto st = start; st != last; st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; if (st->variant() == ENTRY_STAT) continue; if (isSgExecutableStatement(st) == NULL || st->lineNumber() <= 0) continue; if (activeOps.size() && activeOps.find(st) == activeOps.end()) continue; if (st->variant() == ASSIGN_STAT) { SgExpression *left = st->expr(0); fillIn(currF, left->lhs(), parNames, false); fillIn(currF, left->rhs(), parNames, false); fillIn(currF, st->expr(1), parNames, false); string symb = ""; if (left->symbol()) symb = left->symbol()->identifier(); else if (left->variant() == ARRAY_OP) { if (left->lhs()->symbol()) symb = left->lhs()->symbol()->identifier(); } fillType(currF, symb, parNames, OUT_BIT); } // TODO: need to extend else if (st->variant() == READ_STAT) { SgInputOutputStmt *read = isSgInputOutputStmt(st); if (read == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto ex = read->itemList(); ex; ex = ex->rhs()) { SgExpression* item = ex->lhs(); if (item->variant() == VAR_REF || isArrayRef(item)) { string symb = ""; if (item->symbol()) symb = item->symbol()->identifier(); fillType(currF, symb, parNames, OUT_BIT); } else if (item->variant() == IOACCESS) { SgExpression* list = item->lhs(); stack queue; queue.push(list); while (!queue.empty()) { auto item = queue.top(); queue.pop(); if (item->lhs()) queue.push(item->lhs()); if (item->rhs()) queue.push(item->rhs()); if (item->variant() == VAR_REF || isArrayRef(item)) { string symb = ""; if (item->symbol()) symb = item->symbol()->identifier(); fillType(currF, symb, parNames, OUT_BIT); } } } } checkSpecList(read->specList(), currF, parNames); } // TODO: need to extend else if (st->variant() == WRITE_STAT) { SgInputOutputStmt* write = isSgInputOutputStmt(st); if (write == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); checkSpecList(write->specList(), currF, parNames); } else if (!isDVM_stat(st)) { bool processed = false; //TODO: for FUNC_CALL if (st->variant() == PROC_STAT && isIntrinsicFunctionName(st->symbol()->identifier())) { const string name = st->symbol()->identifier(); if (supportedKeyWordArg.find(name) != supportedKeyWordArg.end()) { int z = 0; const vector& types = supportedKeyWordArg[name]; for (auto ex = st->expr(0); ex; ex = ex->rhs(), ++z) { SgExpression* arg = ex->lhs(); if (arg->variant() == KEYWORD_ARG) { arg = arg->rhs(); if (types.size() <= z) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (types[z] == OUT_BIT || types[z] == INOUT_BIT) fillType(currF, arg->symbol()->identifier(), parNames, OUT_BIT); if (types[z] == IN_BIT || types[z] == INOUT_BIT) fillIn(currF, arg, parNames, false); } else fillIn(currF, arg, parNames, false); } processed = true; } } if (!processed) { if (st->variant() == PROC_STAT) { SgCallStmt* call = (SgCallStmt*)st; for (int z = 0; z < call->numberOfArgs(); ++z) fillIn(currF, call->arg(z), parNames, true); } else { for (int i = 0; i < 3; ++i) fillIn(currF, st->expr(i), parNames, false); } } } } } //TODO: check common block and module use static void fillFunctionPureStatus(SgStatement *header, FuncInfo *currInfo, vector &messagesForFile, const set& activeOps) { if (!currInfo->isMain) { set lines; bool hasIntent = hasThisIds(header, lines, { INTENT_STMT }, &activeOps); bool declaratedAsPure = (header->symbol()->attributes() & PURE_BIT); if (declaratedAsPure && !hasIntent && ((SgProgHedrStmt*)header)->numberOfParameters()) { messagesForFile.push_back(Messages(ERROR, header->lineNumber(), R143, L"Wrong pure declaration - INTENT mismatch", 4002)); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } if (currInfo->commonBlocks.size() == 0) { lines.clear(); bool has = hasThisIds(header, lines, { DATA_DECL, SAVE_DECL, USE_STMT, WRITE_STAT, READ_STAT, OPEN_STAT, CLOSE_STAT, PRINT_STAT, STOP_STAT, PAUSE_NODE }, &activeOps); if (!has || declaratedAsPure) currInfo->isPure = true; else { for (auto &line : lines) messagesForFile.push_back(Messages(WARR, line, R93, L"Function is impure due to this operator usage", 1049)); } } else if (declaratedAsPure) currInfo->isPure = true; } else currInfo->isPure = true; } static void fillCommons(FuncInfo *currInfo, const map> &commonBlocks) { for (auto &item : commonBlocks) { auto inserted = currInfo->commonBlocks.insert(make_pair(item.first, set())); for (auto& list : item.second) { SgExpression* expr_list = list->lhs(); while (expr_list != NULL) { SgExpression* var = expr_list->lhs(); expr_list = expr_list->rhs(); inserted.first->second.insert(var->symbol()->identifier()); } } } } static void printActiveLines(const set& activeOps) { set lines; for (auto& st : activeOps) lines.insert(st->lineNumber()); for (auto& line : lines) printf("%d\n", line); } static FuncInfo* createNewFuction(const string& funcName, SgStatement *st, SgStatement* entry, vector& messagesForFile, const map>& commonBlocks, const set& activeOps) { SgStatement* lastNode = st->lastNodeOfStmt(); FuncInfo* currInfo = new FuncInfo(funcName, make_pair(entry->lineNumber(), lastNode->lineNumber()), new Statement(entry)); hasThisIds(st, currInfo->linesOfIO, { WRITE_STAT, READ_STAT, OPEN_STAT, CLOSE_STAT, PRINT_STAT }, &activeOps); hasThisIds(st, currInfo->linesOfStop, { STOP_STAT, PAUSE_NODE }, &activeOps); currInfo->isMain = (st->variant() == PROG_HEDR); fillCommons(currInfo, commonBlocks); fillFunctionPureStatus(st, currInfo, messagesForFile, activeOps); if (st->variant() != PROG_HEDR) { SgProgHedrStmt* procFuncHedr = ((SgProgHedrStmt*)st); if (st == entry) fillFuncParams(currInfo, commonBlocks, procFuncHedr); else fillFuncParams(currInfo, commonBlocks, entry); fillInOut(currInfo, st, lastNode, activeOps); } if (isSPF_NoInline(new Statement(st->lexNext()))) { __spf_print(1, "set NOINLINE attribute for function '%s'\n", funcName.c_str()); currInfo->doNotInline = true; } return currInfo; } static FuncInfo* analyzeFunction(const string& funcName, const string& containsPrefix, SgStatement *function, SgStatement* entry, map>& allFuncInfo, const map& mapLoopGraph, vector& messagesForFile, vector& containsFunctions, const set& activeOps) { SgStatement* st = function; SgStatement* lastNode = st->lastNodeOfStmt(); const string fileName = function->fileName(); auto it = allFuncInfo.find(fileName); if (it == allFuncInfo.end()) it = allFuncInfo.insert(it, make_pair(fileName, vector())); map> commonBlocks; getCommonBlocksRef(commonBlocks, function, lastNode); if (function->controlParent()->variant() == GLOBAL) containsFunctions.clear(); findContainsFunctions(function, containsFunctions); auto procInfo = createNewFuction(funcName, function, entry, messagesForFile, commonBlocks, activeOps); it->second.push_back(procInfo); vector macroStats; set macroNames; while (st != lastNode) { if (st->variant() == CONTAINS_STMT) break; if (st->variant() == INTERFACE_STMT) { st = st->lexNext(); while (st && !(st->controlParent()->variant() == INTERFACE_STMT && st->variant() == CONTROL_END)) { if (st->variant() == PROC_HEDR || st->variant() == FUNC_HEDR) { procInfo->interfaceBlocks[st->symbol()->identifier()] = NULL; st = st->lastNodeOfStmt(); } st = st->lexNext(); } } if (st == NULL) { __spf_print(1, "internal error in analysis, parallel directives will not be generated for this file!\n"); break; } if (!isSgExecutableStatement(st)) { if (st->variant() == STMTFN_STAT) { macroStats.push_back(st); macroNames.insert(st->expr(0)->symbol()->identifier()); } } else break; st = st->lexNext(); } st = function; const string file = st->fileName(); 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->variant() == ENTRY_STAT) { st = st->lexNext(); continue; } if (activeOps.size()) { if (st->fileName() == file && isSgExecutableStatement(st) && activeOps.find(st) == activeOps.end()) { st = st->lexNext(); continue; } } // check for external calls if (st->variant() == EXTERN_STAT) for (SgExpression* ex = st->expr(0); ex; ex = ex->rhs()) if (ex->lhs()->symbol()) procInfo->externalCalls.insert(ex->lhs()->symbol()->identifier()); const string prefix = containsPrefix == "" ? string(function->symbol()->identifier()) + "." : containsPrefix; //printf("var %d, line %d, file %s\n", st->variant(), st->lineNumber(), st->fileName()); if (st->variant() == PROC_STAT) { vector pureNameOfCallFunc; pureNameOfCallFunc.push_back(removeString("call ", st->symbol()->identifier())); pureNameOfCallFunc.push_back(removeString("call ", OriginalSymbol(st->symbol())->identifier())); for (auto& elem : pureNameOfCallFunc) correctNameIfContains(st, NULL, elem, containsFunctions, prefix); if (hasRecCall(procInfo, pureNameOfCallFunc)) continue; procInfo->callsFrom.insert(pureNameOfCallFunc.begin(), pureNameOfCallFunc.end()); FuncInfoCallFrom newCall; newCall.detailCallsFrom = make_pair(pureNameOfCallFunc[1], st->lineNumber()); // original name of call newCall.pointerDetailCallsFrom = make_pair(st, PROC_STAT); newCall.parentForPointer = st; newCall.actualParams = FuncParam(); processActualParams(st->expr(0), commonBlocks, newCall.actualParams, procInfo->externalCalls); procInfo->callsFromDetailed.push_back(newCall); // Add func call which we've just found NestedFuncCall funcCall(pureNameOfCallFunc[1]); procInfo->funcsCalledFromThis.push_back(funcCall); // search for using pars of cur func in pars of called throughParams(st->expr(0), *procInfo, containsFunctions, prefix); //find external calls for (SgExpression* par = st->expr(0); par != NULL; par = par->rhs()) { SgExpression* curr = par->lhs(); if (curr) { if (curr->variant() == VAR_REF) { auto s = curr->symbol(); if (procInfo->externalCalls.find(s->identifier()) != procInfo->externalCalls.end() || (s->attributes() & EXTERNAL_BIT)) { vector nameOfCallFunc; nameOfCallFunc.push_back(s->identifier()); nameOfCallFunc.push_back(OriginalSymbol(s)->identifier()); for (auto& elem : nameOfCallFunc) correctNameIfContains(NULL, curr, elem, containsFunctions, prefix); procInfo->callsFrom.insert(nameOfCallFunc.begin(), nameOfCallFunc.end()); FuncInfoCallFrom newCall; newCall.detailCallsFrom = make_pair(nameOfCallFunc[1], st->lineNumber()); // original name of call newCall.pointerDetailCallsFrom = make_pair(curr, VAR_REF); newCall.parentForPointer = st; newCall.actualParams = FuncParam(); procInfo->callsFromDetailed.push_back(newCall); } } } } } else { for (int i = 0; i < 3; ++i) if (st->expr(i)) findParamUsedInFuncCalls(st->expr(i), *procInfo, containsFunctions, prefix); } for (int i = 0; i < 3; ++i) if (st->expr(i)) findFuncCalls(st, st->expr(i), procInfo, st->lineNumber(), commonBlocks, macroNames, containsFunctions, prefix); if (isSgExecutableStatement(st)) { if (procInfo->isParamUsedAsIndex.size()) for (int i = 0; i < 3; i++) findArrayRef(st->expr(i), *procInfo, st->variant() == ASSIGN_STAT && i == 0); if (st->variant() == FOR_NODE) { auto itL = mapLoopGraph.find(st->lineNumber()); if (itL != mapLoopGraph.end()) procInfo->loopsInFunc.push_back(itL->second); } } st = st->lexNext(); } return procInfo; } static set fillActiveOperators(SgStatement* func, const vector& blocks) { if (blocks.size() == 0) return set(); set active; set activeBlocks; activeBlocks.insert(blocks[0]); bool added = true; while (added) { added = false; for (auto& block : activeBlocks) { for (auto& next : block->getNext()) { if (activeBlocks.find(next) == activeBlocks.end()) { activeBlocks.insert(next); added = true; } } } } for (auto& block : activeBlocks) { for (auto& instr : block->getInstructions()) { auto op = instr->getInstruction()->getOperator(); if (op) active.insert(op); } } //complete blocked statements for (auto st = func->lexNext(); st != func->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; if (st->variant() == SWITCH_NODE) { auto select = isSgSwitchStmt(st); int numOfCases = select->numberOfCaseOptions(); for (int z = 0; z < numOfCases; ++z) { auto caseOp = isSgCaseOptionStmt(select->caseOption(z)); if (active.count(caseOp)) { active.insert(st); break; } } } } return active; } //if fullIR not empty -> call this function from CALL_GRAPH2 void functionAnalyzer(SgFile *file, map> &allFuncInfo, const vector &loops, vector &messagesForFile, map> &fullIR) { map mapLoopGraph; createMapLoopGraph(loops, mapLoopGraph); map tmpInfoInIR; for (auto& elem : fullIR) { SgStatement* func = elem.first->funcPointer->GetOriginal(); if (tmpInfoInIR.count(func) != 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); tmpInfoInIR[func] = elem.first; } int funcNum = file->numberOfFunctions(); __spf_print(DEBUG, "functions num in file = %d\n", funcNum); vector containsFunctions; vector functions; for (int i = 0; i < funcNum; ++i) { auto func = file->functions(i); functions.push_back(func); //find entry points for (auto st = func->lexNext(); st != func->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() == ENTRY_STAT) functions.push_back(st); } } FuncInfo* lastNonEntry = NULL; for (auto& function : functions) { bool isEntry = (function->variant() == ENTRY_STAT); const int line = function->lineNumber(); const char* file = function->fileName(); string containsPrefix = ""; SgStatement* st_cp = isEntry ? function->controlParent()->controlParent() : function->controlParent(); if (st_cp->variant() == PROC_HEDR || st_cp->variant() == PROG_HEDR || st_cp->variant() == FUNC_HEDR) containsPrefix = st_cp->symbol()->identifier() + string("."); else if (st_cp->variant() == INTERFACE_STMT) continue; string funcName = ""; if (function->variant() == PROG_HEDR) { SgProgHedrStmt* progH = (SgProgHedrStmt*)function; funcName = progH->nameWithContains(); __spf_print(DEBUG, "*** Program <%s> started at line %d / %s\n", progH->symbol()->identifier(), line, file); } else if (function->variant() == PROC_HEDR) { SgProcHedrStmt* procH = (SgProcHedrStmt*)function; funcName = procH->nameWithContains(); __spf_print(DEBUG, "*** Function <%s> started at line %d / %s\n", procH->symbol()->identifier(), line, file); } else if (function->variant() == FUNC_HEDR) { SgFuncHedrStmt* funcH = (SgFuncHedrStmt*)function; funcName = funcH->nameWithContains(); __spf_print(DEBUG, "*** Function <%s> started at line %d / %s\n", funcH->symbol()->identifier(), line, file); } else if (function->variant() == ENTRY_STAT) { funcName = function->symbol()->identifier(); __spf_print(DEBUG, "*** Entry function <%s> started at line %d / %s\n", funcName.c_str(), line, file); } else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); set activeOps; if (fullIR.size()) { if (tmpInfoInIR.count(function) == 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); activeOps = fillActiveOperators((isEntry ? function->controlParent() : function), fullIR[tmpInfoInIR[function]]); activeOps.insert(function); if (isEntry) activeOps.insert(function->controlParent()); } auto procInfo = analyzeFunction(funcName, containsPrefix, isEntry ? function->controlParent() : function, function, allFuncInfo, mapLoopGraph, messagesForFile, containsFunctions, activeOps); if (isEntry) { if (!lastNonEntry) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); lastNonEntry->entry.push_back(procInfo); } else lastNonEntry = procInfo; } //fill INTERFACE block from modules vector modules; findModulesInFile(file, modules); for (auto& mod : modules) { if (mod->fileName() != string(file->filename())) continue; const string moduleName = mod->symbol()->identifier(); for (auto st = mod->lexNext(); st != mod->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; if (isSgExecutableStatement(st)) break; if (st->variant() == INTERFACE_STMT) { if (needToReplaceInterfaceName(st)) { const string fileName = st->fileName(); auto it = allFuncInfo.find(fileName); if (it == allFuncInfo.end()) it = allFuncInfo.insert(it, make_pair(fileName, vector())); string currF = st->symbol()->identifier(); if (currF.find("::") == string::npos) currF = moduleName + "::" + currF; FuncInfo* funcInterface = new FuncInfo(currF, make_pair(st->lineNumber(), st->lastNodeOfStmt()->lineNumber()), new Statement(st)); funcInterface->isInterface = true; for (auto st_l = st->lexNext(); st_l != st->lastNodeOfStmt(); st_l = st_l->lexNext()) if (st_l->variant() == MODULE_PROC_STMT) { auto list = st_l->expr(0); for (auto ex = list; ex; ex = ex->rhs()) funcInterface->interfaceSynonims[moduleName + "::" + ex->lhs()->symbol()->identifier()] = NULL; } st = st->lastNodeOfStmt(); it->second.push_back(funcInterface); } } } } auto it = allFuncInfo.find(file->filename()); if (it == allFuncInfo.end()) return; if (fullIR.size() == 0) return; vector toRemove; for (auto& func : it->second) { SgStatement* pointer = func->funcPointer->GetOriginal(); if (tmpInfoInIR.find(pointer) != tmpInfoInIR.end()) { auto key = tmpInfoInIR[pointer]; toRemove.push_back(key); fullIR[func] = fullIR[key]; fullIR.erase(key); } } for (auto& func : toRemove) delete func; } static bool findLoopVarInParameter(SgExpression *ex, const string &loopSymb) { bool retVal = false; if (ex) { if (ex->variant() == VAR_REF) { const string ident(ex->symbol()->identifier()); if (ident == loopSymb) retVal = true; } } return retVal; } static int countList(SgExpression *list) { int num = 0; while (list) { num++; list = list->rhs(); } return num; } static bool matchCallAndDefinition(const FuncParam &funcParDef, const FuncParam& funcParCall, const string &funcName, const string &file, const int line, map> &messages) { bool result = true; auto typesDef = funcParDef.parametersT; auto typesCall = funcParCall.parametersT; if (typesDef.size() != typesCall.size()) { wstring bufR, bufE; __spf_printToLongBuf(bufE, L"Function '%s': count of call parameters are not enouth", to_wstring(funcName).c_str()); __spf_printToLongBuf(bufR, R38, to_wstring(funcName).c_str()); //if (needToAddErrors) { messages[file].push_back(Messages(ERROR, line, bufR, bufE, 1013)); __spf_print(1, "Function '%s': count of call parameters are not enouth\n", funcName.c_str()); } result = false; } else { for (int i = 0; i < typesDef.size(); ++i) { if (typesCall[i] != ARRAY_T) { if (typesCall[i] != typesDef[i]) { wstring bufR, bufE; __spf_printToLongBuf(bufE, L"Different type of call (%s : %s) and def (%s : %s) parameter %d for function '%s'", to_wstring(funcParCall.identificators[i]).c_str(), to_wstring(paramNames[typesCall[i]]).c_str(), to_wstring(funcParDef.identificators[i]).c_str(), to_wstring(paramNames[typesDef[i]]).c_str(), i + 1, to_wstring(funcName).c_str()); __spf_printToLongBuf(bufR, R39, to_wstring(funcParCall.identificators[i]).c_str(), to_wstring(paramNames[typesCall[i]]).c_str(), to_wstring(funcParDef.identificators[i]).c_str(), to_wstring(paramNames[typesDef[i]]).c_str(), i + 1, to_wstring(funcName).c_str()); //if (needToAddErrors) { messages[file].push_back(Messages(NOTE, line, bufR, bufE, 1013)); __spf_print(1, "Function '%s': different type of call and def parameter %d\n", funcName.c_str(), i + 1); } //result = false; } } else //TODO { /*if (callArrayRef->numberOfSubscripts() > 0) { wstring bufR, bufE; __spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined, only full array passing was supported", to_wstring(def->funcName).c_str()); __spf_printToLongBuf(bufR, R40, to_wstring(def->funcName).c_str()); //if (needToAddErrors) { messages[file].push_back(Messages(ERROR, line, bufR, bufE, 1013)); __spf_print(1, "Function '%s' needs to be inlined, only full array passing was supported\n", def->funcName.c_str()); } result = false; }*/ } } } return result; } static bool matchCallAndDefinition(SgProject* proj, const map& files, map>& messages, bool needToAddErrors, const map &funcByName) { int count = 0; for (auto& func : funcByName) { FuncInfo* currF = func.second; for (auto& callsTo : currF->callsTo) { for (int cf = 0; cf < callsTo->callsFromDetailed.size(); ++cf) { if (callsTo->callsFromDetailed[cf].detailCallsFrom.first == currF->funcName) { auto callInfo = callsTo->callsFromDetailed[cf].pointerDetailCallsFrom; if (callInfo.second == VAR_REF) // external call through proc parameter continue; auto itF = files.find(callsTo->fileName); if (itF == files.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); bool localR = matchCallAndDefinition(currF->funcParams, callsTo->callsFromDetailed[cf].actualParams, currF->funcName, callsTo->fileName, callsTo->callsFromDetailed[cf].detailCallsFrom.second, messages); if (!localR) count++; } } } } return count > 0; } bool isPassFullArray(SgExpression *ex) { if (ex->lhs() == NULL && ex->rhs() == NULL) return true; else return false; } static bool hasCuttingDims(SgExpression *ex) { if (ex->lhs()) { if (ex->lhs()->variant() == EXPR_LIST) { SgExpression *list = ex->lhs(); for (auto list = ex->lhs(); list; list = list->rhs()) { if (list->lhs() && list->lhs()->variant() == DDOT) return true; } } } return false; } static bool checkDimSizesBetweenParams(bool type2, const FuncInfo* func, int parNum, SgStatement* decl, SgSymbol* symb, vector& messages, const int& statLine) { bool ret = false; if (type2) { DIST::Array* inFunction = (DIST::Array*)func->funcParams.parameters[parNum]; DIST::Array* mainArray = getArrayFromDeclarated(decl, symb->identifier()); if (mainArray == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (mainArray->GetDimSize() != inFunction->GetDimSize() && !(inFunction->IsNotDistribute() && !mainArray->IsNotDistribute())) { wstring bufE, bufR; __spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined due to different dimension sizes in formal (size = %d) and actual(size = %d) parameters for array reference '%s'", to_wstring(func->funcName).c_str(), inFunction->GetDimSize(), mainArray->GetDimSize(), to_wstring(symb->identifier()).c_str()); __spf_printToLongBuf(bufR, R43, to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), inFunction->GetDimSize(), mainArray->GetDimSize()); messages.push_back(Messages(ERROR, statLine, bufR, bufE, 1013)); __spf_print(1, "Function '%s' needs to be inlined due to different dimension sizes in formal (size = %d) and actual(size = %d) parameters for array reference '%s'\n", func->funcName.c_str(), inFunction->GetDimSize(), mainArray->GetDimSize(), symb->identifier()); ret = true; } } else { wstring bufE, bufR; __spf_printToLongBuf(bufE, L"Type mismatch in function '%s' in formal and actual parameters for array reference '%s'\n", to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str()); __spf_printToLongBuf(bufR, R44, to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str()); messages.push_back(Messages(ERROR, statLine, bufR, bufE, 1013)); __spf_print(1, "Type mismatch in function '%s' in formal and actual parameters for array reference '%s'\n", func->funcName.c_str(), symb->identifier()); ret = true; } return ret; } static bool checkParameter(SgExpression *ex, vector &messages, const int statLine, SgForStmt *loop, bool needToAddErrors, const FuncInfo *func, int parNum, const map> &arrayLinksByFuncCalls) { bool ret = false; if (ex) { if (isArrayRef(ex)) { SgArrayRefExp *arrayRef = isSgArrayRefExp(ex); SgType *type = ex->symbol()->type(); if (arrayRef && type && type->variant() != T_STRING) { SgSymbol *symb = OriginalSymbol(arrayRef->symbol()); if (symb) { SgStatement *decl = declaratedInStmt(symb); set privatesVars; tryToFindPrivateInAttributes(decl, privatesVars); fillNonDistrArraysAsPrivate(decl, declaredArrays, declaratedArraysSt, privatesVars); if (privatesVars.find(symb->identifier()) == privatesVars.end()) { bool type1 = (func->funcParams.inout_types[parNum] & OUT_BIT) != 0; bool type2 = func->funcParams.parametersT[parNum] == ARRAY_T; string add = ""; wstring addW = L""; if (type1) { add += "(as out argument"; addW += wstring(L"(") + RR42_1; } if (type2) { if (type1) { add += ", as array in function)"; addW += L"," + wstring(RR42_2) + L")"; } else { add += "(as array in function)"; addW += L"(" + wstring(RR42_2) + L")"; } } else add += ")"; if (!isPassFullArray(ex)) { bool _hasCuttingDims = hasCuttingDims(ex); if (_hasCuttingDims) { if (needToAddErrors) { if (loop) { wstring bufE, bufR; __spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined due to non private array reference '%s' under loop on line %d %s", to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), loop->lineNumber(), to_wstring(add).c_str()); __spf_printToLongBuf(bufR, R41, to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), loop->lineNumber(), addW.c_str()); messages.push_back(Messages(ERROR, statLine, bufR, bufE, 1013)); __spf_print(1, "Function '%s' needs to be inlined due to non private array reference '%s' under loop on line %d %s\n", func->funcName.c_str(), symb->identifier(), loop->lineNumber(), add.c_str()); } else { wstring bufE, bufR; __spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined due to non private array reference '%s' %s", to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), to_wstring(add).c_str()); __spf_printToLongBuf(bufR, R42, to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), addW.c_str()); messages.push_back(Messages(ERROR, statLine, bufR, bufE, 1013)); __spf_print(1, "Function '%s' needs to be inlined due to non private array reference '%s' %s\n", func->funcName.c_str(), symb->identifier(), add.c_str()); } } ret = true; } else { //deprecate N first dims to distribute if (type2) { ret = checkDimSizesBetweenParams(type2, func, parNum, decl, symb, messages, statLine); if (!ret) { DIST::Array *inFunction = (DIST::Array*)func->funcParams.parameters[parNum]; DIST::Array *mainArray = getArrayFromDeclarated(decl, symb->identifier()); if (mainArray == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); set realArrayRefs; getRealArrayRefs(mainArray, mainArray, realArrayRefs, arrayLinksByFuncCalls); const int toDepDims = inFunction->GetDimSize(); for (auto &array : realArrayRefs) for (int z = 0; z < toDepDims; ++z) array->DeprecateDimension(z); for (int z = 0; z < toDepDims; ++z) mainArray->DeprecateDimension(z); inFunction->DeprecateAllDims(); inFunction->SetDistributeFlag(DIST::NO_DISTR); wstring bufE, bufR; if (inFunction->GetDimSize() == 1) __spf_printToLongBuf(bufE, L"First dimension of array '%s' were deprecated to distributon due to function call '%s'", to_wstring(symb->identifier()).c_str(), to_wstring(func->funcName).c_str()); else __spf_printToLongBuf(bufE, L"First %d dimensions of array '%s' were deprecated to distributon due to function call '%s'", inFunction->GetDimSize(), to_wstring(symb->identifier()).c_str(), to_wstring(func->funcName).c_str()); if (inFunction->GetDimSize() == 1) __spf_printToLongBuf(bufR, R73, to_wstring(symb->identifier()).c_str(), to_wstring(func->funcName).c_str()); else __spf_printToLongBuf(bufR, R72, inFunction->GetDimSize(), to_wstring(symb->identifier()).c_str(), to_wstring(func->funcName).c_str()); messages.push_back(Messages(NOTE, statLine, bufR, bufE, 1040)); } } } } else // check dim sizes between formal and actual parameters ret = checkDimSizesBetweenParams(type2, func, parNum, decl, symb, messages, statLine); } } } } if (ex->lhs()) { bool res = checkParameter(ex->lhs(), messages, statLine, loop, needToAddErrors, func, parNum, arrayLinksByFuncCalls); ret |= res; } if (ex->rhs()) { bool res = checkParameter(ex->rhs(), messages, statLine, loop, needToAddErrors, func, parNum, arrayLinksByFuncCalls); ret |= res; } } return ret; } static bool checkParameter(SgExpression *parList, vector &messages, bool needToAddErrors, const FuncInfo *func, const int funcOnLine, SgForStmt *loop, const map> &arrayLinksByFuncCalls) { int parNum = 0; bool needInsert = false; while (parList) { bool res = checkParameter(parList->lhs(), messages, funcOnLine, loop, needToAddErrors, func, parNum, arrayLinksByFuncCalls); needInsert |= res; ++parNum; parList = parList->rhs(); } return needInsert; } static vector findNoOfParWithLoopVar(SgExpression *pars, const string &loopSymb) { vector parsWithLoopSymb; int parNo = 0; for (SgExpression *par = pars; par != NULL; par = par->rhs(), parNo++) { if (findLoopVarInParameter(par->lhs(), loopSymb)) parsWithLoopSymb.push_back(parNo); } return parsWithLoopSymb; } static bool processParameterList(SgExpression *parList, SgForStmt *loop, const FuncInfo *func, const int funcOnLine, bool needToAddErrors, vector &messages, const map> &arrayLinksByFuncCalls) { bool needInsert = false; bool hasLoopVar = false; if (loop) hasLoopVar = findLoopVarInParameter(parList, loop->symbol()->identifier()); if (hasLoopVar) { const vector parsWithLoopSymb = findNoOfParWithLoopVar(parList, loop->symbol()->identifier()); int idx = -1; for (auto &par : parsWithLoopSymb) { if (func->isParamUsedAsIndex[par]) { idx = par + 1; break; } } if (idx != -1) { wstring bufE, bufR; __spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined due to use of loop's symbol on line %d as index of an array inside this call, in parameter num %d", to_wstring(func->funcName).c_str(), loop->lineNumber(), idx); __spf_printToLongBuf(bufR, R45, to_wstring(func->funcName).c_str(), idx, loop->lineNumber()); if (needToAddErrors) { messages.push_back(Messages(ERROR, funcOnLine, bufR, bufE, 1013)); __spf_print(1, "Function '%s' needs to be inlined due to use of loop's symbol on line %d as index of an array inside this call, in parameter num %d\n", func->funcName.c_str(), loop->lineNumber(), idx); } needInsert = true; } else needInsert = checkParameter(parList, messages, needToAddErrors, func, funcOnLine, loop, arrayLinksByFuncCalls); } else needInsert = checkParameter(parList, messages, needToAddErrors, func, funcOnLine, loop, arrayLinksByFuncCalls); return needInsert; } static bool findFuncCall(SgExpression *ex, const FuncInfo *func, vector &messages, const int statLine, SgForStmt *loop, bool needToAddErrors, const map &funcByName, const map> &arrayLinksByFuncCalls, bool processAll = false, set *funcChecked = NULL, set *needToInsert = NULL) { bool ret = false; if (ex) { if (ex->variant() == FUNC_CALL) { if (processAll) { if (funcChecked && needToInsert) { const string fName = ex->symbol()->identifier(); if (funcChecked->find(fName) == funcChecked->end()) { funcChecked->insert(fName); auto itF = funcByName.find(fName); if (itF != funcByName.end()) { ret = processParameterList(ex->lhs(), loop, itF->second, statLine, needToAddErrors, messages, arrayLinksByFuncCalls); if (ret) needToInsert->insert(fName); } } } else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } else { if (ex->symbol()->identifier() == func->funcName) { bool res = processParameterList(ex->lhs(), loop, func, statLine, needToAddErrors, messages, arrayLinksByFuncCalls); ret |= res; } } } bool resL = findFuncCall(ex->lhs(), func, messages, statLine, loop, needToAddErrors, funcByName, arrayLinksByFuncCalls, processAll, funcChecked, needToInsert); bool resR = findFuncCall(ex->rhs(), func, messages, statLine, loop, needToAddErrors, funcByName, arrayLinksByFuncCalls, processAll, funcChecked, needToInsert); ret |= resL || resR; } return ret; } static SgStatement* getStatByLine(string file, const int line, const map> &statByLine) { auto itF = statByLine.find(file); if (itF == statByLine.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto itS = itF->second.find(line); if (itS == itF->second.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SwitchFile(itS->second->getFileId()); return itS->second; } static void findInsertedFuncLoopGraph(const vector &childs, set &needToInsert, SgFile *currF, vector &messages, bool needToAddErrors, const map &funcByName, const map> &statByLine, const map> &arrayLinksByFuncCalls, set &funcChecked) { for (int k = 0; k < (int)childs.size(); ++k) { auto stat = getStatByLine(currF->filename(), childs[k]->lineNum, statByLine); if (stat == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgForStmt *loop = isSgForStmt(stat); if (loop == NULL && stat->variant() != WHILE_NODE) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (loop && loop->lineNumber() != childs[k]->lineNum) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); // TODO: find loop variable in common block or module //dont check loop outside of parallel region and DO_WHILE if (childs[k]->region && loop) { for (int i = 0; i < (int)childs[k]->calls.size(); ++i) { //dont check call with !$SPF NOINLINE bool needToCheck = true; const string &funcName = childs[k]->calls[i].first; funcChecked.insert(funcName); auto it = funcByName.find(funcName); if (it != funcByName.end()) needToCheck = !(it->second->doNotInline == true); else // function not found needToCheck = false; if (!needToCheck) continue; int funcOnLine = childs[k]->calls[i].second; SgStatement *func = getStatByLine(currF->filename(), funcOnLine, statByLine); bool needInsert = false; const int var = func->variant(); if (var == PROC_STAT) { bool res = processParameterList(func->expr(0), loop, it->second, funcOnLine, needToAddErrors, messages, arrayLinksByFuncCalls); needInsert |= res; } else for (int z = 0; z < 3; ++z) { bool res = findFuncCall(func->expr(z), it->second, messages, funcOnLine, loop, needToAddErrors, funcByName, arrayLinksByFuncCalls); needInsert |= res; } if (needInsert) needToInsert.insert(childs[k]->calls[i].first); } } findInsertedFuncLoopGraph(childs[k]->children, needToInsert, currF, messages, needToAddErrors, funcByName, statByLine, arrayLinksByFuncCalls, funcChecked); } } static bool runCheckOutOfLoop(SgExpression *parList, const FuncInfo *func, const int lineFromCall, bool needToAddErrors, vector &messages, const map> &arrayLinksByFuncCalls) { bool needInsert = processParameterList(parList, NULL, func, lineFromCall, needToAddErrors, messages, arrayLinksByFuncCalls); return needInsert; } static void findInsertedFuncLoopGraph(const map> &loopGraph, set &needToInsert, SgProject *proj, const map &files, map> &allMessages, bool needToAddErrors, const map &funcByName, const map> &statByLine, const map> &arrayLinksByFuncCalls, const vector ®ions) { set funcChecked; for (auto &loop : loopGraph) { const int fileN = files.find(loop.first)->second; SgFile *currF = &(proj->file(fileN)); SwitchFile(fileN); auto itM = allMessages.find(loop.first); if (itM == allMessages.end()) itM = allMessages.insert(itM, make_pair(loop.first, vector())); findInsertedFuncLoopGraph(loop.second, needToInsert, currF, itM->second, needToAddErrors, funcByName, statByLine, arrayLinksByFuncCalls, funcChecked); } //not checked, out of loops for (int f = 0; f < proj->numberOfFiles(); ++f) { SgFile *currF = &(proj->file(f)); SwitchFile(f); auto itM = allMessages.find(currF->filename()); if (itM == allMessages.end()) itM = allMessages.insert(itM, make_pair(currF->filename(), vector())); for (int z = 0; z < currF->numberOfFunctions(); ++z) { SgStatement *funcInFile = currF->functions(z); for (SgStatement *st = funcInFile->lexNext(); st != funcInFile->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; if (st->lineNumber() == -1) continue; if (!__gcov_doesThisLineExecuted(st->fileName(), st->lineNumber())) continue; set allRegs = getAllRegionsByLine(regions, st->fileName(), st->lineNumber()); if (allRegs.size() == 0) continue; if (isSgExecutableStatement(st)) { if (st->variant() == PROC_STAT) { const string fName = st->symbol()->identifier(); auto it = funcChecked.find(fName); auto itF = funcByName.find(fName); if (it == funcChecked.end() && itF != funcByName.end()) { bool needInsert = runCheckOutOfLoop(st->expr(0), itF->second, st->lineNumber(), needToAddErrors, itM->second, arrayLinksByFuncCalls); if (needInsert) needToInsert.insert(fName); } } else for (int z = 0; z < 3; ++z) findFuncCall(st->expr(z), NULL, itM->second, st->lineNumber(), NULL, needToAddErrors, funcByName, arrayLinksByFuncCalls, true, &funcChecked, &needToInsert); } } } } } //TODO: 'needToAddErrors' is deprecated and always true int CheckFunctionsToInline(SgProject *proj, const map &files, const char *fileName, map> &funcByFile, const map> &loopGraph, map> &allMessages, bool needToAddErrors, const map> &arrayLinksByFuncCalls, const vector ®ions) { map> statByLine; //file -> map //build info for (int i = 0; i < proj->numberOfFiles(); ++i) { map toAdd; SgFile *file = &(proj->file(i)); SwitchFile(i); SgStatement *st = file->firstStatement(); string currF = file->filename(); while (st) { if (st->lineNumber() != 0 && st->fileName() == currF) toAdd[st->lineNumber()] = st; st = st->lexNext(); } statByLine[file->filename()] = toAdd; } map funcByName; for (auto& byFile : funcByFile) { for (int k = 0; k < byFile.second.size(); ++k) { string name = byFile.second[k]->funcName; auto itF = funcByName.find(name); if (itF == funcByName.end()) funcByName.insert(itF, make_pair(name, byFile.second[k])); else { __spf_print(1, "function with name '%s' was found in file '%s' on line %d, current position is file '%s' and line %d\n", name.c_str(), itF->second->fileName.c_str(), itF->second->linesNum.first, byFile.second[k]->fileName.c_str(), byFile.second[k]->linesNum.first); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } } } set needToInsert; findInsertedFuncLoopGraph(loopGraph, needToInsert, proj, files, allMessages, needToAddErrors, funcByName, statByLine, arrayLinksByFuncCalls, regions); bool err = matchCallAndDefinition(proj, files, allMessages, needToAddErrors, funcByName); if (err) return -1; if (needToInsert.size() > 0) { for (auto it = needToInsert.begin(); it != needToInsert.end(); ++it) { auto itF = funcByName.find(*it); if (itF != funcByName.end()) itF->second->needToInline = true; } } if (fileName) { FILE *out = fopen(fileName, "w"); if (out == NULL) { __spf_print(1, "can not open file %s\n", fileName); throw -1; } fprintf(out, "digraph G{\n"); auto it = funcByFile.begin(); set noInline; int fileNum = 0; while (it != funcByFile.end()) { fprintf(out, "subgraph cluster%d {\n", fileNum); const int dimSize = (int)it->second.size(); set uniqNames; for (int k = 0; k < dimSize; ++k) { const string currfunc = it->second[k]->funcName; if (it->second[k]->doNotInline) noInline.insert(currfunc); set::iterator it = uniqNames.find(currfunc); if (it == uniqNames.end()) { uniqNames.insert(it, currfunc); fprintf(out, "\"%s\"\n", currfunc.c_str()); } } fprintf(out, "label = \"file <%s>\"\n", removeString(".\\", it->first).c_str()); fprintf(out, "}\n"); fileNum++; it++; } it = funcByFile.begin(); while (it != funcByFile.end()) { const char *formatString = "\"%s\" -> \"%s\" [minlen=2.0];\n"; const int dimSize = (int)it->second.size(); for (int k = 0; k < dimSize; ++k) { const string callFrom = it->second[k]->funcName; set::const_iterator i = it->second[k]->callsFrom.begin(); for (; i != it->second[k]->callsFrom.end(); i++) fprintf(out, formatString, callFrom.c_str(), i->c_str()); } it++; } auto it_set = needToInsert.begin(); for (; it_set != needToInsert.end(); it_set++) { if (noInline.find(*it_set) == noInline.end()) fprintf(out, "\"%s\" [color=red]\n", it_set->c_str()); } fprintf(out, "overlap=false\n"); fprintf(out, "}\n"); fclose(out); } return needToInsert.size(); } static string printChainRec(const vector ¤tChainCalls) { string out = ""; for (int i = 0; i < currentChainCalls.size(); ++i) { out += currentChainCalls[i]->funcName; if (i != currentChainCalls.size() - 1) out += " -> "; } return out; } static bool hasRecursionChain(vector currentChainCalls, const FuncInfo *current, const map &allFuncinfo, vector &messagesForFile) { bool retVal = false; vector toCallNext; for (auto it = current->callsFrom.begin(); it != current->callsFrom.end(); ++it) { auto itF = allFuncinfo.find(*it); if (itF == allFuncinfo.end()) continue; if (std::find(currentChainCalls.begin(), currentChainCalls.end(), itF->second) != currentChainCalls.end()) { if (itF->second == currentChainCalls[0]) { retVal = true; currentChainCalls.push_back(itF->second); const string &chain = printChainRec(currentChainCalls); __spf_print(1, " For function on line %d found recursive chain calls: %s\n", currentChainCalls[0]->linesNum.first, chain.c_str()); wstring bufE, bufR; __spf_printToLongBuf(bufE, L" Found recursive chain calls: %s, this function will be ignored", to_wstring(chain).c_str()); __spf_printToLongBuf(bufR, R46, to_wstring(chain).c_str()); messagesForFile.push_back(Messages(NOTE, currentChainCalls[0]->linesNum.first, bufR, bufE, 1014)); break; } } else toCallNext.push_back(itF->second); } if (!retVal) { for (int i = 0; i < toCallNext.size() && !retVal; ++i) { currentChainCalls.push_back(toCallNext[i]); retVal = retVal || hasRecursionChain(currentChainCalls, toCallNext[i], allFuncinfo, messagesForFile); currentChainCalls.pop_back(); } } return retVal; } void checkForRecursion(SgFile *file, map> &allFuncInfo, vector &messagesForFile) { auto itCurrFuncs = allFuncInfo.find(file->filename()); if (itCurrFuncs == allFuncInfo.end()) return; map mapFuncInfo; createMapOfFunc(allFuncInfo, mapFuncInfo); for (int i = 0; i < itCurrFuncs->second.size(); ++i) { __spf_print(1, " run for func %s\n", itCurrFuncs->second[i]->funcName.c_str()); if (hasRecursionChain( { itCurrFuncs->second[i] }, itCurrFuncs->second[i], mapFuncInfo, messagesForFile)) itCurrFuncs->second[i]->doNotAnalyze = true; } } void propagateWritesToArrays(map> &allFuncInfo) { map funcByName; createMapOfFunc(allFuncInfo, funcByName); bool change = true; while (change) { change = false; for (auto &func : funcByName) { if (func.second->funcParams.countOfPars == 0) continue; for (int z = 0; z < func.second->funcParams.countOfPars; ++z) { if ((func.second->funcParams.inout_types[z] & OUT_BIT) == 0) continue; for (auto &callsTo : func.second->callsTo) { map parNames; for (int p = 0; p < callsTo->funcParams.countOfPars; ++p) parNames[callsTo->funcParams.identificators[p]] = p; bool ok = callsTo->funcPointer->GetOriginal()->switchToFile(); if (!ok) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto &callFromInfo : callsTo->callsFromDetailed) { auto& callFrom = callFromInfo.pointerDetailCallsFrom; if (callFrom.second == VAR_REF) // pass procedure through parameter continue; SgExpression *arg = NULL; if (callFrom.second == PROC_STAT) { SgCallStmt *call = (SgCallStmt*)callFrom.first; if (call->symbol()->identifier() != func.second->funcName) continue; if (z >= call->numberOfArgs()) continue; arg = call->arg(z); } else if (callFrom.second == FUNC_CALL) { SgFunctionCallExp *call = (SgFunctionCallExp*)callFrom.first; if (call->symbol()->identifier() != func.second->funcName) continue; if (z >= call->numberOfArgs()) continue; arg = call->arg(z); } if (arg == NULL) { if ((func.second->funcParams.inout_types[z] & OPTIONAL_BIT) != 0) continue; else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } string argName = ""; if (arg->symbol()) argName = arg->symbol()->identifier(); auto it = parNames.find(argName); if (it != parNames.end() && ((callsTo->funcParams.inout_types[it->second] & OUT_BIT) == 0)) { change = true; callsTo->funcParams.inout_types[it->second] |= OUT_BIT; if ((func.second->funcParams.inout_types[z] & IN_BIT) != 0) callsTo->funcParams.inout_types[it->second] |= IN_BIT; } } } } } } } //TODO: inmprove checker void detectCopies(map> &allFuncInfo) { map mapOfFunc; createMapOfFunc(allFuncInfo, mapOfFunc); for (auto& byFile : allFuncInfo) { for (auto& func : byFile.second) { string name = func->funcName; auto offset = name.rfind("_spf_"); if (offset != string::npos) { string orig = name.substr(0, offset); auto it = mapOfFunc.find(orig); if (it != mapOfFunc.end()) it->second->fullCopiesOfThisFunction.push_back(func); } } } } void fillInterfaceBlock(map>& allFuncInfo) { map mapOfFunc; createMapOfFunc(allFuncInfo, mapOfFunc); for (auto& byFile : allFuncInfo) { for (auto& func : byFile.second) { for (auto& interface : func->interfaceBlocks) { auto itF = mapOfFunc.find(interface.first); if (itF == mapOfFunc.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); set namesToFind = { interface.first }; for (auto& elem : itF->second->fullCopiesOfThisFunction) namesToFind.insert(elem->funcName); for (auto& elem : namesToFind) { auto isCalled = func->callsFrom.find(elem); if (isCalled != func->callsFrom.end()) { interface.second = itF->second; break; } } } //filted interfaces map copy = func->interfaceBlocks; func->interfaceBlocks.clear(); for (auto& interface : func->interfaceBlocks) if (interface.second) func->interfaceBlocks[interface.first] = interface.second; } } for (auto& byFile : allFuncInfo) { for (auto& func : byFile.second) { if (!func->isInterface) continue; if (func->interfaceSynonims.size() == 0) continue; for (auto& syn : func->interfaceSynonims) { auto itF = mapOfFunc.find(syn.first); if (itF == mapOfFunc.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); syn.second = itF->second; } } } } void removeDistrStateFromDeadFunctions(const map>& allFuncInfo, const map, pair>& declaredArrays) { map funcByName; createMapOfFunc(allFuncInfo, funcByName); // remove distr state of arrays from dead functions for (auto& elem : declaredArrays) { DIST::Array* array = elem.second.first; if (array->GetLocation().first == DIST::l_PARAMETER) { if (array->IsNotDistribute() == false) { auto declInfo = array->GetDeclInfo(); auto place = *declInfo.begin(); if (SgFile::switchToFile(place.first) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgStatement *st = SgStatement::getStatementByFileAndLine(place.first, place.second); checkNull(st, convertFileName(__FILE__).c_str(), __LINE__); SgProgHedrStmt *hedr = isSgProgHedrStmt(getFuncStat(st)); checkNull(hedr, convertFileName(__FILE__).c_str(), __LINE__); const string funcName = hedr->nameWithContains(); auto it = funcByName.find(funcName.c_str()); if (it == funcByName.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (it->second->deadFunction) array->SetDistributeFlag(DIST::NO_DISTR); } } } } int getLvlCall(FuncInfo* currF, int lvl, const string& func, const string& file, int line) { if (currF->funcName == func) return 0; for (auto& callsFromInfo : currF->callsFromDetailed) { auto& callsFrom = callsFromInfo.detailCallsFrom; if (callsFrom.first == func && callsFrom.second == line && currF->fileName == file) return lvl; } int whatLvl = -1; for (auto& callsFrom : currF->callsFromV) { int outLvl = getLvlCall(callsFrom, lvl + 1, func, file, line); if (outLvl != -1) { whatLvl = outLvl; break; } } return whatLvl; } void setInlineAttributeToCalls(const map& allFunctions, const map>>& inDataChains, const map>& hiddenData) { set> pointsForShadowCopies; for (auto& elem : allFunctions) { auto itNeed = inDataChains.find(elem.first); const FuncInfo* curr = elem.second; set> needToInline; if (itNeed != inDataChains.end()) needToInline = itNeed->second; for (int k = 0; k < curr->callsFromDetailed.size(); ++k) { if (needToInline.find(curr->callsFromDetailed[k].detailCallsFrom) == needToInline.end() && !isIntrinsicFunctionName(curr->callsFromDetailed[k].detailCallsFrom.first.c_str())) { pair detail = curr->callsFromDetailed[k].pointerDetailCallsFrom; if (SgFile::switchToFile(curr->fileName) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (detail.second == PROC_STAT) ((SgStatement*)detail.first)->addAttribute(BOOL_VAL); else if (detail.second == FUNC_CALL) { //TODO: many functions in same statement SgStatement* callSt = SgStatement::getStatementByFileAndLine(curr->fileName, curr->callsFromDetailed[k].detailCallsFrom.second); if (!callSt) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //((SgExpression*)detail.first)->addAttribute(BOOL_VAL); callSt->addAttribute(BOOL_VAL); } else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); pointsForShadowCopies.insert(make_pair(curr->fileName, curr->callsFromDetailed[k].detailCallsFrom.second)); __spf_print(1, " added attribute to '%s' <%s, %d>\n", curr->callsFromDetailed[k].detailCallsFrom.first.c_str(), curr->fileName.c_str(), curr->callsFromDetailed[k].detailCallsFrom.second); } } } if (pointsForShadowCopies.size()) { for (auto& byFile : hiddenData) { if (SgFile::switchToFile(byFile.first) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto& stF : byFile.second) for (auto st = stF; st != stF->lastNodeOfStmt(); st = st->lexNext()) if (pointsForShadowCopies.find(make_pair(st->fileName(), st->lineNumber())) != pointsForShadowCopies.end()) { st->addAttribute(BOOL_VAL); //__spf_print(1, " added attribute to shadow copy in file '%s' <%s %d>\n", byFile.first.c_str(), st->fileName(), st->lineNumber()); } } } } static json convertToJson(const FuncInfo* currFunc) { json func; if (currFunc) { func["funcName"] = currFunc->funcName; func["line"] = currFunc->linesNum.first; func["lineEnd"] = currFunc->linesNum.second; func["isMain"] = (int)currFunc->isMain; func["needToInline"] = (int)currFunc->needToInline; func["doNotInline"] = (int)currFunc->doNotInline; func["doNotAnalyze"] = (int)currFunc->doNotAnalyze; json func_pars = json::array(); for (int z = 0; z < currFunc->funcParams.countOfPars; ++z) { json par; par["inoutType"] = currFunc->funcParams.inout_types[z]; par["identificator"] = currFunc->funcParams.identificators[z]; par["parameterT"] = string(paramNames[currFunc->funcParams.parametersT[z]]); func_pars.push_back(par); } func["params"] = func_pars; json calls_from = json::array(); for (const auto& call_from : currFunc->callsFromDetailed) { json call; call["line"] = call_from.detailCallsFrom.second; call["funcName"] = call_from.detailCallsFrom.first; calls_from.push_back(call); } func["callsFrom"] = calls_from; } return func; } json convertToJson(const map>& funcsByFileMap) { json loopsByFile = json::array(); for (auto& byFile : funcsByFileMap) { json func; const string& file = byFile.first; json func_array = json::array(); for (auto& func : byFile.second) { auto conv = convertToJson(func); if (!conv.empty()) func_array.push_back(conv); } func["file"] = file; func["functions"] = func_array; loopsByFile.push_back(func); } json allFuncs; allFuncs["allFunctions"] = loopsByFile; return allFuncs; } #undef DEBUG