#include "../Utils/leak_detector.h" #include #include #include #include #include #include #include #include #include #include #include "dvm.h" #include "../Utils/errors.h" #include "../Utils/SgUtils.h" #include "uniq_call_chain_dup.h" #include "../GraphCall/graph_calls.h" #include "../GraphCall/graph_calls_func.h" #include "../ExpressionTransform/expr_transform.h" #include "../VerificationCode/verifications.h" using namespace std; struct callVars { callVars() { } callVars(const pair& place, const vector& var, void* parentSt) : callVariant(var) { callPlaces.push_back(make_tuple(place.first, place.second, parentSt)); } vector> callPlaces; vector callVariant; string copiedName; }; struct callInfo { callInfo() { countCalls = 0; } int countCalls; vector variantCall; }; static bool checkUniqAndAdd(vector &vars, const vector ¤t, const pair &callPlace, void* parentSt) { for (auto& elem : vars) { if (elem.callVariant == current) { elem.callPlaces.push_back(make_tuple(callPlace.first, callPlace.second, parentSt)); return false; } } vars.push_back(callVars(callPlace, current, parentSt)); return true; } static vector createParamCalls(const pair &callPointer, const string &fileN) { if (SgFile::switchToFile(fileN) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgExpression *callList = NULL; if (callPointer.second == PROC_STAT) callList = ((SgStatement*)callPointer.first)->expr(0); else if (callPointer.second == FUNC_CALL) callList = ((SgExpression*)callPointer.first)->lhs(); else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); vector packCall; while (callList) { auto curr = callList->lhs(); if (curr->variant() == ARRAY_REF) { SgSymbol* par = OriginalSymbol(callList->lhs()->symbol()); DIST::Array* array = getArrayFromDeclarated(declaratedInStmt(par), par->identifier()); if (array) { if (array->IsNotDistribute() == false) packCall.push_back(array); else packCall.push_back(NULL); } else packCall.push_back(NULL); } else packCall.push_back(NULL); callList = callList->rhs(); } return packCall; } static map countOfCalls(const map> &allFuncs, const map &mapOfFunc) { map count; map> variantCall; for (auto& fromFile : allFuncs) { for (auto& elem : fromFile.second) { count[elem] = 0; variantCall[elem] = vector(); } } for (auto& fromFile : allFuncs) { for (auto& elem : fromFile.second) { int p = 0; for (auto& callInfo : elem->callsFromDetailed) { auto& detailed = callInfo.detailCallsFrom; auto it = mapOfFunc.find(detailed.first); if (it != mapOfFunc.end()) { auto var = variantCall.find(it->second); auto createPackCall = createParamCalls(elem->callsFromDetailed[p].pointerDetailCallsFrom, elem->fileName); if (checkUniqAndAdd(var->second, createPackCall, elem->callsFromDetailed[p].pointerDetailCallsFrom, elem->callsFromDetailed[p].parentForPointer)) count[it->second]++; } ++p; } } } map retInfo; for (auto& elem : count) retInfo[elem.first].countCalls = elem.second; for (auto& elem : variantCall) retInfo[elem.first].variantCall = elem.second; return retInfo; } static int getRealCallCount(const callInfo &info, const map> &arrayLinksByFuncCall) { if (info.variantCall.size() > 1) return info.countCalls; else if (info.variantCall.size() == 0) return 0; else { const callVars& var = info.variantCall[0]; for (int z = 0; z < var.callVariant.size(); ++z) { if (var.callVariant[z]) { DIST::Array* ref = (DIST::Array*)var.callVariant[z]; set realRefs; getRealArrayRefs(ref, ref, realRefs, arrayLinksByFuncCall); if (realRefs.size() > 1) return 2; } } return 1; } } static vector detect(const map> &allFuncs, const map &mapOfFunc, map &funcInfoOfCall, const map>& arrayLinksByFuncCall) { vector retVal; funcInfoOfCall = countOfCalls(allFuncs, mapOfFunc); for (auto &fromFile : allFuncs) { if (SgFile::switchToFile(fromFile.first) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto &elem : fromFile.second) { SgProgHedrStmt *prog = isSgProgHedrStmt(elem->funcPointer->GetOriginal()); checkNull(prog, convertFileName(__FILE__).c_str(), __LINE__); if (prog->variant() == PROG_HEDR) continue; if (getRealCallCount(funcInfoOfCall[elem], arrayLinksByFuncCall) <= 1) continue; for (int z = 0; z < prog->numberOfParameters(); ++z) { SgSymbol *par = OriginalSymbol(prog->parameter(z)); DIST::Array *array = getArrayFromDeclarated(declaratedInStmt(par), par->identifier()); if (array) { if (array->IsNotDistribute() == false) { retVal.push_back(elem); break; } } } } } return retVal; } static set getFullCallsFrom(FuncInfo *from, const map &mapOfFunc) { set callsFromFull; callsFromFull.insert(from); bool change = true; while (change) { change = false; set newAdd; for (auto& func: callsFromFull) { for (auto& elem : func->callsFrom) { auto it = mapOfFunc.find(elem); if (it != mapOfFunc.end()) { auto it2 = callsFromFull.find(it->second); if (callsFromFull.end() == it2) { newAdd.insert(it->second); change = true; } } } } for (auto& elem : newAdd) callsFromFull.insert(elem); } return callsFromFull; } static bool isAllDone(const vector& done) { for (const auto& elem : done) if (elem == false) return false; return true; } static map> groupByMainCall(const vector &toCopy, const map &mapOfFunc) { set copySet(toCopy.begin(), toCopy.end()); vector done(toCopy.size()); std::fill(done.begin(), done.end(), false); map> groups; while (!isAllDone(done)) { int z = 0; for (; z < done.size(); ++z) { if (!done[z]) { for (auto& callsTo : toCopy[z]->callsTo) { if (copySet.find(callsTo) != copySet.end()) continue; } done[z] = true; break; } } if (z == done.size() + 1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); groups[toCopy[z]] = set(); set fullCalls = getFullCallsFrom(toCopy[z], mapOfFunc); for (int p = 0; p < done.size(); ++p) { //self if (p == z) continue; if (fullCalls.find(toCopy[p]) != fullCalls.end()) { groups[toCopy[z]].insert(toCopy[p]); done[p] = true; } } } return groups; } static void fillOrigCopyEx(SgExpression *orig, SgExpression *copy, map &origCopyEx) { if (orig) { origCopyEx[orig] = copy; fillOrigCopyEx(orig->lhs(), copy->lhs(), origCopyEx); fillOrigCopyEx(orig->rhs(), copy->rhs(), origCopyEx); } } static void findAllFunctionCalls(SgExpression* ex, const vector ¶mVar, const string& file, set& toChange) { if (ex) { if (ex->variant() == FUNC_CALL) { pair callPointer = make_pair(ex, FUNC_CALL); if (createParamCalls(callPointer, file) == paramVar) toChange.insert(ex); } if (ex->lhs()) findAllFunctionCalls(ex->lhs(), paramVar, file, toChange); if (ex->rhs()) findAllFunctionCalls(ex->rhs(), paramVar, file, toChange); } } static void findDeclAndDuplicate(SgStatement* func, const string& funcName, const string& funcNameCopy, int variant) { if (SgFile::switchToFile(func->fileName()) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (variant != FUNC_HEDR) return; SgStatement* end = func->lastNodeOfStmt(); bool hasImplicit = false; for (auto st = func; st != end; st = st ->lexNext()) { if (isSgExecutableStatement(st)) break; if (st->variant() == IMPL_DECL) { hasImplicit = true; break; } } if (!hasImplicit) return; for (auto st = func; st != end; st = st->lexNext()) { if (isSgExecutableStatement(st)) break; if (st->variant() == VAR_DECL || st->variant() == VAR_DECL_90) { SgExpression* ex = st->expr(0); while (ex) { auto s = ex->lhs()->symbol(); if (s && s->identifier() == funcName) { SgExpression* copy = ex->lhs()->copyPtr(); copy->setSymbol(s->copy()); copy->symbol()->changeName(funcNameCopy.c_str()); SgExpression* next = ex->rhs(); ex->setRhs(new SgExpression(ex->variant(), copy, next)); break; } ex = ex->rhs(); } } } } static void findInterfaceBlockAndDuplicate(SgStatement* func, const string& ifaceName, const string& ifaceCopy, int variant) { if (SgFile::switchToFile(func->fileName()) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgStatement* end = func->lastNodeOfStmt(); for ( ; func != end; func = func->lexNext()) { if (func->variant() == INTERFACE_STMT) { SgStatement* ifaceEnd = func->lastNodeOfStmt(); bool found = false; for (auto st = func->lexNext(); st != ifaceEnd; st = st->lexNext()) { if (st->variant() == variant && st->symbol()->identifier() == ifaceName) { auto copy = st->copyBlockPtr(); st->insertStmtBefore(*copy, *st->controlParent()); SgSymbol* copyS = ©->symbol()->copy(); copyS->changeName(ifaceCopy.c_str()); copy->setSymbol(*copyS); found = true; break; } } if (found) break; } if (isSgExecutableStatement(func) && !isDVM_stat(func) && !isSPF_stat(func)) break; if (func->variant() == CONTAINS_STMT) break; } } static void copyGroup(const map &mapOfFunc, const vector &toCopyGroups, map &funcInfoOfCall) { if (toCopyGroups.size() == 0) return; // function -> functions with interface to thisF map> interfaceInfo; for (auto& func: mapOfFunc) for (auto& interf : func.second->interfaceBlocks) interfaceInfo[interf.second].insert(func.second); bool changed = true; map numCopyF; map> toChangeSt; map> toChangeEx; map> addedFuncDecl; int iterCount = 0; while (changed) { changed = false; SgStatement::cleanParentStatsForExprs(); for (auto& currFunc : toCopyGroups) { auto info = funcInfoOfCall.find(currFunc); if (info == funcInfoOfCall.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (numCopyF.find(currFunc) == numCopyF.end()) numCopyF[currFunc] = 1; for (auto& varCall : info->second.variantCall) { int numCopy = numCopyF[currFunc]; if (varCall.copiedName.size() != 0) continue; changed = true; if (SgFile::switchToFile(currFunc->fileName) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgStatement* pointToF = currFunc->funcPointer->GetOriginal(); SgSymbol* orig = pointToF->symbol(); string origName = orig->identifier(); origName = getOrigName(pointToF->fileName(), origName); const string newName = checkSymbNameAndCorrect(origName + string("_spf_") + to_string(numCopy)); SgStatement* toMove = duplicateProcedure(pointToF, &newName, false, false, false); varCall.copiedName = newName; map origCopySt; map origCopyEx; // set line numbers and pointer to attributes for (auto origStat = pointToF, copyStat = toMove; origStat != pointToF->lastNodeOfStmt()->lexNext(); origStat = origStat->lexNext(), copyStat = copyStat->lexNext()) { if (copyStat->variant() != origStat->variant()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); copyStat->setlineNumber(origStat->lineNumber()); copyStat->setLocalLineNumber(origStat->localLineNumber()); BIF_FILE_NAME(copyStat->thebif) = BIF_FILE_NAME(origStat->thebif); if (origStat->numberOfAttributes() > 0) copyStat->addAttributeTree(origStat->getAttribute(0)); origCopySt[origStat] = copyStat; if (origStat->comments()) copyStat->setComments(origStat->comments()); for (int z = 0; z < 3; ++z) fillOrigCopyEx(origStat->expr(z), copyStat->expr(z), origCopyEx); } int varOfCall = PROC_HEDR; //replace calls for (auto& places : varCall.callPlaces) { if (get<1>(places) == PROC_STAT) { SgStatement* proc = (SgStatement*)get<0>(places); if (SgFile::switchToFile(proc->fileName()) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgSymbol* newS = &proc->symbol()->copy(); newS->changeName(newName.c_str()); toChangeSt[proc->fileName()][proc] = newS; } else if (get<1>(places) == FUNC_CALL) { varOfCall = FUNC_HEDR; SgExpression* proc = (SgExpression*)get<0>(places); SgStatement* parent = (SgStatement*)get<2>(places); if (parent == NULL) parent = findReplacedExpression(proc); checkNull(parent, convertFileName(__FILE__).c_str(), __LINE__); if (SgFile::switchToFile(parent->fileName()) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgSymbol* newS = &proc->symbol()->copy(); set allPlaces; for (int z = 0; z < 3; ++z) findAllFunctionCalls(parent->expr(z), varCall.callVariant, parent->fileName(), allPlaces); if (allPlaces.size() == 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); newS->changeName(newName.c_str()); for (auto &elem : allPlaces) toChangeEx[parent->fileName()][elem] = newS; //duplicate names if parent func has implicit (none) auto funcStat = getFuncStat(parent); const string fName = funcStat->symbol()->identifier(); if (addedFuncDecl.find(fName) == addedFuncDecl.end()) addedFuncDecl[fName] = set(); if (addedFuncDecl[fName].find(newName) == addedFuncDecl[fName].end()) { findDeclAndDuplicate(funcStat, origName, newName, varOfCall); addedFuncDecl[fName].insert(newName); } } else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } //duplicate interfaces auto itInterf = interfaceInfo.find(currFunc); if (itInterf != interfaceInfo.end()) for (auto& func : itInterf->second) findInterfaceBlockAndDuplicate(func->funcPointer->GetOriginal(), origName, newName, varOfCall); // fill additional places to next replaces for (int z = 0; z < currFunc->callsFromDetailed.size(); ++z) { pair place = currFunc->callsFromDetailed[z].pointerDetailCallsFrom; if (place.second == PROC_STAT) { SgStatement* proc = (SgStatement*)place.first; if (SgFile::switchToFile(proc->fileName()) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgStatement* copyPoint = origCopySt[proc]; const string toFind = proc->symbol()->identifier(); auto itF = mapOfFunc.find(toFind.c_str()); if (itF == mapOfFunc.end()) continue; FuncInfo* toAdd = itF->second; auto infoAdd = funcInfoOfCall.find(toAdd); if (infoAdd == funcInfoOfCall.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); vector tmp; infoAdd->second.variantCall.push_back(callVars(make_pair(copyPoint, PROC_STAT), tmp, currFunc->callsFromDetailed[z].parentForPointer)); } else if (place.second == FUNC_CALL) { SgExpression* proc = (SgExpression*)place.first; SgStatement* parent = (SgStatement*)currFunc->callsFromDetailed[z].parentForPointer; checkNull(parent, convertFileName(__FILE__).c_str(), __LINE__); if (SgFile::switchToFile(parent->fileName()) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgExpression* copyPoint = origCopyEx[proc]; const string toFind = proc->symbol()->identifier(); auto itF = mapOfFunc.find(toFind.c_str()); if (itF == mapOfFunc.end()) continue; FuncInfo* toAdd = itF->second; auto infoAdd = funcInfoOfCall.find(toAdd); if (infoAdd == funcInfoOfCall.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); vector tmp; infoAdd->second.variantCall.push_back(callVars(make_pair(copyPoint, FUNC_CALL), tmp, currFunc->callsFromDetailed[z].parentForPointer)); } else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } numCopyF[currFunc]++; } } ++iterCount; } for (auto& elem : toChangeSt) { if (SgFile::switchToFile(elem.first) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto& toSet : elem.second) toSet.first->setSymbol(*toSet.second); } for (auto& elem : toChangeEx) { if (SgFile::switchToFile(elem.first) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto& toSet : elem.second) toSet.first->setSymbol(*toSet.second); } } static bool checkForData(FuncInfo* info, map>& messages) { bool retVal = true; if (info->isMain || info->isInterface) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgStatement* funcP = info->funcPointer->GetOriginal(); if (!funcP->switchToFile()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto st = funcP; st != funcP->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; if (isSgExecutableStatement(st)) break; if (st->variant() == VAR_DECL || st->variant() == VAR_DECL_90) { SgExpression* list = st->expr(0); while (list) { auto value = list->lhs(); if (value->variant() == ASSGN_OP) { wstring bufE, bufR; __spf_printToLongBuf(bufE, L"SAVE or DATA operators prevent function duplication: variable '%s'", to_wstring(value->lhs()->symbol()->identifier()).c_str()); __spf_printToLongBuf(bufR, R174, to_wstring(value->lhs()->symbol()->identifier()).c_str()); messages[st->fileName()].push_back(Messages(ERROR, st->lineNumber(), bufR, bufE, 2013)); retVal = false; } else if (value->symbol() && (value->symbol()->attributes() & DATA_BIT)) { wstring bufE, bufR; __spf_printToLongBuf(bufE, L"SAVE or DATA operators prevent function duplication: variable '%s'", to_wstring(value->symbol()->identifier()).c_str()); __spf_printToLongBuf(bufR, R174, to_wstring(value->symbol()->identifier()).c_str()); messages[st->fileName()].push_back(Messages(ERROR, st->lineNumber(), bufR, bufE, 2013)); retVal = false; } list = list->rhs(); } } else if (st->variant() == SAVE_DECL || st->variant() == DATA_DECL) { wstring bufE, bufR; __spf_printToLongBuf(bufE, L"SAVE or DATA operators prevent function duplication"); __spf_printToLongBuf(bufR, R173); messages[st->fileName()].push_back(Messages(ERROR, st->lineNumber(), bufR, bufE, 2012)); retVal = false; } } return retVal; } bool duplicateFunctions(const map> &allFuncs, const map>& arrayLinksByFuncCall, map>& messages) { map mapOfFunc; createMapOfFunc(allFuncs, mapOfFunc); map funcInfoOfCall; vector toCopy = detect(allFuncs, mapOfFunc, funcInfoOfCall, arrayLinksByFuncCall); map> toCopyGroups = groupByMainCall(toCopy, mapOfFunc); vector toCopyVec; for (auto& elem : toCopyGroups) toCopyVec.push_back(elem.first); for (auto& elem : toCopyGroups) for (auto &inG : elem.second) toCopyVec.push_back(inG); bool checkOk = true; //check for save vars for (auto& func : toCopyVec) { bool res = checkForData(func, messages); checkOk = checkOk && res; } if (checkOk) copyGroup(mapOfFunc, toCopyVec, funcInfoOfCall); return checkOk; } static void changeFuncNameInDvmDirs(SgExpression* ex, const string& to, const string& from, map& changed) { if (ex) { if (ex->variant() == VAR_REF) { auto s = ex->symbol(); if (s->identifier() == from || from.find("::") != string::npos && from.find(s->identifier()) != string::npos) { changed[s] = s->identifier(); s->changeName(to.c_str()); } } changeFuncNameInDvmDirs(ex->lhs(), to, from, changed); changeFuncNameInDvmDirs(ex->rhs(), to, from, changed); } } static map changeFuncNameInDvmDirs(const string& to, const string &from, SgStatement* func) { map changed; SgStatement* st = func; SgStatement* last = st->lastNodeOfStmt(); while (st != last) { if (isDVM_stat(st)) for (int z = 0; z < 3; ++z) changeFuncNameInDvmDirs(st->expr(z), to, from, changed); st = st->lexNext(); } return changed; } static map> getUniqCopies(const vector &toCmp) { map> dict; string cmpName = "testCmpName"; for (auto& elem : toCmp) { SgSymbol *s = elem->funcPointer->GetOriginal()->symbol(); string saveName = s->identifier(); s->changeName(cmpName.c_str()); map changed; if (elem->funcPointer->GetOriginal()->variant() == FUNC_HEDR) changed = changeFuncNameInDvmDirs(cmpName, saveName, elem->funcPointer->GetOriginal()); const char* buf = elem->funcPointer->GetOriginal()->unparse(); dict[buf].insert(elem); s->changeName(saveName.c_str()); for (auto& elem : changed) elem.first->changeName(elem.second.c_str()); } map> uniq; for (auto& elem : dict) { auto it = elem.second.begin(); FuncInfo* base = *it; uniq[base] = set(); for (it++; it != elem.second.end(); it++) uniq[base].insert(*it); } return uniq; } static map> removed; static map> copied; static map newNamesOfUniqCopies; map> replaced; static map> hiddenInterfaceBlocks; static map> unitedDecls; static bool removeThisFunctions(const string &file, const map> &uniqCopies, const vector& toRem) { bool wasRemoved = false; for (auto& rem : toRem) { if (uniqCopies.find(rem) == uniqCopies.end() && removed[file].find(rem) == removed[file].end()) { SgStatement* orig = rem->funcPointer->GetOriginal(); SgStatement* last = orig->lastNodeOfStmt(); while (orig != last) { orig->setVariant(orig->variant() * -1); orig = orig->lexNext(); } wasRemoved = true; removed[file].insert(rem); } } return wasRemoved; } static bool removeThisFunctions(const string& file, FuncInfo* toRem) { vector tmp = { toRem }; map> info; return removeThisFunctions(file, info, tmp); } static void restoreFunctions(const string &file) { for (auto& elem : removed[file]) { SgStatement* orig = elem->funcPointer->GetOriginal(); SgStatement* last = orig->lastNodeOfStmt(); while (orig != last) { orig->setVariant(orig->variant() * -1); orig = orig->lexNext(); } } removed[file].clear(); } static void createCopies(const string &file, const string &baseName, const map> &uniqCopies) { int newNum = 0; for (auto& toCopy : uniqCopies) { const string newName = newNum > 0 ? baseName + "_spfr_" + to_string(newNum) : baseName; ++newNum; const string clearNameS = getClearName(newName); SgStatement* duplicated = duplicateProcedure(toCopy.first->funcPointer->GetOriginal(), &clearNameS, true, true); if (duplicated->variant() == FUNC_HEDR) changeFuncNameInDvmDirs(clearNameS, toCopy.first->funcPointer->GetOriginal()->symbol()->identifier(), duplicated); copied[toCopy.first->funcPointer->GetOriginal()->fileName()].insert(duplicated); newNamesOfUniqCopies[toCopy.first->funcName] = newName; for (auto &theSame : toCopy.second) newNamesOfUniqCopies[theSame->funcName] = newName; removeThisFunctions(file, toCopy.first); } } static void doReplacements(SgSymbol* s, map> &replaced) { auto itR = replaced.find(s); if (itR == replaced.end()) { auto it = newNamesOfUniqCopies.find(s->identifier()); if (it != newNamesOfUniqCopies.end()) { s->changeName(it->second.c_str()); replaced.insert(itR, make_pair(s, *it)); } else // for modules and contains? { vector toReplace; string ident = s->identifier(); for (auto& elem : newNamesOfUniqCopies) if (getClearName(elem.first) == ident) toReplace.push_back(elem.second); if (toReplace.size() == 1) { s->changeName(getClearName(toReplace[0]).c_str()); replaced.insert(itR, make_pair(s, make_pair(ident, toReplace[0]))); } } } } static void doReplacements(SgExpression* ex, map> *replaced) { if (ex) { if (ex->variant() == FUNC_CALL) { SgSymbol* s = ex->symbol(); if (replaced) doReplacements(s, *replaced); else doReplacements(s, ::replaced); } doReplacements(ex->lhs(), replaced); doReplacements(ex->rhs(), replaced); } } static void doReplacements(SgStatement* st, SgStatement* last, map> *replaced = NULL) { while (st != last) { if (st->variant() == PROC_STAT) { SgSymbol *s = st->symbol(); if (replaced) doReplacements(s, *replaced); else doReplacements(s, ::replaced); } for (int z = 0; z < 3; ++z) doReplacements(st->expr(z), replaced); st = st->lexNext(); } } static void removeUnnecessaryReplacedFunctionDecls(SgStatement* st, SgStatement* last) { map> replacedIdx; for (auto& elem : replaced) { if (replacedIdx.find(elem.first->id()) != replacedIdx.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); replacedIdx[elem.first->id()] = elem.second; } if (replacedIdx.size() == 0) return; SgStatement* orig = st; while (st != last) { if (st->variant() == CONTAINS_STMT) break; if (st->variant() == VAR_DECL || st->variant() == VAR_DECL_90) { SgExpression* ex = st->expr(0); /*while (ex) { auto arg = ex->lhs(); if (arg && arg->symbol()) { auto s = arg->symbol(); auto it = replacedIdx.find(s->id()); //restore original name and copy symbol if (it != replacedIdx.end()) { auto copy = &s->copy(); copy->changeName(it->second.first.c_str()); arg->setSymbol(copy); } } ex = ex->rhs(); }*/ bool hasReplaces = false; while (ex) { auto arg = ex->lhs(); if (arg && arg->symbol()) { auto s = arg->symbol(); auto it = replacedIdx.find(s->id()); //restore original name and copy symbol if (it != replacedIdx.end()) { hasReplaces = true; break; } } ex = ex->rhs(); } if (hasReplaces) { auto copy = st->copy(); //united decls ex = copy.expr(0); SgExpression* prev = NULL; set has; while (ex) { auto arg = ex->lhs(); if (arg && arg->symbol()) { auto s = arg->symbol(); if (has.find(s->identifier()) != has.end()) { if (prev) prev->setRhs(ex->rhs()); else copy.setExpression(0, ex->rhs()); ex = ex->rhs(); continue; } else has.insert(s->identifier()); } prev = ex; ex = ex->rhs(); } st->insertStmtBefore(copy, *st->controlParent()); st->setVariant(st->variant() * -1); unitedDecls[current_file->filename()].insert(st); } } st = st->lexNext(); } } static void hiddenInterfaces(SgStatement* func) { SgStatement* last = func; const string fileName = func->fileName(); for (auto st = func->lexNext(); st != last; st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; if (isSgExecutableStatement(st) && !isDVM_stat(st) && !isSPF_stat(st)) break; if (st->variant() == INTERFACE_STMT) { int total = 0; map> objects; SgStatement* iEnd = st->lastNodeOfStmt(); for (auto iSt = st->lexNext(); iSt != iEnd; iSt = iSt->lexNext()) { if (iSt->variant() == PROC_HEDR || iSt->variant() == FUNC_HEDR) objects[iSt->symbol()->identifier()].insert(iSt); total++; iSt = iSt->lastNodeOfStmt(); } if (objects.size() != total) { for (auto& uniq : objects) { int first = 0; for (auto& obj : uniq.second) { if (first) { obj->setVariant(-obj->variant()); hiddenInterfaceBlocks[fileName].insert(obj); --total; } ++first; } } } if (total == 0) { st->setVariant(-st->variant()); hiddenInterfaceBlocks[fileName].insert(st); } st = iEnd; } } } static void replaceNewNames(const map> &allFuncs) { for (auto& byfile : allFuncs) { if (SgFile::switchToFile(byfile.first) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto& func : byfile.second) { if (func->funcPointer->GetOriginal()->variant() < 0) continue; SgStatement* p = func->funcPointer->GetOriginal(); doReplacements(p, p->lastNodeOfStmt()); hiddenInterfaces(p); removeUnnecessaryReplacedFunctionDecls(p, p->lastNodeOfStmt()); } map> replaced_tmp; if (copied.find(byfile.first) != copied.end()) { for (auto& func : copied[byfile.first]) doReplacements(func, func->lastNodeOfStmt(), &replaced_tmp); } } } void removeCopies(const map>& allFuncs) { bool changed = true; while (changed) { changed = false; for (auto& byFile : allFuncs) { string fileS = byFile.first; if (SgFile::switchToFile(fileS) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto& func : byFile.second) { if (func->fullCopiesOfThisFunction.size() && removed[fileS].find(func) == removed[fileS].end()) { map> uniqCopies = getUniqCopies(func->fullCopiesOfThisFunction); if (uniqCopies.size() == func->fullCopiesOfThisFunction.size()) continue; if (uniqCopies.size() == 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); bool ret1 = removeThisFunctions(fileS, uniqCopies, func->fullCopiesOfThisFunction); bool ret2 = removeThisFunctions(fileS, func); changed = ret1 || ret2; if (changed) createCopies(fileS, func->funcName, uniqCopies); } } } if (changed) replaceNewNames(allFuncs); } } void restoreCopies(SgFile* file) { const string fileName = file->filename(); auto itU = unitedDecls.find(fileName); if (itU != unitedDecls.end()) { for (auto& st : itU->second) { st->setVariant(st->variant() * -1); auto prev = st->lexPrev(); prev->deleteStmt(); } unitedDecls.erase(itU); } restoreFunctions(fileName); for (auto& elem : copied[file->filename()]) elem->deleteStmt(); copied[file->filename()].clear(); for (auto& elem : replaced) elem.first->changeName(elem.second.first.c_str()); replaced.clear(); newNamesOfUniqCopies.clear(); auto it = hiddenInterfaceBlocks.find(fileName); if (it != hiddenInterfaceBlocks.end()) { for (auto& obj : it->second) if (obj->variant() < 0) obj->setVariant(-obj->variant()); hiddenInterfaceBlocks.erase(it); } }