This commit is contained in:
2025-03-12 12:37:19 +03:00
committed by Dudarenko
parent 0c9f0664fd
commit d4fb323f86
428 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
#include "leak_detector.h"
#include "DvmhRegion.h"
DvmhRegion::DvmhRegion(LoopGraph *loopNode, const std::string &fun_name) : fun_name(fun_name)
{
loops.push_back(loopNode);
}
SgStatement* DvmhRegion::getFirstSt() const
{
if (loops.size() < 1)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
return loops.front()->loop->GetOriginal();
}
SgStatement* DvmhRegion::getLastSt() const
{
if (loops.size() < 1)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
return loops.back()->loop->GetOriginal()->lastNodeOfStmt();
}
void DvmhRegion::append(DvmhRegion& region)
{
for (auto& loop : region.getLoops())
addLoop(loop);
}
int DvmhRegion::getLineForSort() const
{
if (loops.size() == 0)
return -1;
int line = loops[0]->lineNum;
if (line < 0)
line = loops[0]->altLineNum;
return line;
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "../GraphLoop/graph_loops_func.h"
#include <string>
class DvmhRegion
{
private:
std::vector<LoopGraph*> loops;
std::string fun_name;
public:
DvmhRegion() { }
DvmhRegion(LoopGraph *loopNode, const std::string &fun_name);
SgStatement* getFirstSt() const;
SgStatement* getLastSt() const;
void addLoop(LoopGraph* newLoop) { loops.push_back(newLoop); }
const std::string& getFunName() const { return fun_name; }
void setFunName(const std::string& newName) { fun_name = newName; }
const std::vector<LoopGraph*>& getLoops() const { return loops; }
std::string getFileName() const { return getFirstSt()->fileName(); }
void append(DvmhRegion& region);
int getLineForSort() const;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
#pragma once
#include "../GraphCall/graph_calls_func.h"
#include "../GraphLoop/graph_loops_func.h"
#include "../ExpressionTransform/expr_transform.h"
#include "../ParallelizationRegions/ParRegions.h"
#include "../Utils/SgUtils.h"
#include "ReadWriteAnalyzer.h"
#include "DvmhRegion.h"
typedef std::set<DIST::Array* > ArraySet;
struct ReadWrite
{
ArraySet read;
ArraySet write;
};
typedef std::map<int, ReadWrite> UsageByLine;
typedef std::map<std::string, UsageByLine> UsageByFile;
class DvmhRegionInserter
{
// input data
SgFile *file;
std::map<int, LoopGraph*> loopGraphMap;
const std::vector<LoopGraph*> loopGraph;
const std::map<std::string, FuncInfo*> allFunctions;
const std::vector<FuncInfo*> funcsForFile;
bool isMpiProgram;
ReadWriteAnalyzer& rw_analyzer;
std::map<FuncInfo*, std::set<LoopGraph*>> parallel_functions;
std::set<DIST::Array*> writesToArraysInParallelLoops;
std::set<DIST::Array*> usedArraysInParallelLoops;
const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls;
// operating data
std::vector<DvmhRegion*> regions;
// region directives
void findEdgesForRegions(const std::vector<LoopGraph*>&);
bool hasLimitsToDvmhParallel(const LoopGraph*) const;
void insertRegionDirectives();
// actual directives
ArraySet symbs_to_arrs(std::set<SgSymbol*>) const;
ArraySet get_used_arrs(SgStatement* st, int usage_type) const;
ArraySet get_used_arrs_for_block(SgStatement* st, int usage_type) const;
SgStatement* processSt(SgStatement *st, const std::vector<ParallelRegion*>* regs);
void insertActualDirective(SgStatement*, const ArraySet&, int, bool, const std::set<std::string>* = NULL);
void parFuncsInNode(LoopGraph *loop, bool isParallel);
bool isLoopParallel(const LoopGraph *loop) const;
std::vector<SgExpression*> getArrayList(Statement* start, Statement* end, bool left = false) const;
ArraySet applyUseFilter(const ArraySet& block, const std::set<DIST::Array*>& filter) const;
ArraySet excludePrivates(const ArraySet& block) const;
ArraySet excludeRemotes(const ArraySet& block, SgStatement* remoteDir) const;
void insertForProcCall(SgStatement* st, bool& skipGetActualIfProcCall, bool& skipActualIfProcCall);
public:
explicit DvmhRegionInserter(
SgFile* curFile,
const std::vector<LoopGraph*>& curLoopGraph,
ReadWriteAnalyzer& rws,
const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls,
const std::map<std::string, FuncInfo*>& allFunctions,
const std::vector<FuncInfo*>& funcsForFile,
bool mpi_program
) : file(curFile), loopGraph(curLoopGraph), rw_analyzer(rws), arrayLinksByFuncCalls(arrayLinksByFuncCalls), allFunctions(allFunctions), funcsForFile(funcsForFile), isMpiProgram(mpi_program)
{
if (loopGraph.size())
createMapLoopGraph(loopGraph, loopGraphMap);
}
void insertDirectives(const std::vector<ParallelRegion*>* regs = NULL);
void insertActualDirectives(const std::vector<ParallelRegion*>* regs);
void updateParallelFunctions(const std::map<std::string, std::vector<LoopGraph*>>& loopGraphs);
void createInterfaceBlockForParallelFunctions(bool onlyRoutine = true);
void removePrivatesFromParallelLoops();
void addPrivatesToParallelLoops();
void addUsedArrays(std::set<DIST::Array*>& arrays);
void addUsedWriteArrays(std::set<DIST::Array*>& arrays);
void updateUsedArrays(const std::set<DIST::Array*>& used, const std::set<DIST::Array*>& usedForWrite)
{
ArraySet newSet = usedForWrite;
for (auto& elem : usedForWrite)
getRealArrayRefs(elem, elem, newSet, arrayLinksByFuncCalls);
writesToArraysInParallelLoops = newSet;
newSet = used;
for (auto& elem : used)
getRealArrayRefs(elem, elem, newSet, arrayLinksByFuncCalls);
usedArraysInParallelLoops = newSet;
}
const std::set<FuncInfo*> getParallelFunctions() const {
std::set<FuncInfo*> retVal;
for (auto& elem : parallel_functions)
retVal.insert(elem.first);
return retVal;
}
static void createInterfaceBlockForOutCall(FuncInfo* func, FuncInfo* callFrom);
static void createInterfaceBlockForOutCalls(FuncInfo* func);
~DvmhRegionInserter()
{
for (auto& reg : regions)
delete reg;
}
};
int insertDvmhRegions(SgProject& project, int files, const std::vector<ParallelRegion*>& parallelRegions,
std::map<std::string, std::vector<FuncInfo*>>& allFuncInfo,
std::map<std::string, std::vector<LoopGraph*>> loopGraph,
ReadWriteAnalyzer& rw_analyzer,
std::map<std::string, std::vector<Messages>>& SPF_messages,
const std::map<DIST::Array*, std::set<DIST::Array*>> arrayLinksByFuncCalls);

View File

@@ -0,0 +1,72 @@
#include "leak_detector.h"
#include "LoopChecker.h"
using namespace std;
void LoopChecker::updateLoopGraph(const map<string, FuncInfo*> &allFuncs)
{
for (auto &loopNode : loopGraph)
updateLoopNode(loopNode, allFuncs);
}
LoopCheckResults LoopChecker::updateLoopNode(LoopGraph *loop, const map<string, FuncInfo*> &allFuncs)
{
LoopCheckResults loopChecks = checkLoopForPurenessAndIO(loop, allFuncs);
bool hasImpureCalls = loopChecks.hasImpureCalls;
bool usesIO = loopChecks.usesIO;
if (loopChecks.linesOfIO.size() && usesIO)
for (auto& elem : loopChecks.linesOfIO)
loop->linesOfIO.insert(elem);
for (auto &nestedLoop : loop->children)
{
loopChecks = updateLoopNode(nestedLoop, allFuncs);
hasImpureCalls |= loopChecks.hasImpureCalls;
usesIO |= loopChecks.usesIO;
}
loop->hasNonPureProcedures |= hasImpureCalls;
loop->hasPrints |= usesIO;
return LoopCheckResults(loop->hasPrints, loop->hasNonPureProcedures);
}
// checks loop node itself, doesn't check its children
LoopCheckResults LoopChecker::checkLoopForPurenessAndIO(const LoopGraph *loopNode, const map<string, FuncInfo*> &allFuncs) const
{
LoopCheckResults loopCheckResults;
for (auto &nameAndLineOfFuncCalled : loopNode->calls)
{
FuncInfo *calledFuncInfo = NULL;
auto it = allFuncs.find(nameAndLineOfFuncCalled.first);
if (it != allFuncs.end())
calledFuncInfo = it->second;
if (!calledFuncInfo)
{
if (isIntrinsicFunctionName(nameAndLineOfFuncCalled.first.c_str()))
continue;
else
{ // if funcInfo was not found assume func to be impure
loopCheckResults.hasImpureCalls = true;
loopCheckResults.usesIO = true;
loopCheckResults.linesOfIO.push_back(nameAndLineOfFuncCalled.second);
}
continue;
}
if (!calledFuncInfo->isPure)
loopCheckResults.hasImpureCalls = true;
if (calledFuncInfo->usesIO())
{
loopCheckResults.usesIO = true;
loopCheckResults.linesOfIO.push_back(nameAndLineOfFuncCalled.second);
}
}
return loopCheckResults;
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "../GraphLoop/graph_loops_func.h"
#include "../GraphCall/graph_calls_func.h"
#include <vector>
#include <string>
#include <map>
struct LoopCheckResults
{
bool usesIO;
bool hasImpureCalls;
std::vector<int> linesOfIO;
LoopCheckResults() : usesIO(false), hasImpureCalls(false) { }
LoopCheckResults(bool io, bool calls) : usesIO(io), hasImpureCalls(calls) { }
};
class LoopChecker
{
std::vector<LoopGraph*> &loopGraph;
LoopCheckResults checkLoopForPurenessAndIO(const LoopGraph *loopNode, const std::map<std::string, FuncInfo*> &allFuncs) const;
LoopCheckResults updateLoopNode(LoopGraph *loop, const std::map<std::string, FuncInfo*> &allFuncs);
public:
explicit LoopChecker(std::vector<LoopGraph*> &graph) : loopGraph(graph) { }
void updateLoopGraph(const std::map<std::string, FuncInfo*> &allFuncs);
};

View File

@@ -0,0 +1,341 @@
#include "leak_detector.h"
#include "ReadWriteAnalyzer.h"
using namespace std;
void ReadWriteAnalyzer::init(SgFile* forFile)
{
auto save = current_file->filename();
modified_pars = ReadWriteAnalyzer::load_modified_pars(funcInfo);
for (int j = 0; j < forFile->numberOfFunctions(); ++j)
{
SgStatement* func_hdr = forFile->functions(j);
SgStatement* last = func_hdr->lastNodeOfStmt();
for (SgStatement* runner = func_hdr->lexNext(); runner != last; runner = runner->lexNext())
{
// TODO: is it ok to skip all of them?
if (!isSgExecutableStatement(runner) || isDVM_stat(runner) || isSPF_stat(runner))
continue;
if (runner->variant() == CONTAINS_STMT)
break;
VarUsages usages = findUsagesInStatement(runner);
auto it = usages_by_statement.find(runner);
if (it != usages_by_statement.end())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
usages_by_statement[runner] = usages;
}
}
initialized.insert(forFile->filename());
if (SgFile::switchToFile(save) == -1)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
}
VarUsages ReadWriteAnalyzer::findUsagesInStatement(SgStatement* st) const
{
// *special* statements, TODO: what i've missed?
if (st->variant() == ASSIGN_STAT)
return findUsagesInAssignment(st);
if (st->variant() == PROC_STAT)
return findUsagesInFuncCall(st->expr(0), st->symbol()->identifier());
else if (!isDVM_stat(st) && !isSPF_stat(st))
{
VarUsages st_usages;
for (int i = 0; i < 3; ++i)
st_usages.extend(findUsagesInExpr(st->expr(i)));
return st_usages;
}
return VarUsages();
}
VarUsages ReadWriteAnalyzer::findUsagesInAssignment(SgStatement* st) const
{
// load read & writes from the right part
VarUsages usages = findUsagesInExpr(st->expr(1));
// load usages from array indexes
VarUsages usages_in_arr_indexing = findUsagesInExpr(st->expr(1)->lhs());
usages.extend(usages_in_arr_indexing);
usages_in_arr_indexing = findUsagesInExpr(st->expr(1)->rhs());
usages.extend(usages_in_arr_indexing);
usages_in_arr_indexing = findUsagesInExpr(st->expr(0)->lhs());
usages.extend(usages_in_arr_indexing);
usages_in_arr_indexing = findUsagesInExpr(st->expr(0)->rhs());
usages.extend(usages_in_arr_indexing);
// finally add explicitly modified var
auto ex = st->expr(0);
auto s = st->expr(0)->symbol();
if (s && (ex->variant() == VAR_REF || isArrayRef(ex)))
usages.insert_write(ex);
return usages;
}
VarUsages ReadWriteAnalyzer::findUsagesInExpr(SgExpression* exp) const
{
VarUsages usages;
queue<SgExpression*> buf;
buf.push(exp);
while (!buf.empty())
{
SgExpression* cur = buf.front();
buf.pop();
if (!cur)
continue;
const int e_type = cur->variant();
if (e_type == VAR_REF || isArrayRef(cur))
usages.insert_read(cur);
else if (e_type == FUNC_CALL)
usages.extend(findUsagesInFuncCall(cur->lhs(), cur->symbol()->identifier()));
buf.push(cur->lhs());
buf.push(cur->rhs());
}
return usages;
}
void ReadWriteAnalyzer::findReadUsagesInExpression(SgExpression* ex, VarUsages& usages) const
{
if (ex)
{
if (ex->variant() == VAR_REF || ex->variant() == ARRAY_REF)
usages.insert_read(ex);
findReadUsagesInExpression(ex->lhs(), usages);
findReadUsagesInExpression(ex->rhs(), usages);
}
}
//TODO: need to improve to MPI_* functions
VarUsages ReadWriteAnalyzer::findUsagesInFuncCall(SgExpression* params_tree, const string& func_key) const
{
VarUsages usages;
vector<int> inOutTypes;
bool isIntrinsic = isIntrinsicFunctionName(func_key.c_str());
if (!isIntrinsic)
{
auto it = modified_pars.find(func_key);
if (it != modified_pars.end())
inOutTypes = it->second;
}
else if (isMpiFunction(func_key.c_str()))
{
if (func_key == "mpi_abort")
inOutTypes = { IN_BIT, IN_BIT, OUT_BIT };
if (func_key == "mpi_send")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
if (func_key == "mpi_isend")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_recv")
inOutTypes = { IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_irecv")
inOutTypes = { IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_alltoall")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_alltoallv")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_allgather")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_allgatherv")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_allreduce")
inOutTypes = { IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_reduce")
inOutTypes = { IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_reduce_scatter")
inOutTypes = { IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_scatter")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_scatterv")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_gather")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_gatherv")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_sendrecv")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_sendrecv_replace")
inOutTypes = { IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_scan")
inOutTypes = { IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT };
else if (func_key == "mpi_bcast")
inOutTypes = { IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT };
else if (func_key == "mpi_bsend")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT };
else if (func_key == "mpi_bsend_init")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT };
else if (func_key == "mpi_ibsend")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT };
else if (func_key == "mpi_irsend")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT };
else if (func_key == "mpi_issend")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT };
else if (func_key == "mpi_recv_init")
inOutTypes = { OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT };
else if (func_key == "mpi_rsend")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT };
else if (func_key == "mpi_rsend_init")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT };
else if (func_key == "mpi_send_init")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT };
else if (func_key == "mpi_ssend")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT };
else if (func_key == "mpi_ssend_init")
inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT };
}
int param_no = 0;
while (params_tree)
{
SgExpression* param = params_tree->lhs();
if (param->variant() == VAR_REF || isArrayRef(param))
{
if (inOutTypes.size())
{
if (param_no >= inOutTypes.size())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
if (FuncParam::isArgIn((int64_t)inOutTypes[param_no]))
usages.insert_read(param);
if (FuncParam::isArgOut((int64_t)inOutTypes[param_no]))
usages.insert_write(param);
}
else
{
usages.insert_read(param);
if (!isIntrinsic)
usages.insert_write(param);
}
findReadUsagesInExpression(param->lhs(), usages);
findReadUsagesInExpression(param->rhs(), usages);
}
param_no++;
params_tree = params_tree->rhs();
}
return usages;
}
VarUsages ReadWriteAnalyzer::get_usages(SgStatement* st)
{
if (initialized.find(st->fileName()) == initialized.end())
init(st->getFile());
VarUsages usages;
// if statement is compound
if (compound_statements.find(st->variant()) != compound_statements.end())
usages = gatherUsagesForCompound(st);
else
{
auto it = usages_by_statement.find(st);
if (it == usages_by_statement.end())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
usages = it->second;
}
return usages;
}
VarUsages ReadWriteAnalyzer::get_usages(vector<SgStatement*> &statements)
{
auto usages = VarUsages();
for (auto& st : statements)
{
auto st_usages = get_usages(st);
usages.extend(st_usages);
}
return usages;
}
VarUsages ReadWriteAnalyzer::gatherUsagesForCompound(SgStatement* compoundStatement) const
{
VarUsages all_usages;
SgStatement* last = compoundStatement->lastNodeOfStmt();
SgStatement* runner = compoundStatement;
while (runner != last)
{
if (runner->variant() == CONTAINS_STMT)
break;
if (!isSgExecutableStatement(runner) || isDVM_stat(runner) || isSPF_stat(runner))
{
runner = runner->lexNext();
continue;
}
all_usages.extend(findUsagesInStatement(runner));
runner = runner->lexNext();
}
return all_usages;
}
void ReadWriteAnalyzer::print() const
{
auto save = current_file->filename();
for (int i = 0; i < CurrentProject->numberOfFiles(); i++)
{
printf("file: %s\n", CurrentProject->file(i).filename());
for (int j = 0; j < CurrentProject->file(i).numberOfFunctions(); j++)
{
printf("function: %s\n", CurrentProject->file(i).functions(j)->symbol()->identifier());
SgStatement* runner = CurrentProject->file(i).functions(j);
auto last = runner->lastNodeOfStmt();
while (runner != last)
{
if (runner->variant() == CONTAINS_STMT)
break;
auto it = usages_by_statement.find(runner);
if (it != usages_by_statement.end())
{
runner->unparsestdout();
it->second.print();
}
runner = runner->lexNext();
}
}
}
if (SgFile::switchToFile(save) == -1)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
}
map<string, vector<int>> ReadWriteAnalyzer::load_modified_pars(const map<string, vector<FuncInfo*>> &files)
{
map<string, vector<int>> res;
for (auto& funcs : files)
{
string file_name = funcs.first;
for (auto& func : funcs.second)
{
string func_key = func->funcName;
res[func_key] = func->funcParams.inout_types;
}
}
return res;
}

