547 lines
19 KiB
C++
547 lines
19 KiB
C++
#pragma once
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <map>
|
|
#include <set>
|
|
|
|
#include "errors.h"
|
|
#include "types.h"
|
|
#include "../Distribution/DvmhDirective.h"
|
|
#include "../Distribution/Distribution.h"
|
|
|
|
struct DistrVariant;
|
|
struct ParallelDirective;
|
|
struct ParallelRegion;
|
|
class Statement;
|
|
struct FuncInfo;
|
|
|
|
namespace Distribution
|
|
{
|
|
class Array;
|
|
}
|
|
namespace DIST = Distribution;
|
|
|
|
void getRealArrayRefs(DIST::Array* addTo, DIST::Array* curr, std::set<DIST::Array*>& realArrayRefs, const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls);
|
|
void getAllArrayRefs(DIST::Array* addTo, DIST::Array* curr, std::set<DIST::Array*>& realArrayRefs, const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls);
|
|
|
|
enum class LoopType { NONE, FOR, WHILE, IMPLICIT };
|
|
|
|
struct InductiveVariables
|
|
{
|
|
private:
|
|
std::string mainVar;
|
|
std::set<std::string> allVars;
|
|
|
|
public:
|
|
InductiveVariables() { }
|
|
|
|
explicit InductiveVariables(const std::string& mainVar, const std::set<std::string>& allVars) : mainVar(mainVar), allVars(allVars) { };
|
|
|
|
std::string getMainVar() const { return mainVar; }
|
|
std::set<std::string> getAllVars() const { return allVars; }
|
|
|
|
void addVar(const std::string& var) { allVars.insert(var); }
|
|
void addMainVar(const std::string& var) { mainVar = var; allVars.insert(var); }
|
|
|
|
void replaceMainVar(const std::string& var)
|
|
{
|
|
allVars.erase(mainVar);
|
|
|
|
addMainVar(var);
|
|
}
|
|
};
|
|
|
|
struct LoopGraph
|
|
{
|
|
private:
|
|
std::vector<std::pair<DIST::Array*, DistrVariant*>> redistributeRules;
|
|
LoopGraph* needToSwapWith;
|
|
|
|
//for local directive creating in MPI mode
|
|
DIST::GraphCSR<int, double, attrType> accessGraph;
|
|
DIST::GraphCSR<int, double, attrType> reducedAccessGraph;
|
|
DataDirective dataDirectives;
|
|
//
|
|
|
|
public:
|
|
LoopGraph()
|
|
{
|
|
lineNumAfterLoop = lineNum = altLineNum = -1;
|
|
perfectLoop = 0;
|
|
hasGoto = false;
|
|
hasPrints = false;
|
|
hasUnknownArrayDep = false;
|
|
hasUnknownScalarDep = false;
|
|
hasUnknownArrayAssigns = false;
|
|
hasNonRectangularBounds = false;
|
|
hasIndirectAccess = false;
|
|
withoutDistributedArrays = false;
|
|
hasWritesToNonDistribute = false;
|
|
hasUnknownDistributedMap = false;
|
|
hasDifferentAlignRules = false;
|
|
hasNonPureProcedures = false;
|
|
hasDvmIntervals = false;
|
|
hasStops = false;
|
|
directive = NULL;
|
|
oldDirective = NULL;
|
|
directiveForLoop = NULL;
|
|
region = NULL;
|
|
needToSwapWith = NULL;
|
|
countOfIters = 0;
|
|
countOfIterNested = 1;
|
|
loop = NULL;
|
|
parent = NULL;
|
|
userDvmDirective = NULL;
|
|
startVal = endVal = stepVal = 0;
|
|
calculatedCountOfIters = 0;
|
|
executionTimeInSec = -1.0;
|
|
inDvmhRegion = 0;
|
|
loopType = LoopType::NONE;
|
|
inCanonicalFrom = false;
|
|
hasAccessToSubArray = false;
|
|
hasSubstringRefs = false;
|
|
}
|
|
|
|
~LoopGraph()
|
|
{
|
|
needToSwapWith = NULL;
|
|
if (directive != NULL)
|
|
delete directive;
|
|
|
|
if (directiveForLoop != NULL)
|
|
delete directiveForLoop;
|
|
|
|
for (int i = 0; i < children.size(); ++i)
|
|
delete children[i];
|
|
|
|
calls.clear();
|
|
readOpsArray.clear();
|
|
readOps.clear();
|
|
writeOps.clear();
|
|
hasConflicts.clear();
|
|
acrossOutAttribute.clear();
|
|
accessGraph.ClearGraphCSR();
|
|
reducedAccessGraph.ClearGraphCSR();
|
|
}
|
|
|
|
void setForSwap(LoopGraph* with) { needToSwapWith = with; }
|
|
|
|
LoopGraph* getForSwap() const { return needToSwapWith; }
|
|
|
|
void clearForSwap()
|
|
{
|
|
for (auto& ch : children)
|
|
ch->clearForSwap();
|
|
needToSwapWith = NULL;
|
|
}
|
|
|
|
bool hasLimitsToParallel() const
|
|
{
|
|
return hasUnknownArrayDep || hasUnknownScalarDep || hasGoto || hasPrints || (hasConflicts.size() != 0) || hasStops || hasNonPureProcedures ||
|
|
hasUnknownArrayAssigns || hasNonRectangularBounds || hasIndirectAccess || hasWritesToNonDistribute || hasDifferentAlignRules || hasDvmIntervals ||
|
|
!isFor() || lastprivateScalars.size() || hasAccessToSubArray || hasSubstringRefs;
|
|
}
|
|
|
|
bool hasLimitsToSplit() const
|
|
{
|
|
return hasGoto || hasStops || !isFor() || hasPrints;
|
|
}
|
|
|
|
bool hasLimitsToCombine() const
|
|
{
|
|
return hasGoto || hasStops || !isFor() || hasPrints || linesOfCycle.size();
|
|
}
|
|
|
|
void addConflictMessages(std::vector<Messages> *messages)
|
|
{
|
|
if (messages == NULL)
|
|
return;
|
|
|
|
const int line = altLineNum > 0 ? altLineNum : lineNum;
|
|
if (hasUnknownArrayDep)
|
|
messages->push_back(Messages(NOTE, line, R113, L"unknown array dependency prevents parallelization of this loop", 3006));
|
|
|
|
if (hasUnknownScalarDep)
|
|
messages->push_back(Messages(NOTE, line, R114, L"unknown scalar dependency prevents parallelization of this loop", 3006));
|
|
|
|
if (hasGoto)
|
|
messages->push_back(Messages(NOTE, line, R115, L"internal/external moves via GOTO or EXIT operations prevent parallelization of this loop", 3006));
|
|
|
|
if (hasPrints)
|
|
messages->push_back(Messages(NOTE, line, R116, L"IO operations prevent parallelization of this loop", 3006));
|
|
|
|
if (hasStops)
|
|
messages->push_back(Messages(NOTE, line, R117, L"stop operations prevent parallelization of this loop", 3006));
|
|
|
|
if (hasConflicts.size() != 0)
|
|
messages->push_back(Messages(NOTE, line, R118, L"conflict writes operations prevent parallelization of this loop", 3006));
|
|
|
|
if (hasUnknownArrayAssigns)
|
|
messages->push_back(Messages(NOTE, line, R119, L"unknown array reference for writes prevent parallelization of this loop", 3006));
|
|
|
|
if (hasNonRectangularBounds)
|
|
messages->push_back(Messages(NOTE, line, R144, L"non rectangular bounds prevent parallelization of this loop", 3006));
|
|
|
|
if (hasIndirectAccess)
|
|
messages->push_back(Messages(NOTE, line, R120, L"indirect access by distributed array prevents parallelization of this loop", 3006));
|
|
|
|
if (hasWritesToNonDistribute)
|
|
messages->push_back(Messages(NOTE, line, R121, L"writes to non distributed array prevents parallelization of this loop", 3006));
|
|
|
|
if (hasDifferentAlignRules)
|
|
messages->push_back(Messages(NOTE, line, R122, L"different aligns between writes to distributed array prevents parallelization of this loop", 3006));
|
|
|
|
if (hasNonPureProcedures)
|
|
messages->push_back(Messages(NOTE, line, R123, L"non pure procedures prevent parallelization of this loop", 3006));
|
|
|
|
if (hasDvmIntervals)
|
|
messages->push_back(Messages(NOTE, line, R145, L"DVM intervals prevent parallelization of this loop", 3006));
|
|
|
|
if (!isFor() || !inCanonicalFrom)
|
|
messages->push_back(Messages(NOTE, line, R178, L"This type of loop is not supported by the system", 3006));
|
|
|
|
if (lastprivateScalars.size())
|
|
messages->push_back(Messages(NOTE, line, R199, L"lastprivate scalar dependency prevents parallelization of this loop", 3006));
|
|
}
|
|
|
|
void setNewRedistributeRules(const std::vector<std::pair<DIST::Array*, DistrVariant*>> &newRedistributeRules)
|
|
{
|
|
// set to top and for all childs
|
|
redistributeRules = newRedistributeRules;
|
|
for (int i = 0; i < children.size(); ++i)
|
|
children[i]->setNewRedistributeRules(newRedistributeRules);
|
|
}
|
|
|
|
DistrVariant* getRedistributeRule(const DIST::Array *arrayT) const
|
|
{
|
|
DistrVariant *retVal = NULL;
|
|
|
|
for (int i = 0; i < redistributeRules.size(); ++i)
|
|
{
|
|
if (redistributeRules[i].first == arrayT)
|
|
{
|
|
retVal = redistributeRules[i].second;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool hasRedistribute() const { return redistributeRules.size(); }
|
|
|
|
ParallelDirective* recalculateParallelDirective()
|
|
{
|
|
std::vector<ParallelDirective*> baseDirs(perfectLoop);
|
|
LoopGraph *next = this;
|
|
for (int z = 0; z < perfectLoop; ++z)
|
|
{
|
|
baseDirs[z] = next->directiveForLoop;
|
|
if (z != perfectLoop - 1)
|
|
next = next->children[0];
|
|
}
|
|
|
|
ParallelDirective *parDirective = baseDirs[0];
|
|
for (int z = 1; z < baseDirs.size() && baseDirs[z]; ++z)
|
|
{
|
|
ParallelDirective *old = parDirective;
|
|
parDirective = *parDirective + *baseDirs[z];
|
|
|
|
if (z != 1)
|
|
delete old;
|
|
}
|
|
|
|
oldDirective = directive;
|
|
directive = parDirective;
|
|
return directive;
|
|
}
|
|
|
|
void restoreDirective()
|
|
{
|
|
if (oldDirective)
|
|
{
|
|
delete directive;
|
|
directive = oldDirective;
|
|
}
|
|
|
|
for (int i = 0; i < children.size(); ++i)
|
|
children[i]->restoreDirective();
|
|
}
|
|
|
|
void setRegionToChilds()
|
|
{
|
|
for (auto &loop : children)
|
|
{
|
|
loop->region = region;
|
|
loop->setRegionToChilds();
|
|
}
|
|
}
|
|
|
|
void recalculatePerfect();
|
|
|
|
void setWithOutDistrFlagToFalse()
|
|
{
|
|
for (auto &loop : children)
|
|
{
|
|
loop->withoutDistributedArrays = false;
|
|
loop->setWithOutDistrFlagToFalse();
|
|
}
|
|
}
|
|
|
|
void propagateUserDvmDir()
|
|
{
|
|
for (auto &loop : children)
|
|
{
|
|
if (loop->userDvmDirective == NULL)
|
|
loop->userDvmDirective = userDvmDirective;
|
|
loop->propagateUserDvmDir();
|
|
}
|
|
}
|
|
|
|
void propagateDvmhRegion(const int flag)
|
|
{
|
|
for (auto& loop : children)
|
|
{
|
|
loop->inDvmhRegion = flag;
|
|
loop->propagateDvmhRegion(flag);
|
|
}
|
|
}
|
|
|
|
std::string genLoopArrayName(const std::string &funcName) const
|
|
{
|
|
return funcName + "_loop_" + std::to_string(lineNum);
|
|
}
|
|
|
|
std::set<DIST::Array*> getAllArraysInLoop()
|
|
{
|
|
std::set<DIST::Array*> retVal(readOpsArray);
|
|
for (auto &elem : writeOps)
|
|
retVal.insert(elem.first);
|
|
return retVal;
|
|
}
|
|
|
|
void removeNonDistrArrays()
|
|
{
|
|
std::set<DIST::Array*> newUsedArrays;
|
|
for (auto &elem : usedArrays)
|
|
if (elem->GetDistributeFlagVal() == DIST::DISTR)
|
|
newUsedArrays.insert(elem);
|
|
usedArrays = newUsedArrays;
|
|
|
|
std::set<DIST::Array*> newUsedArraysW;
|
|
for (auto &elem : usedArraysWrite)
|
|
if (elem->GetDistributeFlagVal() == DIST::DISTR)
|
|
newUsedArraysW.insert(elem);
|
|
usedArraysWrite = newUsedArraysW;
|
|
|
|
readOpsArray.clear();
|
|
readOps.clear();
|
|
writeOps.clear();
|
|
hasConflicts.clear();
|
|
|
|
for (auto &ch : children)
|
|
ch->removeNonDistrArrays();
|
|
}
|
|
|
|
void removeGraphData()
|
|
{
|
|
accessGraph.ClearGraphCSR();
|
|
reducedAccessGraph.ClearGraphCSR();
|
|
|
|
for (auto& ch : children)
|
|
ch->removeGraphData();
|
|
}
|
|
|
|
void clearUserDirectives();
|
|
|
|
bool isArrayTemplatesTheSame(DIST::Array*& sameTemplate, const uint64_t regId, const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls)
|
|
{
|
|
if (sharedMemoryParallelization != 0)
|
|
return true;
|
|
|
|
std::set<DIST::Array*> usedForRegAccess;
|
|
for (auto& array : writeOps)
|
|
{
|
|
std::set<DIST::Array*> realArrayRefs;
|
|
getRealArrayRefs(array.first, array.first, realArrayRefs, arrayLinksByFuncCalls);
|
|
for (auto& realArr : realArrayRefs)
|
|
usedForRegAccess.insert(realArr);
|
|
}
|
|
|
|
//read operations can be REMOTE_ACCESS
|
|
/*for (auto& array : readOps)
|
|
{
|
|
std::set<DIST::Array*> realArrayRefs;
|
|
getRealArrayRefs(array.first, array.first, realArrayRefs, arrayLinksByFuncCalls);
|
|
for (auto& realArr : realArrayRefs)
|
|
usedForRegAccess.insert(realArr);
|
|
}*/
|
|
|
|
std::set<DIST::Array*> usedTemplates;
|
|
for (auto& array : usedArrays)
|
|
{
|
|
std::set<DIST::Array*> realArrayRefs;
|
|
getRealArrayRefs(array, array, realArrayRefs, arrayLinksByFuncCalls);
|
|
for (auto& realArr : realArrayRefs)
|
|
{
|
|
if (usedForRegAccess.find(realArr) == usedForRegAccess.end())
|
|
continue;
|
|
|
|
auto templ = realArr->GetTemplateArray(regId);
|
|
//TODO: what about NULL?
|
|
if (templ)
|
|
usedTemplates.insert(templ);
|
|
}
|
|
}
|
|
|
|
if (usedArrays.size())
|
|
{
|
|
if (usedTemplates.size() == 0 || usedTemplates.size() > 1)
|
|
return false;
|
|
else
|
|
sameTemplate = *usedTemplates.begin();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool hasParallelLoopsInChList();
|
|
|
|
DIST::GraphCSR<int, double, attrType>& getGraphToModify() { return accessGraph; }
|
|
const DIST::GraphCSR<int, double, attrType>& getGraph() const { return accessGraph; }
|
|
|
|
DataDirective& getDataDirToModify() { return dataDirectives; }
|
|
const DataDirective& getDataDir() const { return dataDirectives; }
|
|
|
|
void reduceAccessGraph();
|
|
|
|
void createVirtualTemplateLinks(const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls, std::map<std::string, std::vector<Messages>>& SPF_messages, bool isMpiProgram = false);
|
|
|
|
bool hasParalleDirectiveBefore();
|
|
|
|
void analyzeParallelDirs();
|
|
|
|
void* getRealStat(const char* file) const;
|
|
|
|
bool isFor() const { return loopType == LoopType::FOR; }
|
|
|
|
bool isWhile() const { return loopType == LoopType::WHILE; }
|
|
|
|
bool isImplicit() const { return loopType == LoopType::IMPLICIT; }
|
|
|
|
std::string loopSymbol() const { return loopSymbols.getMainVar(); }
|
|
|
|
public:
|
|
int lineNum;
|
|
int altLineNum;
|
|
int lineNumAfterLoop;
|
|
std::string fileName;
|
|
int perfectLoop;
|
|
int countOfIters; // calculated total with nested loops
|
|
double countOfIterNested;
|
|
double executionTimeInSec;
|
|
int calculatedCountOfIters; // calculated for current loop
|
|
|
|
int startVal, endVal, stepVal;
|
|
std::tuple<Expression*, Expression*, Expression*> startEndStepVals;
|
|
|
|
InductiveVariables loopSymbols;
|
|
std::pair<Expression*, Expression*> startEndExpr;
|
|
|
|
bool hasGoto;
|
|
std::vector<int> linesOfInternalGoTo;
|
|
std::vector<int> linesOfExternalGoTo;
|
|
std::vector<int> linesOfCycle;
|
|
|
|
bool hasPrints;
|
|
std::set<int> linesOfIO;
|
|
|
|
bool hasStops;
|
|
std::set<int> linesOfStop;
|
|
|
|
bool hasUnknownScalarDep;
|
|
std::vector<int> linesOfScalarDep;
|
|
|
|
bool hasUnknownArrayDep;
|
|
|
|
bool hasUnknownArrayAssigns;
|
|
|
|
bool hasNonRectangularBounds;
|
|
|
|
bool hasIndirectAccess;
|
|
|
|
bool hasWritesToNonDistribute;
|
|
|
|
bool withoutDistributedArrays;
|
|
|
|
bool hasUnknownDistributedMap;
|
|
|
|
bool hasDifferentAlignRules;
|
|
|
|
bool hasNonPureProcedures;
|
|
|
|
bool hasDvmIntervals;
|
|
// make sense only for NODIST regime
|
|
bool hasAccessToSubArray;
|
|
|
|
bool hasSubstringRefs;
|
|
|
|
LoopType loopType;
|
|
|
|
bool inCanonicalFrom;
|
|
|
|
|
|
std::vector<LoopGraph*> children;
|
|
std::vector<LoopGraph*> funcChildren;
|
|
LoopGraph *parent;
|
|
std::vector<LoopGraph*> funcParents;
|
|
|
|
// PAIR<FUNC_NAME, LINE>
|
|
std::vector<std::pair<std::string, int>> calls;
|
|
|
|
std::set<std::string> lastprivateScalars;
|
|
std::set<std::string> privateScalars;
|
|
|
|
std::map<DIST::Array*, std::vector<ArrayOp>> readOpsForLoop;
|
|
std::map<DIST::Array*, std::vector<ArrayOp>> writeOpsForLoop;
|
|
|
|
// agregated read and write operations by arrays
|
|
std::set<DIST::Array*> readOpsArray;
|
|
std::map<DIST::Array*, std::pair<std::vector<ArrayOp>, std::vector<bool>>> readOps;
|
|
std::map<DIST::Array*, std::vector<ArrayOp>> writeOps;
|
|
std::map<DIST::Array*, std::vector<ArrayOp>> remoteRegularReads;
|
|
std::map<DIST::Array*, bool> hasConflicts;
|
|
|
|
std::set<DIST::Array*> acrossOutAttribute;
|
|
|
|
ParallelDirective *directive; // united directive for nested loops
|
|
ParallelDirective *oldDirective; // save old directive for reverse
|
|
ParallelDirective *directiveForLoop; // part of directive for loop
|
|
Statement *userDvmDirective; // user's DVM PARALLEL directive
|
|
|
|
ParallelRegion *region;
|
|
|
|
Statement *loop;
|
|
|
|
std::set<DIST::Array*> usedArrays;// without NON DIST
|
|
std::set<DIST::Array*> usedArraysAll;
|
|
std::set<DIST::Array*> usedArraysWrite; // without NON DIST
|
|
std::set<DIST::Array*> usedArraysWriteAll;
|
|
|
|
int inDvmhRegion; // 0 -unknown, -1 - no, 1 - yes
|
|
};
|
|
|
|
void processLoopInformationForFunction(std::map<LoopGraph*, std::map<DIST::Array*, ArrayInfo*>>& loopInfo);
|
|
void addToDistributionGraph(const std::map<LoopGraph*, std::map<DIST::Array*, ArrayInfo*>>& loopInfo, const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls);
|
|
void selectFreeLoopsForParallelization(const std::vector<LoopGraph*>& loops, const std::string& funcName, bool isDistribute, const std::vector<ParallelRegion*>& regions, std::vector<Messages>& messagesForFile);
|
|
|
|
int printLoopGraph(const char* fileName, const std::map<std::string, std::vector<LoopGraph*>>& loopGraph, bool withRegs = false);
|
|
void checkCountOfIter(std::map<std::string, std::vector<LoopGraph*>>& loopGraph, const std::map<std::string, std::vector<FuncInfo*>>& allFuncInfo, std::map<std::string, std::vector<Messages>>& SPF_messages);
|
|
|
|
void createMapLoopGraph(const std::vector<LoopGraph*>& loops, std::map<int, LoopGraph*>& mapGraph);
|
|
void updateLoopIoAndStopsByFuncCalls(std::map<std::string, std::vector<LoopGraph*>>& loopGraph, const std::map<std::string, std::vector<FuncInfo*>>& allFuncInfo);
|
|
void checkArraysMapping(const std::map<std::string, std::vector<LoopGraph*>>& loopGraph, std::map<std::string, std::vector<Messages>>& SPF_messages, const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls);
|
|
void filterArrayInCSRGraph(std::map<std::string, std::vector<LoopGraph*>>& loopGraph, std::map<std::string, std::vector<FuncInfo*>>& allFuncs, ParallelRegion* reg, const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls, std::map<std::string, std::vector<Messages>>& messages);
|
|
void swapLoopsForParallel(std::map<std::string, std::vector<LoopGraph*>>& loopGraph, std::map<std::string, std::vector<Messages>>& SPF_messages, const int rev);
|
|
|