#include "private_removing.h" #include "../Utils/errors.h" #include "../Utils/SgUtils.h" #include "../Utils/utils.h" #include "../ExpressionTransform/expr_transform.h" #include "dead_code.h" using std::make_pair; using std::map; using std::pair; using std::set; using std::string; using std::vector; using std::wstring; using CFG_Type = map>; using UsersDirectives = map, set>; // RegularExpr represents expressions like ( coefA * I + coefB ), // where I is a variable and coefA or coefB can be equal to zero struct RegularExpr { int coefA; int coefB; string var; SgSymbol* varSymbol; RegularExpr(): coefA(0), coefB(0), var(""), varSymbol(nullptr) {} string toString() const { string result = var; if (coefA != 1) result = std::to_string(coefA) + "*" + var; if (coefB > 0) result += " + " + std::to_string(coefB); else if (coefB < 0) result += " - " + std::to_string((-1) * coefB); return result; } }; static bool operator==(const RegularExpr& left, const RegularExpr& right) { return left.var == right.var && left.coefA == right.coefA && left.coefB == right.coefB; } static bool operator<(const RegularExpr& left, const RegularExpr& right) { if (left.var == right.var && left.coefA < right.coefA && left.coefB <= right.coefB) return true; if (left.var == right.var && left.coefA == right.coefA && left.coefB < right.coefB) return true; return false; } // FixedSubscript represents subscript of array. Subscript is fixed if it is INT_VAL value struct ArraySubscript { bool isFixed; int value; bool isRegIndex; RegularExpr regExprStart; RegularExpr regExprEnd; ArraySubscript() { isFixed = false; value = 0; isRegIndex = false; regExprStart = RegularExpr{}; regExprEnd = RegularExpr{}; } string toStringStart() const { if (isFixed) return std::to_string(value); return regExprStart.toString(); } string toStringEnd() const { if (isFixed) return std::to_string(value); return regExprEnd.toString(); } string toString() const { if (regExprStart == regExprEnd) return this->toStringStart(); return this->toStringStart() + ":" + this->toStringEnd(); } }; // DefUseStmtsPair represents pair of DEF and USE statements for private variable using DefUseStmtsPair = pair; // privatesToRemoveGlobal stores the result of PRIVATE_REMOVING_ANALYSIS, // used in PRIVATE_REMOVING pass - private vars that can be removed static vector privatesToRemoveGlobal; /* ******************************* * * Block of common used functions: * * ******************************* */ // fillDirectArrayRefs fills all direct arraySym references in exp into refs static void fillDirectArrayRefs(SgExpression* exp, SgSymbol* arraySym, vector& refs) { if (exp == nullptr) return; if (exp->variant() == ARRAY_REF && exp->symbol() != nullptr && isEqSymbols(exp->symbol(), arraySym)) { refs.push_back((SgArrayRefExp*)exp); return; } fillDirectArrayRefs(exp->lhs(), arraySym, refs); fillDirectArrayRefs(exp->rhs(), arraySym, refs); } // getDirectArrayRefs returns all direct arraySym references in compound stmt, // except VAR_DECL statements static vector getDirectArrayRefs(SgStatement* stmt, SgSymbol* arraySym) { vector arrayRefs; if (stmt == nullptr) return arrayRefs; SgStatement* st = stmt; while (true) { if (st->variant() != VAR_DECL && st->variant() != VAR_DECL_90) // skip var declaration stmt for (int i = 0; i < 3; ++i) fillDirectArrayRefs(st->expr(i), arraySym, arrayRefs); if (st == stmt->lastNodeOfStmt()) break; else st = st->lexNext(); } return arrayRefs; } // getDirectArrayRefs returns all direct arraySym references in single stmt, // except VAR_DECL statements static vector getDirectArrayRefsFromSingleStmt(SgStatement* stmt, SgSymbol* arraySym) { vector arrayRefs; if (stmt == nullptr) return arrayRefs; if (stmt->variant() != VAR_DECL && stmt->variant() != VAR_DECL_90) // skip var declaration stmt for (int i = 0; i < 3; ++i) fillDirectArrayRefs(stmt->expr(i), arraySym, arrayRefs); return arrayRefs; } static bool isArrayRefInVector(SgArrayRefExp* ref, const vector& arrayRefs) { for (SgArrayRefExp* arrayRef : arrayRefs) if (arrayRef->id() == ref->id()) return true; return false; } // findAnyVar returns first found VAR_REF in expr static SgSymbol* findAnyVar(SgExpression* expr) { if (expr == nullptr) return nullptr; if (expr->variant() == VAR_REF) return expr->symbol(); SgSymbol* res = findAnyVar(expr->lhs()); if (res != nullptr) return res; return findAnyVar(expr->rhs()); } // checkAndFillRegularExpr checks if expr is regular and fills regularExpr struct // with info about expr static bool checkAndFillRegularExpr(SgExpression* expr, RegularExpr& regularExpr, SgSymbol* iterationVar) { if (expr == nullptr) return false; // hack for cases when iterationVar doesn't matter: if (iterationVar == nullptr) iterationVar = findAnyVar(expr); bool deleteTmpVar = false; if (iterationVar == nullptr) { iterationVar = new SgSymbol(VARIABLE_NAME, "tmp"); deleteTmpVar = true; } pair retCoefs; getCoefsOfSubscript(retCoefs, expr, iterationVar); regularExpr.coefA = retCoefs.first; regularExpr.coefB = retCoefs.second; if (!deleteTmpVar) { regularExpr.var = iterationVar->identifier(); regularExpr.varSymbol = iterationVar; } if (deleteTmpVar) delete iterationVar; if (retCoefs.first != 0 || retCoefs.second != 0) return true; // check if expr is like ( 0 ), because we cannot separate zero const int expr from incorrect expr: if (expr->variant() == INT_VAL) return true; return false; } // getShortFixedSubscriptsVector returns vector of fixed INT_VAL subscripts of arrayRef static vector getShortFixedSubscriptsVector(SgArrayRefExp* arrayRef, const vector& fixedDimensionsMask, Regime regime) { if (regime == Regime::DEFLT) { vector subscriptsVector; for (int i = 0; i < fixedDimensionsMask.size(); ++i) if (fixedDimensionsMask[i]) subscriptsVector.push_back(arrayRef->subscript(i)->valueInteger()); return subscriptsVector; } else if (regime == Regime::REGULAR_INDEXES) { vector subscriptsVector; SgExprListExp* indexExprList = (SgExprListExp*)arrayRef->lhs(); for (int i = 0; i < indexExprList->length(); ++i) { SgExpression* indexExpr = indexExprList->elem(i); RegularExpr regularExpr; if (!checkAndFillRegularExpr(indexExpr, regularExpr, nullptr)) return vector{}; subscriptsVector.push_back(regularExpr.coefA); subscriptsVector.push_back(regularExpr.coefB); } return subscriptsVector; } return vector{}; } // removeDuplicateArrayRefs returns unique array refereces in fixed dimensions static vector removeDuplicateArrayRefs(const vector& arrayRefs, const vector& fixedDimensionsMask, Regime regime) { map, SgArrayRefExp*> uniqueRefs; for (SgArrayRefExp* arrayRef : arrayRefs) { vector subscripts = getShortFixedSubscriptsVector(arrayRef, fixedDimensionsMask, regime); if (uniqueRefs.find(subscripts) == uniqueRefs.end()) uniqueRefs.insert(make_pair(subscripts, arrayRef)); } vector result; for (auto& ref : uniqueRefs) result.push_back(ref.second); return result; } static bool isSymbolInExpression(SgSymbol* symbol, SgExpression* exp) { if (exp == nullptr) return false; if (exp->symbol() != nullptr && (exp->variant() == VAR_REF || exp->variant() == ARRAY_REF) && isEqSymbols(exp->symbol(), symbol)) { return true; } return isSymbolInExpression(symbol, exp->lhs()) || isSymbolInExpression(symbol, exp->rhs()); } // findFuncByName searches function by its name among all functions (and subroutines) in program static FuncInfo* findFuncByName(string funcName, const map>& allFuncInfo) { for (const auto& fileFuncs : allFuncInfo) for (auto funcInfo : fileFuncs.second) if (funcInfo->funcName == funcName) return funcInfo; return nullptr; } // getCurrentFunc return FuncInfo about current function for stmt static FuncInfo* getCurrentFunc(SgStatement* stmt, const map>& allFuncInfo) { auto fileInfo = allFuncInfo.find(stmt->fileName()); if (fileInfo == allFuncInfo.end()) return nullptr; int stmtLine = stmt->lineNumber(); for (auto funcInfo : fileInfo->second) if (funcInfo->linesNum.first <= stmtLine && stmtLine <= funcInfo->linesNum.second) return funcInfo; return nullptr; } // fillIterationVariables fills SgSymbol* set with iteration variables of all loops // from stmt to outerLoopStmt. If outerLoopStmt is nullptr, it fill with iteration variables // from all outer loops static void fillIterationVars(SgStatement* stmt, SgStatement* outerLoopStmt, vector& vars) { if (stmt == nullptr) return; if (stmt->variant() == FOR_NODE) vars.push_back(((SgForStmt*)stmt)->doName()); if (stmt != outerLoopStmt) fillIterationVars(stmt->controlParent(), outerLoopStmt, vars); } /* ************************************** * * End of block of common used functions: * * ************************************** */ /* ************************************* * * Block of creating messages functions: * * ************************************* */ static void addMessageVarNotAlignedWithLoop(vector& messages, string varName, int loopLineNum) { __spf_print(1, " WARR: cannot remove private var '%s' - its references have different alignment with the loop %d\n", varName.c_str(), loopLineNum); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Cannot remove private var '%s' - its references have different alignment with the loop", to_wstring(varName).c_str()); __spf_printToLongBuf(messageR, R198, to_wstring(varName).c_str()); messages.push_back(Messages(typeMessage::WARR, loopLineNum, messageR, messageE, 2024)); } static void addMessageRemovePrivateVar(vector& messages, string varName, int loopLineNum) { __spf_print(1, " NOTE: private variable '%s' was removed in loop %d\n", varName.c_str(), loopLineNum); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Private variable '%s' was removed", to_wstring(varName).c_str()); __spf_printToLongBuf(messageR, R191, to_wstring(varName).c_str()); messages.push_back(Messages(typeMessage::NOTE, loopLineNum, messageR, messageE, 2018)); } static void addMessageRemovePrivateVarPart(vector& messages, string varName, int loopLineNum) { __spf_print(1, " NOTE: private variable '%s' was partially removed in loop %d\n", varName.c_str(), loopLineNum); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Private variable '%s' was partially removed", to_wstring(varName).c_str()); __spf_printToLongBuf(messageR, R201, to_wstring(varName).c_str()); messages.push_back(Messages(typeMessage::NOTE, loopLineNum, messageR, messageE, 2018)); } static void addMessageCannotFindRD(vector& messages, string varName, int loopLineNum) { __spf_print(1, " WARR: cannot remove private var '%s' - cannot find reaching definition for the statement in line %d\n", varName.c_str(), loopLineNum); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Cannot remove private var '%s' - cannot find reaching definition for the statement", to_wstring(varName).c_str()); __spf_printToLongBuf(messageR, R194, to_wstring(varName).c_str()); messages.push_back(Messages(typeMessage::WARR, loopLineNum, messageR, messageE, 2021)); } static void addMessagePossibleDifferentAssumption(vector& messages, string varName, string ref1, string ref2, int loopLineNum) { __spf_print(1, " WARR: removing of private var '%s' was made with assumption that references '%s' and '%s' are different in line %d\n", varName.c_str(), ref1.c_str(), ref2.c_str(), loopLineNum); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Removing of private var '%s' was made with assumption that references '%s' and '%s' are different", to_wstring(varName).c_str(), to_wstring(ref1).c_str(), to_wstring(ref2).c_str()); __spf_printToLongBuf(messageR, R192, to_wstring(varName).c_str(), to_wstring(ref1).c_str(), to_wstring(ref2).c_str()); messages.push_back(Messages(typeMessage::WARR, loopLineNum, messageR, messageE, 2019)); } static void addMessageRecursiveDependency(vector& messages, string varName, int lineNum) { __spf_print(1, " WARR: cannot remove private var '%s' in line %d - it has recursive dependency\n", varName.c_str(), lineNum); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Cannot remove private var '%s' - it has recursive dependency", to_wstring(varName).c_str()); __spf_printToLongBuf(messageR, R189, to_wstring(varName).c_str()); messages.push_back(Messages(typeMessage::WARR, lineNum, messageR, messageE, 2017)); } static void addMessageDependOnNonInvariant(vector& messages, string varName, string dependOn, int lineNum) { __spf_print(1, " WARR: cannot remove private var '%s' in line %d - it depends on non-invariant var '%s'\n", varName.c_str(), lineNum, dependOn.c_str()); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Cannot remove private var '%s' - it depends on non-invariant var '%s'", to_wstring(varName).c_str(), to_wstring(dependOn).c_str()); __spf_printToLongBuf(messageR, R190, to_wstring(varName).c_str(), to_wstring(dependOn).c_str()); messages.push_back(Messages(typeMessage::WARR, lineNum, messageR, messageE, 2017)); } static void addMessageDoesNotMatchMask(vector& messages, string varName, int loopLineNum) { __spf_print(1, " WARR: cannot remove private var '%s' in loop %d - it doesn't match any fixed dimensions mask\n", varName.c_str(), loopLineNum); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Cannot remove private var '%s' - it doesn't match any fixed dimensions mask", to_wstring(varName).c_str()); __spf_printToLongBuf(messageR, R188, to_wstring(varName).c_str()); messages.push_back(Messages(typeMessage::WARR, loopLineNum, messageR, messageE, 2016)); } static void addMessageUsageInFunctionCall(vector& messages, string varName, string funcName, int loopLineNum, int stmtLineNum) { __spf_print(1, " WARR: cannot remove private var '%s' in loop %d - it is used in the call of function '%s' in line %d\n", varName.c_str(), loopLineNum, funcName.c_str(), stmtLineNum); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Cannot remove private var '%s' - it is used in the call of function '%s'", to_wstring(varName).c_str(), to_wstring(funcName).c_str()); __spf_printToLongBuf(messageR, R203, to_wstring(varName).c_str(), to_wstring(funcName).c_str()); messages.push_back(Messages(typeMessage::WARR, stmtLineNum, messageR, messageE, 2025)); } /* ****************************************** * * End of block of creating messages functions: * * ******************************************** */ /* ************************************ * * PRIVATE_REMOVING block of functions: * * ************************************ */ // getDimensionVarName returns var name in style A(1, 2, *) static string getDimensionVarName(SgSymbol* var, const vector& subscripts, const vector& fixedDimensions, Regime regime) { string result = var->identifier(); result += "("; if (regime == Regime::DEFLT) { for (int i = 0; i < fixedDimensions.size(); ++i) { if (fixedDimensions[i]) result += std::to_string(subscripts[i]); else result += "*"; if (i != fixedDimensions.size() - 1) result += ", "; } } else if (regime == Regime::REGULAR_INDEXES) { for (int i = 0; i < subscripts.size(); i += 2) { if (subscripts[i] == 0 && subscripts[(size_t)i + 1] == 0) result += "0"; else { if (subscripts[i] != 0) { if (subscripts[i] != 1) result += "I_" + std::to_string(i / 2 + 1); else result += std::to_string(subscripts[i]) + " * I_" + std::to_string(i / 2 + 1); if (subscripts[(size_t)i + 1] > 0) result += " + "; else if (subscripts[(size_t)i + 1] < 0) result += " - "; } if (subscripts[(size_t)i + 1] != 0) result += std::to_string(std::abs(subscripts[(size_t)i + 1])); } if (i != subscripts.size() - 2) result += ", "; } } result += ")"; return result; } // getDimensionVarName returns var name in style A(1, 2, *) static string getDimensionVarName(SgSymbol* var, const vector& fixedSubscripts) { string result = var->identifier(); result += "("; for (int i = 0; i < fixedSubscripts.size(); ++i) { if (fixedSubscripts[i].isFixed) result += std::to_string(fixedSubscripts[i].value); else result += "*"; if (i != fixedSubscripts.size() - 1) result += ", "; } result += ")"; return result; } // findExpByVar returns expression related to var in varToExpMap static SgExpression* findExpByVar(SgSymbol* var, const map& varToExpMap) { for (const auto& pair : varToExpMap) if (isEqSymbols(pair.first, var)) return pair.second; return nullptr; } // replaceVarsWithExps changes variables to expressions in exp using varToExpMap, // returns modified expression static SgExpression* replaceVarsWithExps(SgExpression* exp, const map& varToExpMap) { if (exp == nullptr) return nullptr; if (exp->variant() == VAR_REF) { SgExpression* toReplace = findExpByVar(exp->symbol(), varToExpMap); if (toReplace != nullptr) return toReplace; return exp; } exp->setLhs(replaceVarsWithExps(exp->lhs(), varToExpMap)); exp->setRhs(replaceVarsWithExps(exp->rhs(), varToExpMap)); return exp; } // substituteExpressions replaces expressions-array references in exp using refToExpMap static SgExpression* substituteExpressions(SgExpression* exp, const map& refToExpMap) { if (exp == nullptr) return nullptr; if (exp->variant() == ARRAY_REF) { const auto& refToExp = refToExpMap.find(exp->unparse()); if (refToExp != refToExpMap.end()) return refToExp->second; } exp->setLhs(substituteExpressions(exp->lhs(), refToExpMap)); exp->setRhs(substituteExpressions(exp->rhs(), refToExpMap)); return exp; } static bool isVarReadInLoop(SgSymbol* var, SgForStmt* loopStmt) { for (SgStatement* st = loopStmt->lexNext(); st != loopStmt->lastNodeOfStmt(); st = st->lexNext()) { int i = 0; if (st->variant() == ASSIGN_STAT && isEqSymbols(st->expr(0)->symbol(), var)) i = 1; for (; i < 3; ++i) if (st->expr(i) && isSymbolInExpression(var, st->expr(i))) return true; } return false; } // isVarChangedBetween checks if the var is changed between first and second statement // by assignment to var (it doesn't check if the var is indirectly or implicitly by function call) static bool isVarChangedBetween(string var, SgStatement* first, SgStatement* second) { for (SgStatement* st = first->lexNext(); st != second; st = st->lexNext()) if (st->variant() == ASSIGN_STAT && st->expr(0)->symbol()->identifier() == var) return true; return false; } static vector getShortFixedSubscriptsVector(SgArrayRefExp* arrayRef, const PrivateToRemove& varToRemove) { return getShortFixedSubscriptsVector(arrayRef, varToRemove.fixedDimensions, varToRemove.regime); } // fillReadShortFixedSumscripts fills all short fixed subscripts vectors of array var, // which are used for reading from array var in exp static void fillReadShortFixedSubscripts(SgExpression* exp, const PrivateToRemove& var, set>& fixedSubscripts) { if (exp == nullptr) return; if (exp->symbol() != nullptr && (exp->symbol()->variant() == ARRAY_REF || exp->symbol()->variant() == VARIABLE_NAME) && isEqSymbols(exp->symbol(), var.varSymbol)) { auto subscripts = getShortFixedSubscriptsVector((SgArrayRefExp*)exp, var); fixedSubscripts.insert(subscripts); return; } fillReadShortFixedSubscripts(exp->lhs(), var, fixedSubscripts); fillReadShortFixedSubscripts(exp->rhs(), var, fixedSubscripts); } // getReadShortFixedSubscripts return set of all short fixed subscripts vectors of array var from loop, // which are used for reading from array var static set> getReadShortFixedSubscripts(const PrivateToRemove& var, SgForStmt* loopStmt) { set> fixedSubscripts; for (SgStatement* st = loopStmt->lexNext(); st != loopStmt->lastNodeOfStmt(); st = st->lexNext()) { int i = 0; if (st->variant() == ASSIGN_STAT && isEqSymbols(st->expr(0)->symbol(), var.varSymbol)) i = 1; for (; i < 3; ++i) fillReadShortFixedSubscripts(st->expr(i), var, fixedSubscripts); } return fixedSubscripts; } // removeExcessiveDefs removes assignments to var in loop, which are excessive -- // there are no any reading from var with such fixed subscripts vector static void removeExcessiveDefs(const PrivateToRemove& var) { SgForStmt* loopStmt = (SgForStmt*)var.loop->loop->GetOriginal(); set> usedFixedSubscripts = getReadShortFixedSubscripts(var, loopStmt); vector stmtsToRemove; for (SgStatement* st = loopStmt->lexNext(); st != loopStmt->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() != ASSIGN_STAT) continue; if (st->expr(0)->symbol() == nullptr || !isEqSymbols(st->expr(0)->symbol(), var.varSymbol)) continue; auto subscripts = getShortFixedSubscriptsVector((SgArrayRefExp*) st->expr(0), var); if (usedFixedSubscripts.find(subscripts) == usedFixedSubscripts.end()) stmtsToRemove.push_back(st); } for (auto st : stmtsToRemove) st->deleteStmt(); } // removeVarFromPrivateAttributes removes var from SPF ANALYSIS PRIVATE attributes of loop static void removeVarFromPrivateAttributes(SgSymbol* var, LoopGraph* loop) { SgStatement* loopStmt = loop->loop->GetOriginal(); for (int i = 0; i < loopStmt->numberOfAttributes(); ++i) { SgAttribute* attr = loopStmt->getAttribute(i); if (attr->getAttributeType() != SPF_ANALYSIS_DIR) continue; SgStatement* data = (SgStatement*) attr->getAttributeData(); SgExprListExp* analysisList = (SgExprListExp*) data->expr(0); if (analysisList == nullptr) continue; vector newAnalysisList; for (int i = 0; i < analysisList->length(); ++i) { if (analysisList->elem(i)->variant() == ACC_PRIVATE_OP) { SgExprListExp* varList = (SgExprListExp*) analysisList->elem(i)->lhs(); vector newVarList; for (int j = 0; j < varList->length(); ++j) if (!isEqSymbols(var, varList->elem(j)->symbol())) newVarList.push_back(varList->elem(j)->copyPtr()); if (!newVarList.empty()) newAnalysisList.push_back(new SgExpression(ACC_PRIVATE_OP, makeExprList(newVarList))); } else newAnalysisList.push_back(analysisList->elem(i)->copyPtr()); } if (!newAnalysisList.empty()) data->setExpression(0, makeExprList(newAnalysisList)); else loopStmt->deleteAttribute(i); } } // getVarToExpMap returns map SgSymbol* from defRef -> SgExpression* from useRef static map getVarToExpMap(SgArrayRefExp* defRef, SgArrayRefExp* useRef, const vector& fixedDimensions, Regime regime) { map varToExpMap; for (int i = 0; i < fixedDimensions.size(); ++i) { if (fixedDimensions[i]) continue; // check not fixed dimension: if (regime == Regime::REGULAR_INDEXES) { RegularExpr useExpr; checkAndFillRegularExpr(useRef->subscript(i), useExpr, nullptr); RegularExpr defExpr; checkAndFillRegularExpr(defRef->subscript(i), defExpr, nullptr); varToExpMap.insert(make_pair(defExpr.varSymbol, new SgVarRefExp(useExpr.varSymbol))); } else varToExpMap.insert(make_pair(defRef->subscript(i)->symbol(), useRef->subscript(i))); } return varToExpMap; } // removeArray removes array by substituting it in DEF-USE pairs. // Returns set of removed fixed subscripts static set> removeArray(string filename, PrivateToRemove& arrayToRemove) { set> removedFixedSubscripts; auto& fixedDimensions = arrayToRemove.fixedDimensions; for (auto& defUsePair : arrayToRemove.defUseStmtsPairs) { map refToExpMap; SgAssignStmt* defStmt = defUsePair.first; SgStatement* useStmt = defUsePair.second; SgArrayRefExp* defRef = (SgArrayRefExp*)defStmt->lhs(); vector defFixedSubscripts = getShortFixedSubscriptsVector(defRef, arrayToRemove); int startIndex = 0; if (useStmt->variant() == ASSIGN_STAT) startIndex = 1; for (int i = startIndex; i < 3; ++i) { vector arrayUseRefs; fillDirectArrayRefs(useStmt->expr(i), arrayToRemove.varSymbol, arrayUseRefs); if (arrayUseRefs.empty()) continue; for (SgArrayRefExp* useRef : arrayUseRefs) { vector useFixedSubscripts = getShortFixedSubscriptsVector(useRef, arrayToRemove); if (defFixedSubscripts != useFixedSubscripts) continue; // because useRef and defRef can be different in subscripts of fixed dimensions removedFixedSubscripts.insert(useFixedSubscripts); auto varToExpMap = getVarToExpMap(defRef, useRef, fixedDimensions, arrayToRemove.regime); SgExpression* expToSubst = defStmt->rhs()->copyPtr(); expToSubst = replaceVarsWithExps(expToSubst, varToExpMap); refToExpMap.insert(make_pair(useRef->unparse(), expToSubst)); } SgExpression* substExp = substituteExpressions(useStmt->expr(i), refToExpMap); useStmt->setExpression(i, *substExp); } } return removedFixedSubscripts; } void removePrivates(string filename, vector& messages, const map& commonBlocks, const map>& allFuncInfo, int& countOfTransform) { set removeDC; for (auto& varToRemove : privatesToRemoveGlobal) { if (filename != varToRemove.loop->fileName) continue; auto removedDimensions = removeArray(filename, varToRemove); countOfTransform++; removeExcessiveDefs(varToRemove); removeDC.insert(varToRemove.loop); vector varRefs = getDirectArrayRefs(varToRemove.loop->loop, varToRemove.varSymbol); int loopLineNum = varToRemove.loop->lineNum; string varName = varToRemove.varSymbol->identifier(); auto& fixedDimensions = varToRemove.fixedDimensions; if (varRefs.empty()) { removeVarFromPrivateAttributes(varToRemove.varSymbol, varToRemove.loop); addMessageRemovePrivateVar(messages, varName, loopLineNum); } else { varRefs = removeDuplicateArrayRefs(varRefs, fixedDimensions, varToRemove.regime); for (auto& varRef : varRefs) { vector subscripts = getShortFixedSubscriptsVector(varRef, varToRemove); if (removedDimensions.find(subscripts) != removedDimensions.end()) { varName = getDimensionVarName(varToRemove.varSymbol, subscripts, fixedDimensions, varToRemove.regime); addMessageRemovePrivateVarPart(messages, varName, loopLineNum); } removedDimensions.erase(subscripts); } for (auto& removedDimension : removedDimensions) { varName = getDimensionVarName(varToRemove.varSymbol, removedDimension, fixedDimensions, varToRemove.regime); addMessageRemovePrivateVar(messages, varName, loopLineNum); } } } // remove dead code from loop: for (auto& dcLoopRem : removeDC) { auto loopStmt = dcLoopRem->loop->GetOriginal(); FuncInfo* currFunc = getCurrentFunc(loopStmt, allFuncInfo); if (currFunc == nullptr) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); removeDeadCode(currFunc->funcPointer, allFuncInfo, commonBlocks, loopStmt, loopStmt->lastNodeOfStmt()); } } /* ****************************************** * * End of PRIVATE_REMOVING block of functions * * ****************************************** */ /* ********************************************* * * PRIVATE_REMOVING_ANALYSIS block of functions: * * ********************************************* */ // Context stores general info about current loop and array to remove struct Context { const map>& allFuncInfo; const map& commonBlocks; vector& messages; string filename; Regime regime; LoopGraph* loop; SgForStmt* loopStmt; SgSymbol* arraySymbol; int dimensionsNum; vector explicitArrayRefs; vector fixedDimensionsMask; }; // ReducedArrayVars represents mapping of array reference to reduced scalar var: // arr(1, i) -> pair, SgSymbol*>: [1], arr_1 class ReducedArrayVarsMap { map, SgSymbol*> arrayMap; public: void insert(vector subscripts, SgSymbol* var) { this->arrayMap.insert(make_pair(subscripts, var)); } // find looks up for reduced array var with provided subscripts, // returns this var or nullptr SgSymbol* find(const vector& subscripts) const { const auto& arr = this->arrayMap.find(subscripts); if (arr == this->arrayMap.end()) return nullptr; return arr->second; } // getAllVars returns all reduced array vars vector getAllVars() const { vector vars; for (auto& reducedVar : this->arrayMap) vars.push_back(reducedVar.second); return vars; } }; enum class TypeOfInsertedStmt { DEF = 1, USE, DECLARATION, NONE }; // InsertedStatement represents inserted statement for reaching definition analysis struct InsertedStatement { TypeOfInsertedStmt type = TypeOfInsertedStmt::NONE; SgStatement* insertedStmt = nullptr; SgStatement* relatedToStmt = nullptr; bool isRecursive = false; // true for DEF stmt if it is recursive InsertedStatement() {}; InsertedStatement(TypeOfInsertedStmt type, SgStatement* insertedStmt) { this->type = type; this->insertedStmt = insertedStmt; } }; // findInsertedStmt looking for stmt in insertedStmts static vector::const_iterator findInsertedStmt(const vector& insertedStmts, SgStatement* stmt) { for (auto iter = insertedStmts.begin(); iter != insertedStmts.end(); ++iter) if (iter->insertedStmt->id() == stmt->id()) return iter; return insertedStmts.end(); } static vector getShortFixedSubscriptsVector(Context* ctx, SgArrayRefExp* arrayRef) { return getShortFixedSubscriptsVector(arrayRef, ctx->fixedDimensionsMask, ctx->regime); } // getLoopsInfo return vector of pair (string, int) - doName and level for each loop // from stmt up to outerLoop (not only closely nested). Loop levels start from 1 static void getLoopsInfo(SgStatement* stmt, SgStatement* outerLoop, vector>& loopsInfo) { if (stmt == nullptr) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (stmt->variant() == FOR_NODE) { string doName = ((SgForStmt*)stmt)->doName()->identifier(); loopsInfo.push_back(make_pair(doName, 0)); } if (stmt == outerLoop) { int levelsNum = loopsInfo.size(); for (int i = 0; i < levelsNum; ++i) loopsInfo[i].second = levelsNum - i; return; } getLoopsInfo(stmt->controlParent(), outerLoop, loopsInfo); } // checkLoopAlignmentMatching checks if all array references in loop has the same alignment // with nested loops static bool checkLoopAlignmentMatching(Context* ctx) { // Loop alignment is a pair of loop alignment vector // and a number of nested loops for current statement context (not only closely nested). // Loop alignment vector is a vector of ctx->dimensionsNum length of loop levels // or -1, if dimension is not aligned with any loop. // Dimension is aligned with loop, if subscript expression has iteration var of this loop // (and only of this loop). set, int>> loopAlignmentSet; for (SgStatement* st = ctx->loopStmt; st != ctx->loopStmt->lastNodeOfStmt(); st = st->lexNext()) { vector arrayRefs = getDirectArrayRefsFromSingleStmt(st, ctx->arraySymbol); if (arrayRefs.empty()) continue; vector> loopsInfoVector; getLoopsInfo(st, ctx->loopStmt, loopsInfoVector); for (SgArrayRefExp* arrayRef : arrayRefs) { vector arrayRefLoopAlignment; for (int i = 0; i < ctx->dimensionsNum; ++i) { bool foundIterationVar = false; set vars; getVariables(arrayRef->subscript(i), vars, { VAR_REF }); for (string var : vars) { for (auto& loopInfo : loopsInfoVector) { if (loopInfo.first != var) continue; // There are two iteration vars in subscript expression // or one var is iteration var for more than one loop: if (foundIterationVar) return false; foundIterationVar = true; arrayRefLoopAlignment.push_back(loopInfo.second); } } if (!foundIterationVar) arrayRefLoopAlignment.push_back(-1); } loopAlignmentSet.insert(make_pair(arrayRefLoopAlignment, loopsInfoVector.size())); } } // Check if all loop alignments has similar alignment diff. // Alignment diff is a difference between the number of nested loops (size of loopInfoVector) // and the number of aligned dimensions (alignment counter). int alignmentDiff = -1; for (auto& loopAlignment : loopAlignmentSet) { int currentAlignmentCounter = ctx->dimensionsNum; for (int i = 0; i < ctx->dimensionsNum; ++i) if (loopAlignment.first[i] == -1) // if dimension is not aligned currentAlignmentCounter--; int currentAlignmentDiff = loopAlignment.second - currentAlignmentCounter; if (alignmentDiff == -1) alignmentDiff = currentAlignmentDiff; else if (alignmentDiff != currentAlignmentDiff) return false; } // Check if there are any different loop alignments. // Two loop alignments are different if they have different loop level alignments // in the same dimension. The case when one of two different loop level is -1 // (there is no loop alignment) is not a problem for (int i = 0; i < ctx->dimensionsNum; ++i) { int currentLoopLevel = -1; for (auto& loopAlignment : loopAlignmentSet) { if (loopAlignment.first[i] != -1) // if loop alignment is not empty { if (currentLoopLevel == -1) currentLoopLevel = loopAlignment.first[i]; else if (currentLoopLevel != loopAlignment.first[i]) return false; } } } return true; } // matchesFixedDimensionsMask checks if all array references have INT_VAL value in fixed dimension static bool checkFixedDimensionsMaskMatching(Context* ctx) { for (SgArrayRefExp* ref : ctx->explicitArrayRefs) for (int i = 0; i < ctx->fixedDimensionsMask.size(); ++i) if (ctx->fixedDimensionsMask[i] && ref->subscript(i)->variant() != INT_VAL) return false; return true; } // checkDefStmtRefsMatchesMask checks if all DEF array refs have INT_VAL value in fixed dimensions // and VAR_REF in non-fixed dimensions static bool checkDefStmtRefsMatchesMask(Context* ctx) { for (SgStatement* st = ctx->loopStmt->lexNext(); st != ctx->loopStmt->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() != ASSIGN_STAT) continue; vector iterationVars; fillIterationVars(st, ctx->loopStmt, iterationVars); if (isEqSymbols(st->expr(0)->symbol(), ctx->arraySymbol)) // DEF statement { SgArrayRefExp* ref = (SgArrayRefExp*)st->expr(0); for (int i = 0; i < ctx->fixedDimensionsMask.size(); ++i) { if (ctx->fixedDimensionsMask[i] && ref->subscript(i)->variant() == INT_VAL) continue; if (!ctx->fixedDimensionsMask[i] && ref->subscript(i)->variant() == VAR_REF) { bool isIterationVar = false; for (auto iterationvVar : iterationVars) if (isEqSymbols(ref->subscript(i)->symbol(), iterationvVar)) isIterationVar = true; if (!isIterationVar) return false; continue; } return false; } } } return true; } // getFixedDimensionsVector returns vector of fixed dimensions for arrayRef. // dimension is fixed, when the value of subsctipt is INT_VAL static vector getFixedDimensionsVector(SgArrayRefExp* arrayRef) { vector fixedDimensions(arrayRef->numberOfSubscripts(), false); for (int i = 0; i < arrayRef->numberOfSubscripts(); ++i) if (arrayRef->subscript(i)->variant() == INT_VAL) fixedDimensions[i] = true; return fixedDimensions; } // sunparseFixedDimensionsVector unparses fixed dimensions vector as string static string sunparseFixedDimensionsVector(const vector& fixedDimensions) { string result = "<"; result.reserve(result.size() + 7 * fixedDimensions.size()); for (int i = 0; i < fixedDimensions.size(); ++i) { if (fixedDimensions[i] == true) result += "true"; else result += "false"; if (i != fixedDimensions.size() - 1) result += ", "; } result += ">"; return result; } static bool checkRegularIndexRefs(Context* ctx) { vector newArrayRefsVector; for (SgStatement* st = ctx->loopStmt->lexNext(); st != ctx->loopStmt->lastNodeOfStmt(); st = st->lexNext()) { vector iterationVars; fillIterationVars(st, ctx->loopStmt, iterationVars); vector arrayRefs = getDirectArrayRefsFromSingleStmt(st, ctx->arraySymbol); for (auto arrayRef : arrayRefs) { if (!isArrayRefInVector(arrayRef, ctx->explicitArrayRefs)) continue; // check if unfixed dimension index contains iteration var: SgExprListExp* indexExprList = (SgExprListExp*)arrayRef->lhs(); for (int i = 0; i < indexExprList->length(); ++i) { if (ctx->fixedDimensionsMask[i]) continue; SgExpression* indexExpr = indexExprList->elem(i); RegularExpr regularExpr; if (!checkAndFillRegularExpr(indexExpr, regularExpr, nullptr)) return false; if (regularExpr.coefA == 0) return false; bool isIterationVar = false; for (SgSymbol* iterationVar : iterationVars) { if (iterationVar->identifier() == regularExpr.var) { isIterationVar = true; break; } } if (!isIterationVar) return false; } } } return true; } // getFixedDimensionsMask finds fixed dimensions vector with minimum number of fixed dimensions // and writes messages if array doesn't have fixed dimensions static vector getFixedDimensionsMask(Context* ctx) { vector resultMask(ctx->dimensionsNum, true); for (const auto arrayRef : ctx->explicitArrayRefs) { vector fixedDimensions = getFixedDimensionsVector(arrayRef); for (int i = 0; i < ctx->dimensionsNum; ++i) resultMask[i] = resultMask[i] && fixedDimensions[i]; } string unparsedFixedDimensions = sunparseFixedDimensionsVector(resultMask); __spf_print(1, " NOTE: found fixed subsripts mask %s for array '%s' in loop %d\n", unparsedFixedDimensions.c_str(), ctx->arraySymbol->identifier(), ctx->loop->lineNum); return resultMask; } // getScopeLoopStmt returns least outer scope loop statement static SgForStmt* getScopeLoopStmt(SgStatement* stmt) { while (stmt != nullptr && stmt->variant() != FOR_NODE) stmt = stmt->controlParent(); return (SgForStmt*)stmt; } // getLoopStmtForVar searches for loop with iteration var equal loopVar starting from from stmt static SgForStmt* getLoopStmtForVar(SgStatement* stmt, string loopVar) { while (stmt != nullptr) { SgForStmt* loopStmt = getScopeLoopStmt(stmt); if (loopStmt->doName()->identifier() == loopVar) return loopStmt; stmt = stmt->controlParent(); } return nullptr; } // getFixedSubscriptsVector returns vector of fixed INT_VAL subscripts of arrayRef // true - subscript is fixed, false - it isn't static vector getFixedSubscriptsVector(SgArrayRefExp* arrayRef, int dimensionsNum = 0, SgStatement* stmt = nullptr) { if (arrayRef == nullptr || arrayRef->numberOfSubscripts() == 0) return vector(dimensionsNum); vector subscriptsVector; for (int i = 0; i < arrayRef->numberOfSubscripts(); ++i) { SgExpression* subscriptExpr = arrayRef->subscript(i); ArraySubscript sub; if (subscriptExpr->variant() == INT_VAL) { sub.isFixed = true; sub.value = subscriptExpr->valueInteger(); } else if (stmt != nullptr && subscriptExpr->variant() == VAR_REF) { SgForStmt* loopStmt = getLoopStmtForVar(stmt, subscriptExpr->symbol()->identifier()); if (loopStmt != nullptr) { RegularExpr regExprStep; SgExpression* step = loopStmt->step(); if (step == nullptr || checkAndFillRegularExpr(step, regExprStep, nullptr) && regExprStep.coefA == 0) { SgExpression* start = loopStmt->start(); SgExpression* end = loopStmt->end(); if (regExprStep.coefB < 0) std::swap(start, end); bool isRegular = true; isRegular = isRegular && checkAndFillRegularExpr(start, sub.regExprStart, nullptr); isRegular = isRegular && checkAndFillRegularExpr(end, sub.regExprEnd, nullptr); sub.isRegIndex = isRegular; } } } else { RegularExpr regExpr; if (checkAndFillRegularExpr(subscriptExpr, regExpr, nullptr)) { sub.isRegIndex = true; sub.regExprStart = regExpr; sub.regExprEnd = regExpr; } } subscriptsVector.push_back(sub); } return subscriptsVector; } // checkImplicitDirectUsage returns masks of array implicit usage (as out argument) // in any function call in exp and writes message about each usage static void checkImplicitDirectUsage(Context* ctx, SgExpression* exp, int stmtLineNum, vector>& fixedSubscripts) { if (exp == nullptr) return; if (exp->variant() == FUNC_CALL) { SgFunctionCallExp* funcCallExp = (SgFunctionCallExp*)exp; string funcName = funcCallExp->funName()->identifier(); FuncInfo* funcInfo = findFuncByName(funcName, ctx->allFuncInfo); if (funcInfo != nullptr) { for (int i = 0; i < funcCallExp->numberOfArgs(); ++i) { SgExpression* funcArg = funcCallExp->arg(i); if (funcArg->symbol() == nullptr || !isEqSymbols(funcArg->symbol(), ctx->arraySymbol)) continue; if (funcInfo->funcParams.isArgOut(i) || funcArg->lhs() == nullptr) { auto fixedVec = getFixedSubscriptsVector((SgArrayRefExp*)funcArg, ctx->dimensionsNum); fixedSubscripts.push_back(fixedVec); addMessageUsageInFunctionCall(ctx->messages, getDimensionVarName(ctx->arraySymbol, fixedVec), funcName, ctx->loop->lineNum, stmtLineNum); } } } } checkImplicitDirectUsage(ctx, exp->lhs(), stmtLineNum, fixedSubscripts); checkImplicitDirectUsage(ctx, exp->rhs(), stmtLineNum, fixedSubscripts); } // checkImplicitDirectUsage returns masks of array implicit usage (as out argument) // and reference to whole array (like fcall(A, 1)) in any function call in loop // and writes message about each usage static vector> checkImplicitDirectUsage(Context* ctx) { vector> fixedSubscripts; for (SgStatement* st = ctx->loopStmt->lexNext(); st != ctx->loopStmt->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() != PROC_STAT) { for (int i = 0; i < 3; ++i) checkImplicitDirectUsage(ctx, st->expr(i), st->lineNumber(), fixedSubscripts); continue; } // st->variant() == PROC_STAT: SgCallStmt* callStmt = (SgCallStmt*)st; string procName = callStmt->name()->identifier(); FuncInfo* funcInfo = findFuncByName(procName, ctx->allFuncInfo); for (int i = 0; i < callStmt->numberOfArgs(); ++i) { SgExpression* callArg = callStmt->arg(i); if (callArg->symbol() == nullptr || !isEqSymbols(callArg->symbol(), ctx->arraySymbol)) continue; if (funcInfo == nullptr || // no info about function funcInfo->funcParams.isArgOut(i) || // implicit direct usage callArg->lhs() == nullptr) // reference to whole array { auto mask = getFixedSubscriptsVector((SgArrayRefExp*)callArg, ctx->dimensionsNum); fixedSubscripts.push_back(mask); addMessageUsageInFunctionCall(ctx->messages, getDimensionVarName(ctx->arraySymbol, mask), procName, ctx->loop->lineNum, st->lineNumber()); } } } return fixedSubscripts; } static vector getCommonBlockGroupedVar(FuncInfo* curFunc, SgSymbol* varSymbol, const map& commonBlocks) { for (auto& block : commonBlocks) { for (auto& groupedVar : block.second->getGroupedVars()) { for (Variable* var : groupedVar.second) { for (const CommonVariableUse& varUse : var->getAllUse()) { if (varUse.getFileName() == curFunc->fileName && varUse.getFunctionName() == curFunc->funcName && isEqSymbols(varUse.getUseS(), varSymbol)) { return groupedVar.second; } } } } } return vector{}; } // checkIndirectUsage returns masks of array indirect usage in function // (indirect usage is usage through common blocks) and writes messages about it static void checkIndirectUsage(Context* ctx, FuncInfo* calledFunc, vector commonBlockGroupedVar, set& visitedFuncs, vector>& indirectUsageMasks) { if (calledFunc == nullptr) return; if (visitedFuncs.find(calledFunc->funcName) != visitedFuncs.end()) return; visitedFuncs.insert(calledFunc->funcName); for (Variable* commonBlockVar : commonBlockGroupedVar) { for (const CommonVariableUse& varUse : commonBlockVar->getAllUse()) { if (varUse.getFileName() != calledFunc->fileName || varUse.getFunctionName() != calledFunc->funcName) continue; SgStatement* calledFuncStmt = varUse.getFunction(); calledFuncStmt->switchToFile(); vector directArrayRefs = getDirectArrayRefs(calledFuncStmt, varUse.getUseS()); for (auto arrayRef : directArrayRefs) { auto mask = getFixedSubscriptsVector(arrayRef, ctx->dimensionsNum); indirectUsageMasks.push_back(mask); addMessageUsageInFunctionCall(ctx->messages, getDimensionVarName(ctx->arraySymbol, mask), calledFunc->funcName, ctx->loop->lineNum, ctx->loop->lineNum); } ctx->loopStmt->switchToFile(); } } for (FuncInfo* subCalledFunc : calledFunc->callsFromV) checkIndirectUsage(ctx, subCalledFunc, commonBlockGroupedVar, visitedFuncs, indirectUsageMasks); } // checkIndirectUsage returns masks of array indirect usage in any function call in exp // (indirect usage is usage through common blocks) and writes messages about it static void checkIndirectUsage(Context* ctx, SgExpression* exp, vector commonBlockGroupedVar, set& visitedFuncs, vector>& indirectUsageMasks) { if (exp == nullptr) return; if (exp->variant() == FUNC_CALL) { SgFunctionCallExp* funcCallExp = (SgFunctionCallExp*)exp; string funcName = funcCallExp->funName()->identifier(); FuncInfo* funcInfo = findFuncByName(funcName, ctx->allFuncInfo); if (funcInfo != nullptr) checkIndirectUsage(ctx, funcInfo, commonBlockGroupedVar, visitedFuncs, indirectUsageMasks); } checkIndirectUsage(ctx, exp->lhs(), commonBlockGroupedVar, visitedFuncs, indirectUsageMasks); checkIndirectUsage(ctx, exp->rhs(), commonBlockGroupedVar, visitedFuncs, indirectUsageMasks); } // checkIndirectUsage returns masks of array indirect usage in any function call in loop // (indirect usage is usage through common blocks) and writes messages about it static vector> checkIndirectUsage(Context* ctx) { vector> indirectUsageMasks; FuncInfo* currentFunc = getCurrentFunc(ctx->loopStmt, ctx->allFuncInfo); if (currentFunc == nullptr) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); const auto& blocks = ctx->commonBlocks; vector commonBlockGroupedVar = getCommonBlockGroupedVar(currentFunc, ctx->arraySymbol, blocks); if (commonBlockGroupedVar.empty()) return indirectUsageMasks; set visitedFunctions = { currentFunc->funcName }; for (SgStatement* st = ctx->loopStmt->lexNext(); st != ctx->loopStmt->lastNodeOfStmt(); st = st->lexNext()) { if (st->variant() == PROC_STAT) { SgCallStmt* callStmt = (SgCallStmt*)st; string procName = callStmt->name()->identifier(); FuncInfo* calledFunc = findFuncByName(procName, ctx->allFuncInfo); checkIndirectUsage(ctx, calledFunc, commonBlockGroupedVar, visitedFunctions, indirectUsageMasks); } for (int i = 0; i < 3; ++i) checkIndirectUsage(ctx, st->expr(i), commonBlockGroupedVar, visitedFunctions, indirectUsageMasks); } return indirectUsageMasks; } // checkImplicitAndIndirectUsage returns masks of implicit or indirect array usage in loop static vector> checkImplicitAndIndirectUsage(Context* ctx) { vector> implicitMasks = checkImplicitDirectUsage(ctx); vector> indirectMasks = checkIndirectUsage(ctx); implicitMasks.insert(implicitMasks.end(), indirectMasks.begin(), indirectMasks.end()); return implicitMasks; } // filterArrayRefs removes from arrayRefs all refs that are not different from fixedVectors static void filterArrayRefs(Context* ctx, vector& arrayRefs, const vector>& masks) { if (masks.empty()) return; vector filteredArrayRefs; for (auto arrayRef : arrayRefs) { vector arrayRefVec = getFixedSubscriptsVector(arrayRef, ctx->dimensionsNum); bool isDifferent = false; for (auto& mask : masks) { for (int i = 0; i < arrayRefVec.size(); i++) { if (arrayRefVec[i].isFixed && mask[i].isFixed && arrayRefVec[i].value != mask[i].value) { isDifferent = true; break; } } if (isDifferent) break; } if (isDifferent) filteredArrayRefs.push_back(arrayRef); } arrayRefs.swap(filteredArrayRefs); } // getReducedArrayVarName returns name for new reduced array variable, // made by symbol and subscripts: arr, [1, 2] -> arr_1_2 static string getReducedArrayVarName(SgSymbol* symbol, const vector& subscripts) { string name = OriginalSymbol(symbol)->identifier(); if (subscripts.empty()) return name + "_"; name.reserve(name.size() + subscripts.size() * 3); for (int i : subscripts) { if (i < 0) name += "_M" + std::to_string((-1) * i); else name += "_" + std::to_string(i); } return name; } // getReducedArrayVars makes reduced array vars for arrayRefs static ReducedArrayVarsMap getReducedArrayVars(Context* ctx) { ReducedArrayVarsMap reducedArrayVars; SgType* type = ctx->explicitArrayRefs[0]->type(); SgStatement* scope = ctx->loopStmt->getScopeForDeclare(); for (SgArrayRefExp* arrayRef : ctx->explicitArrayRefs) { vector subscripts = getShortFixedSubscriptsVector(ctx, arrayRef); if (reducedArrayVars.find(subscripts) == nullptr) { string name = getReducedArrayVarName(arrayRef->symbol(), subscripts); if (checkSymbNameAndCorrect(name, "_") != name) { int nameNumber = checkSymbNameAndCorrect(name + "__", 0); name = name + "__" + std::to_string(nameNumber); } SgSymbol* newSymbol = new SgSymbol(VARIABLE_NAME, name.c_str(), type, scope); reducedArrayVars.insert(subscripts, newSymbol); } } return reducedArrayVars; } // getVarsToDependOn returns all vars that var depends on static set getVarsToDependOn(SgForStmt* loopStmt, SgSymbol* var) { set dependOn; for (SgStatement* st = loopStmt->lexNext(); st != loopStmt->lastNodeOfStmt(); st = st->lexNext()) if (st->variant() == ASSIGN_STAT && isEqSymbols(st->expr(0)->symbol(), var)) getVariables(st->expr(1), dependOn, { VAR_REF, ARRAY_REF }); return dependOn; } // getDefStmtForReducedArray returns DFE statement for reduced array variable static InsertedStatement getDefStmtForReducedArray(Context* ctx, SgArrayRefExp* arrayRef, const ReducedArrayVarsMap& reducedArrayVars) { vector subscriptVector = getShortFixedSubscriptsVector(ctx, arrayRef); SgSymbol* reducedVar = reducedArrayVars.find(subscriptVector); if (reducedVar == nullptr) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgExpression* lhs = new SgVarRefExp(reducedVar); SgExpression* rhs = new SgValueExp(0); SgStatement* assignStmt = new SgAssignStmt(*lhs, *rhs); return InsertedStatement(TypeOfInsertedStmt::DEF, assignStmt); } // getUseStmtForReducedArray returns USE statement for reduced array variable // (assignment to receiverVar) static InsertedStatement getUseStmtForReducedArray(Context* ctx, SgArrayRefExp* arrayRef, const ReducedArrayVarsMap& reducedArrayVars, SgSymbol* receiverVar) { vector subscriptVector = getShortFixedSubscriptsVector(ctx, arrayRef); SgSymbol* reducedVar = reducedArrayVars.find(subscriptVector); if (reducedVar == nullptr) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgExpression* lhs = new SgVarRefExp(receiverVar); SgExpression* rhs = new SgVarRefExp(reducedVar); SgStatement* assignStmt = new SgAssignStmt(*lhs, *rhs); return InsertedStatement(TypeOfInsertedStmt::USE, assignStmt); } // insertReducedArrayVarStmts inserts in loop assignment statements with reduced vars, // returns vector of inserted statements static vector insertReducedArrayVarStmts(Context* ctx, const ReducedArrayVarsMap& reducedArrayVars, SgSymbol* receiverVar) { vector insertedStmts; for (SgStatement* st = ctx->loopStmt->lexNext(); st != ctx->loopStmt->lastNodeOfStmt(); st = st->lexNext()) { bool isUseStmt = false; int startIndex = 0; if (st->variant() == ASSIGN_STAT) startIndex = 1; for (int i = startIndex; i < 3; ++i) { if (isSymbolInExpression(ctx->arraySymbol, st->expr(i))) // reading from array - USE stmt { vector arrayRefs; fillDirectArrayRefs(st->expr(i), ctx->arraySymbol, arrayRefs); arrayRefs = removeDuplicateArrayRefs(arrayRefs, ctx->fixedDimensionsMask, ctx->regime); if (!arrayRefs.empty()) isUseStmt = true; for (SgArrayRefExp* arrayRef : arrayRefs) { if (!isArrayRefInVector(arrayRef, ctx->explicitArrayRefs)) continue; InsertedStatement useStmt = getUseStmtForReducedArray(ctx, arrayRef, reducedArrayVars, receiverVar); useStmt.relatedToStmt = st; st->insertStmtBefore(*useStmt.insertedStmt, *st->controlParent()); insertedStmts.push_back(useStmt); } } } if (st->variant() == ASSIGN_STAT && isEqSymbols(st->expr(0)->symbol(), ctx->arraySymbol) && // assignment to array - DEF stmt isArrayRefInVector((SgArrayRefExp*)st->expr(0), ctx->explicitArrayRefs)) { InsertedStatement defStmt = getDefStmtForReducedArray(ctx, (SgArrayRefExp*)st->expr(0), reducedArrayVars); defStmt.relatedToStmt = st; defStmt.isRecursive = isUseStmt; st->insertStmtBefore(*defStmt.insertedStmt, *st->controlParent()); insertedStmts.push_back(defStmt); } } return insertedStmts; } // makeTmpVar returns new temporary var with name like tmp_N static SgSymbol* makeTmpVar(Context* ctx) { SgStatement* scope = ctx->loopStmt->getScopeForDeclare(); string varName = "tmp_"; int nameNumber = checkSymbNameAndCorrect(varName, 0); varName = "tmp_" + std::to_string(nameNumber); return new SgSymbol(VARIABLE_NAME, varName.c_str(), ctx->explicitArrayRefs[0]->type(), scope); } // buildDefUsePairs builds pairs of DEF and USE statements for array static vector buildDefUsePairs(Context* ctx, const CFG_Type& CFGraph, const vector& insertedStmts) { vector defUsePairs; string arrayName = ctx->arraySymbol->identifier(); for (const InsertedStatement& useInsertedStmt : insertedStmts) { if (useInsertedStmt.type != TypeOfInsertedStmt::USE) // analysis for USE stmt continue; int useLineNum = useInsertedStmt.relatedToStmt->lineNumber(); // looking for reaching definitions for the current block: auto useInsAndBlock = getInstructionAndBlockByStatement(CFGraph, useInsertedStmt.insertedStmt); auto useArg = useInsAndBlock.first->getArg1(); const auto& RD_In = useInsAndBlock.second->getRD_In(); const auto& RD_forUseArg = RD_In.find(useArg); if (RD_forUseArg == RD_In.end()) // cannot find reaching definitions for argument { addMessageCannotFindRD(ctx->messages, arrayName, useLineNum); continue; } set RD_defArgs = RD_forUseArg->second; // make copy // delete recursive, uninit and definitions that cannot reach use stmt from RD def args: set tmpRD_defArgs; for (int defArgNum : RD_defArgs) { if (defArgNum == SAPFOR::CFG_VAL::UNINIT) continue; auto defInsAndBlock = getInstructionAndBlockByNumber(CFGraph, defArgNum); if (defInsAndBlock.first == nullptr) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgStatement* defStmt = defInsAndBlock.first->getOperator(); auto defInsertedStmt = findInsertedStmt(insertedStmts, defStmt); if (useLineNum <= defInsertedStmt->relatedToStmt->lineNumber()) continue; tmpRD_defArgs.insert(defArgNum); } RD_defArgs.swap(tmpRD_defArgs); SgStatement* defStmt = nullptr; if (RD_defArgs.size() != 1) { bool defIsFound = false; // try to find definition not from RD_defArgs, by search in the block instructions: string defVarName = useInsertedStmt.insertedStmt->expr(1)->symbol()->identifier(); const auto& blockInstructionsVector = useInsAndBlock.second->getInstructions(); for (auto& instruction : blockInstructionsVector) { SgStatement* stmt = instruction->getInstruction()->getOperator(); if (stmt == useInsertedStmt.insertedStmt) break; if (stmt->variant() == ASSIGN_STAT && stmt->expr(0)->symbol()->identifier() == defVarName && !isVarChangedBetween(defVarName, stmt, useInsertedStmt.insertedStmt)) { defIsFound = true; defStmt = stmt; break; } } if (!defIsFound) { addMessageCannotFindRD(ctx->messages, arrayName, useLineNum); continue; } } else { auto defInsAndBlock = getInstructionAndBlockByNumber(CFGraph, *RD_defArgs.begin()); if (defInsAndBlock.first == nullptr) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); defStmt = defInsAndBlock.first->getOperator(); } auto defInsertedStmt = findInsertedStmt(insertedStmts, defStmt); if (defInsertedStmt == insertedStmts.end()) { addMessageCannotFindRD(ctx->messages, arrayName, useLineNum); continue; } //don't substitute def stmt into use, if def is recursive if (defInsertedStmt->isRecursive) { addMessageRecursiveDependency(ctx->messages, arrayName, useLineNum); continue; } SgAssignStmt* def = (SgAssignStmt*)defInsertedStmt->relatedToStmt; SgAssignStmt* use = (SgAssignStmt*)useInsertedStmt.relatedToStmt; defUsePairs.push_back(make_pair(def, use)); } return defUsePairs; } // findChildLoop returns LoopGraph for provided loop statement static LoopGraph* findLoop(LoopGraph* outerLoop, SgForStmt* loopStmt) { SgStatement* outerLoopStmt = outerLoop->loop->GetOriginal(); if (outerLoopStmt->id() == loopStmt->id()) return outerLoop; for (auto childLoop : outerLoop->children) { auto childLoopGraph = findLoop(childLoop, loopStmt); if (childLoopGraph != nullptr) return childLoopGraph; } return nullptr; } // minCommonAncestor finds least common ancestor of a and b loops in loop graph tree with root parent static LoopGraph* leastCommonAncestor(LoopGraph* a, LoopGraph* b, LoopGraph* parent) { LoopGraph* tmp; int aDepth = 0; tmp = a; while (tmp != parent) { aDepth++; tmp = tmp->parent; } int bDepth = 0; tmp = b; while (tmp != parent) { bDepth++; tmp = tmp->parent; } while (aDepth != bDepth) { if (aDepth > bDepth) { a = a->parent; aDepth--; } else { b = b->parent; bDepth--; } } while (a->lineNum != b->lineNum) { a = a->parent; b = b->parent; } return a; } // fillFullFixedSubscriptsVectorsOfAllVars return vector of pairs (name of var, its fixed subscripts vector) // of all VAR_REF and ARRAY_REF vars in exp static void fillFixedSubscriptsVectorsOfAllVars(SgExpression* exp, vector>>& vec, SgStatement* stmt = nullptr) { if (exp == nullptr) return; if (exp->symbol() != nullptr) { if (exp->variant() == VAR_REF) { for (const auto& elem : vec) if (elem.first == exp->symbol()->identifier()) return; vec.push_back(make_pair(exp->symbol()->identifier(), vector{})); } else if (exp->variant() == ARRAY_REF) { vec.push_back(make_pair(exp->symbol()->identifier(), getFixedSubscriptsVector((SgArrayRefExp*)exp, 0, stmt))); SgExprListExp* exprList = (SgExprListExp*)exp->lhs(); for (int i = 0; i < exprList->length(); ++i) fillFixedSubscriptsVectorsOfAllVars(exprList->elem(i), vec, stmt); } return; } fillFixedSubscriptsVectorsOfAllVars(exp->lhs(), vec, stmt); fillFixedSubscriptsVectorsOfAllVars(exp->rhs(), vec, stmt); } // fixedSubscriptLess checks if left FixedSubscript is less than right static bool fixedSubscriptLess(const ArraySubscript& left, const ArraySubscript& right) { if (left.isFixed && right.isFixed && left.value < right.value) return true; if (left.isFixed && right.isRegIndex && right.regExprStart.coefA == 0 && left.value < right.regExprStart.coefB) return true; if (left.isRegIndex && right.isFixed && left.regExprEnd.coefA == 0 && left.regExprEnd.coefB < right.value) return true; if (left.isRegIndex && right.isRegIndex) return left.regExprEnd < right.regExprStart; return false; } // fixedSubscriptLess checks if left and right FixedSubscripts are different, // using empirical methods static bool arePossibleDifferent(ArraySubscript left, ArraySubscript right) { if (left.isFixed && right.isRegIndex && right.regExprStart == right.regExprEnd) { return true; // in general, this is not true } return false; } // areDifferentRefs checks if exp (var reference) is different from var static bool areDifferentRefs(Context* ctx, SgExpression* exp, const pair>& var, SgStatement* stmt) { if (exp->symbol()->identifier() != var.first) return true; if (exp->variant() == VAR_REF) return false; vector leftVec = getFixedSubscriptsVector((SgArrayRefExp*)exp, 0, stmt); if (leftVec.size() != var.second.size()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (int i = 0; i < leftVec.size(); i++) { if (fixedSubscriptLess(leftVec[i], var.second[i]) || fixedSubscriptLess(var.second[i], leftVec[i])) { return true; } else if (arePossibleDifferent(leftVec[i], var.second[i])) { string varRefStr = var.first + "("; for (int i = 0; i < var.second.size(); ++i) { varRefStr += var.second[i].toString(); if (i != var.second.size() - 1) varRefStr += ","; } varRefStr += ")"; addMessagePossibleDifferentAssumption(ctx->messages, ctx->arraySymbol->identifier(), exp->sunparse(), varRefStr, stmt->lineNumber()); return true; } } return false; } static pair> findVarInRDSet(const map>& RD_In, const string& var) { for (auto& RD_InElem : RD_In) { string elemName = RD_InElem.first->getValue(); size_t pos = elemName.find('%'); if (pos == string::npos) continue; if (var == elemName.substr(pos+1, elemName.length() - pos - 1)) return RD_InElem; } return make_pair(nullptr, set{}); } // checkDefUsePair checks if def statement from pair can be substituted into use statement // and creates messages static bool checkDefUsePair(Context* ctx, const DefUseStmtsPair& defUse, const CFG_Type& CFGraph) { if (defUse.first->lineNumber() > defUse.second->lineNumber()) return false; string arrayName = ctx->arraySymbol->identifier(); vector>> dependOnVars; SgArrayRefExp* defRef = (SgArrayRefExp*)defUse.first->expr(0); vector arrayUseRefs = getDirectArrayRefsFromSingleStmt(defUse.second, ctx->arraySymbol); for (auto useRef : arrayUseRefs) { map varToExpMap; varToExpMap = getVarToExpMap(defRef, useRef, ctx->fixedDimensionsMask, ctx->regime); SgExpression* expToSubst = defUse.first->rhs()->copyPtr(); expToSubst = replaceVarsWithExps(expToSubst, varToExpMap); fillFixedSubscriptsVectorsOfAllVars(expToSubst, dependOnVars, defUse.second); } vector iterationVars{}; fillIterationVars(defUse.second, nullptr, iterationVars); auto defInsAndBlock = getInstructionAndBlockByStatement(CFGraph, defUse.first); const auto& defRD_In = defInsAndBlock.second->getRD_In(); auto useInsAndBlock = getInstructionAndBlockByStatement(CFGraph, defUse.second); const auto& useRD_In = useInsAndBlock.second->getRD_In(); for (const auto& var : dependOnVars) { if (var.second.size() == 0) // check scalar vars { // iteration var doesn't obstruct the removing: bool isIterationVar = false; for (auto iterationVar : iterationVars) { if (iterationVar->identifier() == var.first) { isIterationVar = true; break; } } if (isIterationVar) continue; auto defArg = findVarInRDSet(defRD_In, var.first); if (defArg.first == nullptr) // there is no any RD for common vars or parameters continue; auto useArg = findVarInRDSet(useRD_In, var.first); if (defArg.second.size() != 1 || useArg.second.size() != 1 || *defArg.second.begin() != *useArg.second.begin()) { if (defInsAndBlock.second->getNumber() == useInsAndBlock.second->getNumber()) if (!isVarChangedBetween(var.first, defUse.first, defUse.second)) continue; addMessageDependOnNonInvariant(ctx->messages, arrayName, var.first, defUse.first->lineNumber()); return false; } } } // checking arrays: auto defLoopStmt = getScopeLoopStmt(defUse.first); auto useLoopStmt = getScopeLoopStmt(defUse.second); LoopGraph* loop = ctx->loop; while (loop->perfectLoop != 1) loop = loop->children[0]; LoopGraph* defLoop = findLoop(loop, defLoopStmt); LoopGraph* useLoop = findLoop(loop, useLoopStmt); if (!defLoopStmt || !useLoopStmt || !defLoop || !useLoop) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); int minCommonLoopLine = leastCommonAncestor(defLoop, useLoop, loop)->lineNum; if (defLoop->lineNum != minCommonLoopLine) while (defLoop->parent->lineNum != minCommonLoopLine) defLoop = defLoop->parent; if (useLoop->lineNum != minCommonLoopLine) while (useLoop->parent->lineNum != minCommonLoopLine) useLoop = useLoop->parent; int defLoopLine = defLoop->lineNum; int useLoopLine = useLoop->lineNum; SgStatement *startStmt = nullptr, *endStmt = nullptr; if (defLoopLine != minCommonLoopLine && useLoopLine != minCommonLoopLine) { startStmt = defLoop->loop; endStmt = useLoop->loop->lastNodeOfStmt(); } else if (defLoopLine != minCommonLoopLine && useLoopLine == minCommonLoopLine) { startStmt = defLoop->loop; endStmt = defUse.second; } else if (defLoopLine == minCommonLoopLine && useLoopLine != minCommonLoopLine) { startStmt = defUse.first; endStmt = useLoop->loop->lastNodeOfStmt(); } else if (defLoopLine == minCommonLoopLine && useLoopLine == minCommonLoopLine) { startStmt = defUse.first; endStmt = defUse.second; } else return false; for (const auto& var : dependOnVars) { for (SgStatement* st = startStmt; st != endStmt; st = st->lexNext()) { if (st == defUse.second) continue; if (st->variant() == ASSIGN_STAT && !areDifferentRefs(ctx, st->expr(0), var, st)) { addMessageDependOnNonInvariant(ctx->messages, arrayName, var.first, defUse.first->lineNumber()); return false; } } } return true; } // getPrivateArraysFromUserDirs returns private arrays from user directives ANALYSIS PRIVATE static set getPrivateArraysForLoop(LoopGraph* loop, const UsersDirectives& dirs) { set privateArrays; auto loopDirectives = dirs.find(make_pair(loop->fileName.c_str(), loop->lineNum)); if (loopDirectives == dirs.end()) // no directives for loop return privateArrays; set privateVars; for (SgStatement* dir : loopDirectives->second) { Statement* dirStmt = new Statement(dir); fillPrivatesFromComment(dirStmt, privateVars); delete dirStmt; } for (Symbol* var : privateVars) if (var->type()->variant() == T_ARRAY) privateArrays.insert(var->GetOriginal()); return privateArrays; } static void removePrivateAnalyze(Context *ctx) { // inserting assignment to reduced array variables for getting reaching definitions analysis: auto reducedArrayVars = getReducedArrayVars(ctx); SgSymbol* receiverVar = makeTmpVar(ctx); auto insertedStmts = insertReducedArrayVarStmts(ctx, reducedArrayVars, receiverVar); // declare reduced array variables and receiver: insertedStmts.push_back(InsertedStatement( TypeOfInsertedStmt::DECLARATION, makeDeclaration(ctx->loopStmt, reducedArrayVars.getAllVars(), nullptr) )); insertedStmts.push_back(InsertedStatement( TypeOfInsertedStmt::DECLARATION, makeDeclaration(ctx->loopStmt, vector {receiverVar}, nullptr) )); CFG_Type CFG_ForFunc = buildCFGforCurrentFunc(ctx->loopStmt, SAPFOR::CFG_Settings(true, true), ctx->commonBlocks, ctx->allFuncInfo); if (CFG_ForFunc.empty()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto defUseStmtsPairs = buildDefUsePairs(ctx, CFG_ForFunc, insertedStmts); if (!defUseStmtsPairs.empty()) // DEF-USE pairs were build successfully { vector resultDefUsePairs; for (auto& pair : defUseStmtsPairs) { if (checkDefUsePair(ctx, pair, CFG_ForFunc)) { resultDefUsePairs.push_back(pair); // don't revert substitutions in use and def stmts: cancelRevertionForStatement(ctx->filename, pair.first, 1); cancelRevertionForStatement(ctx->filename, pair.second, 0); cancelRevertionForStatement(ctx->filename, pair.second, 1); cancelRevertionForStatement(ctx->filename, pair.second, 2); } } PrivateToRemove newPrivateToRemove; newPrivateToRemove.loop = ctx->loop; newPrivateToRemove.varSymbol = ctx->arraySymbol; newPrivateToRemove.regime = ctx->regime; newPrivateToRemove.defUseStmtsPairs.swap(resultDefUsePairs); newPrivateToRemove.fixedDimensions.swap(ctx->fixedDimensionsMask); privatesToRemoveGlobal.push_back(newPrivateToRemove); } // delete inserted statements: for (auto& stmt : insertedStmts) stmt.insertedStmt->deleteStmt(); deleteCFG(CFG_ForFunc); } void removePrivatesAnalysis(string filename, vector& loopGraphs, vector& messages, const UsersDirectives& usersDirectives, const map& commonBlocks, const map>& allFuncInfo) { for (LoopGraph* loop : loopGraphs) { if (!loop->isFor) continue; SgForStmt* loopStmt = (SgForStmt*)loop->loop->GetOriginal(); set privateArrays = getPrivateArraysForLoop(loop, usersDirectives); if (privateArrays.empty()) continue; while (true) { SgSymbol* arrayToRemove = nullptr; vector arrayRefs; // choose arrayToRemove: for (SgSymbol* arrayToCheck : privateArrays) { arrayRefs = getDirectArrayRefs(loopStmt, arrayToCheck); if (arrayRefs.empty()) // no references to array continue; set dependOnVars = getVarsToDependOn(loopStmt, arrayToCheck); bool skip = false; for (string dependOnVar : dependOnVars) for (SgSymbol* notChecked : privateArrays) if (dependOnVar == notChecked->identifier() && !isEqSymbols(arrayToCheck, notChecked)) skip = true; if (skip) // check this array again later continue; privateArrays.erase(arrayToCheck); arrayToRemove = arrayToCheck; break; // arrayToRemove is chosen } if (arrayToRemove == nullptr) // no array to remove break; Context context = Context{allFuncInfo, commonBlocks, messages, filename}; context.regime = Regime::DEFLT; context.loop = loop; context.loopStmt = loopStmt; context.dimensionsNum = ((SgArrayType*)arrayToRemove->type())->dimension(); context.arraySymbol = arrayToRemove; string arrayName = arrayToRemove->identifier(); auto filterMasks = checkImplicitAndIndirectUsage(&context); filterArrayRefs(&context, arrayRefs, filterMasks); context.explicitArrayRefs.swap(arrayRefs); if (context.explicitArrayRefs.empty()) continue; if (!checkLoopAlignmentMatching(&context)) { addMessageVarNotAlignedWithLoop(messages, arrayName, context.loop->lineNum); continue; } context.fixedDimensionsMask = getFixedDimensionsMask(&context); if (!context.fixedDimensionsMask.empty() && checkFixedDimensionsMaskMatching(&context) && checkDefStmtRefsMatchesMask(&context)) { removePrivateAnalyze(&context); } else if (checkRegularIndexRefs(&context)) { context.regime = Regime::REGULAR_INDEXES; removePrivateAnalyze(&context); } else addMessageDoesNotMatchMask(messages, arrayName, context.loop->lineNum); } } for (LoopGraph* loop : loopGraphs) { removePrivatesAnalysis(filename, loop->children, messages, usersDirectives, commonBlocks, allFuncInfo); } }