View File

@@ -0,0 +1,44 @@
#pragma once
#include "dvm.h"
#include "../Utils/SgUtils.h"
#include "VarUsages.h"
#include <set>
#include <tuple>
#include <queue>
#include <vector>
#include <exception>
#include <map>
class ReadWriteAnalyzer
{
std::map<std::string, std::vector<FuncInfo*>> &funcInfo; // TODO: could be not initilized; should be rebuilt on invalidate()
std::map<std::string, std::vector<int>> modified_pars; // func -> used for [in, inout, out] params,
std::map<SgStatement*, VarUsages> usages_by_statement; // maps statements to variables used in them
std::set<std::string> initialized; // files was inited
void init(SgFile*);
VarUsages findUsagesInStatement(SgStatement* st) const;
VarUsages findUsagesInAssignment(SgStatement* st) const;
void findReadUsagesInExpression(SgExpression* ex, VarUsages& toExtend) const;
const std::set<int> compound_statements = { FOR_NODE, LOOP_NODE, FUNC_HEDR, PROC_HEDR };
VarUsages gatherUsagesForCompound(SgStatement* st) const;
public:
explicit ReadWriteAnalyzer(std::map<std::string, std::vector<FuncInfo*>> &funcInfo) : funcInfo(funcInfo)
{ }
void invalidate(const std::string& fileName) { initialized.erase(fileName); }
VarUsages get_usages(SgStatement*);
VarUsages get_usages(std::vector<SgStatement*>&);
VarUsages findUsagesInExpr(SgExpression* exp) const;
VarUsages findUsagesInFuncCall(SgExpression*, const std::string&) const;
void print() const;
static std::map<std::string, std::vector<int>> load_modified_pars(const std::map<std::string, std::vector<FuncInfo*>>&);
};

