Files
SAPFOR/src/Transformations/GlobalVariables/fix_common_blocks.cpp

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);
}
}