From bbb1f0895968ede5ef88393739df4e92cf8b6e73 Mon Sep 17 00:00:00 2001 From: Grigorii Gusev Date: Tue, 16 Apr 2024 00:06:24 +0300 Subject: [PATCH] private_remoing: add loop alignment check and fix messages --- .../_src/Transformations/private_removing.cpp | 249 +++++++++++++++--- .../experts/Sapfor_2017/_src/Utils/errors.h | 10 +- .../_src/Utils/russian_errors_text.txt | 4 +- 3 files changed, 226 insertions(+), 37 deletions(-) diff --git a/sapfor/experts/Sapfor_2017/_src/Transformations/private_removing.cpp b/sapfor/experts/Sapfor_2017/_src/Transformations/private_removing.cpp index 2bb2b7a..58bb712 100644 --- a/sapfor/experts/Sapfor_2017/_src/Transformations/private_removing.cpp +++ b/sapfor/experts/Sapfor_2017/_src/Transformations/private_removing.cpp @@ -25,6 +25,21 @@ struct RegularExpr { string var; RegularExpr(): coefA(0), coefB(0), var("") {} + + 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) @@ -52,13 +67,38 @@ struct ArraySubscript { RegularExpr regExprStart; RegularExpr regExprEnd; - ArraySubscript() { + 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 @@ -337,15 +377,17 @@ static void fillIterationVars(SgStatement* stmt, SgStatement* outerLoopStmt, vec * Block of creating messages functions: * * ************************************* */ -static void addMessageRemoveLoop(vector& messages, int loopLineNum) +static void addMessageVarNotAlignedWithLoop(vector& messages, string varName, int loopLineNum) { - __spf_print(1, "NOTE: loop on line %d was removed\n", 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"Loop on line %d was removed", loopLineNum); - __spf_printToLongBuf(messageR, R198, loopLineNum); + __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::NOTE, loopLineNum, messageR, messageE, 2024)); + messages.push_back(Messages(typeMessage::WARR, loopLineNum, messageR, messageE, 2024)); } static void addMessageRemovePrivateVar(vector& messages, string varName, int loopLineNum) @@ -385,19 +427,19 @@ static void addMessageCannotFindRD(vector& messages, string varName, i messages.push_back(Messages(typeMessage::WARR, loopLineNum, messageR, messageE, 2021)); } -// TODO: unused: -//static void addMessageMoreThanOneRD(vector& messages, string varName, int loopLineNum) -//{ -// __spf_print(1, "WARR: cannot remove private var '%s' - more than one definition reaches the statement in line %d\n", -// varName.c_str(), loopLineNum); -// -// wstring messageE, messageR; -// __spf_printToLongBuf(messageE, L"Cannot remove private var '%s' - more than one definition reaches the statement", -// to_wstring(varName).c_str()); -// __spf_printToLongBuf(messageR, R193, to_wstring(varName).c_str()); -// -// messages.push_back(Messages(typeMessage::WARR, loopLineNum, messageR, messageE, 2020)); -//} +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) { @@ -963,6 +1005,126 @@ static vector getShortFixedSubscriptsVector(Context* ctx, SgArrayRefExp* ar return getShortFixedSubscriptsVector(arrayRef, ctx->fixedDimensionsMask, ctx->regime, iterationVars); } +// 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) @@ -1848,9 +2010,8 @@ static bool fixedSubscriptLess(const ArraySubscript& left, const ArraySubscript& // fixedSubscriptLess checks if left and right FixedSubscripts are different, // using empirical methods -static bool possibleDifferent(ArraySubscript left, ArraySubscript right) +static bool arePossibleDifferent(ArraySubscript left, ArraySubscript right) { - // TODO: add warning? if (left.isFixed && right.isRegIndex && right.regExprStart == right.regExprEnd) { return true; // in general, this is not true } @@ -1858,9 +2019,9 @@ static bool possibleDifferent(ArraySubscript left, ArraySubscript right) return false; } -// isDifferentRefs checks if exp (var reference) is different from var. Refs are different -// if they has at least one different fixed subscript: arr(i, 1) is different from arr(j, 2) -static bool isDifferentRefs(SgExpression* exp, const pair>& var, SgStatement* stmt) +// 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; @@ -1876,11 +2037,26 @@ static bool isDifferentRefs(SgExpression* exp, const pairmessages, ctx->arraySymbol->identifier(), + exp->sunparse(), varRefStr, stmt->lineNumber()); + return true; + } + } return false; @@ -1972,7 +2148,7 @@ static bool checkDefUsePair(Context* ctx, const DefUseStmtsPair& defUse, const C auto useLoopStmt = getScopeLoopStmt(defUse.second); LoopGraph* loop = ctx->loop; - while (loop->perfectLoop != 1) // (what is it? - TODO: may be remove it) + while (loop->perfectLoop != 1) loop = loop->children[0]; LoopGraph* defLoop = findLoop(loop, defLoopStmt); @@ -2022,7 +2198,7 @@ static bool checkDefUsePair(Context* ctx, const DefUseStmtsPair& defUse, const C { if (st == defUse.second) continue; - if (st->variant() == ASSIGN_STAT && !isDifferentRefs(st->expr(0), var, st)) + if (st->variant() == ASSIGN_STAT && !areDifferentRefs(ctx, st->expr(0), var, st)) { addMessageDependOnNonInvariant(ctx->messages, arrayName, var.first, defUse.first->lineNumber()); @@ -2179,6 +2355,13 @@ void removePrivatesAnalysis(string filename, if (context.explicitArrayRefs.empty()) continue; + if (!checkLoopAlignmentMatching(&context)) + { + addMessageVarNotAlignedWithLoop(messages, context.arraySymbol->identifier(), + context.loop->lineNum); + continue; + } + context.fixedDimensionsMask = getFixedDimensionsMask(&context); if (!context.fixedDimensionsMask.empty() && @@ -2194,10 +2377,16 @@ void removePrivatesAnalysis(string filename, removePrivateAnalyze(&context); } else - addMessageDoesNotMatchMask(messages, context.arraySymbol->identifier(), context.loop->lineNum); + { + addMessageDoesNotMatchMask(messages, context.arraySymbol->identifier(), + context.loop->lineNum); + } } } for (LoopGraph* loop : loopGraphs) - removePrivatesAnalysis(filename, loop->children, messages, usersDirectives, commonBlocks, allFuncInfo); + { + removePrivatesAnalysis(filename, loop->children, messages, + usersDirectives, commonBlocks, allFuncInfo); + } } diff --git a/sapfor/experts/Sapfor_2017/_src/Utils/errors.h b/sapfor/experts/Sapfor_2017/_src/Utils/errors.h index 4a35466..7cf30ad 100644 --- a/sapfor/experts/Sapfor_2017/_src/Utils/errors.h +++ b/sapfor/experts/Sapfor_2017/_src/Utils/errors.h @@ -95,12 +95,12 @@ enum typeMessage { WARR, ERROR, NOTE }; // 16 "cannot remove private var '%s' - it doesn't match any fixed dimensions mask" // 17 cannot remove private var '%s' - it has recursive dependency or it depends on non-invariant var '%s' // 18 "private variable '%s' was removed" or "private variable '%s' was partially removed" -// 19 "cannot remove private var '%s' - it doesn't have any fixed dimensions" +// 19 "Removing of private var '%s' was made with assumption that references '%s' and '%s' are different" // 20 "cannot remove private var '%s' - more than one definition reaches the statement" // 21 "cannot remove private var '%s' - cannot find reaching definition for the statement" // 22 "cannot transform ..." // 23 "cannot transform ..." -// 24 "loop on line %d was removed" +// 24 "Cannot remove private var '%s' - its references have different alignment with the loop" // 25 "Cannot remove private var '%s' - it is used in the call of function '%s'" // 30xx PARALLEL GROUP @@ -521,9 +521,9 @@ static const wchar_t *R190 = L"R190:%s#%s"; static const wchar_t *R191 = L"R191:%s"; static const wchar_t *R201 = L"R201:%s"; //2019 -static const wchar_t *R192 = L"R192:%s"; +static const wchar_t *R192 = L"R192:%s#%s#%s"; //2020 -static const wchar_t *R193 = L"R193:%s"; +// static const wchar_t *R193 = L"R193:%s"; //2021 static const wchar_t *R194 = L"R194:%s"; //2022 @@ -531,7 +531,7 @@ static const wchar_t *R196 = L"R196:"; //2023 static const wchar_t *R197 = L"R197:"; //2024 -static const wchar_t *R198 = L"R198:%d"; +static const wchar_t *R198 = L"R198:%s"; //2025 static const wchar_t *R203 = L"R203:%s#%s"; diff --git a/sapfor/experts/Sapfor_2017/_src/Utils/russian_errors_text.txt b/sapfor/experts/Sapfor_2017/_src/Utils/russian_errors_text.txt index 7c5e39f..ef25a33 100644 --- a/sapfor/experts/Sapfor_2017/_src/Utils/russian_errors_text.txt +++ b/sapfor/experts/Sapfor_2017/_src/Utils/russian_errors_text.txt @@ -231,7 +231,7 @@ R190 = "Нельзя удалить приватную переменную '%s' R191 = "Приватная переменная '%s' была удалена" R201 = "Приватная переменная '%s' была частично удалена" //2019 -R192 = "Нельзя удалить приватную переменную '%s' - она не имеет фиксированных измерений" +R192 = "Удаление приватной переменной '%s' было выполнено в предположении, что выражения '%s' и '%s' различны" //2020 R193 = "Нельзя удалить приватную переменную '%s' - более одного определения достигают оператора" //2021 @@ -241,7 +241,7 @@ R196 = "Невозможно выполнить преобразование ц //2023 R197 = "Преобразование не может быть выполнено - не произошло никаких изменений в коде" //2024 -R198 = "Цикл на строке %d был удалён" +R198 = "Нельзя удалить приватную переменную '%s' - обращения к ней имеют разное выравнивание с циклом" //2025 R203 = "Нельзя удалить приватную переменную '%s' - она используется в вызове функции %s"