View File

@@ -0,0 +1,195 @@
#include "leak_detector.h"
#include "RegionsMerger.h"
using namespace std;
bool RegionsMerger::compareByStart(const DvmhRegion *a, const DvmhRegion *b)
{
if (a->getLoops().size() < 1 || b->getLoops().size() < 1)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
int lineLeft = a->getLoops()[0]->lineNum;
if (lineLeft < 0)
lineLeft = a->getLoops()[0]->altLineNum;
int lineRight = b->getLoops()[0]->lineNum;
if (lineRight < 0)
lineRight = b->getLoops()[0]->altLineNum;
return lineLeft < lineRight;
}
bool RegionsMerger::canBeMoved(SgStatement* st, const DvmhRegion *region) const
{
// For now: st [a, d = b + c] can be moved IF [b, c] are not modified in region AND [a, d] not used for read in region
// get usages for statement
VarUsages st_usages = rw_analyzer.get_usages(st);
// get usages for region
auto loop_statements = vector<SgStatement*>();
for (auto& loop : region->getLoops())
loop_statements.push_back(loop->loop);
auto region_usages = rw_analyzer.get_usages(loop_statements);
// analyze if statement can be placed before region
if (sets_intersect(st_usages.get_reads(), region_usages.get_writes())) // check that [b, c] not modified in region
return false;
if (sets_intersect(st_usages.get_writes(), region_usages.get_reads())) // check that [a, d] not read in region
return false;
return true; // everything's ok
}
vector<SgStatement*> RegionsMerger::getStatementsToMove(const DvmhRegion *first, const DvmhRegion *second, bool &can) const
{
// can not, abort operation
if (first->getFileName() != second->getFileName() || first->getFunName() != second->getFunName())
{
can = false;
return vector<SgStatement*>();
}
vector<SgStatement*> toMove;
SgStatement* mediumSt = first->getLastSt()->lexNext();
// skip DVM PARALLEL and hidden stats
while (mediumSt->variant() == DVM_PARALLEL_ON_DIR || mediumSt->variant() < 0)
mediumSt = mediumSt->lexNext();
//no statements between regions, so can
if (mediumSt == second->getFirstSt() && mediumSt->variant() == FOR_NODE)
{
can = true;
return vector<SgStatement*>();
} //TODO
else
{
can = false;
return vector<SgStatement*>();
}
//TODO: need to check and correct
while (mediumSt->id() != second->getFirstSt()->id())
{
if (mediumSt->variant() == DVM_PARALLEL_ON_DIR)
{
mediumSt = mediumSt->lexNext();
continue;
}
if (canBeMoved(mediumSt, first))
toMove.push_back(mediumSt);
else // can not, abort operation
{
can = false;
return vector<SgStatement*>();
}
mediumSt = mediumSt->lexNext();
}
return toMove;
}
// Places statements before region
void RegionsMerger::moveStatements(const vector<SgStatement*>& sts, const DvmhRegion* region)
{
SgStatement* prev = region->getFirstSt()->lexPrev();
while (isDVM_stat(prev))
prev = prev->lexPrev();
for (auto& st : sts)
{
SgStatement *toInsert = st->copyPtr();
prev->insertStmtAfter(*toInsert, *prev->controlParent());
prev = toInsert;
st->deleteStmt();
}
rw_analyzer.invalidate(region->getFileName());
}
vector<DvmhRegion*> RegionsMerger::mergeRegions()
{
if (regions.size() < 2)
return regions;
map<string, map<int, DvmhRegion*>> byFunc;
for (auto& elem : regions)
{
const int line = elem->getLineForSort();
const string fName = elem->getFunName();
auto& itF = byFunc[fName];
if (itF.find(line) != itF.end())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
itF[line] = elem;
}
vector<DvmhRegion*> newRegions;
for (auto& regsForFunc : byFunc)
{
map<int, DvmhRegion*>& regionsByFunc = regsForFunc.second;
if (regionsByFunc.size() == 0)
continue;
DvmhRegion* newRegion = new DvmhRegion();
DvmhRegion* regionPrev = regionsByFunc.begin()->second;
bool isFirst = true;
for (auto& loop : regionPrev->getLoops())
newRegion->addLoop(loop);
for (auto& region : regionsByFunc)
{
if (newRegion->getFunName() == "" && region.second->getLoops().size() > 0)
{
SgStatement* func_st = getFuncStat(region.second->getLoops()[0]->loop);
string fun_name = func_st->symbol()->identifier();
newRegion->setFunName(fun_name);
}
if (isFirst) // skip first region
{
isFirst = false;
continue;
}
bool can = true;
auto toMove = getStatementsToMove(regionPrev, region.second, can);
if (can)
{
//TODO
if (toMove.size())
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
// moveStatements(toMove, regionPrev);
}
else
{
__spf_print(1, " region before loop on line %d (alt %d) cannot be merged\n",
region.second->getLoops()[0]->lineNum, region.second->getLoops()[0]->altLineNum);
toMove = getStatementsToMove(regionPrev, region.second, can);
newRegions.push_back(newRegion);
newRegion = new DvmhRegion();
}
newRegion->append(*region.second);
regionPrev = region.second;
}
newRegions.push_back(newRegion);
}
for (auto& old : regions)
delete old;
regions.clear();
return newRegions;
}
bool RegionsMerger::sets_intersect(const set<SgSymbol*>& set1, const set<SgSymbol*>& set2) const
{
for (auto& symb : set1)
if (set2.find(symb) != set2.end())
return true;
return false;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "DvmhRegions/DvmhRegionInserter.h"
class RegionsMerger
{
std::vector<DvmhRegion*> &regions;
ReadWriteAnalyzer &rw_analyzer;
bool canBeMoved(SgStatement* st, const DvmhRegion *region) const;
std::vector<SgStatement*> getStatementsToMove(const DvmhRegion *first, const DvmhRegion *second, bool&) const;
void moveStatements(const std::vector<SgStatement*>& sts, const DvmhRegion* region);
bool sets_intersect(const std::set<SgSymbol*>&, const std::set<SgSymbol*>&) const;
static bool compareByStart(const DvmhRegion* a, const DvmhRegion* b);
public:
explicit RegionsMerger(std::vector<DvmhRegion*>& old_regions, ReadWriteAnalyzer& rw) : regions(old_regions), rw_analyzer(rw) { }
std::vector<DvmhRegion*> mergeRegions();
};

View File

@@ -0,0 +1,36 @@
#include "leak_detector.h"
#include "TypedSymbol.h"
using namespace std;
TypedSymbol::TypedSymbol(SgExpression* orig_exp)
{
if (orig_exp->variant() == VAR_REF || orig_exp->variant() == ARRAY_REF)
orig = OriginalSymbol(orig_exp->symbol());
type = VAR_TYPE::VAR_UNDEFINED;
if (orig_exp->variant() == VAR_REF)
type = VAR_TYPE::VAR_SCALAR;
if (orig_exp->variant() == ARRAY_REF)
{
type = VAR_TYPE::VAR_ARR;
DIST::Array* arr = getArrayFromDeclarated(declaratedInStmt(orig), orig->identifier());
if (arr == NULL) //for strings charecter(*)
type = VAR_TYPE::VAR_SCALAR;
else if (!arr->IsNotDistribute())
type = VAR_TYPE::VAR_DISTR_ARR;
}
}
bool operator== (const TypedSymbol& lhs, const TypedSymbol& rhs)
{
return string(OriginalSymbol(lhs.orig)->identifier()) == string(OriginalSymbol(rhs.orig)->identifier()) &&
OriginalSymbol(lhs.orig)->scope()->id() == OriginalSymbol(rhs.orig)->scope()->id();
}
bool operator< (const TypedSymbol& lhs, const TypedSymbol& rhs)
{
return OriginalSymbol(lhs.orig)->id() < OriginalSymbol(rhs.orig)->id();
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include "dvm.h"
#include "../Utils/SgUtils.h"
#include <string>
enum class VAR_TYPE { VAR_ARR, VAR_DISTR_ARR, VAR_SCALAR, VAR_ANY, VAR_UNDEFINED };
class TypedSymbol
{
public:
SgSymbol* orig;
VAR_TYPE type;
TypedSymbol(SgExpression*);
friend bool operator== (const TypedSymbol& lhs, const TypedSymbol& rhs);
friend bool operator< (const TypedSymbol& lhs, const TypedSymbol& rhs);
};

View File

@@ -0,0 +1,97 @@
#include "leak_detector.h"
#include "VarUsages.h"
using namespace std;
void VarUsages::extend(const VarUsages& to_insert)
{
undefined |= to_insert.undefined;
reads.insert(to_insert.reads.begin(), to_insert.reads.end());
writes.insert(to_insert.writes.begin(), to_insert.writes.end());
}
set<SgSymbol*> VarUsages::get_reads(const set<VAR_TYPE> var_type) const
{
if (undefined)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
return filter(reads, var_type);
}
set<SgSymbol*> VarUsages::get_writes(const set<VAR_TYPE> var_type) const
{
if (undefined)
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
return filter(writes, var_type);
}
set<SgSymbol*> VarUsages::get_all(const set<VAR_TYPE> var_type) const
{
set<TypedSymbol> all_usages;
all_usages.insert(reads.begin(), reads.end());
all_usages.insert(writes.begin(), writes.end());
return filter(all_usages, var_type);
}
set<SgSymbol*> VarUsages::get_reads() const { return get_reads({ VAR_TYPE::VAR_ANY }); }
set<SgSymbol*> VarUsages::get_writes() const { return get_writes({ VAR_TYPE::VAR_ANY }); }
set<SgSymbol*> VarUsages::get_all() const { return get_all({ VAR_TYPE::VAR_ANY }); }
set<SgSymbol*> VarUsages::filter(const set<TypedSymbol> &symbols, const set<VAR_TYPE> var_type)
{
set<SgSymbol*> filtered;
if (var_type.find(VAR_TYPE::VAR_ANY) != var_type.end())
for (auto& s : symbols)
filtered.insert(s.orig);
else
for (auto& s : symbols)
if (var_type.find(s.type) != var_type.end())
filtered.insert(s.orig);
return filtered;
}
void VarUsages::insert_undefined(const TypedSymbol& s)
{
undefined = true;
reads.insert(s);
writes.insert(s);
}
void VarUsages::insert_read(const TypedSymbol& s) { reads.insert(s); }
void VarUsages::insert_write(const TypedSymbol& s) { writes.insert(s); }
void VarUsages::print() const
{
printf("reads: ");
if (undefined)
printf("not_defined");
else
{
for (auto& s : reads)
printf("%s ", s.orig->identifier());
}
printf("\n");
printf("writes: ");
if (undefined)
printf("not_defined");
else
{
for (auto& s : writes)
printf("%s ", s.orig->identifier());
}
printf("\n");
printf("all: ");
for (auto& s : get_all({ VAR_TYPE::VAR_ANY }))
printf("%s ", s->identifier());
printf("\n");
printf("***\n");
}
bool VarUsages::is_undefined() const { return undefined; }

View File

@@ -0,0 +1,33 @@
#pragma once
#include "dvm.h"
#include "TypedSymbol.h"
#include <set>
class VarUsages
{
std::set<TypedSymbol> reads;
std::set<TypedSymbol> writes;
bool undefined;
public:
VarUsages() : undefined(false) { }
void extend(const VarUsages&);
void insert_undefined(const TypedSymbol&);
void insert_read(const TypedSymbol&);
void insert_write(const TypedSymbol&);
bool is_undefined() const;
std::set<SgSymbol*> get_reads(const std::set<VAR_TYPE>) const;
std::set<SgSymbol*> get_writes(const std::set<VAR_TYPE>) const;
std::set<SgSymbol*> get_all(const std::set<VAR_TYPE>) const;
std::set<SgSymbol*> get_reads() const;
std::set<SgSymbol*> get_writes() const;
std::set<SgSymbol*> get_all() const;
static std::set<SgSymbol*> filter(const std::set<TypedSymbol>&, const std::set<VAR_TYPE>);
void print() const;
};