955 lines
36 KiB
C++
955 lines
36 KiB
C++
#include "fix_common_blocks.h"
|
|
|
|
using std::vector;
|
|
using std::map;
|
|
using std::set;
|
|
using std::string;
|
|
using std::to_string;
|
|
using std::pair;
|
|
using std::make_pair;
|
|
using std::stack;
|
|
using std::deque;
|
|
using std::reverse;
|
|
using std::tuple;
|
|
|
|
//// main function --> fixCommonBlocks
|
|
|
|
////// step1: build union for each common block
|
|
|
|
/// main function:
|
|
// renew unions for all common blocks in the file
|
|
static void BuildNewCommDecls(SgFile* file, const map<string, CommonBlock*> allCommonBlocks,
|
|
map<string, deque<CommConstraint>>& newCommonDecls, map<string, map<string, deque<CommConstraint>>>& commDecls,
|
|
set<string>& badCommon, map<string, set<string>>& notUsedVars, vector<SgStatement*>& programUnits);
|
|
|
|
// get names of variables and array elements, which were referenced in programm unit
|
|
static set<string> getUses(SgStatement* firstSt, const set<string>& commonVarNames);
|
|
static void getUsesFromExpr(SgExpression* expr, const set<string>& commonVarNames, set<string>& used);
|
|
|
|
// splits arrays into elements and replaces not used vars with empty constraints
|
|
static bool splitType(deque<CommConstraint>& d, bool check_use, const set<string>& namesOfUsedVars);
|
|
// create constraits set
|
|
static deque<CommConstraint> makeConstraints(deque<CommConstraint>& constraints, const set<string>& namesOfUsedVars, set<string>& notUsedVars);
|
|
// build union
|
|
static bool buildConstraintsUnion(deque<CommConstraint>& U, deque<CommConstraint> B, const set<string>& namesOfUsedVars, pair<CommConstraint, CommConstraint>& problemConstraints);
|
|
static bool docheckUnequalConstraints(deque<CommConstraint>& U, deque<CommConstraint>& B, deque<CommConstraint>& newU, pair<CommConstraint, CommConstraint>& problemConstraints);
|
|
static bool check(deque<CommConstraint>& A, deque<CommConstraint>& B, pair<CommConstraint, CommConstraint>& problemConstraints);
|
|
|
|
/// small help functions:
|
|
static string getParentName(const string& name);
|
|
static bool equalDims(const CommConstraint& a, const CommConstraint& b);
|
|
static bool equalConstraints(const CommConstraint& a, const CommConstraint& b);
|
|
static void addElem(deque<CommConstraint>& comm, const CommConstraint& elem);
|
|
//////
|
|
|
|
// change names of variables in 'constraints'
|
|
static void fixNames(deque<CommConstraint>& constraints, const string& commName);
|
|
|
|
////// step2: transformation
|
|
|
|
/// main function
|
|
// peform transformation on every program unit in the file
|
|
static void fixFunctions(SgFile* file, vector<SgStatement*> programUnits, map<string, deque<CommConstraint>>& newCommonDecls,
|
|
map<string, map<string, deque<CommConstraint>>>& commDecls, const set<string>& badCommon, map<string, set<string>>& notUsedVars);
|
|
|
|
// get pairs of names (namesOldToNew) for renaming
|
|
static bool getNamesOldToNew(deque<CommConstraint> newDecl, deque<CommConstraint> oldDecl, map<string, string>& namesOldToNew);
|
|
|
|
// create new symbols for new variables in new common declaration (constraints)
|
|
static void makeCommVarSymbs(const deque<CommConstraint>& constraints, SgFile* file, SgStatement* func, string commName,
|
|
map<string, SgSymbol*>& symbs, vector<SgSymbol*>& needNewDecl);
|
|
// delete from program unit all references to names in commVarNames
|
|
static void deleteOldVars(SgStatement* firstSt, const set<string>& commVarNames);
|
|
|
|
// calls fixExpression for each statement, replaces names in data statement
|
|
static void renameVariables(SgStatement* firstSt, const map<string, SgSymbol*>& newVarSymbs, const map<string, string>& namesOldToNew);
|
|
// replacing variables or array elements in expression expr if their names are in namesOldToNew
|
|
static SgExpression* fixExpression(SgExpression* expr, const map<string, SgSymbol*>& newSymbs, const map<string, string>& namesOldToNew);
|
|
|
|
// make new exprList exprssion for new declaration decl with symbols from newSymbs
|
|
static SgExpression* makeExprListForCommon(const deque<CommConstraint>& decl, const map<string, SgSymbol*>& newSymbs,
|
|
SgFile* file, SgStatement* firstSt);
|
|
// replace old common declarations with new ones
|
|
static void rewriteCommon(SgStatement* firstSt, map<string, SgExpression*>& commListExprs);
|
|
|
|
/// help functions:
|
|
static SgExpression* makeIdxFromStr(const string& str);
|
|
// make new expression of array element
|
|
static SgExpression* newArrElemExpr(const string& newName, const map<string, SgSymbol*>& newSymbs);
|
|
static bool variablePositionComp(const Variable* lhs, const Variable* rhs);
|
|
//////
|
|
|
|
|
|
|
|
CommConstraint::CommConstraint(const Variable* var, bool u, const string& funcName, const string& fileName)
|
|
{
|
|
used = u;
|
|
for (const auto& use : var->getAllUse())
|
|
{
|
|
if (use.getFunctionName() == funcName)
|
|
{
|
|
SgSymbol* symb = use.getUseS();
|
|
identifier = symb->identifier();
|
|
DeclInfo dInfo = DeclInfo(identifier, fileName, use.getDeclaratedPlace()->lineNumber());
|
|
uses.push_back(dInfo);
|
|
if ((symb->attributes() & DATA_BIT) != 0)
|
|
used = true;
|
|
type = symb->type();
|
|
typeVariant = type->variant();
|
|
vector<SgStatement*> decls;
|
|
declaratedInStmt(symb, &decls, false);
|
|
Distribution::Array* arr = NULL;
|
|
for (auto decl : decls)
|
|
{
|
|
arr = getArrayFromDeclarated(decl, identifier);
|
|
// TODO: for arrays located in the same place in common, with the same names, the same structure will be given,
|
|
// even if they have DIFFERENT dimensions (should be different structures)
|
|
if (arr != NULL)
|
|
break;
|
|
}
|
|
if (arr != NULL)
|
|
{
|
|
arrayInfo = arr;
|
|
size = arr->GetTypeSize();
|
|
for (auto x : arr->GetSizes())
|
|
size *= x.second - x.first + 1;
|
|
SgArrayType* arrType = isSgArrayType(type);
|
|
if (arrType != NULL)
|
|
typeVariant = arrType->baseType()->variant();
|
|
else
|
|
__spf_print(1, "! array with no array type!\n");
|
|
}
|
|
else
|
|
size = getSizeOfType(type);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
CommConstraint::CommConstraint(const string& name, SgType* t, bool u) : used(u), type(t), identifier(name)
|
|
{
|
|
typeVariant = type->variant();
|
|
size = getSizeOfType(type);
|
|
}
|
|
|
|
|
|
CommConstraint::CommConstraint(const string& name, SgType* t, bool u, vector<DeclInfo>& us) : used(u), type(t), identifier(name), uses(us)
|
|
{
|
|
typeVariant = type->variant();
|
|
size = getSizeOfType(type);
|
|
}
|
|
|
|
|
|
string getParentName(const string& name)
|
|
{
|
|
size_t len = name.find("%");
|
|
size_t posB = name.find("(");
|
|
if (len == string::npos)
|
|
if (posB == string::npos)
|
|
return name;
|
|
else
|
|
len = posB;
|
|
else if (posB != string::npos && posB < len)
|
|
len = posB;
|
|
return name.substr(0, len);
|
|
}
|
|
|
|
|
|
void getUsesFromExpr(SgExpression* expr, const set<string>& commonVarNames, set<string>& used)
|
|
{
|
|
if (expr == NULL)
|
|
return;
|
|
if (expr->variant() == VAR_REF || expr->variant() == ARRAY_REF)
|
|
{
|
|
string name = expr->symbol()->identifier();
|
|
if (commonVarNames.find(getParentName(name)) != commonVarNames.end())
|
|
{
|
|
if (expr->variant() == VAR_REF)
|
|
used.insert(name);
|
|
else if (expr->variant() == ARRAY_REF)
|
|
{
|
|
SgArrayRefExp* arrExpr = (SgArrayRefExp*)expr;
|
|
if (arrExpr->lhs() == NULL)
|
|
used.insert(name);
|
|
else // it's array element
|
|
{
|
|
SgExpression* exprList = arrExpr->lhs();
|
|
bool ok = true;
|
|
int x;
|
|
while (exprList != NULL && ok) // TODO: evaluate indexes of elements if they are written using loop variable
|
|
{
|
|
if (-1 == CalculateInteger(exprList->lhs(), x))
|
|
ok = false;
|
|
exprList = exprList->rhs();
|
|
}
|
|
if (ok)
|
|
used.insert(expr->sunparse());
|
|
else
|
|
used.insert(name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
getUsesFromExpr(expr->lhs(), commonVarNames, used);
|
|
getUsesFromExpr(expr->rhs(), commonVarNames, used);
|
|
}
|
|
|
|
|
|
set<string> getUses(SgStatement* firstSt, const set<string>& commonVarNames)
|
|
{
|
|
set<string> used;
|
|
SgStatement* lastSt = firstSt->lastNodeOfStmt();
|
|
for (SgStatement* curSt = firstSt; curSt != lastSt; curSt = curSt->lexNext())
|
|
{
|
|
int var = curSt->variant();
|
|
if (var != COMM_STAT && var != VAR_DECL && var != VAR_DECL_90 && var != DIM_STAT) //
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
if (curSt->expr(i) != NULL)
|
|
getUsesFromExpr(curSt->expr(i), commonVarNames, used);
|
|
}
|
|
}
|
|
return used;
|
|
}
|
|
|
|
|
|
bool equalDims(const CommConstraint& a, const CommConstraint& b)
|
|
{
|
|
const vector<pair<int, int>>& adim = a.arrayInfo->GetSizes();
|
|
const vector<pair<int, int>>& bdim = b.arrayInfo->GetSizes();
|
|
if (adim.size() != bdim.size())
|
|
return false;
|
|
for (int i = 0; i < adim.size(); i++)
|
|
{
|
|
if (adim[i].second - adim[i].first != bdim[i].second - bdim[i].first)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
// TODO: add attributes to CommConstraints, check if a and b have equal attributes
|
|
bool equalConstraints(const CommConstraint& a, const CommConstraint& b)
|
|
{
|
|
if ((a.arrayInfo != NULL && b.arrayInfo == NULL) || ((a.arrayInfo == NULL && b.arrayInfo != NULL)))
|
|
return false;
|
|
if (a.typeVariant != b.typeVariant || a.size != b.size)
|
|
return false;
|
|
if (a.arrayInfo != NULL)
|
|
return a.arrayInfo->GetTypeSize() == b.arrayInfo->GetTypeSize() && equalDims(a, b);
|
|
return true;
|
|
}
|
|
|
|
|
|
void addElem(deque<CommConstraint>& comm, const CommConstraint& elem)
|
|
{
|
|
if (elem.typeVariant == 0 && !comm.empty() && comm.back().typeVariant == 0)
|
|
comm.back().size += elem.size;
|
|
else
|
|
comm.push_back(elem);
|
|
}
|
|
|
|
|
|
// TODO: check attributes: do not split arrays with pointer or target attributes if check_use == true
|
|
bool splitType(deque<CommConstraint>& d, bool check_use, const set<string>& namesOfUsedVars = {})
|
|
{
|
|
CommConstraint var = d.front();
|
|
string name = var.identifier;
|
|
if (var.typeVariant == 0 || (check_use && var.used))
|
|
return false;
|
|
if (var.arrayInfo != NULL) // TODO: arrays can be split not only into individual elements, but also into smaller arrays
|
|
{
|
|
d.pop_front();
|
|
const auto dims = var.arrayInfo->GetSizes();
|
|
int numOfDims = dims.size();
|
|
SgType* elemType = new SgType(var.typeVariant);
|
|
int elemNum = var.size / var.arrayInfo->GetTypeSize();
|
|
for (int k = elemNum - 1; k >= 0; k--)
|
|
{
|
|
string newName = name + "(";
|
|
int ind = k;
|
|
for (int i = 0; i < numOfDims; i++)
|
|
{
|
|
auto d = dims[i];
|
|
int dimLen = d.second - d.first + 1;
|
|
newName += to_string(ind % dimLen + d.first);
|
|
if (i < numOfDims - 1)
|
|
newName += ",";
|
|
ind = ind / dimLen;
|
|
}
|
|
newName += ")";
|
|
CommConstraint newVar = CommConstraint(newName, elemType, var.used, var.uses);
|
|
if (check_use && !newVar.used && namesOfUsedVars.find(newName) != namesOfUsedVars.end())
|
|
newVar.used = true;
|
|
d.push_front(newVar);
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (check_use && (var.used == false))
|
|
{
|
|
d.pop_front();
|
|
CommConstraint newVar = CommConstraint(var.identifier, var.size);
|
|
d.push_front(newVar);
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
deque<CommConstraint> makeConstraints(deque<CommConstraint>& constraints, const set<string>& namesOfUsedVars, set<string>& notUsedVars)
|
|
{
|
|
deque<CommConstraint> res;
|
|
while (!constraints.empty())
|
|
{
|
|
string curName = constraints.front().identifier;
|
|
if (!splitType(constraints, true, namesOfUsedVars))
|
|
{
|
|
addElem(res, constraints.front());
|
|
constraints.pop_front();
|
|
}
|
|
else
|
|
notUsedVars.insert(curName);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
bool check(deque<CommConstraint>& A, deque<CommConstraint>& B, pair<CommConstraint, CommConstraint>& problemConstraints)
|
|
{
|
|
while (!A.empty() && !B.empty())
|
|
{
|
|
if (B.front().size > A.front().size)
|
|
{
|
|
if (!splitType(B, false))
|
|
{
|
|
problemConstraints.second = A.front();
|
|
return false;
|
|
}
|
|
}
|
|
else if (B.front().size < A.front().size)
|
|
{
|
|
if (A.front().typeVariant == 0)
|
|
{
|
|
A.front().size -= B.front().size;
|
|
B.pop_front();
|
|
}
|
|
else
|
|
{
|
|
problemConstraints.second = A.front();
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (A.front().typeVariant != 0 && B.front().typeVariant != 0 && !equalConstraints(A.front(), B.front()))
|
|
{
|
|
problemConstraints.second = A.front();
|
|
return false;
|
|
}
|
|
B.pop_front();
|
|
A.pop_front();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool docheckUnequalConstraints(deque<CommConstraint>& U, deque<CommConstraint>& B, deque<CommConstraint>& newU, pair<CommConstraint, CommConstraint>& problemConstraints)
|
|
{
|
|
if (U.front().typeVariant == 0)
|
|
{
|
|
addElem(newU, B.front());
|
|
U.front().size -= B.front().size;
|
|
B.pop_front();
|
|
}
|
|
else
|
|
{
|
|
deque<CommConstraint> temp;
|
|
temp.push_front(U.front());
|
|
if (!check(B, temp, problemConstraints))
|
|
{
|
|
problemConstraints.first = U.front();
|
|
return false;
|
|
}
|
|
addElem(newU, U.front());
|
|
U.pop_front();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool buildConstraintsUnion(deque<CommConstraint>& U, deque<CommConstraint> B, const set<string>& namesOfUsedVars, pair<CommConstraint, CommConstraint>& problemConstraints)
|
|
{
|
|
deque<CommConstraint> newU;
|
|
while (!U.empty() && !B.empty())
|
|
{
|
|
if (U.front().size < B.front().size)
|
|
{
|
|
if (!docheckUnequalConstraints(B, U, newU, problemConstraints))
|
|
return false;
|
|
}
|
|
else if (U.front().size > B.front().size)
|
|
{
|
|
if (!docheckUnequalConstraints(U, B, newU, problemConstraints))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (U.front().typeVariant == 0 || B.front().typeVariant == 0
|
|
|| equalConstraints(U.front(), B.front()))
|
|
{
|
|
if (U.front().typeVariant == 0)
|
|
addElem(newU, B.front());
|
|
else if (B.front().typeVariant == 0)
|
|
addElem(newU, U.front());
|
|
else
|
|
{
|
|
U.front().uses.insert(U.front().uses.end(), B.front().uses.begin(), B.front().uses.end()); // adding to funcs
|
|
addElem(newU, U.front());
|
|
}
|
|
U.pop_front();
|
|
B.pop_front();
|
|
}
|
|
else
|
|
{
|
|
problemConstraints = make_pair(B.front(), U.front());
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
while (!B.empty())
|
|
{
|
|
addElem(newU, B.front());
|
|
B.pop_front();
|
|
}
|
|
while (!U.empty())
|
|
{
|
|
addElem(newU, U.front());
|
|
U.pop_front();
|
|
}
|
|
if (!newU.empty() && newU.back().typeVariant == 0)
|
|
newU.pop_back();
|
|
U = newU;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool getNamesOldToNew(deque<CommConstraint> newDecl, deque<CommConstraint> oldDecl, map<string, string>& namesOldToNew)
|
|
{
|
|
bool needChange = false;
|
|
map<string, string> rename;
|
|
while (!oldDecl.empty() && !newDecl.empty())
|
|
{
|
|
if (newDecl.front().typeVariant == 0) // => oldDecl.front().typeVariant == 0
|
|
{
|
|
if (oldDecl.front().size > newDecl.front().size)
|
|
{
|
|
oldDecl.front().size -= newDecl.front().size;
|
|
needChange = true;
|
|
}
|
|
else
|
|
oldDecl.pop_front();
|
|
newDecl.pop_front();
|
|
}
|
|
else if (newDecl.front().size > oldDecl.front().size)
|
|
{
|
|
needChange = true;
|
|
deque<CommConstraint> tmp;
|
|
tmp.push_front(newDecl.front());
|
|
splitType(tmp, false);
|
|
while (!tmp.empty() && !oldDecl.empty())
|
|
{
|
|
if (oldDecl.front().typeVariant == 0)
|
|
{
|
|
if (oldDecl.front().size > tmp.front().size)
|
|
oldDecl.front().size -= tmp.front().size;
|
|
else
|
|
oldDecl.pop_front();
|
|
}
|
|
else
|
|
{
|
|
rename[oldDecl.front().identifier] = tmp.front().identifier;
|
|
oldDecl.pop_front();
|
|
}
|
|
tmp.pop_front();
|
|
}
|
|
newDecl.pop_front();
|
|
}
|
|
else if (oldDecl.front().size > newDecl.front().size) // => oldDecl.front().typeVariant == 0
|
|
{
|
|
needChange = true;
|
|
oldDecl.front().size -= newDecl.front().size;
|
|
newDecl.pop_front();
|
|
}
|
|
else // == and newDecl.front().typeVariant != 0
|
|
{
|
|
if (oldDecl.front().typeVariant == 0)
|
|
needChange = true;
|
|
else
|
|
{
|
|
if (oldDecl.front().identifier.find('(') != string::npos)
|
|
{
|
|
needChange = true;
|
|
rename[oldDecl.front().identifier] = newDecl.front().identifier;
|
|
}
|
|
else
|
|
rename[oldDecl.front().identifier] = newDecl.front().identifier;
|
|
}
|
|
oldDecl.pop_front();
|
|
newDecl.pop_front();
|
|
}
|
|
}
|
|
if (!oldDecl.empty() || !newDecl.empty())
|
|
needChange = true;
|
|
if (needChange)
|
|
namesOldToNew.insert(rename.begin(), rename.end());
|
|
return needChange;
|
|
}
|
|
|
|
|
|
void makeCommVarSymbs(const deque<CommConstraint>& constraints, SgFile* file, SgStatement* func, string commName,
|
|
map<string, SgSymbol*>& symbs, vector<SgSymbol*>& needNewDecl)
|
|
{
|
|
for (const CommConstraint& var : constraints)
|
|
{
|
|
if (var.typeVariant != 0)
|
|
{
|
|
SgSymbol* symb = findSymbolOrCreate(file, var.identifier, var.type->copyPtr(), func);
|
|
symbs[var.identifier] = symb;
|
|
needNewDecl.push_back(symb);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void deleteOldVars(SgStatement* firstSt, const set<string>& commVarNames)
|
|
{
|
|
SgStatement* lastSt = firstSt->lastNodeOfStmt();
|
|
vector<SgStatement*> stmtsToDelete;
|
|
for (SgStatement* curSt = firstSt; curSt != lastSt; curSt = curSt->lexNext())
|
|
{
|
|
if (curSt->variant() == VAR_DECL || curSt->variant() == VAR_DECL_90)
|
|
{
|
|
SgVarDeclStmt* varDeclSt = (SgVarDeclStmt*)curSt;
|
|
vector<SgExpression*> varsToDelete;
|
|
for (int i = 0; i < varDeclSt->numberOfVars(); i++)
|
|
{
|
|
SgExpression* var = varDeclSt->var(i);
|
|
string varName = "";
|
|
if (var->variant() == ASSGN_OP)
|
|
varName = var->lhs()->symbol()->identifier();
|
|
else
|
|
varName = var->symbol()->identifier();
|
|
if (commVarNames.find(varName) != commVarNames.end())
|
|
varsToDelete.push_back(var);
|
|
}
|
|
if (varDeclSt->numberOfVars() == varsToDelete.size())
|
|
stmtsToDelete.push_back(curSt);
|
|
else
|
|
for (SgExpression* var : varsToDelete)
|
|
varDeclSt->deleteTheVar(*var);
|
|
}
|
|
else if (curSt->variant() == DIM_STAT)
|
|
{
|
|
SgExpression* ex = curSt->expr(0);
|
|
bool first = true;
|
|
vector<SgExpression*> leftExprs;
|
|
while (ex != NULL)
|
|
{
|
|
string name = ex->lhs()->symbol()->identifier();
|
|
if (commVarNames.find(name) == commVarNames.end())
|
|
leftExprs.push_back(ex->lhs());
|
|
ex = ex->rhs();
|
|
}
|
|
if (leftExprs.empty())
|
|
stmtsToDelete.push_back(curSt);
|
|
else
|
|
curSt->setExpression(0, makeExprList(leftExprs));
|
|
}
|
|
// TODO: delete common variables form attributes statements (like DIM_STAT)
|
|
}
|
|
for (SgStatement* st : stmtsToDelete)
|
|
st->deleteStmt();
|
|
}
|
|
|
|
|
|
SgExpression* makeIdxFromStr(const string& str)
|
|
{
|
|
vector<SgExpression*> items;
|
|
int num = 0;
|
|
for (char c : str)
|
|
{
|
|
if ('0' <= c && c <= '9')
|
|
num = num * 10 + (c - '0');
|
|
else if (c == ',' || c == ')')
|
|
{
|
|
SgExpression* ex = new SgValueExp(num);
|
|
items.push_back(ex);
|
|
num = 0;
|
|
}
|
|
}
|
|
reverse(items.begin(), items.end());
|
|
SgExpression* exprList = makeExprList(items, false);
|
|
return exprList;
|
|
}
|
|
|
|
|
|
SgExpression* newArrElemExpr(const string& newName, const map<string, SgSymbol*>& newSymbs)
|
|
{
|
|
size_t pos = newName.find('(');
|
|
SgExpression* newExpr = new SgArrayRefExp(*newSymbs.at(newName.substr(0, pos)));
|
|
newExpr->setLhs(makeIdxFromStr(newName.substr(pos)));
|
|
return newExpr;
|
|
}
|
|
|
|
|
|
SgExpression* fixExpression(SgExpression* expr, const map<string, SgSymbol*>& newSymbs, const map<string, string>& namesOldToNew)
|
|
{
|
|
if (expr == NULL)
|
|
return NULL;
|
|
if (expr->variant() == VAR_REF || expr->variant() == ARRAY_REF)
|
|
{
|
|
string name = expr->symbol()->identifier();
|
|
auto nameIt = namesOldToNew.find(name);
|
|
if (nameIt != namesOldToNew.end())
|
|
{
|
|
string newName = nameIt->second;
|
|
auto symbIt = newSymbs.find(newName);
|
|
if (symbIt == newSymbs.end()) // variable -> array element
|
|
return newArrElemExpr(newName, newSymbs);
|
|
else // variable -> variable or array name -> array name
|
|
{
|
|
SgSymbol* newSymb = symbIt->second;
|
|
expr->setSymbol(newSymb);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
string fullName = expr->sunparse();
|
|
auto fullNameIt = namesOldToNew.find(fullName);
|
|
if (fullNameIt != namesOldToNew.end())
|
|
{
|
|
string newName = fullNameIt->second;
|
|
auto symbIt = newSymbs.find(newName);
|
|
if (symbIt == newSymbs.end()) // array element -> array element
|
|
return newArrElemExpr(newName, newSymbs);
|
|
else // array element -> variable
|
|
{
|
|
SgVariableSymb* varSymb = (SgVariableSymb*)symbIt->second;
|
|
SgExpression* newExpr = new SgVarRefExp(*varSymb);
|
|
return newExpr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SgExpression* lhs = fixExpression(expr->lhs(), newSymbs, namesOldToNew);
|
|
if (lhs != NULL)
|
|
expr->setLhs(lhs);
|
|
SgExpression* rhs = fixExpression(expr->rhs(), newSymbs, namesOldToNew);
|
|
if (rhs != NULL)
|
|
expr->setRhs(rhs);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void renameVariables(SgStatement* firstSt, const map<string, SgSymbol*>& newVarSymbs, const map<string, string>& namesOldToNew)
|
|
{
|
|
SgStatement* lastSt = firstSt->lastNodeOfStmt();
|
|
for (SgStatement* curSt = firstSt; curSt != NULL && curSt != lastSt; curSt = curSt->lexNext())
|
|
{
|
|
if (curSt->variant() == DATA_DECL)
|
|
{
|
|
SgValueExp* dataExpr = (SgValueExp*)curSt->expr(0);
|
|
map<string, string> data = splitData({ dataExpr });
|
|
string newDataStr = "data ";
|
|
bool needChange = false;
|
|
int left = data.size();
|
|
for (pair<const string, string>& item : data)
|
|
{
|
|
auto nameIt = namesOldToNew.find(item.first);
|
|
if (nameIt != namesOldToNew.end())
|
|
{
|
|
newDataStr += nameIt->second + "/" + item.second + "/";
|
|
needChange = true;
|
|
}
|
|
else
|
|
newDataStr += item.first + "/" + item.second + "/";
|
|
left--;
|
|
if (left != 0)
|
|
newDataStr += ", ";
|
|
}
|
|
if (needChange)
|
|
{
|
|
SgExpression* es = new SgExpression(STMT_STR);
|
|
char* value = (char*)malloc(newDataStr.size() + 1);
|
|
value[newDataStr.size()] = '\0';
|
|
memcpy(value, newDataStr.c_str(), sizeof(char) * newDataStr.size());
|
|
es->thellnd->entry.string_val = value;
|
|
curSt->setExpression(0, es);
|
|
}
|
|
}
|
|
else if (isSgExecutableStatement(curSt) || curSt->variant() == EQUI_STAT)
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
SgExpression* expr = fixExpression(curSt->expr(i), newVarSymbs, namesOldToNew);
|
|
if (expr != NULL)
|
|
curSt->setExpression(i, expr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
SgExpression* makeExprListForCommon(const deque<CommConstraint>& decl, const map<string, SgSymbol*>& newSymbs,
|
|
SgFile* file, SgStatement* firstSt)
|
|
{
|
|
vector<SgExpression*> items;
|
|
for (auto it = decl.rbegin(); it != decl.rend(); it++)
|
|
{
|
|
if (it->typeVariant == 0)
|
|
continue;
|
|
SgSymbol* symb = NULL;
|
|
bool old = false;
|
|
auto symbIt = newSymbs.find(it->identifier);
|
|
if (symbIt != newSymbs.end())
|
|
symb = symbIt->second;
|
|
else
|
|
{
|
|
symb = findSymbolOrCreate(file, it->identifier, it->type, firstSt);
|
|
old = true;
|
|
}
|
|
SgVariableSymb* varSymb = isSgVariableSymb(symb);
|
|
if (varSymb->type()->variant() == T_ARRAY)
|
|
{
|
|
SgExpression* newExpr = new SgArrayRefExp(*varSymb);
|
|
items.push_back(newExpr);
|
|
}
|
|
else
|
|
{
|
|
SgExpression* newExpr = new SgVarRefExp(symb);
|
|
items.push_back(newExpr);
|
|
}
|
|
}
|
|
SgExpression* exprList = makeExprList(items, false);
|
|
return exprList;
|
|
}
|
|
|
|
|
|
void rewriteCommon(SgStatement* firstSt, map<string, SgExpression*>& commListExprs)
|
|
{
|
|
vector<SgStatement*> commonStmtsToDelete;
|
|
for (SgStatement* st = firstSt; st != firstSt->lastDeclaration()->lexNext(); st = st->lexNext())
|
|
{
|
|
if (st->variant() == COMM_STAT)
|
|
{
|
|
SgExpression* ex = st->expr(0);
|
|
bool first = true;
|
|
SgExpression* prev = NULL;
|
|
while (ex != NULL)
|
|
{
|
|
string commName = "";
|
|
SgSymbol* s = ex->symbol();
|
|
if (s == NULL)
|
|
commName = "spf_unnamed";
|
|
else
|
|
commName = s->identifier();
|
|
auto commIt = commListExprs.find(commName);
|
|
if (commIt != commListExprs.end())
|
|
{
|
|
if (commIt->second != NULL)
|
|
{
|
|
ex->setLhs(commIt->second);
|
|
commIt->second = NULL;
|
|
if (first)
|
|
first = false;
|
|
prev = ex;
|
|
ex = ex->rhs();
|
|
}
|
|
else
|
|
{
|
|
if (first)
|
|
{
|
|
st->setExpression(0, ex->rhs());
|
|
ex = st->expr(0);
|
|
}
|
|
else
|
|
{
|
|
prev->setRhs(ex->rhs());
|
|
ex = prev->rhs();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
ex = ex->rhs();
|
|
}
|
|
if (st->expr(0) == NULL)
|
|
commonStmtsToDelete.push_back(st);
|
|
}
|
|
}
|
|
for (SgStatement* st : commonStmtsToDelete)
|
|
st->deleteStmt();
|
|
}
|
|
|
|
|
|
void fixNames(deque<CommConstraint>& constraints, const string& commName)
|
|
{
|
|
for (auto& var : constraints)
|
|
{
|
|
for (char& c : var.identifier)
|
|
{
|
|
if (c == ')' || c == '(')
|
|
c = 'l';
|
|
if (c == ',')
|
|
c = '_';
|
|
}
|
|
var.identifier = commName + "_" + var.identifier;
|
|
}
|
|
}
|
|
|
|
|
|
bool variablePositionComp(const Variable* lhs, const Variable* rhs)
|
|
{
|
|
return lhs->getPosition() < rhs->getPosition();
|
|
}
|
|
|
|
|
|
void fixFunctions(SgFile* file, vector<SgStatement*> programUnits, map<string, deque<CommConstraint>>& newCommonDecls,
|
|
map<string, map<string, deque<CommConstraint>>>& commDecls, const set<string>& badCommon, map<string, set<string>>& notUsedVars)
|
|
{
|
|
for (SgStatement* unitSt : programUnits)
|
|
{
|
|
string funcName = unitSt->symbol()->identifier();
|
|
if (commDecls.find(funcName) == commDecls.end())
|
|
continue;
|
|
SgStatement* firstSt = unitSt;
|
|
map<string, SgExpression*> commListExprs;
|
|
map<string, SgSymbol*> newVarSymbs; // new symbols for new variables
|
|
map<string, string> namesOldToNew; // for ranaming: old name -> new name
|
|
vector<SgSymbol*> needNewDecl;
|
|
for (auto& common : commDecls[funcName])
|
|
{
|
|
string commName = common.first;
|
|
if (badCommon.find(commName) != badCommon.end())
|
|
continue;
|
|
const deque<CommConstraint>& newDecl = newCommonDecls.at(commName);
|
|
vector<CommConstraint> varsNeedNewSymb;
|
|
bool needChange = getNamesOldToNew(newDecl, common.second, namesOldToNew);
|
|
if (!needChange)
|
|
continue;
|
|
makeCommVarSymbs(newDecl, file, firstSt, commName, newVarSymbs, needNewDecl);
|
|
commListExprs[commName] = makeExprListForCommon(newDecl, newVarSymbs, file, firstSt);
|
|
}
|
|
if (!commListExprs.empty())
|
|
{
|
|
for (const auto& item : commListExprs)
|
|
for (const auto& x : commDecls[funcName][item.first])
|
|
notUsedVars[funcName].insert(x.identifier);
|
|
deleteOldVars(unitSt, notUsedVars[funcName]);
|
|
renameVariables(unitSt, newVarSymbs, namesOldToNew);
|
|
makeDeclaration(needNewDecl, unitSt);
|
|
rewriteCommon(firstSt, commListExprs);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void BuildNewCommDecls(SgFile* file, const map<string, CommonBlock*> allCommonBlocks,
|
|
map<string, deque<CommConstraint>>& newCommonDecls, map<string, map<string, deque<CommConstraint>>>& commDecls,
|
|
set<string>& badCommon, map<string, set<string>>& notUsedVars, vector<SgStatement*>& programUnits)
|
|
{
|
|
string fileName = file->filename();
|
|
SgStatement* curSt = file->firstStatement();
|
|
while (curSt != NULL)
|
|
{
|
|
if (curSt->variant() == PROG_HEDR || curSt->variant() == PROC_HEDR || curSt->variant() == FUNC_HEDR || curSt->variant() == BLOCK_DATA || curSt->variant() == MODULE_STMT)
|
|
{
|
|
programUnits.push_back(curSt);
|
|
string funcName = curSt->symbol()->identifier();
|
|
for (auto item : allCommonBlocks)
|
|
{
|
|
string commName = item.first;
|
|
if (badCommon.find(commName) != badCommon.end())
|
|
continue;
|
|
CommonBlock* commonBlock = item.second;
|
|
vector<const Variable*> vars = commonBlock->getVariables(fileName, funcName);
|
|
if (vars.size() == 0)
|
|
continue;
|
|
sort(vars.begin(), vars.end(), variablePositionComp);
|
|
set<string> varNames;
|
|
for (const Variable* var : vars)
|
|
varNames.insert(var->getName());
|
|
set<string> namesOfUsedVars = getUses(curSt, varNames);
|
|
bool hasChar = false;
|
|
bool hasNotChar = false;
|
|
deque<CommConstraint> constraints;
|
|
for (const Variable* var : vars)
|
|
{
|
|
CommConstraint newConstr = CommConstraint(var, false, funcName, fileName);
|
|
if (newConstr.typeVariant == T_STRING || newConstr.typeVariant == T_ARRAY) // ignore common blocks with strings
|
|
hasChar = true;
|
|
else
|
|
hasNotChar = true;
|
|
if (namesOfUsedVars.find(newConstr.identifier) != namesOfUsedVars.end())
|
|
newConstr.used = true;
|
|
constraints.push_back(newConstr);
|
|
}
|
|
if (hasChar && hasNotChar) // TDOO: make proper warning message or separate such common blocks
|
|
__spf_print(1, "common block '%s' ('%s':%d) contains variables of symbolic and numeric types. It is required to divide\n", commName.c_str(), fileName.c_str(), constraints.back().uses.back().lineNum);
|
|
if (hasChar)
|
|
{
|
|
badCommon.insert(commName);
|
|
continue;
|
|
}
|
|
deque<CommConstraint> curComm = makeConstraints(constraints, namesOfUsedVars, notUsedVars[funcName]);
|
|
commDecls[funcName][commName] = curComm;
|
|
bool res;
|
|
pair<CommConstraint, CommConstraint> problemConstraints;
|
|
res = buildConstraintsUnion(newCommonDecls[commName], curComm, namesOfUsedVars, problemConstraints);
|
|
if (!res)
|
|
{
|
|
badCommon.insert(commName);
|
|
for (auto x : problemConstraints.first.uses) // TODO: make proper warning message
|
|
for (auto y : problemConstraints.second.uses)
|
|
__spf_print(1, "variables '%s' and '%s' in one storage association (common block '%s') have different types (files - %s:%d and %s:%d)\n",
|
|
x.varName.c_str(), y.varName.c_str(), commName.c_str(), x.fileName.c_str(), x.lineNum, y.fileName.c_str(), y.lineNum);
|
|
}
|
|
}
|
|
curSt = curSt->lastNodeOfStmt();
|
|
}
|
|
else
|
|
curSt = curSt->lexNext();
|
|
}
|
|
}
|
|
|
|
|
|
// main function
|
|
void fixCommonBlocks(const map<string, vector<FuncInfo*>> allFuncInfo, const map<string, CommonBlock*> allCommonBlocks, SgProject* project) // TODO: separate into 2 steps?
|
|
{
|
|
int filesNum = project->numberOfFiles();
|
|
map<string, map<string, map<string, deque<CommConstraint>>>> commDecls; // file_name -> function_name -> common block name -> old declaration of common block
|
|
map<string, deque<CommConstraint>> newCommonDecls; // name of common block -> cur builded declaration
|
|
map<string, set<string>> notUsedVars;
|
|
map<string, vector<SgStatement*>> programUnitsInFile;
|
|
set<string> badCommon;
|
|
|
|
for (int i = 0; i < filesNum; i++) // first step
|
|
{
|
|
SgFile* file = &project->file(i);
|
|
string fileName = file->filename();
|
|
file->switchToFile(fileName);
|
|
BuildNewCommDecls(file, allCommonBlocks, newCommonDecls, commDecls[fileName], badCommon, notUsedVars, programUnitsInFile[fileName]);
|
|
}
|
|
for (auto& elem : newCommonDecls)
|
|
fixNames(elem.second, elem.first);
|
|
for (int i = 0; i < filesNum; i++) // second step
|
|
{
|
|
SgFile* file = &project->file(i);
|
|
string fileName = file->filename();
|
|
file->switchToFile(fileName);
|
|
fixFunctions(file, programUnitsInFile[fileName], newCommonDecls, commDecls[fileName], badCommon, notUsedVars);
|
|
}
|
|
} |