Files
SAPFOR/src/GraphCall/graph_calls.cpp
2025-10-08 23:07:54 +03:00

2685 lines
102 KiB
C++

#include "leak_detector.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <stack>
#include "dvm.h"
#include "graph_calls_func.h"
#include "CFGraph/CFGraph.h"
#include "graph_loops_func.h"
#include "../DirectiveProcessing/directive_parser.h"
#include "SgUtils.h"
#include "json.hpp"
#include "../ParallelizationRegions/ParRegions_func.h"
#include "../DynamicAnalysis/gCov_parser_func.h"
#include "expr_transform.h"
#include "../LoopAnalyzer/loop_analyzer.h"
#include "../VerificationCode/verifications.h"
using std::vector;
using std::map;
using std::set;
using std::pair;
using std::tuple;
using std::string;
using std::wstring;
using std::make_pair;
using std::to_string;
using std::cout;
using std::endl;
using std::stack;
using json = nlohmann::json;
#define DEBUG 0
//TODO: improve parameter checking
void correctNameIfContains(SgStatement *call, SgExpression *exCall, string &name,
const vector<SgStatement*> &containsFunctions, const string &prefix)
{
if (containsFunctions.size() <= 0)
return;
if (call == NULL && exCall == NULL)
return;
for (auto &func : containsFunctions)
{
if (func->symbol()->identifier() == name)
{
int numPar = 0;
if (call && call->variant() == PROC_STAT)
numPar = isSgCallStmt(call)->numberOfArgs();
else if (exCall && exCall->variant() == FUNC_CALL)
numPar = isSgFunctionCallExp(exCall)->numberOfArgs();
else
return;
SgProgHedrStmt *f = (SgProgHedrStmt*)func;
//XXX
if (f->numberOfParameters() == numPar)
name = prefix + name;
break;
}
}
}
extern map<tuple<int, string, string>, pair<DIST::Array*, DIST::ArrayAccessInfo*>> declaredArrays;
extern map<SgStatement*, set<tuple<int, string, string>>> declaratedArraysSt;
extern int getIntrinsicFunctionType(const char* name);
static parF detectType(SgType *type)
{
parF retT = UNKNOWN_T;
int len = getSizeOfType(type);
int var = type->variant();
switch (var)
{
case DEFAULT:
break;
case T_INT:
if (len == 0 || len == 4)
retT = SCALAR_INT_T;
else if (len == 8)
retT = SCALAR_LONG_INT_T;
else if (len == 2)
retT = SCALAR_SHORT_T;
break;
case T_FLOAT:
if (len == 0 || len == 4)
retT = SCALAR_FLOAT_T;
else if (len == 8)
retT = SCALAR_DOUBLE_T;
break;
case T_DOUBLE:
if (len == 0 || len == 8)
retT = SCALAR_DOUBLE_T;
break;
case T_CHAR:
if (len == 0 || len == 4)
retT = SCALAR_CHAR_T;
break;
case T_BOOL:
if (len == 0 || len == 4)
retT = SCALAR_BOOL_T;
break;
case T_STRING:
retT = STRING_T;
break;
case T_COMPLEX:
if (len == 0 || len == 4)
retT = SCALAR_CMPLX_FLOAT_T;
else if (len == 8)
retT = SCALAR_CMPLX_DOUBLE_T;
break;
case T_DCOMPLEX:
if (len == 0 || len == 8)
retT = SCALAR_CMPLX_DOUBLE_T;
break;
}
return retT;
}
static void fillParam(const int i, SgSymbol *parIn, FuncParam& currParams, const map<string, vector<SgExpression*>> &commonBlocks, bool isArrayRef,
bool isExternal = false)
{
SgSymbol *par = OriginalSymbol(parIn);
currParams.parametersT[i] = UNKNOWN_T;
if ((par->attributes() & OPTIONAL_BIT) != 0)
currParams.inout_types[i] |= OPTIONAL_BIT;
if ((par->attributes() & EXTERNAL_BIT) || isExternal)
{
currParams.parametersT[i] = EXTERNAL_T;
return;
}
if (par->variant() == FUNCTION_NAME)
{
if (isIntrinsicFunctionName(par->identifier()))
{
const int type = getIntrinsicFunctionType(par->identifier());
if (type == T_DOUBLE)
currParams.parametersT[i] = SCALAR_DOUBLE_T;
else if (type == T_FLOAT)
currParams.parametersT[i] = SCALAR_FLOAT_T;
}
else
{
SgType* type = par->type();
currParams.parametersT[i] = detectType(type);
}
return;
}
SgType *type = par->type();
if (type)
{
const int varT = type->variant();
if (isArrayType(type))
{
currParams.parametersT[i] = ARRAY_T;
SgStatement* decl = declaratedInStmt(par);
auto uniqKey = getUniqName(commonBlocks, decl, par);
auto itArray = declaredArrays.find(uniqKey);
if (itArray == declaredArrays.end())
{
__spf_print(1, "array was not in declared list: '%s'\n", par->identifier());
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
}
currParams.parameters[i] = itArray->second.first;
}
else if (isStringArrayType(type))
{
if (isArrayRef)
currParams.parametersT[i] = STRING_T;
else
currParams.parametersT[i] = STRING_ARRAY_T;
}
else
currParams.parametersT[i] = detectType(type);
}
else
{
//printf("var = %d %s\n", par->variant(), tag[par->variant()]);
currParams.parametersT[i] = UNKNOWN_T;
}
}
static void fillFuncParams(FuncInfo *currInfo, const map<string, vector<SgExpression*>> &commonBlocks, SgProgHedrStmt *procHeader)
{
int numOfParams = procHeader->numberOfParameters();
FuncParam& currParams = currInfo->funcParams;
currParams.init(numOfParams);
if (numOfParams > 0)
{
for (int i = 0; i < numOfParams; ++i)
fillParam(i, procHeader->parameter(i), currParams, commonBlocks, false);
for (int i = 0; i < procHeader->numberOfParameters(); ++i)
{
currInfo->funcParams.identificators.push_back((procHeader->parameter(i))->identifier());
currInfo->isParamUsedAsIndex.push_back(false);
}
}
}
static void fillFuncParams(FuncInfo *currInfo, const map<string, vector<SgExpression*>> &commonBlocks, SgStatement *entryHeader)
{
SgExpression *parList = entryHeader->expr(0);
int numOfParams = 0;
for (SgExpression *p = parList; p; p = p->rhs())
numOfParams++;
FuncParam& currParams = currInfo->funcParams;
currParams.init(numOfParams);
if (numOfParams > 0)
{
SgExpression *p = parList;
for (int i = 0; i < numOfParams; ++i, p = p->rhs())
{
fillParam(i, p->lhs()->symbol(), currParams, commonBlocks, (p->lhs()->lhs() || p->lhs()->rhs()));
currInfo->funcParams.identificators.push_back(p->lhs()->symbol()->identifier());
currInfo->isParamUsedAsIndex.push_back(false);
}
}
}
static parF detectMaxTypeOfExpression(SgExpression *ex)
{
if (!ex)
return UNKNOWN_T;
parF res = UNKNOWN_T;
if (ex->variant() == VAR_REF)
{
if (ex->symbol() && ex->symbol()->type())
res = detectType(ex->symbol()->type());
}
else if (isArrayRef(ex))
{
if (ex->symbol() && ex->symbol()->type()->baseType())
res = detectType(ex->symbol()->type()->baseType());
}
else if (ex->variant() == CONST_REF)
{
if (ex->type())
res = detectType(ex->type());
}
else if (ex->variant() >= INT_VAL && ex->variant() <= STRING_VAL || ex->variant() == COMPLEX_VAL)
{
if (ex->type())
res = detectType(ex->type());
}
else
{
parF lF = UNKNOWN_T, rF = UNKNOWN_T;
if (ex->lhs())
lF = detectMaxTypeOfExpression(ex->lhs());
if (ex->rhs())
rF = detectMaxTypeOfExpression(ex->rhs());
res = MAX(res, lF);
res = MAX(res, rF);
}
return res;
}
parF detectExpressionType(SgExpression *exp) {
const int var = exp->variant();
if (var == INT_VAL)
return SCALAR_INT_T;
else if (var == FLOAT_VAL)
return SCALAR_FLOAT_T;
else if (var == DOUBLE_VAL)
return SCALAR_DOUBLE_T;
else if (var == CHAR_VAL)
return SCALAR_CHAR_T;
else if (var == BOOL_VAL)
return SCALAR_BOOL_T;
else if (exp->variant() == VAR_REF && exp->symbol() && (exp->symbol()->attributes() & EXTERNAL_BIT))
return EXTERNAL_T;
else
{
SgType* type = exp->type();
if (type)
{
if (type->variant() == DEFAULT)
return detectMaxTypeOfExpression(exp);
else
return detectType(type);
}
else
return UNKNOWN_T;
}
}
//TODO:: add values
static void processActualParams(SgExpression *parList, const map<string, vector<SgExpression*>> &commonBlocks, FuncParam& currParams,
const set<string>& externalCall)
{
int numOfPar = 0;
for (SgExpression *ex = parList; ex != NULL; ex = ex->rhs())
numOfPar++;
currParams.init(numOfPar);
if (numOfPar > 0)
{
int num = 0;
for (SgExpression *ex = parList; ex != NULL; ex = ex->rhs(), ++num)
{
if (ex->lhs() && ex->lhs()->lhs() == NULL && ex->lhs()->rhs() == NULL)
currParams.identificators.push_back(string(ex->lhs()->unparse()));
else
currParams.identificators.push_back("");
if (ex->lhs()->symbol())
fillParam(num, ex->lhs()->symbol(), currParams, commonBlocks, (ex->lhs()->lhs() || ex->lhs()->rhs()),
externalCall.find(ex->lhs()->symbol()->identifier()) != externalCall.end());
else
{
parF parf = detectExpressionType(ex->lhs());
currParams.parametersT[num] = parf;
if (parf == SCALAR_INT_T)
{
SgExpression* result = CalculateInteger(ex->lhs()->copyPtr());
if (result != ex->lhs())
{
currParams.parameters[num] = new int[1];
addToCollection(__LINE__, __FILE__, currParams.parameters[num], 2);
((int*)currParams.parameters[num])[0] = result->valueInteger();
}
}
}
}
}
}
static void findFuncCalls(SgStatement *parent, SgExpression *curr, FuncInfo* procInfo, const int line,
const map<string, vector<SgExpression*>> &commonBlocks, const set<string> &macroNames,
const vector<SgStatement*> &containsFunctions, const string &prefix)
{
if (curr->variant() == FUNC_CALL && macroNames.find(curr->symbol()->identifier()) == macroNames.end())
{
vector<string> nameOfCallFunc;
nameOfCallFunc.push_back(curr->symbol()->identifier());
nameOfCallFunc.push_back(OriginalSymbol(curr->symbol())->identifier());
for (auto& elem : nameOfCallFunc)
correctNameIfContains(NULL, curr, elem, containsFunctions, prefix);
procInfo->callsFrom.insert(nameOfCallFunc.begin(), nameOfCallFunc.end());
FuncInfoCallFrom newCall;
newCall.detailCallsFrom = make_pair(nameOfCallFunc[1], line); // original name of call
newCall.pointerDetailCallsFrom = make_pair(curr, FUNC_CALL);
newCall.parentForPointer = parent;
newCall.actualParams = FuncParam();
processActualParams(curr->lhs(), commonBlocks, newCall.actualParams, procInfo->externalCalls);
procInfo->callsFromDetailed.push_back(newCall);
}
if (curr->lhs())
findFuncCalls(parent, curr->lhs(), procInfo, line, commonBlocks, macroNames, containsFunctions, prefix);
if (curr->rhs())
findFuncCalls(parent, curr->rhs(), procInfo, line, commonBlocks, macroNames, containsFunctions, prefix);
}
static void findReplaceSymbolByExpression(SgExpression *parentEx, SgExpression *findIn, int pos,
const string &symbol, SgExpression *replace,
vector<tuple<SgExpression*, int, SgExpression*>> &replaces)
{
if (findIn)
{
if (findIn->symbol())
if (findIn->symbol()->identifier() == symbol)
replaces.push_back(std::make_tuple(parentEx, pos, replace->copyPtr()));
findReplaceSymbolByExpression(findIn, findIn->lhs(), 0, symbol, replace, replaces);
findReplaceSymbolByExpression(findIn, findIn->rhs(), 1, symbol, replace, replaces);
}
}
static void doMacroExpand(SgStatement *parent, SgExpression *parentEx, SgExpression *findIn, int pos,
const map<string, SgStatement*> &macroStats,
const set<string> &macroNames, bool &needToIterate,
vector<Messages> &messages)
{
if (findIn)
{
if(findIn->variant() == FUNC_CALL && macroNames.find(string(findIn->symbol()->identifier())) != macroNames.end())
{
const string funcName = string(findIn->symbol()->identifier());
auto it = macroStats.find(funcName);
SgStatement *macroStat = it->second;
vector<SgExpression*> parameters;
for (SgExpression *list = findIn->lhs(); list; list = list->rhs())
parameters.push_back(list->lhs()->copyPtr());
SgExpression *toInsert = macroStat->expr(0)->lhs()->copyPtr();
if (parentEx == NULL)
parent->setExpression(pos, *toInsert);
else
{
if (pos == 0)
parentEx->setLhs(*toInsert);
else if (pos == 1)
parentEx->setRhs(*toInsert);
}
SgSymbol *declSymb = macroStat->expr(0)->symbol();
int parN = lenghtOfParamList(declSymb->thesymb);
vector<tuple<SgExpression*, int, SgExpression*>> replaces;
for (int z = 0; z < parN; ++z)
{
SgSymbol *toExpand = SymbMapping(GetThParam(declSymb->thesymb, z));
findReplaceSymbolByExpression(toInsert, toInsert->lhs(), 0, toExpand->identifier(), parameters[z], replaces);
findReplaceSymbolByExpression(toInsert, toInsert->rhs(), 1, toExpand->identifier(), parameters[z], replaces);
}
for (auto &repl : replaces)
{
if (std::get<1>(repl) == 0)
std::get<0>(repl)->setLhs(std::get<2>(repl));
else if (std::get<1>(repl) == 1)
std::get<0>(repl)->setRhs(std::get<2>(repl));
}
needToIterate = true;
wstring messageE, messageR;
__spf_printToLongBuf(messageE, L"substitute statement function with name '%s'", to_wstring(funcName).c_str());
__spf_printToLongBuf(messageR, R101, to_wstring(funcName).c_str());
messages.push_back(Messages(NOTE, parent->lineNumber(), messageR, messageE, 2006));
}
doMacroExpand(parent, findIn, findIn->lhs(), 0, macroStats, macroNames, needToIterate, messages);
doMacroExpand(parent, findIn, findIn->rhs(), 1, macroStats, macroNames, needToIterate, messages);
}
}
void doMacroExpand(SgFile *file, vector<Messages> &messages)
{
for (int i = 0; i < file->numberOfFunctions(); ++i)
{
SgStatement *st = file->functions(i);
SgStatement *lastNode = st->lastNodeOfStmt();
map<string, SgStatement*> macroStats;
set<string> macroNames;
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 (!isSgExecutableStatement(st))
{
if (st->variant() == STMTFN_STAT)
{
macroStats.insert(make_pair(st->expr(0)->symbol()->identifier(), st));
macroNames.insert(st->expr(0)->symbol()->identifier());
}
}
else
break;
st = st->lexNext();
}
if (macroStats.size() > 0)
{
bool needToIterate = true;
while (needToIterate)
{
needToIterate = false;
for (SgStatement *stat = st; stat != lastNode; stat = stat->lexNext())
for (int i = 1; i < 3; ++i)
if (stat->expr(i))
doMacroExpand(stat, NULL, stat->expr(i), i, macroStats, macroNames, needToIterate, messages);
}
}
}
}
static void findIdxRef(SgExpression *exp, FuncInfo &currInfo)
{
if (exp)
{
if (exp->variant() == VAR_REF)
{
for (int i = 0; i < currInfo.funcParams.identificators.size(); i++)
{
if (exp->symbol()->identifier() == currInfo.funcParams.identificators[i])
currInfo.isParamUsedAsIndex[i] = true;
}
}
findIdxRef(exp->lhs(), currInfo);
findIdxRef(exp->rhs(), currInfo);
}
}
static void findArrayRef(SgExpression *exp, FuncInfo &currInfo, bool isWrite)
{
if (exp)
{
if (isArrayRef(exp))
{
DIST::Array *arrayRef = NULL;
SgSymbol *symbS = OriginalSymbol(exp->symbol());
const string symb = symbS->identifier();
if (symbS)
arrayRef = getArrayFromDeclarated(declaratedInStmt(symbS), symb);
else
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
if (arrayRef)
{
// only distributed arrays were added
if (arrayRef->IsNotDistribute() == false)
{
// Through all indexes
for (SgExpression *ex = exp; ex != NULL; ex = ex->rhs())
findIdxRef(exp->lhs(), currInfo);
currInfo.allUsedArrays.insert(arrayRef);
if (isWrite)
currInfo.usedArraysWrite.insert(arrayRef);
}
}
}
else
{
findArrayRef(exp->lhs(), currInfo, isWrite);
findArrayRef(exp->rhs(), currInfo, isWrite);
}
}
}
static void findParamInParam(SgExpression *exp, FuncInfo &currInfo)
{
// Searching through expression, which parameter presented with
if (exp)
{
if (exp->variant() == VAR_REF || isArrayRef(exp))
{
// check for matching with one of param of func which called this
//cout << "Checking " << exp->symbol()->identifier() << " for match.." << endl;
for (int i = 0; i < currInfo.funcParams.identificators.size(); i++)
{
const string &parName = currInfo.funcParams.identificators[i];
//cout << " with " << parName << ".. ";
if (exp->symbol()->identifier() == parName)
{
//cout << "Success." << endl;
NestedFuncCall &currNestedFuncCall = currInfo.funcsCalledFromThis.back();
currNestedFuncCall.NoOfParamUsedForCall.back().push_back(i);
break;
}
}
}
// do not search further if found, cause VAR_REF is always a leaf
else
{
findParamInParam(exp->lhs(), currInfo);
findParamInParam(exp->rhs(), currInfo);
}
}
}
static bool hasRecCall(const FuncInfo* proc, const vector<string>& newNames)
{
bool has = false;
for (auto& toAdd : newNames)
if (proc->funcName == toAdd)
has = true;
return has;
}
static void findParamUsedInFuncCalls(SgExpression *exp, FuncInfo &currInfo, const vector<SgStatement*>& containsFunctions, const string& prefix);
static void throughParams(SgExpression *pars, FuncInfo &currInfo, const vector<SgStatement*>& containsFunctions, const string& prefix)
{
for (SgExpression *par = pars; par != NULL; par = par->rhs())
{
// initialize vector representing parameter #parNo
NestedFuncCall &currNestedFuncCall = currInfo.funcsCalledFromThis.back();
currNestedFuncCall.NoOfParamUsedForCall.push_back(vector<int>());
findParamInParam(par->lhs(), currInfo);
}
// search another func call, possibly used in parameter
for (SgExpression *par = pars; par != NULL; par = par->rhs())
findParamUsedInFuncCalls(pars->lhs(), currInfo, containsFunctions, prefix);
}
// Takes random expression, finds there func calls and check their parameters
// for using parameters of func where first is called from
static void findParamUsedInFuncCalls(SgExpression *exp, FuncInfo &currInfo,
const vector<SgStatement*>& containsFunctions, const string& prefix)
{
if (exp)
{
if (exp->variant() == FUNC_CALL)
{
vector<string> nameOfCallFunc;
nameOfCallFunc.push_back(exp->symbol()->identifier());
nameOfCallFunc.push_back(OriginalSymbol(exp->symbol())->identifier());
for (auto& elem : nameOfCallFunc)
correctNameIfContains(NULL, exp, elem, containsFunctions, prefix);
if (!hasRecCall(&currInfo, nameOfCallFunc))
{
// Add func call which we've just found
currInfo.funcsCalledFromThis.push_back(NestedFuncCall(nameOfCallFunc[1]));
// For every found func call iterate through pars
//cout << "Through params of the call of " << exp->symbol()->identifier() << endl;
throughParams(exp->lhs(), currInfo, containsFunctions, prefix);
}
}
else
{
// If we've not found func call, search further in all branches
findParamUsedInFuncCalls(exp->rhs(), currInfo, containsFunctions, prefix);
findParamUsedInFuncCalls(exp->lhs(), currInfo, containsFunctions, prefix);
}
}
}
static void printParInfo(const map<string, vector<FuncInfo*>> &allFuncInfo)
{
cout << "*********Which parameters of current function are used in func calls inside it*********" << endl;
for (auto &file1 : allFuncInfo)
{
for (auto &currInfo : file1.second)
{
cout << currInfo->funcName << " calls to:" << endl;
for (auto &calledFunc : currInfo->funcsCalledFromThis)
{
cout << " " << calledFunc.CalledFuncName << " with params:" << endl;
int parNo = 0;
for (auto &paramOfCalled : calledFunc.NoOfParamUsedForCall)
{
cout << " " << parNo << ": ";
for (auto &paramOfCalling : paramOfCalled)
cout << currInfo->funcParams.identificators[paramOfCalling] << " ";
parNo++;
cout << endl;
}
}
}
}
cout << endl;
cout << "*********Which parameters of current function are used as indices for arrays*********" << endl;
for (auto &file1 : allFuncInfo)
{
for (auto &currInfo : file1.second)
{
cout << currInfo->funcName << endl;
for (size_t i = 0; i < currInfo->isParamUsedAsIndex.size(); i++)
{
cout << currInfo->funcParams.identificators[i] << ": ";
if (currInfo->isParamUsedAsIndex[i])
cout << "used" << endl;
else
cout << "not used" << endl;
}
}
}
cout << endl;
}
void findContainsFunctions(SgStatement *st, vector<SgStatement*> &found, const bool searchAll)
{
SgStatement *end = st->lastNodeOfStmt();
bool containsStarted = false;
for (; st != end; st = st->lexNext())
{
if (containsStarted)
{
if (st->variant() == PROC_HEDR || st->variant() == FUNC_HEDR)
{
found.push_back(st);
st = searchAll? st : st->lastNodeOfStmt();
}
else if (!searchAll && st->variant() == CONTAINS_STMT)
break;
}
if (st->variant() == CONTAINS_STMT)
containsStarted = true;
}
}
static void fillIn(FuncInfo *currF, SgExpression *ex, const map<string, int> &parNames, bool isInFuncPar)
{
if (ex)
{
if (!isInFuncPar && (ex->variant() == VAR_REF || isArrayRef(ex)))
{
const char *name = ex->symbol()->identifier();
if (name && name != string(""))
{
auto it = parNames.find(name);
if (it != parNames.end())
currF->funcParams.inout_types[it->second] |= IN_BIT;
}
}
if (ex->variant() == FUNC_CALL) {
SgFunctionCallExp* call = (SgFunctionCallExp*)ex;
for (int z = 0; z < call->numberOfArgs(); ++z)
fillIn(currF, call->arg(z), parNames, true);
}
else {
fillIn(currF, ex->lhs(), parNames, false);
fillIn(currF, ex->rhs(), parNames, false);
}
}
}
static void fillType(FuncInfo* currF, const string& symb, const map<string, int>& parNames, const int type)
{
if (symb != "")
{
auto it = parNames.find(symb);
if (it != parNames.end())
currF->funcParams.inout_types[it->second] |= type;
}
}
static void checkSpecList(SgExpression* pair, FuncInfo* currF, const map<string, int>& parNames, int)
{
auto valExp = isSgKeywordValExp(pair->lhs());
if (valExp->value() == string("unit"))
if (pair->rhs() && pair->rhs()->symbol())
fillType(currF, pair->rhs()->symbol()->identifier(), parNames, INOUT_BIT);
}
static void checkSpecList(SgExpression *spec, FuncInfo* currF, const map<string, int>& parNames)
{
if (spec->variant() == SPEC_PAIR)
checkSpecList(spec, currF, parNames, 0);
else
{
while (spec)
{
if (spec->lhs()->variant() == SPEC_PAIR)
checkSpecList(spec->lhs(), currF, parNames, 0);
spec = spec->rhs();
}
}
}
static void checkInTypeDescription(SgExpression *ex, FuncInfo* currF, const map<string, int>& parNames)
{
if (ex)
{
if (ex->variant() == ARRAY_REF)
fillIn(currF, ex->lhs(), parNames, false);
else
{
checkInTypeDescription(ex->lhs(), currF, parNames);
checkInTypeDescription(ex->rhs(), currF, parNames);
}
}
}
static void fillInOut(FuncInfo *currF, SgStatement *start, SgStatement *last, const set<SgStatement*>& activeOps)
{
if (currF->funcParams.countOfPars == 0)
return;
static map<string, vector<int>> supportedKeyWordArg = { {"system_clock", { OUT_BIT, OUT_BIT, OUT_BIT } } };
map<string, int> parNames;
for (int i = 0; i < currF->funcParams.identificators.size(); ++i)
parNames[currF->funcParams.identificators[i]] = i;
for (auto st = start; st != last; st = st->lexNext())
{
if (st->variant() == CONTAINS_STMT)
break;
if (st->variant() == ENTRY_STAT)
continue;
if (isSgExecutableStatement(st) == NULL) {
checkInTypeDescription(st->expr(0), currF, parNames);
continue;
}
if (st->lineNumber() <= 0)
continue;
if (activeOps.size() && activeOps.find(st) == activeOps.end())
continue;
if (st->variant() == ASSIGN_STAT)
{
SgExpression *left = st->expr(0);
fillIn(currF, left->lhs(), parNames, false);
fillIn(currF, left->rhs(), parNames, false);
fillIn(currF, st->expr(1), parNames, false);
string symb = "";
if (left->symbol())
symb = left->symbol()->identifier();
else if (left->variant() == ARRAY_OP)
{
if (left->lhs()->symbol())
symb = left->lhs()->symbol()->identifier();
}
fillType(currF, symb, parNames, OUT_BIT);
} // TODO: need to extend
else if (st->variant() == READ_STAT)
{
SgInputOutputStmt *read = isSgInputOutputStmt(st);
if (read == NULL)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
for (auto ex = read->itemList(); ex; ex = ex->rhs())
{
SgExpression* item = ex->lhs();
if (item->variant() == VAR_REF || isArrayRef(item))
{
string symb = "";
if (item->symbol())
symb = item->symbol()->identifier();
fillType(currF, symb, parNames, OUT_BIT);
}
else if (item->variant() == IOACCESS)
{
SgExpression* list = item->lhs();
stack<SgExpression*> queue;
queue.push(list);
while (!queue.empty())
{
auto item = queue.top();
queue.pop();
if (item->lhs())
queue.push(item->lhs());
if (item->rhs())
queue.push(item->rhs());
if (item->variant() == VAR_REF || isArrayRef(item))
{
string symb = "";
if (item->symbol())
symb = item->symbol()->identifier();
fillType(currF, symb, parNames, OUT_BIT);
}
}
}
}
checkSpecList(read->specList(), currF, parNames);
} // TODO: need to extend
else if (st->variant() == WRITE_STAT)
{
SgInputOutputStmt* write = isSgInputOutputStmt(st);
if (write == NULL)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
checkSpecList(write->specList(), currF, parNames);
}
else if (!isDVM_stat(st))
{
bool processed = false;
//TODO: for FUNC_CALL
if (st->variant() == PROC_STAT && isIntrinsicFunctionName(st->symbol()->identifier()))
{
const string name = st->symbol()->identifier();
if (supportedKeyWordArg.find(name) != supportedKeyWordArg.end())
{
int z = 0;
const vector<int>& types = supportedKeyWordArg[name];
for (auto ex = st->expr(0); ex; ex = ex->rhs(), ++z)
{
SgExpression* arg = ex->lhs();
if (arg->variant() == KEYWORD_ARG)
{
arg = arg->rhs();
if (types.size() <= z)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
if (types[z] == OUT_BIT || types[z] == INOUT_BIT)
fillType(currF, arg->symbol()->identifier(), parNames, OUT_BIT);
if (types[z] == IN_BIT || types[z] == INOUT_BIT)
fillIn(currF, arg, parNames, false);
}
else
fillIn(currF, arg, parNames, false);
}
processed = true;
}
}
if (!processed)
{
if (st->variant() == PROC_STAT)
{
SgCallStmt* call = (SgCallStmt*)st;
for (int z = 0; z < call->numberOfArgs(); ++z)
fillIn(currF, call->arg(z), parNames, true);
}
else
{
for (int i = 0; i < 3; ++i)
fillIn(currF, st->expr(i), parNames, false);
}
}
}
}
}
//TODO: check common block and module use
static void fillFunctionPureStatus(SgStatement *header, FuncInfo *currInfo, vector<Messages> &messagesForFile, const set<SgStatement*>& activeOps)
{
if (!currInfo->isMain)
{
set<int> lines;
bool hasIntent = hasThisIds(header, lines, { INTENT_STMT }, &activeOps);
bool declaratedAsPure = (header->symbol()->attributes() & PURE_BIT);
if (declaratedAsPure && !hasIntent && ((SgProgHedrStmt*)header)->numberOfParameters())
{
messagesForFile.push_back(Messages(ERROR, header->lineNumber(), R143, L"Wrong pure declaration - INTENT mismatch", 4002));
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
}
if (currInfo->commonBlocks.size() == 0)
{
lines.clear();
bool has = hasThisIds(header, lines, { DATA_DECL, SAVE_DECL, USE_STMT,
WRITE_STAT, READ_STAT, OPEN_STAT, CLOSE_STAT,
PRINT_STAT, STOP_STAT, PAUSE_NODE },
&activeOps);
if (!has || declaratedAsPure)
currInfo->isPure = true;
else
{
for (auto &line : lines)
messagesForFile.push_back(Messages(WARR, line, R93, L"Function is impure due to this operator usage", 1049));
}
}
else if (declaratedAsPure)
currInfo->isPure = true;
}
else
currInfo->isPure = true;
}
static void fillCommons(FuncInfo *currInfo, const map<string, vector<SgExpression*>> &commonBlocks)
{
for (auto &item : commonBlocks)
{
auto inserted = currInfo->commonBlocks.insert(make_pair(item.first, set<string>()));
for (auto& list : item.second)
{
SgExpression* expr_list = list->lhs();
while (expr_list != NULL)
{
SgExpression* var = expr_list->lhs();
expr_list = expr_list->rhs();
inserted.first->second.insert(var->symbol()->identifier());
}
}
}
}
static void printActiveLines(const set<SgStatement*>& activeOps)
{
set<int> lines;
for (auto& st : activeOps)
lines.insert(st->lineNumber());
for (auto& line : lines)
printf("%d\n", line);
}
static FuncInfo* createNewFuction(const string& funcName, SgStatement *st, SgStatement* entry,
vector<Messages>& messagesForFile,
const map<string, vector<SgExpression*>>& commonBlocks,
const set<SgStatement*>& activeOps)
{
SgStatement* lastNode = st->lastNodeOfStmt();
FuncInfo* currInfo = new FuncInfo(funcName, make_pair(entry->lineNumber(), lastNode->lineNumber()), new Statement(entry));
hasThisIds(st, currInfo->linesOfIO, { WRITE_STAT, READ_STAT, OPEN_STAT, CLOSE_STAT, PRINT_STAT }, &activeOps);
hasThisIds(st, currInfo->linesOfStop, { STOP_STAT, PAUSE_NODE }, &activeOps);
currInfo->isMain = (st->variant() == PROG_HEDR);
fillCommons(currInfo, commonBlocks);
fillFunctionPureStatus(st, currInfo, messagesForFile, activeOps);
if (st->variant() != PROG_HEDR)
{
SgProgHedrStmt* procFuncHedr = ((SgProgHedrStmt*)st);
if (st == entry)
fillFuncParams(currInfo, commonBlocks, procFuncHedr);
else
fillFuncParams(currInfo, commonBlocks, entry);
fillInOut(currInfo, st, lastNode, activeOps);
}
if (isSPF_NoInline(new Statement(st->lexNext())))
{
__spf_print(1, "set NOINLINE attribute for function '%s'\n", funcName.c_str());
currInfo->doNotInline = true;
}
return currInfo;
}
static FuncInfo* analyzeFunction(const string& funcName, const string& containsPrefix,
SgStatement *function, SgStatement* entry, map<string, vector<FuncInfo*>>& allFuncInfo,
const map<int, LoopGraph*>& mapLoopGraph, vector<Messages>& messagesForFile,
vector<SgStatement*>& containsFunctions,
const set<SgStatement*>& activeOps)
{
SgStatement* st = function;
SgStatement* lastNode = st->lastNodeOfStmt();
const string fileName = function->fileName();
auto it = allFuncInfo.find(fileName);
if (it == allFuncInfo.end())
it = allFuncInfo.insert(it, make_pair(fileName, vector<FuncInfo*>()));
map<string, vector<SgExpression*>> commonBlocks;
getCommonBlocksRef(commonBlocks, function, lastNode);
if (function->controlParent()->variant() == GLOBAL)
containsFunctions.clear();
findContainsFunctions(function, containsFunctions);
auto procInfo = createNewFuction(funcName, function, entry, messagesForFile, commonBlocks, activeOps);
it->second.push_back(procInfo);
vector<SgStatement*> macroStats;
set<string> macroNames;
while (st != lastNode)
{
if (st->variant() == CONTAINS_STMT)
break;
if (st->variant() == INTERFACE_STMT)
{
st = st->lexNext();
while (st && !(st->controlParent()->variant() == INTERFACE_STMT && st->variant() == CONTROL_END))
{
if (st->variant() == PROC_HEDR || st->variant() == FUNC_HEDR)
{
procInfo->interfaceBlocks[st->symbol()->identifier()] = NULL;
st = st->lastNodeOfStmt();
}
st = st->lexNext();
}
}
if (st == NULL)
{
__spf_print(1, "internal error in analysis, parallel directives will not be generated for this file!\n");
break;
}
if (!isSgExecutableStatement(st))
{
if (st->variant() == STMTFN_STAT)
{
macroStats.push_back(st);
macroNames.insert(st->expr(0)->symbol()->identifier());
}
}
else
break;
st = st->lexNext();
}
st = function;
const string file = st->fileName();
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 (!__gcov_doesThisLineExecuted(st->fileName(), st->lineNumber()) ||
st->variant() == ENTRY_STAT)
{
st = st->lexNext();
continue;
}
if (activeOps.size())
{
if (st->fileName() == file &&
isSgExecutableStatement(st) &&
activeOps.find(st) == activeOps.end())
{
st = st->lexNext();
continue;
}
}
// check for external calls
if (st->variant() == EXTERN_STAT)
for (SgExpression* ex = st->expr(0); ex; ex = ex->rhs())
if (ex->lhs()->symbol())
procInfo->externalCalls.insert(ex->lhs()->symbol()->identifier());
const string prefix = containsPrefix == "" ? string(function->symbol()->identifier()) + "." : containsPrefix;
//printf("var %d, line %d, file %s\n", st->variant(), st->lineNumber(), st->fileName());
if (st->variant() == PROC_STAT)
{
vector<string> pureNameOfCallFunc;
pureNameOfCallFunc.push_back(removeString("call ", st->symbol()->identifier()));
pureNameOfCallFunc.push_back(removeString("call ", OriginalSymbol(st->symbol())->identifier()));
for (auto& elem : pureNameOfCallFunc)
correctNameIfContains(st, NULL, elem, containsFunctions, prefix);
if (hasRecCall(procInfo, pureNameOfCallFunc))
continue;
procInfo->callsFrom.insert(pureNameOfCallFunc.begin(), pureNameOfCallFunc.end());
FuncInfoCallFrom newCall;
newCall.detailCallsFrom = make_pair(pureNameOfCallFunc[1], st->lineNumber()); // original name of call
newCall.pointerDetailCallsFrom = make_pair(st, PROC_STAT);
newCall.parentForPointer = st;
newCall.actualParams = FuncParam();
processActualParams(st->expr(0), commonBlocks, newCall.actualParams, procInfo->externalCalls);
procInfo->callsFromDetailed.push_back(newCall);
// Add func call which we've just found
NestedFuncCall funcCall(pureNameOfCallFunc[1]);
procInfo->funcsCalledFromThis.push_back(funcCall);
// search for using pars of cur func in pars of called
throughParams(st->expr(0), *procInfo, containsFunctions, prefix);
//find external calls
for (SgExpression* par = st->expr(0); par != NULL; par = par->rhs())
{
SgExpression* curr = par->lhs();
if (curr)
{
if (curr->variant() == VAR_REF)
{
auto s = curr->symbol();
if (procInfo->externalCalls.find(s->identifier()) != procInfo->externalCalls.end() ||
(s->attributes() & EXTERNAL_BIT))
{
vector<string> nameOfCallFunc;
nameOfCallFunc.push_back(s->identifier());
nameOfCallFunc.push_back(OriginalSymbol(s)->identifier());
for (auto& elem : nameOfCallFunc)
correctNameIfContains(NULL, curr, elem, containsFunctions, prefix);
procInfo->callsFrom.insert(nameOfCallFunc.begin(), nameOfCallFunc.end());
FuncInfoCallFrom newCall;
newCall.detailCallsFrom = make_pair(nameOfCallFunc[1], st->lineNumber()); // original name of call
newCall.pointerDetailCallsFrom = make_pair(curr, VAR_REF);
newCall.parentForPointer = st;
newCall.actualParams = FuncParam();
procInfo->callsFromDetailed.push_back(newCall);
}
}
}
}
}
else
{
for (int i = 0; i < 3; ++i)
if (st->expr(i))
findParamUsedInFuncCalls(st->expr(i), *procInfo, containsFunctions, prefix);
}
for (int i = 0; i < 3; ++i)
if (st->expr(i))
findFuncCalls(st, st->expr(i), procInfo, st->lineNumber(), commonBlocks, macroNames, containsFunctions, prefix);
if (isSgExecutableStatement(st))
{
if (procInfo->isParamUsedAsIndex.size())
for (int i = 0; i < 3; i++)
findArrayRef(st->expr(i), *procInfo, st->variant() == ASSIGN_STAT && i == 0);
if (st->variant() == FOR_NODE)
{
auto itL = mapLoopGraph.find(st->lineNumber());
if (itL != mapLoopGraph.end())
procInfo->loopsInFunc.push_back(itL->second);
}
}
st = st->lexNext();
}
return procInfo;
}
static set<SgStatement*> fillActiveOperators(SgStatement* func, const vector<SAPFOR::BasicBlock*>& blocks)
{
if (blocks.size() == 0)
return set<SgStatement*>();
set<SgStatement*> active;
set<SAPFOR::BasicBlock*> activeBlocks;
activeBlocks.insert(blocks[0]);
bool added = true;
while (added)
{
added = false;
for (auto& block : activeBlocks)
{
for (auto& next : block->getNext())
{
if (activeBlocks.find(next) == activeBlocks.end())
{
activeBlocks.insert(next);
added = true;
}
}
}
}
for (auto& block : activeBlocks)
{
for (auto& instr : block->getInstructions())
{
auto op = instr->getInstruction()->getOperator();
if (op)
active.insert(op);
}
}
//complete blocked statements
for (auto st = func->lexNext(); st != func->lastNodeOfStmt(); st = st->lexNext())
{
if (st->variant() == CONTAINS_STMT)
break;
if (st->variant() == SWITCH_NODE)
{
auto select = isSgSwitchStmt(st);
int numOfCases = select->numberOfCaseOptions();
for (int z = 0; z < numOfCases; ++z)
{
auto caseOp = isSgCaseOptionStmt(select->caseOption(z));
if (active.count(caseOp))
{
active.insert(st);
break;
}
}
}
}
return active;
}
//if fullIR not empty -> call this function from CALL_GRAPH2
void functionAnalyzer(SgFile *file, map<string, vector<FuncInfo*>> &allFuncInfo, const vector<LoopGraph*> &loops, vector<Messages> &messagesForFile,
map<FuncInfo*, vector<SAPFOR::BasicBlock*>> &fullIR)
{
map<int, LoopGraph*> mapLoopGraph;
createMapLoopGraph(loops, mapLoopGraph);
map<SgStatement*, FuncInfo*> tmpInfoInIR;
for (auto& elem : fullIR)
{
SgStatement* func = elem.first->funcPointer->GetOriginal();
if (tmpInfoInIR.count(func) != 0)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
tmpInfoInIR[func] = elem.first;
}
int funcNum = file->numberOfFunctions();
__spf_print(DEBUG, "functions num in file = %d\n", funcNum);
vector<SgStatement*> containsFunctions;
vector<SgStatement*> functions;
for (int i = 0; i < funcNum; ++i)
{
auto func = file->functions(i);
functions.push_back(func);
//find entry points
for (auto st = func->lexNext(); st != func->lastNodeOfStmt(); st = st->lexNext())
{
if (st->variant() == ENTRY_STAT)
functions.push_back(st);
}
}
FuncInfo* lastNonEntry = NULL;
for (auto& function : functions)
{
bool isEntry = (function->variant() == ENTRY_STAT);
const int line = function->lineNumber();
const char* file = function->fileName();
string containsPrefix = "";
SgStatement* st_cp = isEntry ? function->controlParent()->controlParent() : function->controlParent();
if (st_cp->variant() == PROC_HEDR || st_cp->variant() == PROG_HEDR || st_cp->variant() == FUNC_HEDR)
containsPrefix = st_cp->symbol()->identifier() + string(".");
else if (st_cp->variant() == INTERFACE_STMT)
continue;
string funcName = "";
if (function->variant() == PROG_HEDR)
{
SgProgHedrStmt* progH = (SgProgHedrStmt*)function;
funcName = progH->nameWithContains();
__spf_print(DEBUG, "*** Program <%s> started at line %d / %s\n", progH->symbol()->identifier(), line, file);
}
else if (function->variant() == PROC_HEDR)
{
SgProcHedrStmt* procH = (SgProcHedrStmt*)function;
funcName = procH->nameWithContains();
__spf_print(DEBUG, "*** Function <%s> started at line %d / %s\n", procH->symbol()->identifier(), line, file);
}
else if (function->variant() == FUNC_HEDR)
{
SgFuncHedrStmt* funcH = (SgFuncHedrStmt*)function;
funcName = funcH->nameWithContains();
__spf_print(DEBUG, "*** Function <%s> started at line %d / %s\n", funcH->symbol()->identifier(), line, file);
}
else if (function->variant() == ENTRY_STAT)
{
funcName = function->symbol()->identifier();
__spf_print(DEBUG, "*** Entry function <%s> started at line %d / %s\n", funcName.c_str(), line, file);
}
else
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
set<SgStatement*> activeOps;
if (fullIR.size())
{
if (tmpInfoInIR.count(function) == 0)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
activeOps = fillActiveOperators((isEntry ? function->controlParent() : function), fullIR[tmpInfoInIR[function]]);
activeOps.insert(function);
if (isEntry)
activeOps.insert(function->controlParent());
}
auto procInfo = analyzeFunction(funcName, containsPrefix, isEntry ? function->controlParent() : function, function, allFuncInfo, mapLoopGraph, messagesForFile, containsFunctions, activeOps);
if (isEntry)
{
if (!lastNonEntry)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
lastNonEntry->entry.push_back(procInfo);
}
else
lastNonEntry = procInfo;
}
//fill INTERFACE block from modules
vector<SgStatement*> modules;
findModulesInFile(file, modules);
for (auto& mod : modules)
{
if (mod->fileName() != string(file->filename()))
continue;
const string moduleName = mod->symbol()->identifier();
for (auto st = mod->lexNext(); st != mod->lastNodeOfStmt(); st = st->lexNext())
{
if (st->variant() == CONTAINS_STMT)
break;
if (isSgExecutableStatement(st))
break;
if (st->variant() == INTERFACE_STMT)
{
if (needToReplaceInterfaceName(st))
{
const string fileName = st->fileName();
auto it = allFuncInfo.find(fileName);
if (it == allFuncInfo.end())
it = allFuncInfo.insert(it, make_pair(fileName, vector<FuncInfo*>()));
string currF = st->symbol()->identifier();
if (currF.find("::") == string::npos)
currF = moduleName + "::" + currF;
FuncInfo* funcInterface = new FuncInfo(currF, make_pair(st->lineNumber(), st->lastNodeOfStmt()->lineNumber()), new Statement(st));
funcInterface->isInterface = true;
for (auto st_l = st->lexNext(); st_l != st->lastNodeOfStmt(); st_l = st_l->lexNext())
if (st_l->variant() == MODULE_PROC_STMT)
{
auto list = st_l->expr(0);
for (auto ex = list; ex; ex = ex->rhs())
funcInterface->interfaceSynonims[moduleName + "::" + ex->lhs()->symbol()->identifier()] = NULL;
}
st = st->lastNodeOfStmt();
it->second.push_back(funcInterface);
}
}
}
}
auto it = allFuncInfo.find(file->filename());
if (it == allFuncInfo.end())
return;
if (fullIR.size() == 0)
return;
vector<FuncInfo*> toRemove;
for (auto& func : it->second)
{
SgStatement* pointer = func->funcPointer->GetOriginal();
if (tmpInfoInIR.find(pointer) != tmpInfoInIR.end())
{
auto key = tmpInfoInIR[pointer];
toRemove.push_back(key);
fullIR[func] = fullIR[key];
fullIR.erase(key);
}
}
for (auto& func : toRemove)
delete func;
}
static bool findLoopVarInParameter(SgExpression *ex, const string &loopSymb)
{
bool retVal = false;
if (ex)
{
if (ex->variant() == VAR_REF)
{
const string ident(ex->symbol()->identifier());
if (ident == loopSymb)
retVal = true;
}
}
return retVal;
}
static int countList(SgExpression *list)
{
int num = 0;
while (list)
{
num++;
list = list->rhs();
}
return num;
}
static bool matchCallAndDefinition(const FuncParam &funcParDef, const FuncParam& funcParCall, const string &funcName,
const string &file, const int line, map<string, vector<Messages>> &messages)
{
bool result = true;
auto typesDef = funcParDef.parametersT;
auto typesCall = funcParCall.parametersT;
if (typesDef.size() != typesCall.size())
{
wstring bufR, bufE;
__spf_printToLongBuf(bufE, L"Function '%s': count of call parameters are not enouth", to_wstring(funcName).c_str());
__spf_printToLongBuf(bufR, R38, to_wstring(funcName).c_str());
//if (needToAddErrors)
{
messages[file].push_back(Messages(ERROR, line, bufR, bufE, 1013));
__spf_print(1, "Function '%s': count of call parameters are not enouth\n", funcName.c_str());
}
result = false;
}
else
{
for (int i = 0; i < typesDef.size(); ++i)
{
if (typesCall[i] != ARRAY_T)
{
if (typesCall[i] != typesDef[i])
{
wstring bufR, bufE;
__spf_printToLongBuf(bufE, L"Different type of call (%s : %s) and def (%s : %s) parameter %d for function '%s'",
to_wstring(funcParCall.identificators[i]).c_str(), to_wstring(paramNames[typesCall[i]]).c_str(),
to_wstring(funcParDef.identificators[i]).c_str(), to_wstring(paramNames[typesDef[i]]).c_str(), i + 1, to_wstring(funcName).c_str());
__spf_printToLongBuf(bufR, R39,
to_wstring(funcParCall.identificators[i]).c_str(), to_wstring(paramNames[typesCall[i]]).c_str(),
to_wstring(funcParDef.identificators[i]).c_str(), to_wstring(paramNames[typesDef[i]]).c_str(),
i + 1, to_wstring(funcName).c_str());
//if (needToAddErrors)
{
messages[file].push_back(Messages(NOTE, line, bufR, bufE, 1013));
__spf_print(1, "Function '%s': different type of call and def parameter %d\n", funcName.c_str(), i + 1);
}
//result = false;
}
}
else //TODO
{
/*if (callArrayRef->numberOfSubscripts() > 0)
{
wstring bufR, bufE;
__spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined, only full array passing was supported", to_wstring(def->funcName).c_str());
__spf_printToLongBuf(bufR, R40, to_wstring(def->funcName).c_str());
//if (needToAddErrors)
{
messages[file].push_back(Messages(ERROR, line, bufR, bufE, 1013));
__spf_print(1, "Function '%s' needs to be inlined, only full array passing was supported\n", def->funcName.c_str());
}
result = false;
}*/
}
}
}
return result;
}
static bool matchCallAndDefinition(SgProject* proj, const map<string, int>& files,
map<string, vector<Messages>>& messages, bool needToAddErrors, const map<string, FuncInfo*> &funcByName)
{
int count = 0;
for (auto& func : funcByName)
{
FuncInfo* currF = func.second;
for (auto& callsTo : currF->callsTo)
{
for (int cf = 0; cf < callsTo->callsFromDetailed.size(); ++cf)
{
if (callsTo->callsFromDetailed[cf].detailCallsFrom.first == currF->funcName)
{
auto callInfo = callsTo->callsFromDetailed[cf].pointerDetailCallsFrom;
if (callInfo.second == VAR_REF) // external call through proc parameter
continue;
auto itF = files.find(callsTo->fileName);
if (itF == files.end())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
bool localR = matchCallAndDefinition(currF->funcParams, callsTo->callsFromDetailed[cf].actualParams, currF->funcName,
callsTo->fileName, callsTo->callsFromDetailed[cf].detailCallsFrom.second, messages);
if (!localR)
count++;
}
}
}
}
return count > 0;
}
bool isPassFullArray(SgExpression *ex)
{
if (ex->lhs() == NULL && ex->rhs() == NULL)
return true;
else
return false;
}
static bool hasCuttingDims(SgExpression *ex)
{
if (ex->lhs())
{
if (ex->lhs()->variant() == EXPR_LIST)
{
SgExpression *list = ex->lhs();
for (auto list = ex->lhs(); list; list = list->rhs())
{
if (list->lhs() && list->lhs()->variant() == DDOT)
return true;
}
}
}
return false;
}
static bool checkDimSizesBetweenParams(bool type2, const FuncInfo* func, int parNum, SgStatement* decl, SgSymbol* symb, vector<Messages>& messages, const int& statLine)
{
bool ret = false;
if (type2)
{
DIST::Array* inFunction = (DIST::Array*)func->funcParams.parameters[parNum];
DIST::Array* mainArray = getArrayFromDeclarated(decl, symb->identifier());
if (mainArray == NULL)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
if (mainArray->GetDimSize() != inFunction->GetDimSize() &&
!(inFunction->IsNotDistribute() && !mainArray->IsNotDistribute()))
{
wstring bufE, bufR;
__spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined due to different dimension sizes in formal (size = %d) and actual(size = %d) parameters for array reference '%s'",
to_wstring(func->funcName).c_str(), inFunction->GetDimSize(), mainArray->GetDimSize(), to_wstring(symb->identifier()).c_str());
__spf_printToLongBuf(bufR, R43,
to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), inFunction->GetDimSize(), mainArray->GetDimSize());
messages.push_back(Messages(ERROR, statLine, bufR, bufE, 1013));
__spf_print(1, "Function '%s' needs to be inlined due to different dimension sizes in formal (size = %d) and actual(size = %d) parameters for array reference '%s'\n",
func->funcName.c_str(), inFunction->GetDimSize(), mainArray->GetDimSize(), symb->identifier());
ret = true;
}
}
else
{
wstring bufE, bufR;
__spf_printToLongBuf(bufE, L"Type mismatch in function '%s' in formal and actual parameters for array reference '%s'\n",
to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str());
__spf_printToLongBuf(bufR, R44,
to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str());
messages.push_back(Messages(ERROR, statLine, bufR, bufE, 1013));
__spf_print(1, "Type mismatch in function '%s' in formal and actual parameters for array reference '%s'\n", func->funcName.c_str(), symb->identifier());
ret = true;
}
return ret;
}
static bool checkParameter(SgExpression *ex, vector<Messages> &messages, const int statLine,
SgForStmt *loop, bool needToAddErrors, const FuncInfo *func, int parNum,
const map<DIST::Array*, set<DIST::Array*>> &arrayLinksByFuncCalls)
{
bool ret = false;
if (ex)
{
if (isArrayRef(ex))
{
SgArrayRefExp *arrayRef = isSgArrayRefExp(ex);
SgType *type = ex->symbol()->type();
if (arrayRef && type && type->variant() != T_STRING)
{
SgSymbol *symb = OriginalSymbol(arrayRef->symbol());
if (symb)
{
SgStatement *decl = declaratedInStmt(symb);
set<string> privatesVars;
tryToFindPrivateInAttributes(decl, privatesVars);
fillNonDistrArraysAsPrivate(decl, declaredArrays, declaratedArraysSt, privatesVars);
if (privatesVars.find(symb->identifier()) == privatesVars.end())
{
bool type1 = (func->funcParams.inout_types[parNum] & OUT_BIT) != 0;
bool type2 = func->funcParams.parametersT[parNum] == ARRAY_T;
string add = "";
wstring addW = L"";
if (type1)
{
add += "(as out argument";
addW += wstring(L"(") + RR42_1;
}
if (type2)
{
if (type1)
{
add += ", as array in function)";
addW += L"," + wstring(RR42_2) + L")";
}
else
{
add += "(as array in function)";
addW += L"(" + wstring(RR42_2) + L")";
}
}
else
add += ")";
if (!isPassFullArray(ex))
{
bool _hasCuttingDims = hasCuttingDims(ex);
if (_hasCuttingDims)
{
if (needToAddErrors)
{
if (loop)
{
wstring bufE, bufR;
__spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined due to non private array reference '%s' under loop on line %d %s",
to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), loop->lineNumber(), to_wstring(add).c_str());
__spf_printToLongBuf(bufR, R41,
to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), loop->lineNumber(), addW.c_str());
messages.push_back(Messages(ERROR, statLine, bufR, bufE, 1013));
__spf_print(1, "Function '%s' needs to be inlined due to non private array reference '%s' under loop on line %d %s\n", func->funcName.c_str(), symb->identifier(), loop->lineNumber(), add.c_str());
}
else
{
wstring bufE, bufR;
__spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined due to non private array reference '%s' %s",
to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), to_wstring(add).c_str());
__spf_printToLongBuf(bufR, R42,
to_wstring(func->funcName).c_str(), to_wstring(symb->identifier()).c_str(), addW.c_str());
messages.push_back(Messages(ERROR, statLine, bufR, bufE, 1013));
__spf_print(1, "Function '%s' needs to be inlined due to non private array reference '%s' %s\n", func->funcName.c_str(), symb->identifier(), add.c_str());
}
}
ret = true;
}
else
{
//deprecate N first dims to distribute
if (type2)
{
ret = checkDimSizesBetweenParams(type2, func, parNum, decl, symb, messages, statLine);
if (!ret)
{
DIST::Array *inFunction = (DIST::Array*)func->funcParams.parameters[parNum];
DIST::Array *mainArray = getArrayFromDeclarated(decl, symb->identifier());
if (mainArray == NULL)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
set<DIST::Array*> realArrayRefs;
getRealArrayRefs(mainArray, mainArray, realArrayRefs, arrayLinksByFuncCalls);
const int toDepDims = inFunction->GetDimSize();
for (auto &array : realArrayRefs)
for (int z = 0; z < toDepDims; ++z)
array->DeprecateDimension(z);
for (int z = 0; z < toDepDims; ++z)
mainArray->DeprecateDimension(z);
inFunction->DeprecateAllDims();
inFunction->SetDistributeFlag(DIST::NO_DISTR);
wstring bufE, bufR;
if (inFunction->GetDimSize() == 1)
__spf_printToLongBuf(bufE, L"First dimension of array '%s' were deprecated to distributon due to function call '%s'",
to_wstring(symb->identifier()).c_str(), to_wstring(func->funcName).c_str());
else
__spf_printToLongBuf(bufE, L"First %d dimensions of array '%s' were deprecated to distributon due to function call '%s'",
inFunction->GetDimSize(), to_wstring(symb->identifier()).c_str(), to_wstring(func->funcName).c_str());
if (inFunction->GetDimSize() == 1)
__spf_printToLongBuf(bufR, R73,
to_wstring(symb->identifier()).c_str(), to_wstring(func->funcName).c_str());
else
__spf_printToLongBuf(bufR, R72,
inFunction->GetDimSize(), to_wstring(symb->identifier()).c_str(), to_wstring(func->funcName).c_str());
messages.push_back(Messages(NOTE, statLine, bufR, bufE, 1040));
}
}
}
}
else // check dim sizes between formal and actual parameters
ret = checkDimSizesBetweenParams(type2, func, parNum, decl, symb, messages, statLine);
}
}
}
}
if (ex->lhs())
{
bool res = checkParameter(ex->lhs(), messages, statLine, loop, needToAddErrors, func, parNum, arrayLinksByFuncCalls);
ret |= res;
}
if (ex->rhs())
{
bool res = checkParameter(ex->rhs(), messages, statLine, loop, needToAddErrors, func, parNum, arrayLinksByFuncCalls);
ret |= res;
}
}
return ret;
}
static bool checkParameter(SgExpression *parList, vector<Messages> &messages, bool needToAddErrors,
const FuncInfo *func, const int funcOnLine, SgForStmt *loop,
const map<DIST::Array*, set<DIST::Array*>> &arrayLinksByFuncCalls)
{
int parNum = 0;
bool needInsert = false;
while (parList)
{
bool res = checkParameter(parList->lhs(), messages, funcOnLine, loop, needToAddErrors, func, parNum, arrayLinksByFuncCalls);
needInsert |= res;
++parNum;
parList = parList->rhs();
}
return needInsert;
}
static vector<int> findNoOfParWithLoopVar(SgExpression *pars, const string &loopSymb)
{
vector<int> parsWithLoopSymb;
int parNo = 0;
for (SgExpression *par = pars; par != NULL; par = par->rhs(), parNo++)
{
if (findLoopVarInParameter(par->lhs(), loopSymb))
parsWithLoopSymb.push_back(parNo);
}
return parsWithLoopSymb;
}
static bool processParameterList(SgExpression *parList, SgForStmt *loop, const FuncInfo *func, const int funcOnLine, bool needToAddErrors,
vector<Messages> &messages, const map<DIST::Array*, set<DIST::Array*>> &arrayLinksByFuncCalls)
{
bool needInsert = false;
bool hasLoopVar = false;
if (loop)
hasLoopVar = findLoopVarInParameter(parList, loop->symbol()->identifier());
if (hasLoopVar)
{
const vector<int> parsWithLoopSymb = findNoOfParWithLoopVar(parList, loop->symbol()->identifier());
int idx = -1;
for (auto &par : parsWithLoopSymb)
{
if (func->isParamUsedAsIndex[par])
{
idx = par + 1;
break;
}
}
if (idx != -1)
{
wstring bufE, bufR;
__spf_printToLongBuf(bufE, L"Function '%s' needs to be inlined due to use of loop's symbol on line %d as index of an array inside this call, in parameter num %d",
to_wstring(func->funcName).c_str(), loop->lineNumber(), idx);
__spf_printToLongBuf(bufR, R45,
to_wstring(func->funcName).c_str(), idx, loop->lineNumber());
if (needToAddErrors)
{
messages.push_back(Messages(ERROR, funcOnLine, bufR, bufE, 1013));
__spf_print(1, "Function '%s' needs to be inlined due to use of loop's symbol on line %d as index of an array inside this call, in parameter num %d\n",
func->funcName.c_str(), loop->lineNumber(), idx);
}
needInsert = true;
}
else
needInsert = checkParameter(parList, messages, needToAddErrors, func, funcOnLine, loop, arrayLinksByFuncCalls);
}
else
needInsert = checkParameter(parList, messages, needToAddErrors, func, funcOnLine, loop, arrayLinksByFuncCalls);
return needInsert;
}
static bool findFuncCall(SgExpression *ex, const FuncInfo *func, vector<Messages> &messages, const int statLine, SgForStmt *loop, bool needToAddErrors,
const map<string, FuncInfo*> &funcByName,
const map<DIST::Array*, set<DIST::Array*>> &arrayLinksByFuncCalls,
bool processAll = false, set<string> *funcChecked = NULL, set<string> *needToInsert = NULL)
{
bool ret = false;
if (ex)
{
if (ex->variant() == FUNC_CALL)
{
if (processAll)
{
if (funcChecked && needToInsert)
{
const string fName = ex->symbol()->identifier();
if (funcChecked->find(fName) == funcChecked->end())
{
funcChecked->insert(fName);
auto itF = funcByName.find(fName);
if (itF != funcByName.end())
{
ret = processParameterList(ex->lhs(), loop, itF->second, statLine, needToAddErrors, messages, arrayLinksByFuncCalls);
if (ret)
needToInsert->insert(fName);
}
}
}
else
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
}
else
{
if (ex->symbol()->identifier() == func->funcName)
{
bool res = processParameterList(ex->lhs(), loop, func, statLine, needToAddErrors, messages, arrayLinksByFuncCalls);
ret |= res;
}
}
}
bool resL = findFuncCall(ex->lhs(), func, messages, statLine, loop, needToAddErrors, funcByName, arrayLinksByFuncCalls, processAll, funcChecked, needToInsert);
bool resR = findFuncCall(ex->rhs(), func, messages, statLine, loop, needToAddErrors, funcByName, arrayLinksByFuncCalls, processAll, funcChecked, needToInsert);
ret |= resL || resR;
}
return ret;
}
static SgStatement* getStatByLine(string file, const int line, const map<string, map<int, SgStatement*>> &statByLine)
{
auto itF = statByLine.find(file);
if (itF == statByLine.end())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
auto itS = itF->second.find(line);
if (itS == itF->second.end())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
SwitchFile(itS->second->getFileId());
return itS->second;
}
static void findInsertedFuncLoopGraph(const vector<LoopGraph*> &childs, set<string> &needToInsert, SgFile *currF,
vector<Messages> &messages, bool needToAddErrors, const map<string, FuncInfo*> &funcByName,
const map<string, map<int, SgStatement*>> &statByLine,
const map<DIST::Array*, set<DIST::Array*>> &arrayLinksByFuncCalls, set<string> &funcChecked)
{
for (int k = 0; k < (int)childs.size(); ++k)
{
auto stat = getStatByLine(currF->filename(), childs[k]->lineNum, statByLine);
if (stat == NULL)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
SgForStmt *loop = isSgForStmt(stat);
if (loop == NULL && stat->variant() != WHILE_NODE)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
if (loop && loop->lineNumber() != childs[k]->lineNum)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
// TODO: find loop variable in common block or module
//dont check loop outside of parallel region and DO_WHILE
if (childs[k]->region && loop)
{
for (int i = 0; i < (int)childs[k]->calls.size(); ++i)
{
//dont check call with !$SPF NOINLINE
bool needToCheck = true;
const string &funcName = childs[k]->calls[i].first;
funcChecked.insert(funcName);
auto it = funcByName.find(funcName);
if (it != funcByName.end())
needToCheck = !(it->second->doNotInline == true);
else // function not found
needToCheck = false;
if (!needToCheck)
continue;
int funcOnLine = childs[k]->calls[i].second;
SgStatement *func = getStatByLine(currF->filename(), funcOnLine, statByLine);
bool needInsert = false;
const int var = func->variant();
if (var == PROC_STAT)
{
bool res = processParameterList(func->expr(0), loop, it->second, funcOnLine, needToAddErrors, messages, arrayLinksByFuncCalls);
needInsert |= res;
}
else
for (int z = 0; z < 3; ++z)
{
bool res = findFuncCall(func->expr(z), it->second, messages, funcOnLine, loop, needToAddErrors, funcByName, arrayLinksByFuncCalls);
needInsert |= res;
}
if (needInsert)
needToInsert.insert(childs[k]->calls[i].first);
}
}
findInsertedFuncLoopGraph(childs[k]->children, needToInsert, currF, messages, needToAddErrors, funcByName, statByLine, arrayLinksByFuncCalls, funcChecked);
}
}
static bool runCheckOutOfLoop(SgExpression *parList, const FuncInfo *func, const int lineFromCall, bool needToAddErrors,
vector<Messages> &messages, const map<DIST::Array*, set<DIST::Array*>> &arrayLinksByFuncCalls)
{
bool needInsert = processParameterList(parList, NULL, func, lineFromCall, needToAddErrors, messages, arrayLinksByFuncCalls);
return needInsert;
}
static void findInsertedFuncLoopGraph(const map<string, vector<LoopGraph*>> &loopGraph, set<string> &needToInsert,
SgProject *proj, const map<string, int> &files, map<string, vector<Messages>> &allMessages,
bool needToAddErrors, const map<string, FuncInfo*> &funcByName,
const map<string, map<int, SgStatement*>> &statByLine,
const map<DIST::Array*, set<DIST::Array*>> &arrayLinksByFuncCalls, const vector<ParallelRegion*> &regions)
{
set<string> funcChecked;
for (auto &loop : loopGraph)
{
const int fileN = files.find(loop.first)->second;
SgFile *currF = &(proj->file(fileN));
SwitchFile(fileN);
auto itM = allMessages.find(loop.first);
if (itM == allMessages.end())
itM = allMessages.insert(itM, make_pair(loop.first, vector<Messages>()));
findInsertedFuncLoopGraph(loop.second, needToInsert, currF, itM->second, needToAddErrors, funcByName, statByLine, arrayLinksByFuncCalls, funcChecked);
}
//not checked, out of loops
for (int f = 0; f < proj->numberOfFiles(); ++f)
{
SgFile *currF = &(proj->file(f));
SwitchFile(f);
auto itM = allMessages.find(currF->filename());
if (itM == allMessages.end())
itM = allMessages.insert(itM, make_pair(currF->filename(), vector<Messages>()));
for (int z = 0; z < currF->numberOfFunctions(); ++z)
{
SgStatement *funcInFile = currF->functions(z);
for (SgStatement *st = funcInFile->lexNext(); st != funcInFile->lastNodeOfStmt(); st = st->lexNext())
{
if (st->variant() == CONTAINS_STMT)
break;
if (st->lineNumber() == -1)
continue;
if (!__gcov_doesThisLineExecuted(st->fileName(), st->lineNumber()))
continue;
set<ParallelRegion*> allRegs = getAllRegionsByLine(regions, st->fileName(), st->lineNumber());
if (allRegs.size() == 0)
continue;
if (isSgExecutableStatement(st))
{
if (st->variant() == PROC_STAT)
{
const string fName = st->symbol()->identifier();
auto it = funcChecked.find(fName);
auto itF = funcByName.find(fName);
if (it == funcChecked.end() && itF != funcByName.end())
{
bool needInsert = runCheckOutOfLoop(st->expr(0), itF->second, st->lineNumber(), needToAddErrors, itM->second, arrayLinksByFuncCalls);
if (needInsert)
needToInsert.insert(fName);
}
}
else
for (int z = 0; z < 3; ++z)
findFuncCall(st->expr(z), NULL, itM->second, st->lineNumber(), NULL, needToAddErrors, funcByName, arrayLinksByFuncCalls, true, &funcChecked, &needToInsert);
}
}
}
}
}
//TODO: 'needToAddErrors' is deprecated and always true
int CheckFunctionsToInline(SgProject *proj, const map<string, int> &files, const char *fileName, map<string, vector<FuncInfo*>> &funcByFile,
const map<string, vector<LoopGraph*>> &loopGraph, map<string, vector<Messages>> &allMessages, bool needToAddErrors,
const map<DIST::Array*, set<DIST::Array*>> &arrayLinksByFuncCalls, const vector<ParallelRegion*> &regions)
{
map<string, map<int, SgStatement*>> statByLine; //file -> map
//build info
for (int i = 0; i < proj->numberOfFiles(); ++i)
{
map<int, SgStatement*> toAdd;
SgFile *file = &(proj->file(i));
SwitchFile(i);
SgStatement *st = file->firstStatement();
string currF = file->filename();
while (st)
{
if (st->lineNumber() != 0 && st->fileName() == currF)
toAdd[st->lineNumber()] = st;
st = st->lexNext();
}
statByLine[file->filename()] = toAdd;
}
map<string, FuncInfo*> funcByName;
for (auto& byFile : funcByFile)
{
for (int k = 0; k < byFile.second.size(); ++k)
{
string name = byFile.second[k]->funcName;
auto itF = funcByName.find(name);
if (itF == funcByName.end())
funcByName.insert(itF, make_pair(name, byFile.second[k]));
else
{
__spf_print(1, "function with name '%s' was found in file '%s' on line %d, current position is file '%s' and line %d\n",
name.c_str(), itF->second->fileName.c_str(), itF->second->linesNum.first, byFile.second[k]->fileName.c_str(), byFile.second[k]->linesNum.first);
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
}
}
}
set<string> needToInsert;
findInsertedFuncLoopGraph(loopGraph, needToInsert, proj, files, allMessages, needToAddErrors, funcByName, statByLine, arrayLinksByFuncCalls, regions);
bool err = matchCallAndDefinition(proj, files, allMessages, needToAddErrors, funcByName);
if (err)
return -1;
if (needToInsert.size() > 0)
{
for (auto it = needToInsert.begin(); it != needToInsert.end(); ++it)
{
auto itF = funcByName.find(*it);
if (itF != funcByName.end())
itF->second->needToInline = true;
}
}
if (fileName)
{
FILE *out = fopen(fileName, "w");
if (out == NULL)
{
__spf_print(1, "can not open file %s\n", fileName);
throw -1;
}
fprintf(out, "digraph G{\n");
auto it = funcByFile.begin();
set<string> noInline;
int fileNum = 0;
while (it != funcByFile.end())
{
fprintf(out, "subgraph cluster%d {\n", fileNum);
const int dimSize = (int)it->second.size();
set<string> uniqNames;
for (int k = 0; k < dimSize; ++k)
{
const string currfunc = it->second[k]->funcName;
if (it->second[k]->doNotInline)
noInline.insert(currfunc);
set<string>::iterator it = uniqNames.find(currfunc);
if (it == uniqNames.end())
{
uniqNames.insert(it, currfunc);
fprintf(out, "\"%s\"\n", currfunc.c_str());
}
}
fprintf(out, "label = \"file <%s>\"\n", removeString(".\\", it->first).c_str());
fprintf(out, "}\n");
fileNum++;
it++;
}
it = funcByFile.begin();
while (it != funcByFile.end())
{
const char *formatString = "\"%s\" -> \"%s\" [minlen=2.0];\n";
const int dimSize = (int)it->second.size();
for (int k = 0; k < dimSize; ++k)
{
const string callFrom = it->second[k]->funcName;
set<string>::const_iterator i = it->second[k]->callsFrom.begin();
for (; i != it->second[k]->callsFrom.end(); i++)
fprintf(out, formatString, callFrom.c_str(), i->c_str());
}
it++;
}
auto it_set = needToInsert.begin();
for (; it_set != needToInsert.end(); it_set++)
{
if (noInline.find(*it_set) == noInline.end())
fprintf(out, "\"%s\" [color=red]\n", it_set->c_str());
}
fprintf(out, "overlap=false\n");
fprintf(out, "}\n");
fclose(out);
}
return needToInsert.size();
}
static string printChainRec(const vector<FuncInfo*> &currentChainCalls)
{
string out = "";
for (int i = 0; i < currentChainCalls.size(); ++i)
{
out += currentChainCalls[i]->funcName;
if (i != currentChainCalls.size() - 1)
out += " -> ";
}
return out;
}
static bool hasRecursionChain(vector<FuncInfo*> currentChainCalls, const FuncInfo *current,
const map<string, FuncInfo*> &allFuncinfo, vector<Messages> &messagesForFile)
{
bool retVal = false;
vector<FuncInfo*> toCallNext;
for (auto it = current->callsFrom.begin(); it != current->callsFrom.end(); ++it)
{
auto itF = allFuncinfo.find(*it);
if (itF == allFuncinfo.end())
continue;
if (std::find(currentChainCalls.begin(), currentChainCalls.end(), itF->second) != currentChainCalls.end())
{
if (itF->second == currentChainCalls[0])
{
retVal = true;
currentChainCalls.push_back(itF->second);
const string &chain = printChainRec(currentChainCalls);
__spf_print(1, " For function on line %d found recursive chain calls: %s\n", currentChainCalls[0]->linesNum.first, chain.c_str());
wstring bufE, bufR;
__spf_printToLongBuf(bufE, L" Found recursive chain calls: %s, this function will be ignored", to_wstring(chain).c_str());
__spf_printToLongBuf(bufR, R46, to_wstring(chain).c_str());
messagesForFile.push_back(Messages(NOTE, currentChainCalls[0]->linesNum.first, bufR, bufE, 1014));
break;
}
}
else
toCallNext.push_back(itF->second);
}
if (!retVal)
{
for (int i = 0; i < toCallNext.size() && !retVal; ++i)
{
currentChainCalls.push_back(toCallNext[i]);
retVal = retVal || hasRecursionChain(currentChainCalls, toCallNext[i], allFuncinfo, messagesForFile);
currentChainCalls.pop_back();
}
}
return retVal;
}
void checkForRecursion(SgFile *file, map<string, vector<FuncInfo*>> &allFuncInfo, vector<Messages> &messagesForFile)
{
auto itCurrFuncs = allFuncInfo.find(file->filename());
if (itCurrFuncs == allFuncInfo.end())
return;
map<string, FuncInfo*> mapFuncInfo;
createMapOfFunc(allFuncInfo, mapFuncInfo);
for (int i = 0; i < itCurrFuncs->second.size(); ++i)
{
__spf_print(1, " run for func %s\n", itCurrFuncs->second[i]->funcName.c_str());
if (hasRecursionChain( { itCurrFuncs->second[i] }, itCurrFuncs->second[i], mapFuncInfo, messagesForFile))
itCurrFuncs->second[i]->doNotAnalyze = true;
}
}
void propagateWritesToArrays(map<string, vector<FuncInfo*>> &allFuncInfo)
{
map<string, FuncInfo*> funcByName;
createMapOfFunc(allFuncInfo, funcByName);
bool change = true;
while (change)
{
change = false;
for (auto &func : funcByName)
{
if (func.second->funcParams.countOfPars == 0)
continue;
for (int z = 0; z < func.second->funcParams.countOfPars; ++z)
{
if ((func.second->funcParams.inout_types[z] & OUT_BIT) == 0)
continue;
for (auto &callsTo : func.second->callsTo)
{
map<string, int> parNames;
for (int p = 0; p < callsTo->funcParams.countOfPars; ++p)
parNames[callsTo->funcParams.identificators[p]] = p;
bool ok = callsTo->funcPointer->GetOriginal()->switchToFile();
if (!ok)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
for (auto &callFromInfo : callsTo->callsFromDetailed)
{
auto& callFrom = callFromInfo.pointerDetailCallsFrom;
if (callFrom.second == VAR_REF) // pass procedure through parameter
continue;
SgExpression *arg = NULL;
if (callFrom.second == PROC_STAT)
{
SgCallStmt *call = (SgCallStmt*)callFrom.first;
if (call->symbol()->identifier() != func.second->funcName)
continue;
if (z >= call->numberOfArgs())
continue;
arg = call->arg(z);
}
else if (callFrom.second == FUNC_CALL)
{
SgFunctionCallExp *call = (SgFunctionCallExp*)callFrom.first;
if (call->symbol()->identifier() != func.second->funcName)
continue;
if (z >= call->numberOfArgs())
continue;
arg = call->arg(z);
}
if (arg == NULL)
{
if ((func.second->funcParams.inout_types[z] & OPTIONAL_BIT) != 0)
continue;
else
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
}
string argName = "";
if (arg->symbol())
argName = arg->symbol()->identifier();
auto it = parNames.find(argName);
if (it != parNames.end() && ((callsTo->funcParams.inout_types[it->second] & OUT_BIT) == 0))
{
change = true;
callsTo->funcParams.inout_types[it->second] |= OUT_BIT;
if ((func.second->funcParams.inout_types[z] & IN_BIT) != 0)
callsTo->funcParams.inout_types[it->second] |= IN_BIT;
}
}
}
}
}
}
}
//TODO: inmprove checker
void detectCopies(map<string, vector<FuncInfo*>> &allFuncInfo)
{
map<string, FuncInfo*> mapOfFunc;
createMapOfFunc(allFuncInfo, mapOfFunc);
for (auto& byFile : allFuncInfo)
{
for (auto& func : byFile.second)
{
string name = func->funcName;
auto offset = name.rfind("_spf_");
if (offset != string::npos)
{
string orig = name.substr(0, offset);
auto it = mapOfFunc.find(orig);
if (it != mapOfFunc.end())
it->second->fullCopiesOfThisFunction.push_back(func);
}
}
}
}
void fillInterfaceBlock(map<string, vector<FuncInfo*>>& allFuncInfo)
{
map<string, FuncInfo*> mapOfFunc;
createMapOfFunc(allFuncInfo, mapOfFunc);
for (auto& byFile : allFuncInfo)
{
for (auto& func : byFile.second)
{
for (auto& interface : func->interfaceBlocks)
{
auto itF = mapOfFunc.find(interface.first);
if (itF == mapOfFunc.end())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
set<string> namesToFind = { interface.first };
for (auto& elem : itF->second->fullCopiesOfThisFunction)
namesToFind.insert(elem->funcName);
for (auto& elem : namesToFind)
{
auto isCalled = func->callsFrom.find(elem);
if (isCalled != func->callsFrom.end())
{
interface.second = itF->second;
break;
}
}
}
//filted interfaces
map<string, FuncInfo*> copy = func->interfaceBlocks;
func->interfaceBlocks.clear();
for (auto& interface : func->interfaceBlocks)
if (interface.second)
func->interfaceBlocks[interface.first] = interface.second;
}
}
for (auto& byFile : allFuncInfo)
{
for (auto& func : byFile.second)
{
if (!func->isInterface)
continue;
if (func->interfaceSynonims.size() == 0)
continue;
for (auto& syn : func->interfaceSynonims)
{
auto itF = mapOfFunc.find(syn.first);
if (itF == mapOfFunc.end())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
syn.second = itF->second;
}
}
}
}
void removeDistrStateFromDeadFunctions(const map<string, vector<FuncInfo*>>& allFuncInfo,
const map<tuple<int, string, string>, pair<DIST::Array*, DIST::ArrayAccessInfo*>>& declaredArrays)
{
map<string, FuncInfo*> funcByName;
createMapOfFunc(allFuncInfo, funcByName);
// remove distr state of arrays from dead functions
for (auto& elem : declaredArrays)
{
DIST::Array* array = elem.second.first;
if (array->GetLocation().first == DIST::l_PARAMETER)
{
if (array->IsNotDistribute() == false)
{
auto declInfo = array->GetDeclInfo();
auto place = *declInfo.begin();
if (SgFile::switchToFile(place.first) == -1)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
SgStatement *st = SgStatement::getStatementByFileAndLine(place.first, place.second);
checkNull(st, convertFileName(__FILE__).c_str(), __LINE__);
SgProgHedrStmt *hedr = isSgProgHedrStmt(getFuncStat(st));
checkNull(hedr, convertFileName(__FILE__).c_str(), __LINE__);
const string funcName = hedr->nameWithContains();
auto it = funcByName.find(funcName.c_str());
if (it == funcByName.end())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
if (it->second->deadFunction)
array->SetDistributeFlag(DIST::NO_DISTR);
}
}
}
}
int getLvlCall(FuncInfo* currF, int lvl, const string& func, const string& file, int line)
{
if (currF->funcName == func)
return 0;
for (auto& callsFromInfo : currF->callsFromDetailed)
{
auto& callsFrom = callsFromInfo.detailCallsFrom;
if (callsFrom.first == func && callsFrom.second == line && currF->fileName == file)
return lvl;
}
int whatLvl = -1;
for (auto& callsFrom : currF->callsFromV)
{
int outLvl = getLvlCall(callsFrom, lvl + 1, func, file, line);
if (outLvl != -1)
{
whatLvl = outLvl;
break;
}
}
return whatLvl;
}
void setInlineAttributeToCalls(const map<string, FuncInfo*>& allFunctions,
const map<string, set<pair<string, int>>>& inDataChains,
const map<string, vector<SgStatement*>>& hiddenData)
{
set<pair<string, int>> pointsForShadowCopies;
for (auto& elem : allFunctions)
{
auto itNeed = inDataChains.find(elem.first);
const FuncInfo* curr = elem.second;
set<pair<string, int>> needToInline;
if (itNeed != inDataChains.end())
needToInline = itNeed->second;
for (int k = 0; k < curr->callsFromDetailed.size(); ++k)
{
if (needToInline.find(curr->callsFromDetailed[k].detailCallsFrom) == needToInline.end() &&
!isIntrinsicFunctionName(curr->callsFromDetailed[k].detailCallsFrom.first.c_str()))
{
pair<void*, int> detail = curr->callsFromDetailed[k].pointerDetailCallsFrom;
if (SgFile::switchToFile(curr->fileName) == -1)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
if (detail.second == PROC_STAT)
((SgStatement*)detail.first)->addAttribute(BOOL_VAL);
else if (detail.second == FUNC_CALL)
{
//TODO: many functions in same statement
SgStatement* callSt = SgStatement::getStatementByFileAndLine(curr->fileName, curr->callsFromDetailed[k].detailCallsFrom.second);
if (!callSt)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
//((SgExpression*)detail.first)->addAttribute(BOOL_VAL);
callSt->addAttribute(BOOL_VAL);
}
else
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
pointsForShadowCopies.insert(make_pair(curr->fileName, curr->callsFromDetailed[k].detailCallsFrom.second));
__spf_print(1, " added attribute to '%s' <%s, %d>\n", curr->callsFromDetailed[k].detailCallsFrom.first.c_str(), curr->fileName.c_str(), curr->callsFromDetailed[k].detailCallsFrom.second);
}
}
}
if (pointsForShadowCopies.size())
{
for (auto& byFile : hiddenData)
{
if (SgFile::switchToFile(byFile.first) == -1)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
for (auto& stF : byFile.second)
for (auto st = stF; st != stF->lastNodeOfStmt(); st = st->lexNext())
if (pointsForShadowCopies.find(make_pair(st->fileName(), st->lineNumber())) != pointsForShadowCopies.end())
{
st->addAttribute(BOOL_VAL);
//__spf_print(1, " added attribute to shadow copy in file '%s' <%s %d>\n", byFile.first.c_str(), st->fileName(), st->lineNumber());
}
}
}
}
static json convertToJson(const FuncInfo* currFunc) {
json func;
if (currFunc)
{
func["funcName"] = currFunc->funcName;
func["line"] = currFunc->linesNum.first;
func["lineEnd"] = currFunc->linesNum.second;
func["isMain"] = (int)currFunc->isMain;
func["needToInline"] = (int)currFunc->needToInline;
func["doNotInline"] = (int)currFunc->doNotInline;
func["doNotAnalyze"] = (int)currFunc->doNotAnalyze;
json func_pars = json::array();
for (int z = 0; z < currFunc->funcParams.countOfPars; ++z)
{
json par;
par["inoutType"] = currFunc->funcParams.inout_types[z];
par["identificator"] = currFunc->funcParams.identificators[z];
par["parameterT"] = string(paramNames[currFunc->funcParams.parametersT[z]]);
func_pars.push_back(par);
}
func["params"] = func_pars;
json calls_from = json::array();
for (const auto& call_from : currFunc->callsFromDetailed)
{
json call;
call["line"] = call_from.detailCallsFrom.second;
call["funcName"] = call_from.detailCallsFrom.first;
calls_from.push_back(call);
}
func["callsFrom"] = calls_from;
}
return func;
}
json convertToJson(const map<string, vector<FuncInfo*>>& funcsByFileMap) {
json loopsByFile = json::array();
for (auto& byFile : funcsByFileMap)
{
json func;
const string& file = byFile.first;
json func_array = json::array();
for (auto& func : byFile.second)
{
auto conv = convertToJson(func);
if (!conv.empty())
func_array.push_back(conv);
}
func["file"] = file;
func["functions"] = func_array;
loopsByFile.push_back(func);
}
json allFuncs;
allFuncs["allFunctions"] = loopsByFile;
return allFuncs;
}
#undef DEBUG