#define _LEAK_ #include "../Utils/leak_detector.h" #include #include #include #include #include #include #include "../Utils/SgUtils.h" #include "../Utils/CommonBlock.h" #include "../GraphCall/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); } void BBlock::addInstructionInFront(IR_Block* item) { instructions.insert(instructions.begin(), item); item->setBasicBlock(this); } void BBlock::addInstructionBeforeInstruction(IR_Block* item, Instruction* instruction) { for (auto it = instructions.begin(); it != instructions.end(); ++it) { if ((*it)->getInstruction() == instruction) { instructions.insert(it, item); item->setBasicBlock(this); return; } } } 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>& sets) { map> byName; map 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& bblocks, const vector& 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> getCommonsByFunction(SgFile* file, SgStatement* function, const map& commonBlocks) { vector> 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 bool intersectAndAdd(set& s1, const set& s2) { bool retVal = false; set 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(set&, const set&); static void addToSet(map>& addTo, SAPFOR::Argument* fromArg, const set& 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>& arg, map>& gen_local, map>& 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& CFG, const map& funcByName, const map>>& outForFunc, // actually, RD_out of last IR instruction of function map>>& gen, map>>& kill, map>>* genForIR, map>>* killForIR, map>& notInitedGlobals, const CFG_Settings settings) { for (auto& block : CFG) { map> kill_local; map> gen_local; vector 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> 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 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{ 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& CFG, const FuncInfo* currF, map>& outForCurrFunc, const map>>& outForFunc, const map& funcByName, const CFG_Settings settings) { // create gen kill for blocks map>> gen, kill; map> notInitedGlobals; buildGenKillForCFG(CFG, funcByName, outForFunc, gen, kill, NULL, NULL, notInitedGlobals, settings); //create not inited vars: U AllGen set allGen; for (auto& byBlock : gen) for (auto& genB : byBlock.second) allGen.insert(genB.first); // sort blocks in IR order vector 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{ 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>& 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>& 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 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 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�Sharir algorithm static vector getStronglyConnectedComps(vector>& g) { // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty. auto size = g.size(); vector vis(size); // all false by default vector l(size); // all zero by default auto x = size; // index for filling l in reverse order vector> t(size); // transpose graph // Recursive subroutine 'visit': function 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 c(size); // used for component assignment // Recursive subroutine 'assign': function 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& funcToInt, map& 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> groupByCallDependencies(const map>& callDeps, vector>& scc) { vector> funcGraph; funcGraph.resize(callDeps.size()); map funcToInt; map intTofunc; int fnum = 0; for (auto& funcPair : callDeps) { FuncInfo* call = funcPair.first; const set& 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 scc_v = getStronglyConnectedComps(funcGraph); map> components; for (int f = 0; f < scc_v.size(); ++f) components[scc_v[f]].push_back(f); vector> funcWithRecursion; for (auto& elem : components) if (elem.second.size() > 1) funcWithRecursion.push_back(elem.second); int countWithRec = funcWithRecursion.size(); set added; size_t added_prev_size = 0; size_t added_new_size = 0; set doneRec; vector> runMapForRD; while (added.size() != callDeps.size()) { set 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 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>& CFG, const CFG_Settings& settings) { map> callDeps; map funcByName; map>> outForFunc; for (auto& byFunc : CFG) { callDeps[byFunc.first].insert(byFunc.first->callsFromV.begin(), byFunc.first->callsFromV.end()); funcByName[byFunc.first->funcName] = byFunc.first; } vector> scc; vector> 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> 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(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& createdBlocks, vector& bblocks, const vector& instructions) { if (createdBlocks.count(forIR) == 0) { bblocks.push_back(new BBlock(forIR)); createdBlocks[forIR] = bblocks.back(); } } static vector buildCFG(const vector& instructions, bool withCalls) { vector bblocks; map createdBlocks; map instrToIr; map 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& 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 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 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& bblocks, const string& entryName, const vector& params) { /*set checked; std::stack 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> buildCFG(const map& commonBlocks, const map>& allFuncInfo, const CFG_Settings settings) { map> result; string oldFile = current_file->filename(); for (auto& byFile : allFuncInfo) { if (SgFile::switchToFile(byFile.first) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); map 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 blocks = buildIR(function, currF, getCommonsByFunction(current_file, function, commonBlocks), settings); if (blocks.size()) blocks[0]->setHeader(); vector CFG_forFunc = buildCFG(blocks, settings.withCallsInBlocks); if (result.find(currF) != result.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); result[currF] = CFG_forFunc; } map 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 copy; map oldToNewBB; map 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> 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 (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 getAllIR(const vector& blocks) { vector 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>& blocks, bool withRD) { map, vector>>> toPrint; // sort by IR number for (auto& byFunc : blocks) { vector 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> buildCFGforCurrentFunc(SgStatement* stmt, const SAPFOR::CFG_Settings settings, const map& commonBlocks, const map>& 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& 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> 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); }