1239 lines
43 KiB
C++
1239 lines
43 KiB
C++
#define _LEAK_
|
||
#include "leak_detector.h"
|
||
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <vector>
|
||
#include <set>
|
||
#include <chrono>
|
||
#include <functional>
|
||
|
||
#include "SgUtils.h"
|
||
#include "CommonBlock.h"
|
||
#include "graph_calls.h"
|
||
|
||
#include "dvm.h"
|
||
#include "IR.h"
|
||
#include "CFGraph.h"
|
||
|
||
#define DEB_PRINT 1
|
||
|
||
using namespace std;
|
||
using namespace SAPFOR;
|
||
|
||
using std::chrono::high_resolution_clock;
|
||
using std::chrono::duration_cast;
|
||
using std::chrono::milliseconds;
|
||
|
||
typedef SAPFOR::BasicBlock BBlock;
|
||
|
||
int BBlock::lastNumBlock = 0;
|
||
|
||
BBlock::BasicBlock(IR_Block* item)
|
||
{
|
||
num = lastNumBlock++;
|
||
instructions.push_back(item);
|
||
item->setBasicBlock(this);
|
||
}
|
||
|
||
BBlock::BasicBlock(const BBlock& copyFrom)
|
||
{
|
||
num = lastNumBlock++;
|
||
for (auto& ir : copyFrom.getInstructions())
|
||
{
|
||
instructions.push_back(new IR_Block(*ir));
|
||
instructions.back()->setBasicBlock(this);
|
||
}
|
||
|
||
//need to replace with actual BB
|
||
next = copyFrom.next;
|
||
prev = copyFrom.prev;
|
||
}
|
||
|
||
void BBlock::addInstruction(IR_Block* item)
|
||
{
|
||
instructions.push_back(item);
|
||
item->setBasicBlock(this);
|
||
}
|
||
|
||
int BBlock::removePrev(BBlock* removed)
|
||
{
|
||
auto it = std::remove(prev.begin(), prev.end(), removed);
|
||
auto r = prev.end() - it;
|
||
prev.erase(it, prev.end());
|
||
return r;
|
||
}
|
||
|
||
int BBlock::removeNext(BBlock* removed)
|
||
{
|
||
auto it = std::remove(next.begin(), next.end(), removed);
|
||
auto r = next.end() - it;
|
||
next.erase(it, next.end());
|
||
return r;
|
||
}
|
||
|
||
BBlock::~BasicBlock()
|
||
{
|
||
for (auto& instr : instructions)
|
||
delete instr;
|
||
}
|
||
|
||
static void dumpSets(const map<SAPFOR::Argument*, set<int>>& sets)
|
||
{
|
||
map<string, set<int>> byName;
|
||
map<string, string> types;
|
||
for (auto& elem : sets)
|
||
{
|
||
/*if (elem.first->getType() == CFG_ARG_TYPE::REG)
|
||
continue;*/
|
||
|
||
byName[elem.first->getValue()] = elem.second;
|
||
types[elem.first->getValue()] = elem.first->getMemTypeStr();
|
||
}
|
||
|
||
if (byName.size() != sets.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
for (auto& elem : byName)
|
||
{
|
||
printf(" %s (%s): ", elem.first.c_str(), types[elem.first].c_str());
|
||
for (auto& d : elem.second)
|
||
printf("%d ", d);
|
||
printf("\n");
|
||
}
|
||
}
|
||
|
||
static void debPrint(BBlock* curr, bool withRD)
|
||
{
|
||
printf(" -> [next BB]: ");
|
||
for (auto& next : curr->getNext())
|
||
printf("%d ", next->getNumber());
|
||
printf("\n");
|
||
printf(" -> [prev BB]: ");
|
||
for (auto& next : curr->getPrev())
|
||
printf("%d ", next->getNumber());
|
||
printf("\n");
|
||
|
||
if (withRD)
|
||
{
|
||
printf("IN sets:\n");
|
||
dumpSets(curr->getRD_In());
|
||
|
||
printf("OUT sets:\n");
|
||
dumpSets(curr->getRD_Out());
|
||
}
|
||
else
|
||
{
|
||
printf("IN sets %d\n", (int)curr->getRD_In().size());
|
||
printf("OUT sets %d\n", (int)curr->getRD_Out().size());
|
||
}
|
||
|
||
}
|
||
|
||
static void debPrint(const string& fName, const vector<BBlock*>& bblocks, const vector<IR_Block*>& blocks, bool withRD)
|
||
{
|
||
printf("============================================\n");
|
||
printf("IR and CFG for '%s' function\n", fName.c_str());
|
||
printf("============================================\n");
|
||
|
||
BBlock* curr = blocks[0]->getBasicBlock();
|
||
for (auto& block : blocks)
|
||
{
|
||
auto instr = block->getInstruction();
|
||
auto oper = instr->getOperator();
|
||
|
||
if (curr != block->getBasicBlock())
|
||
{
|
||
debPrint(curr, withRD);
|
||
printf("\n");
|
||
|
||
curr = block->getBasicBlock();
|
||
}
|
||
printf("[%d] [line %d] [BB %d] %s\n", instr->getNumber(), oper ? oper->lineNumber() : -1, block->getBasicBlock()->getNumber(), instr->dump().c_str());
|
||
}
|
||
debPrint(curr, withRD); // for last block
|
||
printf("\n");
|
||
}
|
||
|
||
vector<pair<const Variable*, CommonBlock*>> getCommonsByFunction(SgFile* file, SgStatement* function, const map<string, CommonBlock*>& commonBlocks)
|
||
{
|
||
vector<pair<const Variable*, CommonBlock*>> retVal;
|
||
|
||
for (auto& block : commonBlocks)
|
||
{
|
||
auto vars = block.second->getVariables(file, function);
|
||
for (auto& var : vars)
|
||
retVal.push_back(make_pair(var, block.second));
|
||
}
|
||
return retVal;
|
||
}
|
||
|
||
template<typename T>
|
||
bool intersectAndAdd(set<T>& s1, const set<T>& s2)
|
||
{
|
||
bool retVal = false;
|
||
set<T> intersect;
|
||
set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), inserter(intersect, intersect.begin()));
|
||
if (intersect.size() != s2.size())
|
||
retVal = true;
|
||
|
||
s1.insert(s2.begin(), s2.end());
|
||
return retVal;
|
||
}
|
||
|
||
template bool intersectAndAdd<DIST::Array*>(set<DIST::Array*>&, const set<DIST::Array*>&);
|
||
|
||
static void addToSet(map<SAPFOR::Argument*, set<int>>& addTo,
|
||
SAPFOR::Argument* fromArg, const set<int>& fromSet, bool& changeLoc)
|
||
{
|
||
if (addTo.find(fromArg) == addTo.end())
|
||
{
|
||
addTo[fromArg] = fromSet;
|
||
changeLoc = true;
|
||
}
|
||
else
|
||
{
|
||
bool res = intersectAndAdd(addTo[fromArg], fromSet);
|
||
changeLoc = res || changeLoc;
|
||
}
|
||
}
|
||
|
||
static bool bb_cmp(const BBlock* a, const BBlock* b)
|
||
{
|
||
return a->getInstructions()[0]->getNumber() < b->getInstructions()[0]->getNumber();
|
||
}
|
||
|
||
static void fillGenKillForGlobal(const pair<SAPFOR::Argument*, set<int>>& arg,
|
||
map<SAPFOR::Argument*, set<int>>& gen_local,
|
||
map<SAPFOR::Argument*, set<int>>& kill_local)
|
||
{
|
||
bool notInited = false;
|
||
for (auto& ir : arg.second)
|
||
if (ir == SAPFOR::CFG_VAL::UNINIT)
|
||
notInited = true;
|
||
|
||
if (gen_local.count(arg.first))
|
||
{
|
||
if (notInited)
|
||
{
|
||
for (auto& ir : arg.second)
|
||
if (ir != SAPFOR::CFG_VAL::UNINIT)
|
||
gen_local[arg.first].insert(ir);
|
||
}
|
||
else
|
||
{
|
||
kill_local[arg.first].insert(SAPFOR::CFG_VAL::KILL_ALL);
|
||
|
||
gen_local[arg.first].clear();
|
||
gen_local[arg.first] = arg.second;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (auto& ir : arg.second)
|
||
if (ir != SAPFOR::CFG_VAL::UNINIT)
|
||
gen_local[arg.first].insert(ir);
|
||
|
||
if (!notInited)
|
||
kill_local[arg.first].insert(SAPFOR::CFG_VAL::KILL_ALL);
|
||
}
|
||
}
|
||
|
||
void buildGenKillForCFG(const vector<BBlock*>& CFG, const map<string, FuncInfo*>& funcByName,
|
||
const map<FuncInfo*, map<SAPFOR::Argument*, set<int>>>& outForFunc, // actually, RD_out of last IR instruction of function
|
||
map<BBlock*, map<SAPFOR::Argument*, set<int>>>& gen,
|
||
map<BBlock*, map<SAPFOR::Argument*, set<int>>>& kill,
|
||
map<Instruction*, map<SAPFOR::Argument*, set<int>>>* genForIR,
|
||
map<Instruction*, map<SAPFOR::Argument*, set<int>>>* killForIR,
|
||
map<BBlock*, set<SAPFOR::Argument*>>& notInitedGlobals,
|
||
const CFG_Settings settings)
|
||
{
|
||
for (auto& block : CFG)
|
||
{
|
||
map<SAPFOR::Argument*, set<int>> kill_local;
|
||
map<SAPFOR::Argument*, set<int>> gen_local;
|
||
|
||
vector<Instruction*> lastParamRef;
|
||
for (auto& instr : block->getInstructions())
|
||
{
|
||
auto currInstr = instr->getInstruction();
|
||
auto arg = currInstr->getResult();
|
||
|
||
if (currInstr->getOperation() == CFG_OP::ASSIGN ||
|
||
currInstr->getOperation() == CFG_OP::LOAD)
|
||
{
|
||
if (arg->getType() != CFG_ARG_TYPE::REG ||
|
||
arg->getType() == CFG_ARG_TYPE::REG && settings.withRegisters)
|
||
{
|
||
kill_local[arg].insert(SAPFOR::CFG_VAL::KILL_ALL);
|
||
|
||
gen_local[arg].clear();
|
||
gen_local[arg].insert(currInstr->getNumber());
|
||
}
|
||
}
|
||
else if (currInstr->getOperation() == CFG_OP::F_CALL)
|
||
{
|
||
int count = stoi(currInstr->getArg2()->getValue());
|
||
if (lastParamRef.size() != count)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
map<SAPFOR::Argument*, set<int>> onlyGlobal;
|
||
bool hasOut = false;
|
||
|
||
const string& fName = currInstr->getArg1()->getValue();
|
||
auto itF = funcByName.find(fName);
|
||
if (itF != funcByName.end())
|
||
{
|
||
auto itOut = outForFunc.find(itF->second);
|
||
if (itOut != outForFunc.end())
|
||
{
|
||
hasOut = true;
|
||
for (auto& out : itOut->second)
|
||
if (out.first->isMemGlobal() || out.first->isParameter())
|
||
onlyGlobal[out.first] = out.second;
|
||
}
|
||
}
|
||
// TODO: do it better for user's functions! function not found in project
|
||
else if (!isIntrinsicFunctionName(fName.c_str()) &&
|
||
currInstr->getArg1()->getValue() != "_WRITE" &&
|
||
currInstr->getArg1()->getValue() != "_PRINT")
|
||
{
|
||
set<int> whereDef = { SAPFOR::CFG_VAL::UNINIT, currInstr->getNumber() }; // not inited and out
|
||
for (auto& par : lastParamRef)
|
||
{
|
||
auto arg = par->getArg1();
|
||
if (arg->getType() == CFG_ARG_TYPE::VAR)
|
||
fillGenKillForGlobal(make_pair(arg, whereDef), gen_local, kill_local);
|
||
}
|
||
}
|
||
|
||
// return of function always REG
|
||
if (arg && settings.withRegisters)
|
||
{
|
||
kill_local[arg].insert(SAPFOR::CFG_VAL::KILL_ALL);
|
||
gen_local[arg].clear();
|
||
}
|
||
|
||
if (hasOut)
|
||
{
|
||
bool hasFoundRes = false;
|
||
for (auto& out : onlyGlobal)
|
||
{
|
||
if (out.first->getMemType() == CFG_MEM_TYPE::FUNC_RES_)
|
||
{
|
||
if (arg)
|
||
{
|
||
hasFoundRes = true;
|
||
gen_local[arg].insert(out.second.begin(), out.second.end());
|
||
}
|
||
}
|
||
else if (out.first->isMemGlobal())
|
||
fillGenKillForGlobal(out, gen_local, kill_local);
|
||
else if (out.first->getMemType() == CFG_MEM_TYPE::FUNC_PARAM_)
|
||
{
|
||
int num = getParamIndex(out.first, lastParamRef.size());
|
||
|
||
auto arg = lastParamRef[num]->getArg1();
|
||
if (arg->getType() == CFG_ARG_TYPE::VAR)
|
||
fillGenKillForGlobal(make_pair(arg, out.second), gen_local, kill_local);
|
||
}
|
||
}
|
||
|
||
if (arg && !hasFoundRes)
|
||
gen_local[arg].insert(currInstr->getNumber());
|
||
}
|
||
else if (currInstr->getArg1()->getValue() == "_READ")
|
||
{
|
||
for (auto& arg: lastParamRef) // all is out
|
||
if (arg->getArg1()->getType() == CFG_ARG_TYPE::VAR)
|
||
fillGenKillForGlobal(make_pair(arg->getArg1(), set<int>{ currInstr->getNumber()}), gen_local, kill_local);
|
||
}
|
||
}
|
||
else if (currInstr->getOperation() == CFG_OP::PARAM)
|
||
lastParamRef.push_back(currInstr);
|
||
|
||
if (currInstr->getOperation() != CFG_OP::PARAM)
|
||
lastParamRef.clear();
|
||
|
||
if (genForIR)
|
||
(*genForIR)[currInstr] = gen_local;
|
||
if (killForIR)
|
||
(*killForIR)[currInstr] = kill_local;
|
||
}
|
||
|
||
for (auto& gen : gen_local)
|
||
if (gen.first->isMemGlobal() || gen.first->getMemType() == CFG_MEM_TYPE::FUNC_PARAM_)
|
||
if (gen.second.count(SAPFOR::CFG_VAL::UNINIT))
|
||
notInitedGlobals[block].insert(gen.first);
|
||
|
||
gen[block] = gen_local;
|
||
kill[block] = kill_local;
|
||
}
|
||
}
|
||
|
||
static int buildReachingDefs(const vector<BBlock*>& CFG, const FuncInfo* currF,
|
||
map<SAPFOR::Argument*, set<int>>& outForCurrFunc,
|
||
const map<FuncInfo*, map<SAPFOR::Argument*, set<int>>>& outForFunc,
|
||
const map<string, FuncInfo*>& funcByName, const CFG_Settings settings)
|
||
{
|
||
// create gen kill for blocks
|
||
map<BBlock*, map<SAPFOR::Argument*, set<int>>> gen, kill;
|
||
map<BBlock*, set<SAPFOR::Argument*>> notInitedGlobals;
|
||
|
||
buildGenKillForCFG(CFG, funcByName, outForFunc, gen, kill, NULL, NULL, notInitedGlobals, settings);
|
||
|
||
//create not inited vars: U AllGen
|
||
set<SAPFOR::Argument*> allGen;
|
||
for (auto& byBlock : gen)
|
||
for (auto& genB : byBlock.second)
|
||
allGen.insert(genB.first);
|
||
|
||
// sort blocks in IR order
|
||
vector<BBlock*> sortedByIR = CFG;
|
||
sort(sortedByIR.begin(), sortedByIR.end(), bb_cmp);
|
||
|
||
//set to first block all not inited vars to IN set
|
||
if (sortedByIR.size())
|
||
{
|
||
int firstN = 0;
|
||
auto stF = currF->funcPointer->GetOriginal();
|
||
if (stF->variant() == ENTRY_STAT)
|
||
{
|
||
int z = 0;
|
||
for (auto& block : sortedByIR)
|
||
{
|
||
for (auto& ir : block->getInstructions())
|
||
if (ir->getInstruction()->getOperation() == CFG_OP::ENTRY && ir->getInstruction()->getOperator() == stF)
|
||
firstN = z;
|
||
z++;
|
||
}
|
||
|
||
if (sortedByIR[firstN]->getInstructions()[0]->getInstruction()->getOperation() != CFG_OP::ENTRY && z == 0)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
}
|
||
|
||
auto& firstIn = sortedByIR[firstN]->getModRD_In();
|
||
for (auto& noInited : allGen)
|
||
firstIn[noInited] = set<int>{ SAPFOR::CFG_VAL::UNINIT };
|
||
}
|
||
|
||
bool changed = true;
|
||
int iter = 0;
|
||
while (changed)
|
||
{
|
||
changed = false;
|
||
|
||
//update IN = U OUTp
|
||
//update OUT = GEN U (IN \ KILL)
|
||
for (const auto& block : sortedByIR)
|
||
{
|
||
bool changeLoc = false;
|
||
map<SAPFOR::Argument*, set<int>>& in_loc = block->getModRD_In();
|
||
const auto& prevBlocks = block->getPrev();
|
||
|
||
// IN = U OUTp
|
||
for (auto& prev : prevBlocks)
|
||
{
|
||
const auto& currOut = prev->getRD_Out();
|
||
for (auto& out : currOut)
|
||
{
|
||
bool res = intersectAndAdd(in_loc[out.first], out.second);
|
||
changeLoc = res || changeLoc;
|
||
}
|
||
}
|
||
|
||
if (changeLoc)
|
||
changed = true;
|
||
|
||
map<SAPFOR::Argument*, set<int>>& out_loc = block->getModRD_Out();
|
||
changeLoc = false;
|
||
|
||
const auto& currIn = block->getRD_In();
|
||
const auto& currKill = kill[block];
|
||
const auto& currGen = gen[block];
|
||
|
||
// OUT = GEN
|
||
for (auto& gen : currGen)
|
||
{
|
||
bool genUpdated = false;
|
||
if (gen.first->isMemGlobal() || gen.first->getMemType() == CFG_MEM_TYPE::FUNC_PARAM_)
|
||
{
|
||
if (notInitedGlobals[block].count(gen.first))
|
||
{
|
||
auto inLoc = in_loc.find(gen.first);
|
||
if (inLoc != in_loc.end())
|
||
{
|
||
genUpdated = true;
|
||
set<int> copy;
|
||
for (auto& elem : gen.second)
|
||
{
|
||
if (elem == SAPFOR::CFG_VAL::UNINIT)
|
||
copy.insert(inLoc->second.begin(), inLoc->second.end());
|
||
else
|
||
copy.insert(elem);
|
||
}
|
||
addToSet(out_loc, gen.first, copy, changeLoc);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!genUpdated)
|
||
addToSet(out_loc, gen.first, gen.second, changeLoc);
|
||
}
|
||
|
||
// OUT = GEN U (IN \ KILL)
|
||
for (auto& in : currIn)
|
||
{
|
||
if (currKill.count(in.first))
|
||
{
|
||
auto s1 = in.second;
|
||
const auto& s2 = currKill.find(in.first)->second;
|
||
if (s2.size() && (*s2.begin()) == SAPFOR::CFG_VAL::KILL_ALL)
|
||
;// nothing to add, s1 \ s2 = empty
|
||
else
|
||
{
|
||
set<int> diff;
|
||
set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), inserter(diff, diff.begin()));
|
||
addToSet(out_loc, in.first, diff, changeLoc);
|
||
}
|
||
}
|
||
else
|
||
addToSet(out_loc, in.first, in.second, changeLoc);
|
||
}
|
||
|
||
if (changeLoc)
|
||
changed = true;
|
||
}
|
||
iter++;
|
||
}
|
||
|
||
if (sortedByIR.size())
|
||
outForCurrFunc = sortedByIR.back()->getRD_Out();
|
||
return iter;
|
||
}
|
||
|
||
//Kosaraju<6A>Sharir algorithm
|
||
static vector<int> getStronglyConnectedComps(vector<vector<int>>& g) {
|
||
// 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
|
||
auto size = g.size();
|
||
vector<bool> vis(size); // all false by default
|
||
vector<int> l(size); // all zero by default
|
||
auto x = size; // index for filling l in reverse order
|
||
vector<vector<int>> t(size); // transpose graph
|
||
|
||
// Recursive subroutine 'visit':
|
||
function<void(int)> visit;
|
||
visit = [&](int u)
|
||
{
|
||
if (!vis[u])
|
||
{
|
||
vis[u] = true;
|
||
for (auto v : g[u])
|
||
{
|
||
visit(v);
|
||
t[v].push_back(u); // construct transpose
|
||
}
|
||
l[--x] = u;
|
||
}
|
||
};
|
||
|
||
// 2. For each vertex u of the graph do visit(u)
|
||
for (int i = 0; i < g.size(); ++i)
|
||
visit(i);
|
||
|
||
vector<int> c(size); // used for component assignment
|
||
|
||
// Recursive subroutine 'assign':
|
||
function<void(int, int)> assign;
|
||
assign = [&](int u, int root) {
|
||
if (vis[u]) { // repurpose vis to mean 'unassigned'
|
||
vis[u] = false;
|
||
c[u] = root;
|
||
for (auto v : t[u]) {
|
||
assign(v, root);
|
||
}
|
||
}
|
||
};
|
||
|
||
// 3: For each element u of l in order, do assign(u, u)
|
||
for (auto u : l)
|
||
assign(u, u);
|
||
return c;
|
||
|
||
}
|
||
|
||
static int getFuncNum(FuncInfo* call, map<FuncInfo*, int>& funcToInt, map<int, FuncInfo*>& intTofunc, int &fnum)
|
||
{
|
||
auto it = funcToInt.find(call);
|
||
if (funcToInt.find(call) == funcToInt.end())
|
||
{
|
||
it = funcToInt.insert(it, make_pair(call, fnum));
|
||
intTofunc[fnum] = call;
|
||
fnum++;
|
||
}
|
||
return it->second;
|
||
}
|
||
|
||
//return also strongly connected components if has recursive chains call
|
||
vector<set<FuncInfo*>> groupByCallDependencies(const map<FuncInfo*, set<FuncInfo*>>& callDeps, vector<set<FuncInfo*>>& scc)
|
||
{
|
||
vector<vector<int>> funcGraph;
|
||
funcGraph.resize(callDeps.size());
|
||
|
||
map<FuncInfo*, int> funcToInt;
|
||
map<int, FuncInfo*> intTofunc;
|
||
|
||
int fnum = 0;
|
||
for (auto& funcPair : callDeps)
|
||
{
|
||
FuncInfo* call = funcPair.first;
|
||
const set<FuncInfo*>& callTo = funcPair.second;
|
||
|
||
int callN = getFuncNum(call, funcToInt, intTofunc, fnum);
|
||
for (auto& to : callTo)
|
||
{
|
||
int callToN = getFuncNum(to, funcToInt, intTofunc, fnum);
|
||
if (funcGraph.size() < fnum)
|
||
funcGraph.resize(fnum);
|
||
funcGraph[callN].push_back(callToN);
|
||
}
|
||
}
|
||
vector<int> scc_v = getStronglyConnectedComps(funcGraph);
|
||
map<int, vector<int>> components;
|
||
for (int f = 0; f < scc_v.size(); ++f)
|
||
components[scc_v[f]].push_back(f);
|
||
|
||
vector<vector<int>> funcWithRecursion;
|
||
for (auto& elem : components)
|
||
if (elem.second.size() > 1)
|
||
funcWithRecursion.push_back(elem.second);
|
||
|
||
int countWithRec = funcWithRecursion.size();
|
||
|
||
set<FuncInfo*> added;
|
||
size_t added_prev_size = 0;
|
||
size_t added_new_size = 0;
|
||
set<int> doneRec;
|
||
|
||
vector<set<FuncInfo*>> runMapForRD;
|
||
while (added.size() != callDeps.size())
|
||
{
|
||
set<FuncInfo*> newLvl;
|
||
if (added.size() == 0)
|
||
{
|
||
for (auto& func : callDeps)
|
||
{
|
||
if (func.second.size() == 0)
|
||
newLvl.insert(func.first);
|
||
else
|
||
{
|
||
bool ifHasDep = false;
|
||
for (auto& dep : func.second)
|
||
if (callDeps.count(dep))
|
||
ifHasDep = true;
|
||
|
||
if (!ifHasDep)
|
||
newLvl.insert(func.first);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (auto& func : callDeps)
|
||
{
|
||
bool ifHasDep = false;
|
||
for (auto& dep : func.second)
|
||
if (callDeps.count(dep) && added.count(dep) == 0)
|
||
ifHasDep = true;
|
||
|
||
if (!ifHasDep && added.count(func.first) == 0)
|
||
newLvl.insert(func.first);
|
||
}
|
||
}
|
||
|
||
added.insert(newLvl.begin(), newLvl.end());
|
||
|
||
added_new_size = added.size();
|
||
if (added_new_size == added_prev_size)
|
||
{
|
||
if (countWithRec != 0)
|
||
{
|
||
for (int z = 0; z < funcWithRecursion.size(); ++z)
|
||
{
|
||
if (doneRec.find(z) != doneRec.end())
|
||
continue;
|
||
|
||
set<FuncInfo*> candidate;
|
||
for (int f = 0; f < funcWithRecursion[z].size(); ++f)
|
||
candidate.insert(intTofunc[funcWithRecursion[z][f]]);
|
||
|
||
bool ok = true;
|
||
for (auto& elem : candidate)
|
||
{
|
||
if (candidate.find(elem) != candidate.end())
|
||
continue;
|
||
|
||
if (callDeps.count(elem))
|
||
for (auto& dep : callDeps.at(elem))
|
||
if (added.find(dep) == added.end())
|
||
ok = false;
|
||
}
|
||
|
||
if (!ok)
|
||
continue;
|
||
else
|
||
{
|
||
newLvl = candidate;
|
||
added.insert(newLvl.begin(), newLvl.end());
|
||
added_new_size = added.size();
|
||
--countWithRec;
|
||
doneRec.insert(z);
|
||
|
||
scc.push_back(candidate);
|
||
}
|
||
}
|
||
|
||
if (newLvl.size() == 0)
|
||
{
|
||
__spf_print(1, "recursive call was found, can not resolve dependencies\n");
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
}
|
||
}
|
||
}
|
||
|
||
added_prev_size = added_new_size;
|
||
runMapForRD.push_back(newLvl);
|
||
}
|
||
|
||
return runMapForRD;
|
||
}
|
||
|
||
static void buildReachingDefs(const map<FuncInfo*, vector<BBlock*>>& CFG, const CFG_Settings& settings)
|
||
{
|
||
map<FuncInfo*, set<FuncInfo*>> callDeps;
|
||
map<string, FuncInfo*> funcByName;
|
||
map<FuncInfo*, map<SAPFOR::Argument*, set<int>>> outForFunc;
|
||
|
||
for (auto& byFunc : CFG)
|
||
{
|
||
callDeps[byFunc.first].insert(byFunc.first->callsFromV.begin(), byFunc.first->callsFromV.end());
|
||
funcByName[byFunc.first->funcName] = byFunc.first;
|
||
}
|
||
|
||
vector<set<FuncInfo*>> scc;
|
||
vector<set<FuncInfo*>> callLvlsForRD = groupByCallDependencies(callDeps, scc);
|
||
|
||
//TODO: take into account ssc structure
|
||
__spf_print(DEB_PRINT, " count of functions %d, count of lvls %d\n", (int)CFG.size(), (int)callLvlsForRD.size());
|
||
for (auto& byLvl : callLvlsForRD)
|
||
{
|
||
for (auto& byFunc : byLvl)
|
||
{
|
||
__spf_print(DEB_PRINT, " RD time for '%s' function", byFunc->funcName.c_str());
|
||
auto t = high_resolution_clock::now();
|
||
|
||
auto itCFG = CFG.find(byFunc);
|
||
if (itCFG == CFG.end())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
map<SAPFOR::Argument*, set<int>> outForCurr;
|
||
int iter = buildReachingDefs(itCFG->second, byFunc, outForCurr, outForFunc, funcByName, settings);
|
||
|
||
if (outForFunc.count(byFunc))
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
outForFunc[byFunc] = outForCurr;
|
||
|
||
auto msec = duration_cast<milliseconds>(high_resolution_clock::now() - t).count();
|
||
__spf_print(DEB_PRINT, " is %.3f sec, iters %d\n", msec / 1000., iter);
|
||
}
|
||
__spf_print(DEB_PRINT, "\n");
|
||
}
|
||
}
|
||
|
||
static void createBlock(IR_Block* forIR, map<IR_Block*, BBlock*>& createdBlocks,
|
||
vector<BBlock*>& bblocks,
|
||
const vector<IR_Block*>& instructions)
|
||
{
|
||
if (createdBlocks.count(forIR) == 0)
|
||
{
|
||
bblocks.push_back(new BBlock(forIR));
|
||
createdBlocks[forIR] = bblocks.back();
|
||
}
|
||
}
|
||
|
||
static vector<BBlock*> buildCFG(const vector<IR_Block*>& instructions, bool withCalls)
|
||
{
|
||
vector<BBlock*> bblocks;
|
||
|
||
map<IR_Block*, BBlock*> createdBlocks;
|
||
map<Instruction*, IR_Block*> instrToIr;
|
||
map<int, IR_Block*> instrNumToIr;
|
||
|
||
for (auto& ir : instructions)
|
||
{
|
||
instrToIr[ir->getInstruction()] = ir;
|
||
instrNumToIr[ir->getNumber()] = ir;
|
||
}
|
||
|
||
if (instructions.size())
|
||
{
|
||
bblocks.push_back(new BBlock(instructions[0]));
|
||
createdBlocks[instructions[0]] = bblocks.back();
|
||
}
|
||
|
||
for (int z = 0; z < instructions.size(); ++z)
|
||
{
|
||
if (instructions[z]->getInstruction()->getOperation() == CFG_OP::JUMP ||
|
||
instructions[z]->getInstruction()->getOperation() == CFG_OP::JUMP_IF)
|
||
{
|
||
auto irJump = instrToIr[instructions[z]->getJump()];
|
||
if (irJump == NULL)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
createBlock(irJump, createdBlocks, bblocks, instructions);
|
||
|
||
if (z + 1 < instructions.size())
|
||
createBlock(instructions[z + 1], createdBlocks, bblocks, instructions);
|
||
}
|
||
else if (instructions[z]->getInstruction()->getOperation() == CFG_OP::ENTRY)
|
||
{
|
||
createBlock(instructions[z], createdBlocks, bblocks, instructions);
|
||
if (z + 1 != instructions.size() - 1) // TODO: check this
|
||
createBlock(instructions[z + 1], createdBlocks, bblocks, instructions);
|
||
}
|
||
else if (instructions[z]->getInstruction()->getOperation() == CFG_OP::DVM_DIR ||
|
||
(instructions[z]->getInstruction()->getOperation() == CFG_OP::EXIT && withCalls))
|
||
{
|
||
createBlock(instructions[z], createdBlocks, bblocks, instructions);
|
||
if (z + 1 < instructions.size())
|
||
createBlock(instructions[z + 1], createdBlocks, bblocks, instructions);
|
||
}
|
||
else if (instructions[z]->getInstruction()->getOperation() == CFG_OP::F_CALL && withCalls)
|
||
{
|
||
int prev = z - 1;
|
||
while (prev >= 0 && instructions[prev]->getInstruction()->getOperation() == CFG_OP::PARAM)
|
||
--prev;
|
||
|
||
createBlock(instructions[prev + 1], createdBlocks, bblocks, instructions);
|
||
if (z + 1 < instructions.size())
|
||
createBlock(instructions[z + 1], createdBlocks, bblocks, instructions);
|
||
}
|
||
}
|
||
|
||
BBlock* currBlock = NULL;
|
||
for (auto& ir : instructions)
|
||
{
|
||
if (createdBlocks.count(ir) != 0)
|
||
currBlock = createdBlocks[ir];
|
||
else
|
||
{
|
||
if (currBlock == NULL)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
currBlock->addInstruction(ir);
|
||
}
|
||
}
|
||
|
||
for (auto& bblock : bblocks)
|
||
{
|
||
auto lastInstr = bblock->getInstructions().back();
|
||
|
||
BBlock* fromJump = NULL;
|
||
if (lastInstr->getJump())
|
||
{
|
||
fromJump = instrToIr[lastInstr->getJump()]->getBasicBlock();
|
||
bblock->addNext(fromJump);
|
||
}
|
||
|
||
if (lastInstr->getInstruction()->getOperation() != CFG_OP::JUMP)
|
||
{
|
||
int next = lastInstr->getNumber() + 1;
|
||
if (instrNumToIr.count(next) != 0)
|
||
{
|
||
auto toAdd = instrNumToIr[next]->getBasicBlock();
|
||
if (fromJump != toAdd)
|
||
bblock->addNext(toAdd);
|
||
}
|
||
}
|
||
}
|
||
|
||
for (auto& bblock : bblocks)
|
||
for (auto& next : bblock->getNext())
|
||
next->addPrev(bblock);
|
||
|
||
auto checkIR = getAllIR(bblocks);
|
||
|
||
if (checkIR.size() != instructions.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
return bblocks;
|
||
}
|
||
|
||
static void relaceArgInEntry(SAPFOR::Instruction* ir, const string& entryName, const vector<string>& params)
|
||
{
|
||
for (int z = 0; z < 3; ++z)
|
||
{
|
||
SAPFOR::Argument* arg = NULL;
|
||
if (z == 0)
|
||
arg = ir->getArg1();
|
||
else if (z == 1)
|
||
arg = ir->getArg2();
|
||
else if (z == 2)
|
||
arg = ir->getResult();
|
||
|
||
if (arg == NULL)
|
||
continue;
|
||
|
||
if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_)
|
||
{
|
||
vector<string> splited;
|
||
splitString(arg->getValue(), '%', splited);
|
||
if (splited.size() != 3)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
if (splited[0] != entryName)
|
||
{
|
||
int p = -1;
|
||
for (int t = 0; t < params.size(); ++t)
|
||
if (params[t] == splited[1])
|
||
p = t;
|
||
|
||
SAPFOR::Argument* newArg = NULL;
|
||
if (p < 0)
|
||
newArg = createArg(splited[0] + "%" + splited[1], splited[1], SAPFOR::CFG_MEM_TYPE::LOCAL_);
|
||
else
|
||
newArg = createArg(entryName + "%" + splited[1] + "%" + to_string(p), splited[1], SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_);
|
||
|
||
if (z == 0)
|
||
ir->setArg1(newArg);
|
||
else if (z == 1)
|
||
ir->setArg2(newArg);
|
||
else if (z == 2)
|
||
ir->setResult(newArg);
|
||
}
|
||
}
|
||
else if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::LOCAL_ &&
|
||
arg->getType() == SAPFOR::CFG_ARG_TYPE::VAR)
|
||
{
|
||
vector<string> splited;
|
||
splitString(arg->getValue(), '%', splited);
|
||
if (splited.size() != 2)
|
||
continue;
|
||
|
||
if (splited[0] != entryName)
|
||
{
|
||
int p = -1;
|
||
for (int t = 0; t < params.size(); ++t)
|
||
if (params[t] == splited[1])
|
||
p = t;
|
||
|
||
if (p >= 0)
|
||
{
|
||
auto newArg = createArg(entryName + "%" + splited[1] + "%" + to_string(p), splited[1], SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_);
|
||
|
||
if (z == 0)
|
||
ir->setArg1(newArg);
|
||
else if (z == 1)
|
||
ir->setArg2(newArg);
|
||
else if (z == 2)
|
||
ir->setResult(newArg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static void filterEntryArgs(const vector<BBlock*>& bblocks, const string& entryName, const vector<string>& params)
|
||
{
|
||
/*set<BBlock*> checked;
|
||
std::stack<BBlock*> q;
|
||
q.push(bblocks[0]);
|
||
|
||
checked.insert(bblocks[0]);
|
||
|
||
while (!q.empty())
|
||
{
|
||
BBlock* curr = q.top();
|
||
checked.insert(curr);
|
||
q.pop();
|
||
|
||
for (auto& elem : curr->getNext())
|
||
if (checked.count(elem) == 0)
|
||
q.push(elem);
|
||
}*/
|
||
|
||
for (auto& block : bblocks)
|
||
{
|
||
//if (checked.count(block) == 0) // not checked
|
||
for (auto& ir : block->getInstructions())
|
||
relaceArgInEntry(ir->getInstruction(), "_" + entryName, params);
|
||
}
|
||
}
|
||
|
||
map<FuncInfo*, vector<BBlock*>> buildCFG(const map<string, CommonBlock*>& commonBlocks, const map<string, vector<FuncInfo*>>& allFuncInfo, const CFG_Settings settings)
|
||
{
|
||
map<FuncInfo*, vector<BBlock*>> result;
|
||
|
||
string oldFile = current_file->filename();
|
||
|
||
for (auto& byFile : allFuncInfo)
|
||
{
|
||
if (SgFile::switchToFile(byFile.first) == -1)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
map<SgStatement*, FuncInfo*> byPointer;
|
||
for (auto& func : byFile.second)
|
||
byPointer[func->funcPointer->GetOriginal()] = func;
|
||
|
||
for (auto& byFunc : byFile.second)
|
||
{
|
||
FuncInfo* currF = byFunc;
|
||
SgStatement* function = currF->funcPointer->GetOriginal();
|
||
|
||
if (function->variant() == ENTRY_STAT)
|
||
continue;
|
||
|
||
if (currF->isInterface)
|
||
continue;
|
||
|
||
if (!isSgProgHedrStmt(function)) {
|
||
__spf_print(1, "var %d on file %s and line %d\n", function->variant(), function->fileName(), function->lineNumber());
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
}
|
||
|
||
vector<IR_Block*> blocks = buildIR(function, currF, getCommonsByFunction(current_file, function, commonBlocks), settings);
|
||
if (blocks.size())
|
||
blocks[0]->setHeader();
|
||
|
||
vector<BBlock*> CFG_forFunc = buildCFG(blocks, settings.withCallsInBlocks);
|
||
|
||
if (result.find(currF) != result.end())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
result[currF] = CFG_forFunc;
|
||
}
|
||
|
||
map<SAPFOR::Argument*, SAPFOR::Argument*> argsInc;
|
||
//duplicate graph of parent func for ENTRY points
|
||
for (auto& byFunc : byFile.second)
|
||
{
|
||
FuncInfo* currF = byFunc;
|
||
SgStatement* function = currF->funcPointer->GetOriginal();
|
||
|
||
if (function->variant() != ENTRY_STAT)
|
||
continue;
|
||
|
||
auto parent = function->controlParent();
|
||
if (!isSgProgHedrStmt(parent))
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
if (!byPointer.count(parent))
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
FuncInfo* parentF = byPointer[parent];
|
||
if (!result.count(parentF))
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
if (result.count(currF))
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
const auto& cfg = result[parentF];
|
||
|
||
vector<BBlock*> copy;
|
||
map<BBlock*, BBlock*> oldToNewBB;
|
||
map<Instruction*, Instruction*> oldToNewIR;
|
||
|
||
for (auto& block : cfg)
|
||
{
|
||
copy.push_back(new BBlock(*block));
|
||
oldToNewBB[block] = copy.back();
|
||
|
||
const auto& newIR = copy.back()->getInstructions();
|
||
const auto& oldIR = block->getInstructions();
|
||
if (newIR.size() != oldIR.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
for (int z = 0; z < oldIR.size(); ++z)
|
||
oldToNewIR[oldIR[z]->getInstruction()] = newIR[z]->getInstruction();
|
||
}
|
||
|
||
for (auto& block : copy)
|
||
{
|
||
block->replacePrevNext(oldToNewBB);
|
||
for (auto& ir : block->getInstructions())
|
||
{
|
||
auto jump = ir->getJump();
|
||
if (jump)
|
||
{
|
||
auto it = oldToNewIR.find(jump);
|
||
if (it == oldToNewIR.end())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
ir->setJump(it->second);
|
||
}
|
||
}
|
||
}
|
||
|
||
//need to add goto to ENTRY
|
||
map<FuncInfo*, vector<BBlock*>> tmpInfo;
|
||
tmpInfo[parentF] = copy;
|
||
|
||
auto position = getInstructionAndBlockByStatement(tmpInfo, function);
|
||
if (position.first == NULL || position.second == NULL)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
if (position.first->getOperation() != CFG_OP::ENTRY)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
const int lastIrNum = SAPFOR::Instruction::getNextInstrNum();
|
||
int maxNum = 0;
|
||
|
||
//shift all IR numbers by lastIrNum + 1
|
||
for (auto& block : copy)
|
||
{
|
||
for (auto& instr : block->getInstructions())
|
||
{
|
||
maxNum = std::max(instr->getInstruction()->getNumber(), maxNum);
|
||
|
||
instr->getInstruction()->shiftNumber(lastIrNum + 1);
|
||
auto ir = instr->getInstruction();
|
||
auto type = ir->getOperation();
|
||
if (type == CFG_OP::JUMP || type == CFG_OP::JUMP_IF)
|
||
{
|
||
if (argsInc.find((type == CFG_OP::JUMP) ? ir->getArg1() : ir->getArg2()) == argsInc.end())
|
||
{
|
||
int jumpTo = atoi((type == CFG_OP::JUMP) ? ir->getArg1()->getValue().c_str() : ir->getArg2()->getValue().c_str());
|
||
jumpTo += (lastIrNum + 1);
|
||
SAPFOR::Argument* newArg = new SAPFOR::Argument((type == CFG_OP::JUMP) ? *(ir->getArg1()) : *(ir->getArg2()));
|
||
newArg->setValue(to_string(jumpTo));
|
||
|
||
if (type == CFG_OP::JUMP)
|
||
{
|
||
ir->setArg1(newArg);
|
||
argsInc[ir->getArg1()] = newArg;
|
||
}
|
||
else
|
||
{
|
||
ir->setArg2(newArg);
|
||
argsInc[ir->getArg2()] = newArg;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (type == CFG_OP::JUMP)
|
||
ir->setArg1(argsInc[ir->getArg1()]);
|
||
else
|
||
ir->setArg2(argsInc[ir->getArg2()]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
SAPFOR::Instruction::shiftNextInstrNum(maxNum + 1);
|
||
|
||
// goto to ENTRY
|
||
BBlock* firstBlock = new BBlock();
|
||
IR_Block* newGoto = new IR_Block(new Instruction(CFG_OP::JUMP, lastIrNum, new SAPFOR::Argument(CFG_ARG_TYPE::INSTR, to_string(position.first->getNumber()))));
|
||
newGoto->setJump(position.first);
|
||
newGoto->setHeader();
|
||
|
||
firstBlock->addInstruction(newGoto);
|
||
firstBlock->addNext(position.second);
|
||
position.second->addPrev(firstBlock);
|
||
copy.insert(copy.begin(), firstBlock);
|
||
|
||
filterEntryArgs(copy, function->symbol()->identifier(), currF->funcParams.identificators);
|
||
|
||
result[currF] = copy;
|
||
}
|
||
}
|
||
|
||
if (settings.withRD)
|
||
buildReachingDefs(result, settings);
|
||
|
||
if (settings.withDominators)
|
||
{
|
||
auto t = high_resolution_clock::now();
|
||
for (auto& [func, bblocks] : result)
|
||
SAPFOR::buildDominatorTree(bblocks);
|
||
|
||
auto msec = duration_cast<milliseconds>(high_resolution_clock::now() - t).count();
|
||
__spf_print(1, "dominator build time is %.3f sec\n", msec / 1000.);
|
||
}
|
||
|
||
if (SgFile::switchToFile(oldFile) == -1)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
return result;
|
||
}
|
||
|
||
static bool ir_cmp(const IR_Block* a, const IR_Block* b)
|
||
{
|
||
return a->getNumber() < b->getNumber();
|
||
}
|
||
|
||
vector<IR_Block*> getAllIR(const vector<BBlock*>& blocks)
|
||
{
|
||
vector<IR_Block*> intsrs;
|
||
for (auto& block : blocks)
|
||
for (auto& instr : block->getInstructions())
|
||
intsrs.push_back(instr);
|
||
|
||
sort(intsrs.begin(), intsrs.end(), ir_cmp);
|
||
return intsrs;
|
||
}
|
||
|
||
void dumpCFG(const map<FuncInfo*, vector<BBlock*>>& blocks, bool withRD)
|
||
{
|
||
map<int, map<FuncInfo*, tuple<FuncInfo*, vector<BBlock*>, vector<IR_Block*>>>> toPrint; // sort by IR number
|
||
|
||
for (auto& byFunc : blocks)
|
||
{
|
||
vector<IR_Block*> IR = getAllIR(byFunc.second);
|
||
toPrint[IR[0]->getNumber()][byFunc.first] = make_tuple(byFunc.first, byFunc.second, IR);
|
||
}
|
||
|
||
for (auto& dump : toPrint)
|
||
for (auto& byFunc : dump.second)
|
||
debPrint(get<0>(byFunc.second)->funcName, get<1>(byFunc.second), get<2>(byFunc.second), withRD);
|
||
}
|
||
|
||
// buildCFGforCurrentFunc builds and returns CFG for current function, which contains 'stmt'
|
||
// and for functions, called from current function.
|
||
// CFG is built with reaching definitions analysis
|
||
// and with assupmtion, that every loop executes at least one iteration
|
||
map<FuncInfo*, vector<SAPFOR::BasicBlock*>>
|
||
buildCFGforCurrentFunc(SgStatement* stmt, const SAPFOR::CFG_Settings settings,
|
||
const map<string, CommonBlock*>& commonBlocks,
|
||
const map<string, vector<FuncInfo*>>& allFuncInfo)
|
||
{
|
||
checkNull(stmt, convertFileName(__FILE__).c_str(), __LINE__);
|
||
string file = stmt->fileName();
|
||
|
||
SgProgHedrStmt* curFunc = isSgProgHedrStmt(getFuncStat(stmt));
|
||
checkNull(curFunc, convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
string curFuncName = curFunc->nameWithContains();
|
||
if (allFuncInfo.count(file) == 0)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
const vector<FuncInfo*>& funcInFile = allFuncInfo.at(file);
|
||
|
||
FuncInfo* current = NULL;
|
||
for (auto& func : funcInFile)
|
||
{
|
||
if (func->funcName == curFuncName)
|
||
{
|
||
current = func;
|
||
break;
|
||
}
|
||
}
|
||
checkNull(current, convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
map<string, vector<FuncInfo*>> fileFuncInfoMap;
|
||
fileFuncInfoMap[current->fileName].push_back(current);
|
||
|
||
if (settings.withCallFrom)
|
||
for (auto& callFrom : current->callsFromV)
|
||
fileFuncInfoMap[callFrom->fileName].push_back(callFrom);
|
||
|
||
return buildCFG(commonBlocks, fileFuncInfoMap, settings);
|
||
} |