Files
SAPFOR/Sapfor/_src/VerificationCode/StructureChecker.cpp

652 lines
24 KiB
C++
Raw Normal View History

2023-09-14 19:43:13 +03:00
#include "../Utils/leak_detector.h"
#include <cstdio>
#include <map>
#include <string>
#include <algorithm>
#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<Messages> &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<string, vector<int>> &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<ParallelRegion*> &regions, map<string, vector<Messages>> &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<string, CommonBlock*> &commonBlocks, map<string, vector<Messages>> &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<string, pair<string, int>> &funcNames, map<string, vector<Messages>> &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;
}
2024-05-02 11:05:56 +03:00
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;
}
2023-09-14 19:43:13 +03:00
}
}
return checkOK;
}
void fillFunctionInfo(SgFile* file, map<string, vector<Function>>& 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<Function>& 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<Function> 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<string>& toResolve, const map<string, vector<Function>>& 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<string>& toResolve, const map<string, vector<Function>>& 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<string, vector<Messages>>& currMessages)
{
bool checkOK = true;
set<int> usedLines;
SgStatement* st = file->firstStatement();
string currF = file->filename();
const set<int> cpOnSameLine = { ARITHIF_NODE, LOGIF_NODE, GOTO_NODE , IF_NODE, FORALL_STAT };
2023-09-14 19:43:13 +03:00
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)
2023-09-14 19:43:13 +03:00
{
int var = st->controlParent()->variant();
bool cpWasAdded = cpOnSameLine.find(var) != cpOnSameLine.end() && (usedLines.find(line) != usedLines.end());
2023-09-14 19:43:13 +03:00
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<Messages>& 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<SgStatement*> 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;
2024-05-15 17:54:18 +03:00
if (isSgExecutableStatement(st) && !isDVM_stat(st) && !isSPF_stat(st))
2023-09-14 19:43:13 +03:00
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)
2024-05-15 17:54:18 +03:00
lastNode->insertStmtBefore(*format, *lastNode->controlParent());
2023-09-14 19:43:13 +03:00
}
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;
}