2685 lines
102 KiB
C++
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> ¯oNames,
|
|
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*> ¯oStats,
|
|
const set<string> ¯oNames, 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 ¶mOfCalled : calledFunc.NoOfParamUsedForCall)
|
|
{
|
|
cout << " " << parNo << ": ";
|
|
for (auto ¶mOfCalling : 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*> ®ions)
|
|
{
|
|
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*> ®ions)
|
|
{
|
|
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*> ¤tChainCalls)
|
|
{
|
|
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
|