#include "../Utils/leak_detector.h" #include #include #include #include #include "dvm.h" #include "verifications.h" #include "../ParallelizationRegions/ParRegions.h" #include "../Utils/utils.h" #include "../Utils/SgUtils.h" #include "../Utils/errors.h" using std::vector; using std::map; using std::pair; using std::string; using std::wstring; using std::make_pair; using std::set; bool EndDoLoopChecker(SgFile *file, vector &currMessages) { int funcNum = file->numberOfFunctions(); bool checkOK = true; for (int i = 0; i < funcNum; ++i) { SgStatement *st = file->functions(i); SgStatement *lastNode = st->lastNodeOfStmt(); while (st != lastNode) { if (st == NULL) { __spf_print(1, "internal error in analysis, parallel directives will not be generated for this file!\n"); break; } if (st->variant() == CONTAINS_STMT) break; if (st->variant() == FOR_NODE) { SgForStmt *currSt = (SgForStmt*)st; if (currSt->isEnddoLoop() == 0) { __spf_print(1, " ERROR: Loop on line %d does not have END DO\n", st->lineNumber()); currMessages.push_back(Messages(ERROR, st->lineNumber(), R51, L"This loop does not have END DO format", 1018)); checkOK = false; } } if (st->variant() == FORALL_NODE || st->variant() == FORALL_STAT || st->variant() == WHERE_BLOCK_STMT || st->variant() == WHERE_NODE) { __spf_print(1, " ERROR: Loop on line %d does not have END DO\n", st->lineNumber()); currMessages.push_back(Messages(ERROR, st->lineNumber(), R50, L"This loop does not have END DO format", 1018)); checkOK = false; } if (st->variant() == WHILE_NODE) { auto last = st->lastNodeOfStmt(); auto str = string(last->unparse()); convertToLower(str); if (last->variant() != CONTROL_END || str.find("enddo") == string::npos) { __spf_print(1, " ERROR: Loop on line %d does not have END DO\n", st->lineNumber()); currMessages.push_back(Messages(ERROR, st->lineNumber(), R50, L"This loop does not have END DO format", 1018)); checkOK = false; } } st = st->lexNext(); } } return checkOK; } bool DvmDirectiveChecker(SgFile *file, map> &errors, const int keepDvmDirectives, const int ignoreDvmChecker) { if (keepDvmDirectives != 0) return true; int funcNum = file->numberOfFunctions(); bool checkOK = true; __spf_print(1, " ignoreDvmChecker = %d\n", ignoreDvmChecker); for (int i = 0; i < funcNum; ++i) { SgStatement *st = file->functions(i); SgStatement *lastNode = st->lastNodeOfStmt(); for ( ; st != lastNode; st = st->lexNext()) { if (st->variant() == CONTAINS_STMT) break; if (isDVM_stat(st) && (st->variant() != DVM_INTERVAL_DIR && st->variant() != DVM_ENDINTERVAL_DIR)) { errors[st->fileName()].push_back(st->lineNumber()); checkOK = false; } } } return checkOK; } bool EquivalenceChecker(SgFile *file, const string &fileName, const vector ®ions, map> &currMessages) { int funcNum = file->numberOfFunctions(); bool checkOK = true; for (int i = 0; i < funcNum; ++i) { SgStatement *st = file->functions(i); SgStatement *lastNode = st->lastNodeOfStmt(); int lastLine = 1; while (st != lastNode) { lastLine = st->lineNumber(); if (st == NULL) { __spf_print(1, "internal error in analysis, parallel directives will not be generated for this file!\n"); break; } if (st->variant() == EQUI_STAT) { auto eqList = isSgNestedVarListDeclStmt(st); if (eqList == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); bool needToReport = false; bool checkTmp = true; //TODO: need to check variables in region if (getRegionByLine(regions, st->fileName(), lastLine)) { checkTmp = false; needToReport = true; } else needToReport = true; bool onlyVars = true; for (int z = 0; z < eqList->numberOfLists(); ++z) { auto list = eqList->list(z); while (list) { SgSymbol* symb = list->lhs()->symbol(); checkNull(symb, convertFileName(__FILE__).c_str(), __LINE__); if (isArrayRef(list->lhs()) || symb->type() && symb->type()->variant() == T_ARRAY) { SgStatement* decl = declaratedInStmt(symb); DIST::Array* array = getArrayFromDeclarated(decl, symb->identifier()); if (array && !array->IsNotDistribute()) onlyVars = false; } list = list->rhs(); } } if (onlyVars) { needToReport = false; checkTmp = true; } checkOK &= checkTmp; if (needToReport) { __spf_print(1, "The equivalence operator is not supported yet at line %d of file %s\n", st->lineNumber(), st->fileName()); currMessages[st->fileName()].push_back(Messages(checkOK ? WARR : ERROR, st->lineNumber(), R70, L"An equivalence operator is not supported yet", 1038)); } } if (st->variant() == PAUSE_NODE) { checkOK &= false; __spf_print(1, "The PAUSE operator is not supported yet at line %d of file %s\n", st->lineNumber(), st->fileName()); currMessages[st->fileName()].push_back(Messages(ERROR, st->lineNumber(), R69, L"An PAUSE operator is deprecated to parallel", 1038)); } st = st->lexNext(); } } return checkOK; } bool CommonBlockChecker(SgFile *file, const string &fileName, const map &commonBlocks, map> &messages) { bool checkOK = true; for (auto& block : commonBlocks) { auto vars = block.second->getVariables(); for (int i = 0; i < vars.size(); i++) { int pos = vars[i]->getPosition(); varType type = vars[i]->getType(); //only this file bool needToSkip = true; const CommonVariableUse *currUse = NULL; for (auto &elem : vars[i]->getAllUse()) { if (elem.getFile() == file) { needToSkip = false; currUse = &elem; } } if (needToSkip) continue; for (int j = i + 1; j < vars.size(); j++) { bool needToReport = false; auto typeMessage = NOTE; if ((vars[j]->getPosition() == pos) && ((vars[j]->getType() == ARRAY && type != ARRAY) || (vars[j]->getType() != ARRAY && type == ARRAY))) { DIST::Array *array = NULL; if (vars[j]->getType() == ARRAY) array = getArrayFromDeclarated(vars[j]->getDeclarated(), vars[j]->getName()); else array = getArrayFromDeclarated(vars[i]->getDeclarated(), vars[i]->getName()); if (array == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (array->IsNotDistribute()) typeMessage = WARR; else { checkOK = false; typeMessage = ERROR; } needToReport = true; } else if (vars[j]->getPosition() == pos && vars[j]->getType() != type) { typeMessage = WARR; needToReport = true; } if (needToReport) { wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Variables '%s' and '%s' in one storage association (common block '%s') have different types (files - %s:%d and %s:%d)", to_wstring(vars[i]->getName()).c_str(), to_wstring(vars[j]->getName()).c_str(), to_wstring(block.first).c_str(), to_wstring(vars[i]->getDeclarated()->fileName()).c_str(), vars[i]->getDeclarated()->lineNumber(), to_wstring(vars[j]->getDeclarated()->fileName()).c_str(), vars[j]->getDeclarated()->lineNumber()); __spf_printToLongBuf(messageR, R71, to_wstring(vars[i]->getName()).c_str(), to_wstring(vars[j]->getName()).c_str(), to_wstring(block.first).c_str(), to_wstring(vars[i]->getDeclarated()->fileName()).c_str(), vars[i]->getDeclarated()->lineNumber(), to_wstring(vars[j]->getDeclarated()->fileName()).c_str(), vars[j]->getDeclarated()->lineNumber()); messages[vars[i]->getDeclarated()->fileName()].push_back(Messages(typeMessage, vars[i]->getDeclarated()->lineNumber(), messageR, messageE, 1039)); messages[vars[j]->getDeclarated()->fileName()].push_back(Messages(typeMessage, vars[j]->getDeclarated()->lineNumber(), messageR, messageE, 1039)); } } } } return checkOK; } bool FunctionsChecker(SgFile *file, map> &funcNames, map> &currMessages) { int funcNum = file->numberOfFunctions(); bool checkOK = true; for (int i = 0; i < funcNum; ++i) { SgStatement *st = file->functions(i); SgStatement *lastNode = st->lastNodeOfStmt(); if (st->controlParent()->variant() == GLOBAL) { string funcName = st->symbol()->identifier(); auto it = funcNames.find(funcName); if (it == funcNames.end()) funcNames[funcName] = make_pair(file->filename(), st->lineNumber()); else { __spf_print(1, "the same function name in different places was found: func %s, places %s:%d and %s:%d\n", it->first.c_str(), it->second.first.c_str(), it->second.second, file->filename(), st->lineNumber()); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Function '%s' was declared in more than one place: '%s':%d and '%s':%d", to_wstring(funcName).c_str(), to_wstring(it->second.first).c_str(), it->second.second, to_wstring(file->filename()).c_str(), st->lineNumber()); __spf_printToLongBuf(messageR, R92, to_wstring(funcName).c_str(), to_wstring(it->second.first).c_str(), it->second.second, to_wstring(file->filename()).c_str(), st->lineNumber()); currMessages[st->fileName()].push_back(Messages(ERROR, st->lineNumber(), messageR, messageE, 1048)); currMessages[it->second.first].push_back(Messages(ERROR, it->second.second, messageR, messageE, 1048)); checkOK = false; } if (isIntrinsicFunctionName(funcName.c_str())) { __spf_print(1, "the same function name in different places was found: func %s, places %s:%d and %s:%d\n", funcName.c_str(), file->filename(), st->lineNumber(), "intrinsic", 0); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Function '%s' was declared in more than one place: '%s':%d and '%s':%d", to_wstring(funcName).c_str(), to_wstring(file->filename()).c_str(), st->lineNumber(), to_wstring("intrinsic").c_str(), 0); __spf_printToLongBuf(messageR, R92, to_wstring(funcName).c_str(), to_wstring(file->filename()).c_str(), st->lineNumber(), to_wstring("intrinsic").c_str(), 0); currMessages[st->fileName()].push_back(Messages(ERROR, st->lineNumber(), messageR, messageE, 1048)); checkOK = false; } } } return checkOK; } void fillFunctionInfo(SgFile* file, map>& funcInfo) { const int funcNum = file->numberOfFunctions(); const string fileName = file->filename(); for (int i = 0; i < funcNum; ++i) { SgStatement* st = file->functions(i); SgStatement* lastNode = st->lastNodeOfStmt(); if (st->fileName() != fileName) continue; Function newFunc; newFunc.name = st->symbol()->identifier(); newFunc.line = st->lineNumber(); newFunc.file = file->filename(); newFunc.point = st; if (isSgProgHedrStmt(st) == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); newFunc.parametersCount = ((SgProgHedrStmt*)st)->numberOfParameters(); auto cp = st->controlParent(); if (cp->variant() == GLOBAL) newFunc.type = 1; else if (cp->variant() == MODULE_STMT) { if (string(cp->fileName()) != file->filename()) continue; // add module functions only once newFunc.type = 0; newFunc.parentName = cp->symbol()->identifier(); } else { auto cpcp = cp->controlParent(); if (cpcp->variant() == GLOBAL) { newFunc.type = 2; newFunc.parentName = cp->symbol()->identifier(); } else { newFunc.type = 3; newFunc.parentName = cp->symbol()->identifier(); newFunc.globalName = cpcp->symbol()->identifier(); } } funcInfo[newFunc.name].push_back(newFunc); } } //TODO: for the same parameters count // add support of optilnal parameters static SgSymbol* resolveName(SgFile* file, SgStatement* context, SgExpression* parameters, const vector& functions, const string& name) { SgSymbol* corrected = NULL; int parCount = 0; while (parameters) { parCount++; parameters = parameters->rhs(); } auto cp = getFuncStat(context, { MODULE_STMT } ); auto cpcp = cp->controlParent(); auto globalP = cpcp->controlParent(); const string cpName = cp->symbol()->identifier(); const string cpcpName = (cpcp->variant() == GLOBAL) ? "" : cpcp->symbol()->identifier(); const string global = globalP ? ((globalP->variant() != GLOBAL) ? globalP->symbol()->identifier() : "") : ""; //try to resolve by parameters count vector firstStep, candidates; for (auto& func : functions) if (func.parametersCount == parCount) firstStep.push_back(func); if (firstStep.size() != 1) { for (auto& func : firstStep) { if (func.type == 3) { if (func.parentName == cpName && func.globalName == cpcpName || func.parentName == cpcpName && func.globalName == global) { candidates.push_back(func); } } else if (func.type == 0) { if (func.parentName == cpcpName) candidates.push_back(func); } else if (func.type == 2) { if (func.parentName == cpName || func.parentName == cpcpName) // contains candidates.push_back(func); } else { //TODO: candidates.push_back(func); } } } else candidates = firstStep; if (candidates.size() == 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); //TODO: added candidate filtration by context if (candidates.size() == 1) { Function target = candidates[0]; auto itF = target.resolved.find(file); if (itF != target.resolved.end()) corrected = itF->second; else { if (target.type == 1 || target.type == 2) // global or internal { if (target.file == file->filename()) { corrected = target.point->symbol(); target.resolved[file] = corrected; } /*else //TODO: create needed symbol? printInternalError(convertFileName(__FILE__).c_str(), __LINE__);*/ } else if (target.type == 0) // module { if (target.file == file->filename()) { corrected = target.point->symbol(); target.resolved[file] = corrected; } else ;//TODO: find module symbol clone in current file } } } else // TODO { __spf_print(1, "can not resolve of CALL '%s' function, candidates count %d, file %s and line %d\n", name.c_str(), functions.size(), current_file->filename(), context->lineNumber()); for (auto& func : functions) __spf_print(1, " --> from file file %s and line %d, parameter count - %d\n", func.file.c_str(), func.line, func.parametersCount); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } return corrected; } static void resolveFunctionCalls(SgFile* file, SgStatement* context, SgExpression* ex, const set& toResolve, const map>& funcInfo) { if (ex) { if (ex->variant() == FUNC_CALL) { string name = ex->symbol()->identifier(); if (toResolve.find(name) != toResolve.end()) { auto newS = resolveName(file, context, ex->lhs(), funcInfo.at(name), name); if (newS && ex->symbol()->id() != newS->id()) ex->setSymbol(*newS); } } resolveFunctionCalls(file, context, ex->lhs(), toResolve, funcInfo); resolveFunctionCalls(file, context, ex->rhs(), toResolve, funcInfo); } } void resolveFunctionCalls(SgFile* file, const set& toResolve, const map>& funcInfo) { if (toResolve.size() == 0) return; int funcNum = file->numberOfFunctions(); for (int z = 0; z < funcNum; ++z) { SgStatement* st = file->functions(z); SgStatement* lastNode = st->lastNodeOfStmt(); while (st != lastNode) { if (st->variant() == CONTAINS_STMT) break; if (st->variant() == PROC_STAT) { string name = st->symbol()->identifier(); if (toResolve.find(name) != toResolve.end()) { auto newS = resolveName(file, st, st->expr(0), funcInfo.at(name), name); if (newS && st->symbol()->id() != newS->id()) st->setSymbol(*newS); } } for (int z = 0; z < 3; ++z) resolveFunctionCalls(file, st, st->expr(z), toResolve, funcInfo); st = st->lexNext(); } } } bool OperatorChecker(SgFile* file, map>& currMessages) { bool checkOK = true; set usedLines; SgStatement* st = file->firstStatement(); string currF = file->filename(); const set cpOnSameLine = { ARITHIF_NODE, LOGIF_NODE, GOTO_NODE , IF_NODE, FORALL_STAT }; while (st) { int line = st->lineNumber(); if (line > 0 && st->variant() == PROG_HEDR && st->symbol()->identifier() == string("_MAIN")) ; // skip else if (line > 0 && st->fileName() == currF) { int var = st->controlParent()->variant(); bool cpWasAdded = cpOnSameLine.find(var) != cpOnSameLine.end() && (usedLines.find(line) != usedLines.end()); if (usedLines.find(line) != usedLines.end() && !cpWasAdded) { wstring messageE, messageR; __spf_printToLongBuf(messageE, L"More than one operator found on a line, try to run Code correction pass"); __spf_printToLongBuf(messageR, R179); currMessages[st->fileName()].push_back(Messages(ERROR, line, messageR, messageE, 1027)); checkOK = false; } usedLines.insert(line); } st = st->lexNext(); } return checkOK; } bool checkAndMoveFormatOperators(SgFile* file, vector& currMessages, bool withError) { bool checkOK = true; const int funcNum = file->numberOfFunctions(); for (int i = 0; i < funcNum; ++i) { SgStatement* st = file->functions(i); SgStatement* lastNode = st->lastNodeOfStmt(); vector toMove; while (st != lastNode) { if (st == NULL) { __spf_print(1, "internal error in analysis, parallel directives will not be generated for this file!\n"); break; } if (st->variant() == CONTAINS_STMT) break; if (isSgExecutableStatement(st) && !isDVM_stat(st) && !isSPF_stat(st)) break; if (st->variant() == FORMAT_STAT) { if (withError) { toMove.push_back(st); st = st->lexNext(); } else { SgStatement* needed = st; st = st->lexNext(); toMove.push_back(needed->extractStmt()); } } else st = st->lexNext(); } if (toMove.size() > 0) { if (!withError) { for (auto& format : toMove) lastNode->insertStmtBefore(*format, *lastNode->controlParent()); } else { for (auto& format : toMove) { wstring messageE, messageR; __spf_printToLongBuf(messageE, L"FORMAT operators cannot be placed in the declaration scope in the SAPFOR, try to run Code correction pass"); __spf_printToLongBuf(messageR, R183); currMessages.push_back(Messages(ERROR, format->lineNumber(), messageR, messageE, 1060)); } checkOK = false; } } } return checkOK; }