#include "leak_detector.h" #include #include #include #include #include #include #include "dvm.h" #include "../Utils/errors.h" #include "../Utils/utils.h" #include "../Utils/SgUtils.h" #include "../GraphCall/graph_calls_func.h" #include "inliner.h" #include "../VisualizerCalls/SendMessage.h" #include "expr_transform.h" using std::set; using std::map; using std::vector; using std::pair; using std::make_pair; using std::string; using std::wstring; using std::to_string; using std::get; using std::tuple; #define DEB 0 extern map> hiddenData; static map linkToOrig; static map, map> createdByFunc; // key == static map createdVarCounterByName; static map, map>> replacedConstRef; // key == static map, set> dataDeclsByFunc; // key == static map, map> dataDeclsByFuncS; // key == struct PointCall { private: bool findChainCall(FuncInfo* call, int lvl, vector& str, const string& toFind) const { bool found = false; if (lvl == 0) { for (auto& elem : call->callsFromV) { if (elem->funcName == toFind) { str.push_back(elem->funcName); found = true; break; } } } else { for (auto& elem : call->callsFromV) { str.push_back(elem->funcName); found = findChainCall(elem, lvl - 1, str, toFind); if (found) break; else str.pop_back(); } } return found; } public: pair mainPoint; FuncInfo *func; string currCall; int currLvl; string getChainCall() const { string str = func->funcName; if (currLvl) { vector chain; findChainCall(func, currLvl - 1, chain, currCall); if (chain.size() != currLvl) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (int z = 0; z < chain.size(); ++z) str += "->" + chain[z]; } return str; } }; static void checkSymbols(const int currFileId, const set& symbs) { for (auto& symb : symbs) { if (symb->getFileId() != currFileId) { __spf_print(1, "check failed - given %d, correct %d\n", symb->getFileId(), currFileId); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } } } static map createMapOfArgs(SgStatement* tempHedr, SgExpression* actualArgs) { __spf_print(DEB, "------create map of vars------\n"); SgProgHedrStmt* hedr = isSgProgHedrStmt(tempHedr); checkNull(hedr, convertFileName(__FILE__).c_str(), __LINE__); int numPars = hedr->numberOfParameters(); map vars; int i = 0; while (actualArgs) { if (i >= numPars) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto actualArg = actualArgs->lhs(); auto formalArg = hedr->parameter(i++); auto it = vars.find(formalArg->identifier()); if (it == vars.end()) vars.insert(it, make_pair(formalArg->identifier(), actualArg)); else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); actualArgs = actualArgs->rhs(); } return vars; } static bool isAllocated(SgSymbol* s) { return (s->attributes() & ALLOCATABLE_BIT) || (s->attributes() & POINTER_BIT); } static inline SgSymbol* createSymbAndDecl(const string& funcName, const string& varName, SgSymbol* newS, set& newSymbols, SgType* type = NULL) { SgSymbol* original = newS; if (newS) newS = &newS->copy(); int* count; if (createdVarCounterByName.find(varName) == createdVarCounterByName.end()) { createdVarCounterByName[varName] = 0; count = &createdVarCounterByName[varName]; } else count = &createdVarCounterByName[varName]; const string base = varName + "_"; int nextCount = checkSymbNameAndCorrect(base, count[0]); const string newName = base + to_string(nextCount); const pair key = make_pair(funcName, current_file_id); if (newS) { if (isSgConstantSymb(newS)) { if (funcName != "null" && createdByFunc[key].find(varName) == createdByFunc[key].end() || funcName == "null") { auto it = replacedConstRef[key].find(newS->identifier()); if (it != replacedConstRef[key].end() && it->second.first->identifier() != it->second.second) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (it == replacedConstRef[key].end()) { //check replaces SgSymbol* wasDone = NULL; for (auto& elem : replacedConstRef[key]) if (elem.second.second == varName) wasDone = elem.second.first; if (wasDone == NULL) { replacedConstRef[key][newS->identifier()] = make_pair(newS, newName.c_str()); newS->changeName(newName.c_str()); } else newS = wasDone; } } else if (funcName != "null" && createdByFunc[key].find(varName) != createdByFunc[key].end()) { ; //skip } else newS->changeName(newName.c_str()); } else newS->changeName(newName.c_str()); } else newS = findSymbolOrCreate(current_file, newName, type); if (newS->variant() == PROCEDURE_NAME) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (funcName != "null") { auto itS = createdByFunc[key].find(varName); if (itS == createdByFunc[key].end()) { createdByFunc[key][varName] = newS; count[0] = nextCount; if (original && isAllocated(original)) linkToOrig[newS] = original; } else newS = itS->second; } //printf("newS %s = %d\n", newS->identifier(), newS->id()); newSymbols.insert(newS); checkSymbols(current_file_id, newSymbols); return newS; } static SgStatement* findDuplicateInHidden(SgStatement* data) { SgStatement* clone = NULL; auto itF = hiddenData.find(current_file->filename()); if (itF == hiddenData.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto& func : itF->second) { if (func->fileName() != string(data->fileName())) continue; SgStatement* st = func->lexNext(); SgStatement* last = func->lastNodeOfStmt(); while (st != last) { if (data->lineNumber() == st->lineNumber() && data->variant() == st->variant()) { clone = st; break; } st = st->lexNext(); } if (clone) break; } checkNull(clone, convertFileName(__FILE__).c_str(), __LINE__); return clone; } static SgValueExp* oneExpr = NULL; static SgValueExp* zeroExpr = NULL; static vector getLowBounds(SgSymbol* arrayS) { if (oneExpr == NULL) oneExpr = new SgValueExp(1); SgExpression* list = NULL; if (isAllocated(arrayS)) { SgSymbol* copyFrom = NULL; if (linkToOrig.find(arrayS) == linkToOrig.end()) copyFrom = arrayS; else copyFrom = linkToOrig[arrayS]; SgStatement* decl = declaratedInStmt(copyFrom); checkNull(decl, convertFileName(__FILE__).c_str(), __LINE__); int consistInAllocates = 0; const string origName = OriginalSymbol(copyFrom)->identifier(); auto allocData = getAttributes(decl, set{ ALLOCATE_STMT }); if (allocData.size() == 0) // try to find statements in original file { string declFile(decl->fileName()); int line = decl->lineNumber(); string file_name = current_file->filename(); if (current_file->filename() != declFile) { auto trueDecl = SgStatement::getStatementByFileAndLine(declFile, line); if (trueDecl) { auto trueData = getAttributes(trueDecl, set{ ALLOCATE_STMT }); if (trueData.size()) allocData = trueData; } } SgFile::switchToFile(file_name); } for (auto data : allocData) { if (data->variant() != ALLOCATE_STMT) continue; if (data->getFileId() != current_file_id) data = findDuplicateInHidden(data); SgExpression* iter = data->expr(0); while (iter) { SgArrayRefExp* arrayRef = isSgArrayRefExp(iter->lhs()); if (arrayRef != NULL) { SgSymbol* origS = OriginalSymbol(arrayRef->symbol()); if (origS->identifier() == origName) { consistInAllocates++; list = iter->lhs()->lhs(); } } iter = iter->rhs(); } } if (consistInAllocates != 1) list = NULL; if (list == NULL) __spf_print(1, "find for %s, consistInAllocates = %d\n", arrayS->identifier(), consistInAllocates); checkNull(list, convertFileName(__FILE__).c_str(), __LINE__); } else { auto type = isSgArrayType(arrayS->type()); list = type->getDimList(); } vector bounds; while (list) { SgExpression* elem = list->lhs(); if (elem->variant() == DDOT) bounds.push_back(elem->lhs()); else bounds.push_back(oneExpr); list = list->rhs(); } return bounds; } static vector getBoundsExpression(SgSymbol* arrayS) { if (isAllocated(arrayS)) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto type = isSgArrayType(arrayS->type()); auto list = type->getDimList(); vector bounds; while (list) { SgExpression* elem = list->lhs(); if (elem->variant() == DDOT) bounds.push_back(&(elem->rhs()->copy() - elem->lhs()->copy() + *new SgValueExp(1))); else bounds.push_back(elem->copyPtr()); list = list->rhs(); } return bounds; } static SgArrayRefExp* addressPass(SgArrayRefExp* result, SgArrayRefExp* arrayExpOld, SgArrayRefExp* arrayExpNew, const vector& boundsOld, const vector& boundsNew, map& collection) { //TODO: check dims position for (int z = 0; z < boundsOld.size(); ++z) { checkNull(boundsOld[z], convertFileName(__FILE__).c_str(), __LINE__); checkNull(boundsNew[z], convertFileName(__FILE__).c_str(), __LINE__); SgExpression* shift = NULL; SgExpression& baseShift = (boundsNew[z]->copy() - boundsOld[z]->copy()); if (arrayExpNew->subscript(z) && !isEqExpressions(arrayExpNew->subscript(z), boundsNew[z], collection)) { shift = &(arrayExpNew->subscript(z)->copy() - boundsNew[z]->copy()); } SgExpression& oldSub = arrayExpOld->subscript(z)->copy(); if (isEqExpressions(boundsOld[z], boundsNew[z], collection)) result->addSubscript(shift ? (oldSub + *shift) : oldSub); else result->addSubscript(shift ? (oldSub + baseShift + *shift) : (oldSub + baseShift)); } return result; } static SgArrayRefExp* linearize(SgArrayRefExp* result, SgArrayRefExp* arrayExpOld, SgExpression* oldExp, map>>& argVarsLinearForm, const vector& boundsOld, const vector& boundsNew, map& collection) { const string arrayName = oldExp->symbol()->identifier(); const int numOldSubs = arrayExpOld->numberOfSubscripts(); auto itL = argVarsLinearForm.find(arrayName); if (itL == argVarsLinearForm.end()) { vector> newVars; int boundsN = 0; auto initDeclareBounds = getBoundsExpression(oldExp->symbol()); for (int z = 0; z < boundsOld.size() - 1; ++z) { pair forDim; string dimName = "s_"; int nextBoound = checkSymbNameAndCorrect(dimName, boundsN); dimName += to_string(nextBoound); forDim.first = new SgSymbol(VARIABLE_NAME, dimName.c_str()); forDim.second = initDeclareBounds[z]; newVars.push_back(forDim); } itL = argVarsLinearForm.insert(itL, make_pair(arrayName, newVars)); } SgExpression* linearForm = NULL; if (numOldSubs != 0) { for (int z = 0; z < boundsOld.size(); ++z) { SgExpression* nextArg = &(arrayExpOld->subscript(z)->copy() - boundsOld[z]->copy()); for (int p = 0; p < z; ++p) nextArg = &(*nextArg * *new SgVarRefExp(itL->second[p].first)); if (linearForm) linearForm = &(*linearForm + *nextArg); else linearForm = nextArg; } int numS = result->numberOfSubscripts(); if (!isEqExpressions(zeroExpr, boundsNew[0], collection) && numS == 0) linearForm = &(*linearForm + boundsNew[0]->copy()); if (numS == 0) result->addSubscript(*linearForm); else if (numS == 1) result->replaceSubscripts(*result->subscript(0) + *linearForm); else // TODO printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } return result; } static SgExpression* doReplace(SgExpression* oldExp, SgExpression* newExp, map& collection, map>>& argVarsLinearForm, map>& messages, const PointCall& point) { if (oneExpr == NULL) oneExpr = new SgValueExp(1); if (zeroExpr == NULL) zeroExpr = new SgValueExp(0); SgExpression* retVal = NULL; if (oldExp) { if (oldExp->variant() == ARRAY_REF && oldExp->symbol() && oldExp->symbol()->type()->variant() == T_ARRAY) { if (newExp->variant() != ARRAY_REF) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgArrayRefExp* arrayExpOld = isSgArrayRefExp(oldExp); SgArrayRefExp* arrayExpNew = isSgArrayRefExp(newExp); /*arrayExpOld->unparsestdout(); arrayExpNew->unparsestdout(); printf("\n");*/ auto boundsOld = getLowBounds(oldExp->symbol()); auto boundsNew = getLowBounds(newExp->symbol()); /*for (auto& elem : boundsOld) elem->unparsestdout(); printf("--\n"); for (auto& elem : boundsNew) elem->unparsestdout(); printf("--\n");*/ const int numOldSubs = arrayExpOld->numberOfSubscripts(); const int numNewSubs = arrayExpNew->numberOfSubscripts(); if (numNewSubs == 0) { SgArrayRefExp* result = (SgArrayRefExp*)arrayExpNew->copyPtr(); if (boundsOld.size() != boundsNew.size() && boundsNew.size() != 1 && boundsOld.size() != 1) { std::wstring bufE, bufR; __spf_printToLongBuf(bufE, L"Can not do replace argument of call '%s': sizes mismatch of array reference '%s'", to_wstring(point.getChainCall()).c_str(), to_wstring(oldExp->symbol()->identifier()).c_str()); __spf_printToLongBuf(bufR, R180, to_wstring(point.getChainCall()).c_str(), to_wstring(oldExp->symbol()->identifier()).c_str()); getObjectForFileFromMap(point.mainPoint.first.c_str(), messages).push_back(Messages(ERROR, point.mainPoint.second, bufR, bufE, 2014)); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } if (boundsNew.size() == 1 && boundsOld.size() > 1) result = linearize(result, arrayExpOld, oldExp, argVarsLinearForm, boundsOld, boundsNew, collection); else if (boundsNew.size() > 1 && boundsOld.size() == 1) { std::wstring bufE, bufR; __spf_printToLongBuf(bufE, L"Can not do replace argument of call '%s': sizes mismatch of array reference '%s'", to_wstring(point.getChainCall()).c_str(), to_wstring(oldExp->symbol()->identifier()).c_str()); __spf_printToLongBuf(bufR, R180, to_wstring(point.getChainCall()).c_str(), to_wstring(oldExp->symbol()->identifier()).c_str()); getObjectForFileFromMap(point.mainPoint.first.c_str(), messages).push_back(Messages(ERROR, point.mainPoint.second, bufR, bufE, 2014)); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } else if (numOldSubs != 0) result = addressPass(result, arrayExpOld, arrayExpNew, boundsOld, boundsNew, collection); retVal = result; } else if (numNewSubs >= numOldSubs && numOldSubs != 0) { SgArrayRefExp* result = new SgArrayRefExp(*arrayExpNew->symbol()); if (boundsOld.size() > boundsNew.size()) { std::wstring bufE, bufR; __spf_printToLongBuf(bufE, L"Can not do replace argument of call '%s': sizes mismatch of array reference '%s'", to_wstring(point.getChainCall()).c_str(), to_wstring(oldExp->symbol()->identifier()).c_str()); __spf_printToLongBuf(bufR, R180, to_wstring(point.getChainCall()).c_str(), to_wstring(oldExp->symbol()->identifier()).c_str()); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } result = addressPass(result, arrayExpOld, arrayExpNew, boundsOld, boundsNew, collection); for (int z = 0; z < boundsNew.size() - boundsOld.size(); ++z) result->addSubscript(arrayExpNew->subscript(boundsOld.size() + z)->copy()); retVal = result; } else { if (boundsNew.size() == 1 && boundsOld.size() > 1) { SgArrayRefExp* result = (SgArrayRefExp*)arrayExpNew->copyPtr(); retVal = linearize(result, arrayExpOld, oldExp, argVarsLinearForm, boundsOld, boundsNew, collection); } else { retVal = newExp->copyPtr(); retVal->setLhs(oldExp->lhs()); retVal->setRhs(oldExp->rhs()); } } } else retVal = newExp->copyPtr(); } if (retVal == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return retVal; } //return 0 - local, 1 - common, 2 - module static int isGlobal(SgStatement* st, SgSymbol* toCheckS, vector* allInCommon = NULL, string* globalName = NULL) { auto scope = toCheckS->scope(); bool isFunctionS = (toCheckS->variant() == FUNCTION_NAME); if (toCheckS != OriginalSymbol(toCheckS) || (scope && scope->variant() == MODULE_STMT && !isFunctionS)) { //TODO for module //globalName = return 2; } const string toCheck = toCheckS->identifier(); SgStatement* func = getFuncStat(st); map> commonBlocksRef; getCommonBlocksRef(commonBlocksRef, func, func ? func->lastNodeOfStmt() : NULL); int isCommon = 0; for (auto& commonBlockRef : commonBlocksRef) { for (auto& commExp : commonBlockRef.second) { for (auto exp = commExp->lhs(); exp; exp = exp->rhs()) { SgSymbol* varSymb = exp->lhs()->symbol(); string varName = varSymb->identifier(); if (toCheck == varName) { if (globalName) globalName[0] = commonBlockRef.first; isCommon = 1; break; } } if (isCommon == 1) break; } if (isCommon == 1 && allInCommon) for (auto& commExp : commonBlockRef.second) for (auto exp = commExp->lhs(); exp; exp = exp->rhs()) allInCommon[0].push_back(exp->lhs()->symbol()); if (isCommon == 1) break; } return isCommon; } inline static void findAllConstRef(SgExpression* ex, set& result) { if (ex) { if (ex->variant() == CONST_REF) { result.insert(ex->symbol()); auto constS = isSgConstantSymb(ex->symbol()); if (!constS) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto val = constS->constantValue(); if (!val) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); findAllConstRef(val, result); } findAllConstRef(ex->lhs(), result); findAllConstRef(ex->rhs(), result); } } //globalType: 0 - local, 1 - common, 2 - module static void detectTypeOfSymbol(const string& funcName, SgSymbol* s, int globalType, set& newSymbols, const vector& allInCommon, const string& globalName) { if (newSymbols.find(s) == newSymbols.end()) { char* newAttr = new char[globalName.size() + 1]; strcpy(newAttr, globalName.c_str()); if (globalType == 1) { if (allInCommon.size() == 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); const pair key = make_pair(funcName, current_file_id); int pos = 0; for (auto& commS : allInCommon) { auto attrsC = getAttributes(commS, set { COMM_STAT }); auto attrsPos = getAttributes(commS, set { COMM_LIST }); if (attrsC.size() == 0 && attrsPos.size() == 0 || attrsC.size() && attrsPos.size() && (attrsC[0] != string(newAttr) || *attrsPos[0] != pos)) { commS->addAttribute(COMM_STAT, newAttr, sizeof(char*)); int* posS = new int[1]; posS[0] = pos; commS->addAttribute(COMM_LIST, posS, sizeof(int*)); } if (isSgArrayType(commS->type())) { set constInDecl; auto arrT = isSgArrayType(commS->type()); findAllConstRef(arrT->getDimList(), constInDecl); for (auto& elem : constInDecl) { auto itS = replacedConstRef[key].find(elem->identifier()); if (itS == replacedConstRef[key].end()) { replacedConstRef[key][elem->identifier()] = make_pair(elem, elem->identifier()); newSymbols.insert(elem); checkSymbols(current_file_id, newSymbols); } } } newSymbols.insert(commS); checkSymbols(current_file_id, newSymbols); if (funcName != "null" && commS->attributes() & DATA_BIT) { auto itS = createdByFunc[key].find(commS->identifier()); if (itS == createdByFunc[key].end()) createdByFunc[key][commS->identifier()] = commS; } ++pos; } } else if (globalType == 2) s->addAttribute(MODULE_STMT, newAttr, sizeof(char*)); else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (globalType != 2) newSymbols.insert(s); checkSymbols(current_file_id, newSymbols); } } static void replaceSymbInExp(SgStatement* st, SgExpression* exp, SgExpression* par, const int expIdx, const bool isLeft, const map& argVars, map& locVars, set& newSymbols, const string& funcName, const string& resultName, SgSymbol*& newHedrSymb, map& collection, map>>& argVarsLinearForm, map>& messages, const PointCall& point) { if (exp) { replaceSymbInExp(st, exp->lhs(), exp, expIdx, true, argVars, locVars, newSymbols, funcName, resultName, newHedrSymb, collection, argVarsLinearForm, messages, point); replaceSymbInExp(st, exp->rhs(), exp, expIdx, false, argVars, locVars, newSymbols, funcName, resultName, newHedrSymb, collection, argVarsLinearForm, messages, point); const int var = exp->variant(); if (var == FUNC_CALL && exp->symbol()) if (!isIntrinsicFunctionName(exp->symbol()->identifier()) || exp->symbol()->identifier() == string("dvtime")) newSymbols.insert(exp->symbol()); if ((var == VAR_REF || var == ARRAY_REF || var == CONST_REF || var == IOACCESS) && exp->symbol()) { const string varName = exp->symbol()->identifier(); auto it = argVars.find(varName); if (it != argVars.end()) { SgExpression* copy = NULL; if (!par) { copy = doReplace(st->expr(expIdx), it->second, collection, argVarsLinearForm, messages, point); st->setExpression(expIdx, copy); } else { copy = doReplace((isLeft ? par->lhs() : par->rhs()), it->second, collection, argVarsLinearForm, messages, point); isLeft ? par->setLhs(copy) : par->setRhs(copy); } } else { auto expS = exp->symbol(); string globalName; vector allInCommon; int globalType = isGlobal(st, expS, &allInCommon, &globalName); if (globalType == 0) { auto it = locVars.find(varName); if (it == locVars.end()) { auto symb = createSymbAndDecl(funcName, varName, expS, newSymbols); it = locVars.insert(it, make_pair(varName, symb)); if (varName == resultName && !newHedrSymb) newHedrSymb = symb; if (newHedrSymb != symb) { auto arrType = isSgArrayType(symb->type()); if (arrType) { auto allList = arrType->getDimList(); while (allList) { auto list = allList; if (list && list->lhs()) replaceSymbInExp(NULL, list->lhs(), list, -1, true, argVars, locVars, newSymbols, funcName, resultName, newHedrSymb, collection, argVarsLinearForm, messages, point); allList = allList->rhs(); } } } } exp->setSymbol(*it->second); } else detectTypeOfSymbol(funcName, expS, globalType, newSymbols, allInCommon, globalName); } } } } inline static void replaceSymbInStat(SgStatement* st, SgStatement* tempHedr, const map& argVars, map& locVars, set& newSymbols, const string& funcName, const string& resultName, SgSymbol*& newHedrSymb, map& collection, map>>& argVarsLinearForm, map>& messages, const PointCall& point) { if (st->variant() == SPF_PARALLEL_REG_DIR) return; if (st->symbol() && st->variant() != PROC_STAT) { auto s = st->symbol(); const string varName = s->identifier(); auto it = argVars.find(varName); if (it != argVars.end()) st->setSymbol(*it->second->symbol()); else { string globalName; vector allInCommon; int globalType = isGlobal(st, s, &allInCommon, &globalName); if (globalType == 0) { auto it = locVars.find(varName); if (it == locVars.end()) { auto symb = createSymbAndDecl(funcName, varName, s, newSymbols); it = locVars.insert(it, make_pair(varName, symb)); if (varName == resultName && !newHedrSymb) newHedrSymb = symb; } st->setSymbol(*it->second); } else detectTypeOfSymbol(funcName, s, globalType, newSymbols, allInCommon, globalName); } } for (int i = 0; i < 3; ++i) replaceSymbInExp(st, st->expr(i), NULL, i, false, argVars, locVars, newSymbols, funcName, resultName, newHedrSymb, collection, argVarsLinearForm, messages, point); } static inline void remapVars(SgStatement* tempHedr, map argVars, map& locVars, set& newSymbols, const string& funcName, const string& resultName, SgSymbol*& newHedrSymb, map>& messages, const PointCall& point) { map collection; map>> argVarsLinearForm; for (auto st = tempHedr; st != tempHedr->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; if (st->variant() == ENTRY_STAT) // exclude same argVars { if (st->symbol()) { SgExpression* parList = st->expr(0); for (SgExpression* p = parList; p; p = p->rhs()) { string parName = p->lhs()->symbol()->identifier(); if (argVars.find(parName) != argVars.end()) argVars.erase(parName); } } else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } if (isSgExecutableStatement(st)) replaceSymbInStat(st, tempHedr, argVars, locVars, newSymbols, funcName, resultName, newHedrSymb, collection, argVarsLinearForm, messages, point); else { if (st->variant() == DATA_DECL) dataDeclsByFunc[make_pair(funcName, current_file_id)].insert((SgValueExp*)st->expr(0)); else if (st->variant() == VAR_DECL_90 || st->variant() == VAR_DECL) { SgExpression* list = st->expr(0); while (list) { auto ex = list->lhs(); if (ex->variant() == ASSGN_OP) { SgExpression* tmp = new SgExprListExp(); map>> dummy; auto copy = ex->rhs()->copyPtr(); tmp->setLhs(copy); replaceSymbInExp(NULL, tmp->lhs(), tmp, -1, true, argVars, locVars, newSymbols, funcName, resultName, newHedrSymb, collection, dummy, messages, point); dataDeclsByFuncS[make_pair(funcName, current_file_id)][OriginalSymbol(ex->lhs()->symbol())->identifier()] = copy; } list = list->rhs(); } } } } if (argVarsLinearForm.size()) { SgStatement* lastDecl = tempHedr; for (auto st = tempHedr; st != tempHedr->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; auto next = st->lexNext(); if (next && isSgExecutableStatement(next)) { lastDecl = st; break; } } SgExpression* tmp = new SgExprListExp(); map>> dummy; for (auto& bySymb : argVarsLinearForm) { for (auto& elem : bySymb.second) { newSymbols.insert(elem.first); checkSymbols(current_file_id, newSymbols); tmp->setLhs(elem.second); replaceSymbInExp(NULL, tmp->lhs(), tmp, -1, true, argVars, locVars, newSymbols, funcName, resultName, newHedrSymb, collection, dummy, messages, point); SgAssignStmt* init = new SgAssignStmt(*new SgVarRefExp(elem.first), *tmp->lhs()); lastDecl->insertStmtAfter(*init, *tempHedr); } } } } static void addComment(SgStatement* st, bool isStart, string ident) { string comments = ""; if (st->comments()) { comments = st->comments(); if (isStart) comments += "![INLINING] start of '" + ident + "'\n"; else comments = "![INLINING] end of '" + ident + "'\n" + comments; } else comments = (isStart ? "![INLINING] start of '" : "![INLINING] end of '") + ident + "'\n"; st->setComments(comments.c_str()); } static void insert(SgStatement* callSt, SgStatement* tempHedr, SgStatement* begin, SgSymbol* newHedrSymb, vector& toDelete, set& useStats) { auto prev = callSt->lexPrev(); auto last = tempHedr->lastNodeOfStmt(); auto firstExec = begin->lexNext(); auto lastExec = callSt->lexNext(); while (lastExec && lastExec->variant() == GLOBAL) // bounds marker lastExec = lastExec->lexNext(); vector formats; for (; firstExec && firstExec != tempHedr->lastNodeOfStmt(); firstExec = firstExec->lexNext()) { if (firstExec->variant() == USE_STMT) useStats.insert(firstExec->copyPtr()); if (isSgExecutableStatement(firstExec)) break; if (firstExec->variant() == FORMAT_STAT) formats.push_back(firstExec->copyPtr()); } checkNull(firstExec, convertFileName(__FILE__).c_str(), __LINE__); tempHedr->extractStmt(); SgLabel* callLabel = callSt->label(); prev->insertStmtAfter(*firstExec, *callSt->controlParent()); auto next = prev->lexNext(); if (callSt->comments()) { string callCom(callSt->comments()); if (next->comments()) { string newCom = callCom + next->comments(); next->setComments(newCom.c_str()); } else next->addComment(callCom.c_str()); callSt->delComments(); } auto ident = string(tempHedr->symbol()->identifier()); addComment(next, true, ident); addComment(lastExec, false, ident); if (callLabel) { if (firstExec->label()) { SgContinueStmt* contSt = new SgContinueStmt(); contSt->setLabel(*callLabel); prev->insertStmtAfter(*contSt, *callSt->controlParent()); } else firstExec->setLabel(*callLabel); if (callSt->variant() != PROC_STAT) // function calls callSt->deleteLabel(true); } for (auto &fmt : formats) prev->insertStmtAfter(*fmt, *callSt->controlParent()); for (auto st = prev->lexNext(); st != callSt; st = st->lexNext()) { if (st->lineNumber() > 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); st->setlineNumber(getNextNegativeLineNumber()); } next = prev->lexNext(); next->setlineNumber(callSt->lineNumber()); next->setFileName(callSt->fileName()); last->extractStmt(); if (callSt->variant() == PROC_STAT) toDelete.push_back(callSt); else { callSt->setExpression(1, new SgExpression(VAR_REF)); callSt->expr(1)->setSymbol(newHedrSymb); } } static int clean(const string& funcName, SgStatement* funcSt, const map& funcMap, vector& toDelete) { // site-independent transformation int gotoLabelId = -1; SgLabel* contLab = NULL; SgStatement* cont = NULL; // return goto label if entry function is called auto it = funcMap.find(funcName); if (it != funcMap.end() && it->second->funcPointer->variant() == ENTRY_STAT) gotoLabelId = getNextFreeLabel(); vector insertBeforeEnd; // TODO: move all ENTRY points to the top of the subprogram for (auto st = funcSt; st != funcSt->lastNodeOfStmt()->lexNext(); st = st->lexNext()) { switch (st->variant()) { case ENTRY_STAT: { SgLabel* gotoLab = new SgLabel(getNextFreeLabel()); SgContinueStmt* contSt = new SgContinueStmt(); contSt->setLabel(*gotoLab); st->insertStmtBefore(*contSt, *st->controlParent()); // return goto label if entry function is called if (st->symbol()->identifier() == funcName) gotoLabelId = gotoLab->getLabNumber(); toDelete.push_back(st); break; } case RETURN_STAT: { if (st->lexNext()->variant() == CONTROL_END && funcSt->lastNodeOfStmt() == st->lexNext()) { if (st->label()) { SgStatement* cont = new SgStatement(CONT_STAT); cont->setLabel(*st->label()); st->insertStmtBefore(*cont, *st->controlParent()); } toDelete.push_back(st); break; } if (!cont) // create CONT_STAT { contLab = new SgLabel(getNextFreeLabel()); cont = new SgStatement(CONT_STAT); cont->setLabel(*contLab); insertBeforeEnd.push_back(cont); } SgGotoStmt* gotoSt = new SgGotoStmt(*contLab); st->insertStmtBefore(*gotoSt, *st->controlParent()); toDelete.push_back(st); break; } default: break; } } std::reverse(insertBeforeEnd.begin(), insertBeforeEnd.end()); for (auto& beforeEnd : insertBeforeEnd) funcSt->lastNodeOfStmt()->insertStmtBefore(*beforeEnd, *funcSt); return gotoLabelId; } // true if inserted static inline bool insert(SgStatement* callSt, SgStatement* funcStat, SgExpression* args, set& newSymbols, const map& funcMap, vector& toDelete, set& useStats, map>& messages, const PointCall& point) { SgSymbol* funcSymb = funcStat->symbol(); bool isEntry = false; SgSymbol* entrySymb = NULL; SgStatement* tempHedr = NULL; SgSymbol* tempSymb = NULL; __spf_print(DEB, "------creating template------\n"); // 2.a create function template auto funcSt = funcSymb->body(); if (funcSt->variant() == ENTRY_STAT) { printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //TODO: isEntry = true; entrySymb = funcSymb; while (funcSt && funcSt->variant() != FUNC_HEDR) funcSt = funcSt->lexPrev(); checkNull(funcSt, convertFileName(__FILE__).c_str(), __LINE__); funcSymb = funcSt->symbol(); } // insert template after global statement in current file tempHedr = duplicateProcedure(funcStat, NULL, true, false, false); tempSymb = tempHedr->symbol(); if (string(tempSymb->identifier()) != funcSymb->identifier()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); // set first inserting statement SgStatement* begin = NULL; if (isEntry) { for (auto st = tempHedr; st != tempHedr->lastNodeOfStmt(); st = st->lexNext()) if (st->variant() == ENTRY_STAT && st->symbol()->identifier() == string(entrySymb->identifier())) begin = st; } else begin = tempHedr; checkNull(begin, convertFileName(__FILE__).c_str(), __LINE__); // create map of arguments SgSymbol* newHedrSymb = NULL; // requires for function with return variable map argVars = createMapOfArgs(tempHedr, args); // local argument variable -> top argument variable map locVars; // local varname -> new local var const string funcName = begin->symbol()->identifier(); string resultName = funcName; if (isSgFuncHedrStmt(begin)) if (begin->expr(0) && begin->expr(0)->symbol()) resultName = begin->expr(0)->symbol()->identifier(); remapVars(tempHedr, argVars, locVars, newSymbols, funcName, resultName, newHedrSymb, messages, point); if (!newHedrSymb && tempSymb->variant() == FUNCTION_NAME) // if no textual use of return variable, create new anyway newHedrSymb = createSymbAndDecl("null", string(tempSymb->identifier()) + "_spf", tempSymb, newSymbols); if (newHedrSymb) { //set clear name for module symbols const string clearName = getClearName(newHedrSymb->identifier()); if (clearName != newHedrSymb->identifier()) newHedrSymb->changeName(clearName.c_str()); } // clean function int gotoLabId = clean(funcSymb->identifier(), tempHedr, funcMap, toDelete); if (gotoLabId != -1) { SgLabel* gotoLab = new SgLabel(gotoLabId); SgGotoStmt* gotoSt = new SgGotoStmt(*gotoLab); callSt->insertStmtBefore(*gotoSt, *callSt->controlParent()); } // insert template insert(callSt, tempHedr, begin, newHedrSymb, toDelete, useStats); return true; } static inline void replaceCall(SgExpression* exp, SgExpression* par, const int i, const bool lhs, SgStatement* callSt, set& newSymbols, SgStatement* insertPlace) { // create new call variable for this call and its declaration SgSymbol* v = createSymbAndDecl("null", "arg", exp->symbol(), newSymbols); SgAssignStmt* assign = new SgAssignStmt(*new SgVarRefExp(*v), *exp->copyPtr()); assign->setlineNumber(getNextNegativeLineNumber()); assign->setLocalLineNumber(callSt->lineNumber()); insertPlace->insertStmtBefore(*assign, *callSt->controlParent()); // replace function call to a new variable if (!par) callSt->setExpression(i, new SgVarRefExp(*v)); else lhs ? par->setLhs(new SgVarRefExp(*v)) : par->setRhs(new SgVarRefExp(*v)); } static void recFindFuncCall(FuncInfo* currentFuncI, SgExpression* exp, SgExpression* par, const int i, const bool lhs, const string& funcName, bool& foundCall, SgStatement* callSt, set& newSymbols, SgStatement* insertPlace) { if (exp) { recFindFuncCall(currentFuncI, exp->rhs(), exp, i, false, funcName, foundCall, callSt, newSymbols, insertPlace); recFindFuncCall(currentFuncI, exp->lhs(), exp, i, true, funcName, foundCall, callSt, newSymbols, insertPlace); if (exp->variant() == FUNC_CALL && exp->symbol() && currentFuncI->getCallName(make_pair(exp, exp->variant()), exp->symbol()->identifier(), callSt->lineNumber()) == funcName) { foundCall = true; if (par) // do not extract external func call replaceCall(exp, par, i, lhs, callSt, newSymbols, insertPlace); } } } static int ParameterType(SgExpression* exp, SgStatement* st) { if (isSgVarRefExp(exp) || // scalar variable isSgArrayRefExp(exp) || // array variable exp->variant() == CONST_REF || // symbol (named) constant isSgValueExp(exp))// && exp->type()->variant() != T_STRING) // literal constant return 1; return 0; } static inline void PrecalculateExpression(SgSymbol* sp, SgExpression* e, SgStatement* stmt) { SgStatement* newst; newst = new SgAssignStmt(*new SgVarRefExp(sp), *e); newst->setlineNumber(getNextNegativeLineNumber()); stmt->insertStmtBefore(*newst, *stmt->controlParent()); } static SgType* SgTypeFromFile(SgFile* f, int type) { SgType* t; for (t = f->firstType(); t; t = t->next()) if (t->variant() == type) return t; return new SgType(type); } //TODO: more types static SgType* getTrueType(SgType* inExp, parF funcParType) { if (funcParType == SCALAR_FLOAT_T) return SgTypeFloat(); else if (funcParType == SCALAR_DOUBLE_T) return SgTypeDouble(); else if (funcParType == SCALAR_CMPLX_FLOAT_T) return SgTypeFromFile(current_file, T_COMPLEX); else if (funcParType == SCALAR_CMPLX_DOUBLE_T) return SgTypeFromFile(current_file, T_DCOMPLEX); else return inExp; } static inline void PrecalculateActualParameters(SgStatement* st, SgExpression* e, const FuncInfo* func, set& newSymbols) { // Precalculate actual parameter expressions // e - actual parameter list SgExpression* el; SgSymbol* sp; if (!e) return; //TODO: added exclude list! //if (is_NoExpansionFunction(s)) //return; int i = 0; for (el = e; el; el = el->rhs(), i++) { switch (ParameterType(el->lhs(), st)) { case 1: break; // actual parameter can be accessed by reference //case 2: PrecalculateSubscripts(el->lhs(),stmt); break; default: sp = createSymbAndDecl("null", "arg", NULL, newSymbols, getTrueType(el->lhs()->type(), func->funcParams.parametersT[i])); PrecalculateExpression(sp, el->lhs(), st); //to support access by reference el->setLhs(new SgVarRefExp(sp)); //replace actual parameter expression by 'sp' reference break; } } } static void renameArgs(SgExpression* ex, const map& remapArgs) { if (ex) { if (ex->variant() == VAR_REF || ex->variant() == ARRAY_REF) { auto s = ex->symbol(); if (s) { auto it = remapArgs.find(s->identifier()); if (it != remapArgs.end()) ex->setSymbol(findSymbolOrCreate(current_file, it->second, s->type())); } } renameArgs(ex->lhs(), remapArgs); renameArgs(ex->rhs(), remapArgs); } } static void renameArgsIfGlobalNameIntersection(FuncInfo* func, const set& globalNames) { if (func->isMain) return; map remapArgs; for (auto& par : func->funcParams.identificators) { if (globalNames.find(par) != globalNames.end()) { int tmp = 0; string newName = ""; do { newName = par + to_string(tmp++); } while (globalNames.find(newName) != globalNames.end()); remapArgs[par] = newName; par = newName; } } if (remapArgs.size() == 0) return; auto header = func->funcPointer->GetOriginal(); auto last = header->lastNodeOfStmt(); for (SgStatement* st = header->lexNext(); st != last; st = st->lexNext()) for (int z = 0; z < 3; ++z) renameArgs(st->expr(z), remapArgs); auto prog = isSgProcHedrStmt(header); PTR_SYMB listP = SYMB_FUNC_PARAM(BIF_SYMB(prog->thebif)); vector newElems; for (int p = 0; p < prog->numberOfParameters(); ++p) { SgSymbol* par = prog->parameter(p); auto it = remapArgs.find(par->identifier()); if (it != remapArgs.end()) { SgSymbol* replace = par->copyPtr(); replace->changeName(it->second.c_str()); newElems.push_back(replace->thesymb); } else newElems.push_back(duplicateSymbol(listP)); listP = SYMB_NEXT_DECL(listP); } listP = newElems[0]; PTR_SYMB p = listP; for (int z = 1; z < newElems.size(); ++z) { SYMB_NEXT_DECL(p) = newElems[z]; p = SYMB_NEXT_DECL(p); } SYMB_FUNC_PARAM(BIF_SYMB(prog->thebif)) = listP; } static void findUsed(SgExpression* ex, set& used) { if (ex) { if (ex->variant() == VAR_REF) { auto s = ex->symbol(); if (s) used.insert(s->identifier()); } findUsed(ex->lhs(), used); findUsed(ex->rhs(), used); } } static map> usedByFunc; static bool run_inliner(const map& funcMap, set& toInsert, map>& SPF_messages, const string& fileName, const FuncInfo* func, map>& newSymbsToDeclare, const PointCall& point, const map& commonBlocks) { bool isInlined = false; const string& funcName = func->funcName; set globalNames; for (auto& common : commonBlocks) for (auto& var : common.second->getVariables()) globalNames.insert(var->getName()); for (auto& callSt : toInsert) { SgStatement* insertPlace = callSt; SgProgHedrStmt* currentFunc = (SgProgHedrStmt*) getFuncStat(callSt); if (usedByFunc.find(currentFunc) == usedByFunc.end()) { set used; for (auto st = currentFunc->lexNext(); st != currentFunc->lastNodeOfStmt(); st = st->lexNext()) { if (isSgExecutableStatement(st)) for (int z = 0; z < 3; ++z) findUsed(st->expr(z), used); if (st->variant() == CONTAINS_STMT) break; } usedByFunc[currentFunc] = used; } auto itF = funcMap.find(currentFunc->nameWithContains()); if (itF == funcMap.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); FuncInfo* currentFuncI = itF->second; renameArgsIfGlobalNameIntersection(currentFuncI, globalNames); set useStatsInFunc; for (SgStatement* s = currentFunc; s != currentFunc->lastNodeOfStmt(); s = s->lexNext()) { if (s->variant() == CONTAINS_STMT) break; if (s->variant() == USE_STMT) useStatsInFunc.insert(s->unparse()); } SgStatement* funcStat = func->funcPointer->GetOriginal(); if (funcStat->fileName() != fileName) { //get from shadow copies auto itF = hiddenData.find(fileName); if (itF == hiddenData.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); const string fromFile = funcStat->fileName(); const int line = funcStat->lineNumber(); bool done = false; for (auto& shadowFunc : itF->second) { if (shadowFunc->fileName() == fromFile && shadowFunc->lineNumber() == line) { funcStat = shadowFunc; done = true; break; } } if (!done) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } set newSymbols; bool foundCall = false; if (!callSt || !isSgExecutableStatement(callSt)) { wstring messageE, messageR; __spf_printToLongBuf(messageE, L"It is allowed to inline function only at execution code section."); __spf_printToLongBuf(messageR, R177); getObjectForFileFromMap(fileName.c_str(), SPF_messages).push_back(Messages(ERROR, insertPlace->lineNumber(), messageR, messageE, 2011)); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } __spf_print(DEB, "------start inliner-----\n"); __spf_print(DEB, "---statement preprocessing---\n"); //simple convertation if (callSt->controlParent()->variant() == LOGIF_NODE) LogIftoIfThen(callSt->controlParent()); SgStatement* begin = callSt->lexPrev(); SgStatement* end = callSt->lexNext(); // 1.a: make statement preprocessing // if call statement contains several inlining functions, split every such call for (int i = 0; i < 3; ++i) recFindFuncCall(currentFuncI, callSt->expr(i), NULL, i, false, funcName, foundCall, callSt, newSymbols, insertPlace); __spf_print(DEB, "---argument preprocessing---\n"); // 1.b: make argument preprocessing checkNull(begin, convertFileName(__FILE__).c_str(), __LINE__); // if call statement has any expression as its artument, split this expression for separate statement // if call statement has any function as its argument, split this call for (auto st = begin->lexNext(); st != end; st = st->lexNext()) { if (st->variant() == ASSIGN_STAT) { auto rPart = st->expr(1); int line = st->lineNumber() < 0 ? st->localLineNumber() : st->lineNumber(); if (rPart->variant() == FUNC_CALL && rPart->symbol() && currentFuncI->getCallName(make_pair(rPart, rPart->variant()), rPart->symbol()->identifier(), line) == funcName) { if (isSgVarRefExp(st->expr(0)) || isSgArrayRefExp(st->expr(0)) && !isSgArrayType(st->expr(0)->type())) PrecalculateActualParameters(st, st->expr(1)->lhs(), func, newSymbols); } } else if (st->variant() == PROC_STAT) { if (st->symbol() && currentFuncI->getCallName(make_pair(st, st->variant()), st->symbol()->identifier(), st->lineNumber()) == funcName) { foundCall = true; if (st->expr(0)) PrecalculateActualParameters(st, st->expr(0), func, newSymbols); } } } set useStats; __spf_print(DEB, "---start inlining---\n"); // 2. create function template to modify and insert it if (foundCall) { bool change = true; while (change) { change = false; vector toDelete; for (auto st = begin->lexNext(); st != end; st = st->lexNext()) { switch (st->variant()) { case ASSIGN_STAT: { auto rPart = st->expr(1); int line = st->lineNumber() < 0 ? st->localLineNumber() : st->lineNumber(); if (rPart->variant() == FUNC_CALL && rPart->symbol() && currentFuncI->getCallName(make_pair(rPart, rPart->variant()), rPart->symbol()->identifier(), line) == funcName) { bool doInline = insert(st, funcStat, rPart->lhs(), newSymbols, funcMap, toDelete, useStats, SPF_messages, point); change |= doInline; isInlined |= doInline; } } break; case PROC_STAT: if (st->symbol() && currentFuncI->getCallName(make_pair(st, st->variant()), st->symbol()->identifier(), st->lineNumber()) == funcName) { bool doInline = insert(st, funcStat, st->expr(0), newSymbols, funcMap, toDelete, useStats, SPF_messages, point); change |= doInline; isInlined |= doInline; } break; default: break; } } for (auto& st : toDelete) st->extractStmt(); } } for (auto& use : useStats) { string currUse = use->unparse(); if (useStatsInFunc.find(currUse) == useStatsInFunc.end()) { useStatsInFunc.insert(currUse); currentFunc->insertStmtAfter(*use, *currentFunc); } } checkSymbols(currentFunc->getFileId(), newSymbols); for (auto& symb : newSymbols) { if (symb->variant() == CONSTRUCT_NAME) continue; newSymbsToDeclare[currentFunc].insert(symb); } } return isInlined; } static vector> getNextBounds(SgStatement* point) { vector> parts; pair newPart; bool sectionStarted = false; for (auto st = point; st != point->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; if (st->variant() == GLOBAL) { if (!sectionStarted) { newPart.first = st; sectionStarted = true; } else if (sectionStarted) { newPart.second = st; parts.push_back(newPart); sectionStarted = false; } } } if (sectionStarted) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return parts; } static bool dontInlineByAttribute(SgStatement* st) { bool dontInline = false; for (int k = 0; k < st->numberOfAttributes(); ++k) if (st->getAttribute(k)->getAttributeType() == BOOL_VAL) dontInline = true; if (dontInline) __spf_print(1, " skip call in statement with line %d by attribute\n", st->lineNumber()); return dontInline; } static void fillNewFunctions(SgExpression* ex, SgStatement* main, map>& nextInfo, const map& funcMap) { if (ex) { if (ex->variant() == FUNC_CALL) if (funcMap.find(ex->symbol()->identifier()) != funcMap.end()) if (!dontInlineByAttribute(main)) nextInfo[funcMap.at(ex->symbol()->identifier())].insert(main); fillNewFunctions(ex->lhs(), main, nextInfo, funcMap); fillNewFunctions(ex->rhs(), main, nextInfo, funcMap); } } static void fillNewFunctions(SgStatement* begin, SgStatement* end, map>& nextInfo, const map& funcMap) { for (auto st = begin; st != end; st = st->lexNext()) { if (st->variant() == PROC_STAT) if (funcMap.find(st->symbol()->identifier()) != funcMap.end()) if (!dontInlineByAttribute(st)) nextInfo[funcMap.at(st->symbol()->identifier())].insert(st); for (int z = 0; z < 3; ++z) fillNewFunctions(st->expr(z), st, nextInfo, funcMap); } } static map> fillNextDeep(const set& insertedIn, const map& funcMap) { map> nextInfo; for (auto& point : insertedIn) for (auto& part : getNextBounds(point)) fillNewFunctions(part.first, part.second, nextInfo, funcMap); return nextInfo; } static void addMessage(bool status, map>& SPF_messages, const string& fileName, const int line) { if (status == true) return; wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Function inlining failed with an error."); __spf_printToLongBuf(messageR, R193); getObjectForFileFromMap(fileName.c_str(), SPF_messages).push_back(Messages(ERROR, line, messageR, messageE, 2020)); } static bool inliner(const string& fileName_in, const string& funcName, const int lineNumber, const map>& allFuncInfo, map>& SPF_messages, map>& newSymbsToDeclare, const map& commonBlocks, int deepLvl = 0) { map funcMap; createMapOfFunc(allFuncInfo, funcMap); auto func = getFuncInfo(funcMap, funcName); const string& fileName = (fileName_in == "") ? func->fileName : fileName_in; if (func && !func->doNotInline) { if (SgFile::switchToFile(fileName) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //TODO: // now function is expected to be declared in the target file set toInsert; if (lineNumber > 0) { SgStatement* callSt = SgStatement::getStatementByFileAndLine(fileName, lineNumber); if (callSt) toInsert.insert(callSt); } else { for (auto& callTo : func->callsTo) { for (auto& callInfo : callTo->callsFromDetailed) { auto& callFrom = callInfo.detailCallsFrom; if (callFrom.first == funcName) { SgStatement* callSt = SgStatement::getStatementByFileAndLine(fileName, callFrom.second); if (callSt) toInsert.insert(callSt); } } } } set insertedIn; set markers; for (auto& elem : toInsert) { bool dontInline = dontInlineByAttribute(elem); if (dontInline) continue; insertedIn.insert(getFuncStat(elem)); //insert bounds auto cp = elem->controlParent(); auto boundAfter = new SgStatement(GLOBAL); auto boundBefore = new SgStatement(GLOBAL); elem->insertStmtBefore(*boundAfter, *cp); elem->insertStmtAfter(*boundBefore, *cp); markers.insert(boundAfter); markers.insert(boundBefore); } if (markers.size() == 0) return false; PointCall point; point.mainPoint.first = fileName; point.mainPoint.second = lineNumber; point.func = func; point.currLvl = 0; point.currCall = func->funcName; __spf_print(1, " INLINE %s - ", func->funcName.c_str()); #ifdef _WIN32 sendMessage_2lvl(wstring(L"подстановка функции '") + wstring(func->funcName.begin(), func->funcName.end()) + L"'"); #else sendMessage_2lvl(wstring(L"inlinig of function '") + wstring(func->funcName.begin(), func->funcName.end()) + L"'"); #endif //1 level bool isInlined = run_inliner(funcMap, toInsert, SPF_messages, fileName, func, newSymbsToDeclare, point, commonBlocks); __spf_print(1, "%s\n", isInlined ? "done" : "fault"); addMessage(isInlined, SPF_messages, fileName, lineNumber); if (isInlined == false) { __spf_print(1, " missing ...\n"); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } if (deepLvl >= 0 && isInlined) { int currDeep = 0; bool changed = true; while (changed) { changed = false; currDeep++; if (deepLvl > 0 && deepLvl <= currDeep) break; for (auto& next : fillNextDeep(insertedIn, funcMap)) { for (int p = 0; p < currDeep; ++p) __spf_print(1, " "); if (next.first->doNotInline) { __spf_print(1, "skip %s by flag\n", next.first->funcName.c_str()); continue; } point.currLvl = currDeep; point.currCall = next.first->funcName; __spf_print(1, " INLINE %s - ", next.first->funcName.c_str()); bool isInlined = run_inliner(funcMap, next.second, SPF_messages, fileName, next.first, newSymbsToDeclare, point, commonBlocks); __spf_print(1, "%s\n", isInlined ? "done" : "fault"); addMessage(isInlined, SPF_messages, fileName, lineNumber); changed |= isInlined; } } } for (auto& marker : markers) marker->extractStmt(); } return true; } static bool inliner(const string& allInFunc, const map>& allFuncInfo, map>& SPF_messages, map>& newSymbsToDeclare, const map& commonBlocks, int deepLvl = 0) { bool result = true; map funcMap; createMapOfFunc(allFuncInfo, funcMap); auto func = getFuncInfo(funcMap, allInFunc); if (func && !func->doNotInline) { if (SgFile::switchToFile(func->fileName) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto& callInfo : func->callsFromDetailed) { auto& callFrom = callInfo.detailCallsFrom; bool res = inliner(func->fileName, callFrom.first, callFrom.second, allFuncInfo, SPF_messages, newSymbsToDeclare, commonBlocks, deepLvl); result = result && res; } } return result; } static vector sortConstRefs(const map& constRefs) { map> deps; map> constRefByFunc; // value is for (auto& byF : replacedConstRef) for (auto& s : byF.second) constRefByFunc[s.second.first] = byF.first; bool printInternal = false; for (auto& elem : constRefs) { SgSymbol* s = elem.second; if (constRefByFunc.find(s) == constRefByFunc.end()) { __spf_print(1, " const not found '%s' with id %d\n", s->identifier(), s->id()); printInternal = true; continue; } auto& inFunc = constRefByFunc[s]; map>& byFuncRefpl = replacedConstRef[inFunc]; deps[s] = set(); set tmp; findAllConstRef(isSgConstantSymb(elem.second)->constantValue(), tmp); for (auto& ref : tmp) { auto itS = byFuncRefpl.find(ref->identifier()); if (itS != byFuncRefpl.end()) { auto newName = itS->second.second.c_str(); ref->changeName(newName); deps[elem.second].insert(newName); } else deps[s].insert(ref->identifier()); } } if (printInternal) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); set added; vector result; for (auto& elem : deps) { bool existInRef = false; for (auto& dep : elem.second) if (constRefs.find(dep) != constRefs.end()) existInRef = true; if (!existInRef) { result.push_back(elem.first); added.insert(elem.first->identifier()); } } while (result.size() != constRefs.size()) { for (auto& elem : deps) { if (added.find(elem.first->identifier()) != added.end()) continue; bool needToAdd = true; for (auto& dep : elem.second) if (added.find(dep) == added.end() && (dep != elem.first->identifier())) needToAdd = false; if (needToAdd) { result.push_back(elem.first); added.insert(elem.first->identifier()); } } } return result; } static pair getCommonInfo(SgSymbol* toDec) { pair info = make_pair("NULL", -1); auto attrsC = getAttributes(toDec, set { COMM_STAT }); if (attrsC.size() && attrsC.size() != 1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (attrsC.size()) { auto attrsPos = getAttributes(toDec, set { COMM_LIST }); if (attrsPos.size() && attrsPos.size() != 1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); info.first = attrsC[0]; info.second = *attrsPos[0]; } return info; } static bool addNewCommonDecl(SgSymbol* toDec, const int posNum, const string& commName, map>& commonBlocksRef, const map& commonBlocks, map>& commons, const string& needToRename) { if (posNum != -1) { if (needToRename != "") toDec->changeName(needToRename.c_str()); auto itCommRef = commonBlocksRef.find(commName); if (itCommRef == commonBlocksRef.end()) commons[commName][posNum] = toDec; // sort by position else { auto it = commonBlocks.find(commName); if (it == commonBlocks.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto groupedByPos = it->second->getGroupedVars(); auto itG = groupedByPos.find(posNum); if (itG == groupedByPos.end() || itG != groupedByPos.end() && itG->second.size() == 1) commons[commName][posNum] = toDec; // sort by position else { int idx = 0; SgExpression* ex = NULL; for (auto& elem : itCommRef->second) { for (auto list = elem->lhs(); list && !ex; list = list->rhs(), ++idx) if (idx == posNum) ex = list->lhs(); if (ex) break; } if (ex == NULL) commons[commName][posNum] = toDec; // sort by position else { if (ex->symbol() == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (ex->symbol()->identifier() != string(toDec->identifier())) { toDec->changeName(ex->symbol()->identifier()); return true; } else commons[commName][posNum] = toDec; // sort by position } } } } return false; } static void createDeclarations(const map>& newSymbsToDeclare, const map& commonBlocks) { map, map> preprocDataByFunc; // key is map, map> initValue; for (auto& dataByF : dataDeclsByFunc) preprocDataByFunc[dataByF.first] = splitData(dataByF.second); for (auto& dataByF : dataDeclsByFuncS) { initValue[dataByF.first] = dataByF.second; for (auto& elem : dataByF.second) preprocDataByFunc[dataByF.first][elem.first] = "---"; } map, string>> originalInfo; // value is <, sName> for (auto& elem : createdByFunc) for (auto& s : elem.second) originalInfo[s.second] = make_pair(elem.first, s.first); for (auto& byFunc : newSymbsToDeclare) { if (!byFunc.first->switchToFile()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); __spf_print(1, "symbols checking for function '%s'\n", byFunc.first->symbol()->identifier()); int currFileId = byFunc.first->getFileId(); checkSymbols(currFileId, byFunc.second); map> commonBlocksRef; getCommonBlocksRef(commonBlocksRef, byFunc.first, byFunc.first ? byFunc.first->lastNodeOfStmt() : NULL); map>> groups; map>> groupsConstRefs; map> commons; map constRefs; map saveRefs; map declRefs; map declInitInfo; set allocatable; map commonRenames; SgStatement* place = byFunc.first; while (isSgProgHedrStmt(place) == NULL && place->variant() != MODULE_STMT) place = place->controlParent(); SgStatement* scope = place; set declared, undeclared; map> commonsInCurrFunc; while (isSgExecutableStatement(place) == NULL && place != scope->lastNodeOfStmt()) { if (place->variant() == VAR_DECL || place->variant() == VAR_DECL_90 || place->variant() == DIM_STAT) { for (auto list = place->expr(0); list; list = list->rhs()) { auto elem = list->lhs(); if (elem && elem->symbol()) declared.insert(elem->symbol()->identifier()); } } else if (place->variant() == COMM_STAT) { for (SgExpression* exp = place->expr(0); exp; exp = exp->rhs()) { string commonName = "spf_unnamed"; if (exp->symbol()) commonName = string(exp->symbol()->identifier()); for (auto list = exp->lhs(); list; list = list->rhs()) { auto elem = list->lhs(); if (elem && elem->symbol()) { declared.insert(elem->symbol()->identifier()); commonsInCurrFunc[commonName].insert(elem->symbol()->identifier()); } } } } else if (place->variant() == PARAM_DECL) { SgParameterStmt* param = (SgParameterStmt*)place; for (int z = 0; z < param->numberOfConstants(); ++z) declared.insert(param->constant(z)->identifier()); } place = place->lexNext(); } //find undeclared auto usedVars = usedByFunc.find(byFunc.first); if (usedVars != usedByFunc.end()) { for (auto& var : usedVars->second) if (declared.find(var) == declared.end()) undeclared.insert(var); } vector toDeclV; // firstly - not in common for (auto& toDec : byFunc.second) { const auto commInfo = getCommonInfo(toDec); const int posNum = commInfo.second; if (posNum == -1) toDeclV.push_back(toDec); } // secondly - in common for (auto& toDec : byFunc.second) { const auto commInfo = getCommonInfo(toDec); const int posNum = commInfo.second; if (posNum != -1) toDeclV.push_back(toDec); } if (toDeclV.size() != byFunc.second.size()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); map>> alreadyCommonDecl; for (auto& toDec : toDeclV) { bool isVarFromAnotherCommon = false; string needToRename = ""; int globalType = -1; if (declared.find(toDec->identifier()) != declared.end() || undeclared.find(toDec->identifier()) != undeclared.end()) { const auto commInfo = getCommonInfo(toDec); const int posNum = commInfo.second; if (posNum == -1) continue; else { bool wasUnDeclared = undeclared.find(toDec->identifier()) != undeclared.end(); globalType = 1; bool already = false; if (alreadyCommonDecl.find(commInfo.first) != alreadyCommonDecl.end()) { if (alreadyCommonDecl[commInfo.first].find(posNum) != alreadyCommonDecl[commInfo.first].end()) { auto curr = string(toDec->identifier()); for (auto& s : alreadyCommonDecl[commInfo.first][posNum]) if (s->identifier() == curr) already = true; } } if (!already) { auto itC = commonsInCurrFunc.find(commInfo.first); if (itC == commonsInCurrFunc.end()) { for (auto& currC : commonBlocks) { if (currC.first == commInfo.first && !wasUnDeclared) continue; for (auto& var : currC.second->getVariables()) { if (var->getName() == toDec->identifier()) { const string name = var->getName(); if (commonRenames.find(name) == commonRenames.end()) commonRenames[name] = 0; needToRename = name + "_cr" + to_string(commonRenames[name]); commonRenames[name]++; break; } } if (needToRename != "") break; } } if (itC != commonsInCurrFunc.end()) if (itC->second.find(toDec->identifier()) != itC->second.end()) continue; isVarFromAnotherCommon = true; alreadyCommonDecl[commInfo.first][posNum].insert(toDec); } } } else { declared.insert(toDec->identifier()); const auto commInfo = getCommonInfo(toDec); const int posNum = commInfo.second; if (posNum != -1) { alreadyCommonDecl[commInfo.first][posNum].insert(toDec); globalType = 1; isVarFromAnotherCommon = true; } } if (isSgConstantSymb(toDec)) constRefs[toDec->identifier()] = toDec; if (toDec->attributes()) { if ((toDec->attributes() & SAVE_BIT) || (toDec->attributes() & DATA_BIT)) if (globalType != 1) // not in COMMON saveRefs[toDec->identifier()] = toDec; if (isAllocated(toDec)) allocatable.insert(toDec); if (toDec->attributes() & DATA_BIT) { auto itD = originalInfo.find(toDec); if (itD == originalInfo.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto itDF = preprocDataByFunc.find(itD->second.first); if (itDF == preprocDataByFunc.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (initValue.find(itD->second.first) == initValue.end()) { auto info = itDF->second.find(itD->second.second); if (info == itDF->second.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); declRefs[toDec] = info->second; } else { auto itDF = initValue[itD->second.first]; auto info = itDF.find(itD->second.second); if (info == itDF.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); declInitInfo[toDec] = info->second; } } } globalType = (globalType == -1) ? isGlobal(byFunc.first, toDec) : globalType; if (globalType != 0 && !isVarFromAnotherCommon) continue; else { const auto commInfo = getCommonInfo(toDec); const int posNum = commInfo.second; const string commName = commInfo.first; bool needContinue = addNewCommonDecl(toDec, posNum, commName, commonBlocksRef, commonBlocks, commons, needToRename); if (needContinue) continue; auto attrsM = getAttributes(toDec, set { MODULE_STMT }); if (attrsM.size()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } string newDecl = makeDeclaration(NULL, { toDec })->unparse(); auto it = newDecl.find("::"); if (it == string::npos) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (isSgConstantSymb(toDec)) groupsConstRefs[newDecl.substr(0, it)][toDec->identifier()].push_back(toDec); else groups[newDecl.substr(0, it)][toDec->identifier()].push_back(toDec); } //insert PARAMETER if (constRefs.size()) { for (auto& toDecls : groupsConstRefs) { vector unitedList; for (auto& elem : toDecls.second) unitedList.push_back(elem.second[0]); makeDeclaration(byFunc.first, unitedList); } SgParameterStmt* param = new SgParameterStmt(); for (auto& elem : sortConstRefs(constRefs)) param->addConstant(elem); param->setlineNumber(place->lineNumber()); place->insertStmtBefore(*param, *scope); } for (auto& toDecls : groups) { vector unitedList; vector inits; for (auto& elem : toDecls.second) { unitedList.push_back(elem.second[0]); auto initI = declInitInfo.find(elem.second[0]); if (initI != declInitInfo.end()) inits.push_back(initI->second); else inits.push_back(NULL); } auto inserted = makeDeclaration(byFunc.first, unitedList, &inits); SgExpression* list = inserted->expr(0); bool typeConverted = false; while (list) { if (list->lhs()) { if (!typeConverted) { typeConverted = true; SgType* t = list->lhs()->symbol()->type(); if (t->selector()) { if (t->selector()->variant() == CONST_REF) t->setSelector(CalculateInteger(t->selector()->copyPtr())); } if (t->length()) { if (t->length()->variant() == CONST_REF) { auto result = CalculateInteger(t->length()->copyPtr()); if (result->variant() == INT_VAL) t->setLength(result); } } } auto result = CalculateInteger(list->lhs()->copyPtr()); list->setLhs(result); } list = list->rhs(); } } vector newCommons; for (auto& byCommon : commons) { vector refs; for (auto& s : byCommon.second) refs.push_back(new SgVarRefExp(s.second)); std::reverse(refs.begin(), refs.end()); SgStatement* common = new SgStatement(COMM_STAT); common->setExpression(0, new SgExpression(COMM_LIST, makeExprList(refs, false), NULL, new SgSymbol(COMMON_NAME, byCommon.first.c_str()))); newCommons.push_back(common); } if (newCommons.size()) { for (auto& elem : newCommons) { elem->setlineNumber(place->lineNumber()); place->insertStmtBefore(*elem, *scope); } } //insert SAVE if (saveRefs.size()) { SgStatement* save = new SgStatement(SAVE_DECL); vector refs; for (auto& s : saveRefs) refs.push_back(new SgVarRefExp(s.second)); save->setExpression(0, makeExprList(refs)); save->setlineNumber(place->lineNumber()); place->insertStmtBefore(*save, *scope); } if (declRefs.size()) { SgStatement* decl = new SgStatement(DATA_DECL); SgExpression* value = new SgExpression(STMT_STR); string dataS = "data "; int z = 0; for (auto& elem : declRefs) { dataS += elem.first->identifier() + string("/") + elem.second + "/"; if (z != declRefs.size() - 1) dataS += ","; ++z; } value->thellnd->entry.string_val = new char[dataS.size() + 1]; strcpy(value->thellnd->entry.string_val, dataS.c_str()); decl->setExpression(0, value); decl->setlineNumber(place->lineNumber()); place->insertStmtBefore(*decl, *scope); } //insert ALLOCATABLE if (allocatable.size()) { SgStatement* alloc_stat = new SgStatement(ALLOCATABLE_STMT); vector refs; for (auto& s : allocatable) refs.push_back(new SgVarRefExp(s)); alloc_stat->setExpression(0, makeExprList(refs)); alloc_stat->setlineNumber(place->lineNumber()); place->insertStmtBefore(*alloc_stat, *scope); } } } static void convertLinesToAbsolute(const map>& allFuncInfo, vector>& inDataProc) { set> added; for (int z = 0; z < inDataProc.size(); ++z) { if (std::get<2>(inDataProc[z]) > 0) continue; auto funcToInl = std::get<0>(inDataProc[z]); auto file = std::get<1>(inDataProc[z]); int absoluteLine = 0; int shilftLine = -std::get<2>(inDataProc[z]); for (auto& funcByFile : allFuncInfo) { if (funcByFile.first != file) continue; for (auto& func : funcByFile.second) { int targetLine = func->linesNum.first + shilftLine; //__spf_print(1, "%s target %d + %d = %d\n", func->funcName.c_str(), func->linesNum.first, shilftLine, targetLine); for (auto& detCall : func->callsFromDetailed) { if (detCall.detailCallsFrom == make_pair(funcToInl, targetLine) && added.find(make_tuple(file, funcToInl, targetLine)) == added.end()) { __spf_print(1, "%s %d (was %d) %s\n", funcToInl.c_str(), targetLine, std::get<2>(inDataProc[z]), funcByFile.first.c_str()); added.insert(make_tuple(file, funcToInl, targetLine)); absoluteLine = targetLine; break; } } if (absoluteLine) break; } if (absoluteLine) break; } if (absoluteLine == 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); std::get<2>(inDataProc[z]) = absoluteLine; } } void callInliner(const map>& allFuncInfo, vector>& inDataProc, map>>& inDataChains, const set& inDataChainsStart, map>& SPF_messages, const map& commonBlocks) { map> newSymbsToDeclare; map tmpM; createMapOfFunc(allFuncInfo, tmpM); FuncInfo* mainF = NULL; for (auto& elem : tmpM) if (elem.second->isMain) mainF = elem.second; checkNull(mainF, convertFileName(__FILE__).c_str(), __LINE__); #if 0 //inliner(mainF->funcName, allFuncInfo, SPF_messages, newSymbsToDeclare); #else if (inDataProc.size()) { __spf_print(1, "count of inline data %ld\n", inDataProc.size()); convertLinesToAbsolute(allFuncInfo, inDataProc); map> sortByLvl; int maxLvlCall = 0; for (int z = 0; z < inDataProc.size(); ++z) { if (std::get<2>(inDataProc[z]) != -1) { int lvl = getLvlCall(mainF, 0, std::get<0>(inDataProc[z]), std::get<1>(inDataProc[z]), std::get<2>(inDataProc[z])); if (lvl == -1) { bool found = false; for (auto& func : tmpM) { if (func.second->isMain) continue; int lvlTmp = getLvlCall(func.second, 0, std::get<0>(inDataProc[z]), std::get<1>(inDataProc[z]), std::get<2>(inDataProc[z])); if (lvlTmp != -1) lvl = std::max(lvl, lvlTmp); } if (lvl == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } maxLvlCall = std::max(maxLvlCall, lvl); sortByLvl[lvl].push_back(z); } } for (int z = 0; z < inDataProc.size(); ++z) if (std::get<2>(inDataProc[z]) == -1) sortByLvl[maxLvlCall + 1].push_back(z); for (auto& byLvl : sortByLvl) { for (auto& idx : byLvl.second) { auto& tup = inDataProc[idx]; if (std::get<2>(tup) != -1) { __spf_print(1, " call inliner with [%s %s %d]\n", std::get<1>(tup).c_str(), std::get<0>(tup).c_str(), std::get<2>(tup)); bool isInlined = inliner(std::get<1>(tup), std::get<0>(tup), std::get<2>(tup), allFuncInfo, SPF_messages, newSymbsToDeclare, commonBlocks); if (!isInlined) { __spf_print(1, " missing ...\n"); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } } } } } else if (inDataChains.size()) { setInlineAttributeToCalls(tmpM, inDataChains, hiddenData); for (auto& startPoint : inDataChainsStart) { __spf_print(1, "call inliner from '%s'\n", startPoint.c_str()); inliner(startPoint, allFuncInfo, SPF_messages, newSymbsToDeclare, commonBlocks); } } #endif createDeclarations(newSymbsToDeclare, commonBlocks); }