diff --git a/CMakeLists.txt b/CMakeLists.txt index 87eb86c..1ac1c0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,6 +205,8 @@ set(TRANSFORMS set(CFG src/CFGraph/IR.cpp src/CFGraph/IR.h + src/CFGraph/IR_domTree.cpp + src/CFGraph/IR_domTree.h src/CFGraph/CFGraph.cpp src/CFGraph/CFGraph.h src/CFGraph/RD_subst.cpp diff --git a/src/CFGraph/CFGraph.cpp b/src/CFGraph/CFGraph.cpp index 4c414d4..283e0a4 100644 --- a/src/CFGraph/CFGraph.cpp +++ b/src/CFGraph/CFGraph.cpp @@ -1149,6 +1149,16 @@ map> buildCFG(const map& common 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(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__); diff --git a/src/CFGraph/CFGraph.h b/src/CFGraph/CFGraph.h index cdb190b..f0308fd 100644 --- a/src/CFGraph/CFGraph.h +++ b/src/CFGraph/CFGraph.h @@ -6,6 +6,7 @@ #include #include "IR.h" +#include "IR_domTree.h" namespace SAPFOR { @@ -24,7 +25,7 @@ namespace SAPFOR std::vector next; std::vector prev; - BasicBlock* idom{}; + BasicBlock* directDominator = NULL; //reaching definition std::map> RD_in, RD_out; @@ -34,6 +35,7 @@ namespace SAPFOR bool addLive(const std::map>& to_add, bool in); std::map> getLive(bool in) const; bool removeLive(SAPFOR::Argument* to_remove, bool in); + public: BasicBlock() { num = lastNumBlock++; } BasicBlock(IR_Block* item); @@ -42,7 +44,7 @@ namespace SAPFOR void addInstruction(IR_Block* item); void addPrev(BasicBlock* prev_) { prev.push_back(prev_); } void addNext(BasicBlock* next_) { next.push_back(next_); } - void setIdom(BasicBlock* idom_) { idom = idom_; } + void setDom(BasicBlock* dom) { directDominator = dom; } int removePrev(BasicBlock* removed); int removeNext(BasicBlock* removed); @@ -70,7 +72,16 @@ namespace SAPFOR const std::vector& getInstructions() const { return instructions; } const std::vector& getNext() const { return next; } const std::vector& getPrev() const { return prev; } - BasicBlock* getIdom() const { return idom; } + BasicBlock* getDom() const + { + if (!directDominator) + { + __spf_print(1, "%s\n", "the dominator tree was built with an error or was not built at all"); + printInternalError(convertFileName(__FILE__).c_str(), __LINE__); + } + + return directDominator; + } /* * FOR LIVE ANALYSIS @@ -107,13 +118,15 @@ namespace SAPFOR bool withDVM = false; bool withCallsInBlocks = false; // separate each F_CALL to own BasicBlock bool withCallFrom = true; + bool withDominators = true; explicit CFG_Settings(int) { } explicit CFG_Settings(bool atLeastOneIterInLoop = false, bool withRD = true, bool withRegisters = false, - bool withDVM = false, bool withSPF = false, bool withCallsInBlocks = false, bool withCallFrom = true) : + bool withDVM = false, bool withSPF = false, bool withCallsInBlocks = false, + bool withCallFrom = true, bool withDominators = true) : atLeastOneIterInLoop(atLeastOneIterInLoop), withRD(withRD), withRegisters(withRegisters), withDVM(withDVM), withSPF(withSPF), - withCallsInBlocks(withCallsInBlocks), withCallFrom(withCallFrom) + withCallsInBlocks(withCallsInBlocks), withCallFrom(withCallFrom), withDominators(withDominators) { } }; } diff --git a/src/CFGraph/IR.h b/src/CFGraph/IR.h index a887a39..d61deed 100644 --- a/src/CFGraph/IR.h +++ b/src/CFGraph/IR.h @@ -7,6 +7,7 @@ #include "CFGraph.h" #include "../Utils/CommonBlock.h" +#include "../GraphCall/graph_calls.h" namespace SAPFOR { diff --git a/src/CFGraph/IR_domTree.h b/src/CFGraph/IR_domTree.h new file mode 100644 index 0000000..78a2c8b --- /dev/null +++ b/src/CFGraph/IR_domTree.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +#include "CFGraph.h" + +// Lengauer, Thomas. A fast algorithm for finding dominators in a flowgraph / Thomas Lengauer, Robert Endre Tarjan +// ACM Transactions on Programming Languages and Systems (TOPLAS). — 1979. — Vol. 1, no. 1. — Pp. 121–141. + +namespace SAPFOR { + +class BasicBlock; + +class DominatorFinder { +private: + BasicBlock* entry; + std::vector vertices; + std::unordered_map dfs_num; + std::vector parent, semi, vertex, ancestor, label; + std::vector> bucket; + int n; + + void DFS(BasicBlock* v, int parent_num); + void Compress(int v); + int Eval(int v); + void Link(int v, int w); + +public: + DominatorFinder(std::vector& blocks); +}; + +void buildDominatorTree(std::vector& blocks); +} diff --git a/src/ProjectParameters/domTree.h b/src/ProjectParameters/domTree.h deleted file mode 100644 index 2fe268f..0000000 --- a/src/ProjectParameters/domTree.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -#include "vector" -#include "map" - -#include "../CFGraph/CFGraph.h" -#include - -using namespace std; - -namespace SAPFOR { -class DominatorFinder { -private: - BasicBlock* entry; - std::vector vertices; - std::unordered_map dfs_num; - std::vector parent, semi, vertex, ancestor, label; - std::vector> bucket; - int n; - - void DFS(BasicBlock* v, int parent_num) { - dfs_num[v] = n; - vertex[n] = n; - semi[n] = n; - label[n] = n; - ancestor[n] = -1; - parent[n] = parent_num; - vertices[n++] = v; - - for (const auto& w : v->getNext()) { - if (dfs_num[w] == -1) { - DFS(w, dfs_num[v]); - } - } - } - - void Compress(int v) { - if (ancestor[ancestor[v]] != -1) { - Compress(ancestor[v]); - if (semi[label[ancestor[v]]] < semi[label[v]]) - label[v] = label[ancestor[v]]; - ancestor[v] = ancestor[ancestor[v]]; - } - } - - int Eval(int v) { - if (ancestor[v] == -1) return v; - Compress(v); - return label[v]; - } - - void Link(int v, int w) { - ancestor[w] = v; - } - -public: - DominatorFinder(std::vector& blocks) { - if (blocks.empty()) return; - entry = blocks[0]; - n = 0; - - for (auto block : blocks) dfs_num[block] = -1; - - int max_size = blocks.size(); - vertices.resize(max_size); - parent.assign(max_size, -1); - semi.assign(max_size, -1); - vertex.assign(max_size, -1); - ancestor.assign(max_size, -1); - label.assign(max_size, -1); - bucket.resize(max_size); - - DFS(entry, -1); - - for (int i = n - 1; i > 0; --i) { - int w = vertex[i]; - - for (BasicBlock* v : vertices[w]->getPrev()) { - int u = Eval(dfs_num[v]); - if (semi[u] < semi[w]) - semi[w] = semi[u]; - } - bucket[vertex[semi[w]]].push_back(w); - Link(parent[w], w); - - for (int v : bucket[parent[w]]) - { - int u = Eval(v); - if (semi[u] < semi[v]) - vertices[v]->setIdom(vertices[u]); - else - vertices[v]->setIdom(vertices[parent[w]]); - } - bucket[parent[w]].clear(); - } - - for (int i = 1; i < n; ++i) { - int w = vertex[i]; - if (vertices[w]->getIdom() != vertices[vertex[semi[w]]]) - vertices[w]->setIdom(vertices[w]->getIdom()->getIdom()); - } - - entry->setIdom(nullptr); - } -}; - -void buildDominatorTreeLT(std::vector& blocks) { - DominatorFinder finder(blocks); -} - -} diff --git a/src/ProjectParameters/projectParameters.cpp b/src/ProjectParameters/projectParameters.cpp index 4bf0fec..5060983 100644 --- a/src/ProjectParameters/projectParameters.cpp +++ b/src/ProjectParameters/projectParameters.cpp @@ -18,13 +18,27 @@ #include "../GraphCall/graph_calls.h" #include "../GraphCall/graph_calls_func.h" -#include "libSage++.h" #include "projectParameters.h" -#include "domTree.h" -using namespace std; +using std::set; +using std::map; +using std::string; +using std::vector; +using std::tuple; +using std::pair; +using std::make_tuple; +using std::find_if; -tuple stmtToIR(const map>& CFGraph, SgStatement* stmt) +static map> call_sites; + +enum class MODE +{ + BEFORE, + AFTER +}; + +static tuple +stmtToIR(const map>& CFGraph, SgStatement* stmt) { SgStatement* cur = stmt; cur->switchToFile(); @@ -49,7 +63,8 @@ tuple stmtToIR(const map IRByNumber(const map>& CFGraph, int num) +static tuple +IRByNumber(const map>& CFGraph, int num) { if (num < 0) return { NULL, NULL, NULL }; @@ -60,30 +75,27 @@ tuple IRByNumber(const map return make_tuple(func, getInstructionByNumber(byBB->getInstructions(), num), byBB); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); - return { NULL, NULL, NULL}; + return { NULL, NULL, NULL }; } template -void processArgument(set& worklist, - SAPFOR::Argument* arg, - Iterator instr, - Iterator first_instr) +static void processArgument(set& worklist, + SAPFOR::Argument* arg, + Iterator instr, Iterator first_instr) { if (arg == NULL) return; + if (arg->getType() == SAPFOR::CFG_ARG_TYPE::REG) extract_vars_from_reg(worklist, arg, instr, first_instr); else if (arg->getType() == SAPFOR::CFG_ARG_TYPE::VAR) - { worklist.insert(arg); - } } template -void extract_vars_from_reg(set& worklist, - SAPFOR::Argument* reg, - Iterator instr, - Iterator first_instr) +static void extract_vars_from_reg(set& worklist, + SAPFOR::Argument* reg, + Iterator instr, Iterator first_instr) { for (; instr >= first_instr; instr--) { @@ -96,21 +108,21 @@ void extract_vars_from_reg(set& worklist, } } -void lookup_for_vars(std::set>& where_to_add, - set& worklist, - SAPFOR::Instruction* instr, - SAPFOR::BasicBlock* bblock, - FuncInfo* cur_func, - const std::map>& fullIR) +static void lookup_for_vars(set>& where_to_add, + set& worklist, + SAPFOR::Instruction* instr, + SAPFOR::BasicBlock* bblock, + FuncInfo* cur_func, + const map>& fullIR) { while (bblock) { auto first_instr = bblock->getInstructions().begin(); - auto cur_instr = std::find_if(first_instr, bblock->getInstructions().end(), [instr](SAPFOR::IR_Block* i) { + auto cur_instr = find_if(first_instr, bblock->getInstructions().end(), [instr](SAPFOR::IR_Block* i) { return i->getInstruction() == instr; - }); + }); - for (; cur_instr >= bblock->getInstructions().begin(); cur_instr--) + for (; cur_instr >= bblock->getInstructions().begin(); --cur_instr) { auto instr = (*cur_instr)->getInstruction(); auto result_arg = instr->getResult(); @@ -123,6 +135,7 @@ void lookup_for_vars(std::set>& wher processArgument(worklist, arg2, cur_instr, first_instr); worklist.erase(result_arg); } + if (instr->getOperation() == SAPFOR::CFG_OP::PARAM && worklist.count(arg1)) { // skip to F_CALL @@ -136,7 +149,7 @@ void lookup_for_vars(std::set>& wher auto filename = stmt_before->fileName(); auto line = stmt_before->lineNumber(); auto var_name = arg1->getValue().substr(arg1->getValue().find('%') + 1); - __spf_print(1,"Please specify value of variable %s on line %d of file %s\n", arg1->getValue().c_str(), line, filename); + __spf_print(1, "Please specify value of variable %s on line %d of file %s\n", arg1->getValue().c_str(), line, filename); auto toAdd = make_tuple(stmt_before, var_name, MODE::AFTER); where_to_add.insert(toAdd); worklist.erase(arg1); @@ -159,7 +172,7 @@ void lookup_for_vars(std::set>& wher auto line = stmt_after->lineNumber(); auto var_name = arg->getValue().substr(arg->getValue().find('%') + 1); __spf_print(1, "variable %s has multiple reaching definitions, further analysis is impossible\n", arg->getValue().c_str()); - __spf_print(1,"Please specify value of variable %s on line %d of file %s\n", arg->getValue().c_str(), line, filename); + __spf_print(1, "Please specify value of variable %s on line %d of file %s\n", arg->getValue().c_str(), line, filename); auto toAdd = make_tuple(stmt_after, var_name, MODE::BEFORE); where_to_add.insert(toAdd); worklist.erase(arg); @@ -175,7 +188,8 @@ void lookup_for_vars(std::set>& wher } while (bblock && group_by_block.find(bblock) == group_by_block.end()) - bblock = bblock->getIdom(); + bblock = bblock->getDom(); + if (bblock) instr = group_by_block[bblock]; } @@ -189,6 +203,7 @@ void lookup_for_vars(std::set>& wher set found_rd; if (RD.count(arg)) found_rd = RD.at(arg); + if (found_rd.size() == 0) { auto call_instr = call_sites[cur_func].size() ? call_sites[cur_func].front() : NULL; @@ -202,10 +217,10 @@ void lookup_for_vars(std::set>& wher call_instr = call_sites[call_func].size() ? call_sites[call_func].front() : NULL; } } + if (found_rd.size() == 1 && *found_rd.begin() == SAPFOR::CFG_VAL::UNINIT) - { __spf_print(1, "variable %s has no definition\n", arg->getValue().c_str()); - } else if (found_rd.size() > 1) + else if (found_rd.size() > 1) { auto first_instr = fullIR.at(cur_func).front()->getInstructions().begin(); auto stmt_after = (*first_instr)->getInstruction()->getOperator(); @@ -213,7 +228,7 @@ void lookup_for_vars(std::set>& wher auto line = stmt_after->lineNumber(); auto var_name = arg->getValue().substr(arg->getValue().find('%') + 1); __spf_print(1, "variable %s has multiple reaching definitions, further analysis is impossible\n", arg->getValue().c_str()); - __spf_print(1,"Please specify value of variable %s on line %d of file %s\n", arg->getValue().c_str(), line, filename); + __spf_print(1, "Please specify value of variable %s on line %d of file %s\n", arg->getValue().c_str(), line, filename); auto toAdd = make_tuple(stmt_after, var_name, MODE::BEFORE); where_to_add.insert(toAdd); } @@ -221,7 +236,7 @@ void lookup_for_vars(std::set>& wher { auto instr_num = *found_rd.begin(); auto [func, instr, bblock] = IRByNumber(fullIR, instr_num); - set new_worklist = {arg}; + set new_worklist = { arg }; lookup_for_vars(where_to_add, new_worklist, instr, bblock, func, fullIR); } @@ -236,14 +251,15 @@ void lookup_for_vars(std::set>& wher auto [call_func, _, call_bblock] = IRByNumber(fullIR, call_instr->getNumber()); auto first_instr = call_bblock->getInstructions().begin(); - auto cur_instr = std::find_if(first_instr, call_bblock->getInstructions().end(), [call_instr](SAPFOR::IR_Block* i) { + auto cur_instr = find_if(first_instr, call_bblock->getInstructions().end(), [call_instr](SAPFOR::IR_Block* i) { return i->getInstruction() == call_instr; - }); + }); + for (auto& arg : worklist) { if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_) { - auto param_num= stoi(arg->getValue().substr(arg->getValue().find('%', arg->getValue().find('%') + 1) + 1)); + auto param_num = stoi(arg->getValue().substr(arg->getValue().find('%', arg->getValue().find('%') + 1) + 1)); auto param_instr = (cur_instr - (params_num - param_num)); auto param_arg = (*param_instr)->getInstruction()->getArg1(); processArgument(new_worklist, param_arg, param_instr, first_instr); @@ -254,24 +270,23 @@ void lookup_for_vars(std::set>& wher } -void handle_single_allocate(std::set>& where_to_add, - SgStatement* alloc_statement, - const std::map>& fullIR) +static void handle_single_allocate(set>& where_to_add, + SgStatement* alloc_statement, + const map>& fullIR) { auto [func, instr, bblock] = stmtToIR(fullIR, alloc_statement); auto first_instr = bblock->getInstructions().begin(); - auto cur_instr = std::find_if(first_instr, bblock->getInstructions().end(), [instr](SAPFOR::IR_Block* i) { + auto cur_instr = find_if(first_instr, bblock->getInstructions().end(), [instr](SAPFOR::IR_Block* i) { return i->getInstruction() == instr; - }); + }); auto alloc_instr = cur_instr; // skip to F_CALL _ALLOC n while ((*alloc_instr)->getInstruction()->getOperation() != SAPFOR::CFG_OP::F_CALL || - (*alloc_instr)->getInstruction()->getArg1()->getValue() != "_ALLOC") + (*alloc_instr)->getInstruction()->getArg1()->getValue() != "_ALLOC") alloc_instr++; - auto arrays_num = stoi((*alloc_instr)->getInstruction()->getArg2()->getValue()); set worklist; @@ -281,7 +296,7 @@ void handle_single_allocate(std::set>& wh auto param_reg = (*param_instr)->getInstruction()->getArg1(); while ((*param_instr)->getInstruction()->getOperation() != SAPFOR::CFG_OP::LOAD || - (*param_instr)->getInstruction()->getResult() != param_reg) + (*param_instr)->getInstruction()->getResult() != param_reg) param_instr--; @@ -292,29 +307,29 @@ void handle_single_allocate(std::set>& wh auto ref_instr = --param_instr; if ((*ref_instr)->getInstruction()->getOperation() == SAPFOR::CFG_OP::RANGE) { - vector range_args = {(*ref_instr)->getInstruction()->getArg1(), + vector range_args = { (*ref_instr)->getInstruction()->getArg1(), (*ref_instr)->getInstruction()->getArg2(), - (*ref_instr)->getInstruction()->getResult()}; + (*ref_instr)->getInstruction()->getResult() }; for (auto& arg : range_args) processArgument(worklist, arg, ref_instr, first_instr); - } else + } + else { auto arg = (*ref_instr)->getInstruction()->getArg1(); processArgument(worklist, arg, ref_instr, first_instr); } } } - lookup_for_vars(where_to_add,worklist, instr, bblock, func, fullIR); + lookup_for_vars(where_to_add, worklist, instr, bblock, func, fullIR); } -void handle_single_loop(std::set>& where_to_add, - SgStatement* loop_stmt, - const std::map>& fullIR) +static void handle_single_loop(set>& where_to_add, + SgStatement* loop_stmt, + const map>& fullIR) { auto [func, instr, bblock] = stmtToIR(fullIR, loop_stmt); - auto cur_instr = bblock->getInstructions().end() - 1; set worklist; @@ -323,10 +338,9 @@ void handle_single_loop(std::set>& where_ lookup_for_vars(where_to_add, worklist, (*cur_instr)->getInstruction(), bblock, func, fullIR); } -void -findParameters(ResultSet& foundParameters, - std::map>& fullIR, - const std::map, std::pair>& declaredArrays) +void findParameters(ResultSet& foundParameters, + map>& fullIR, + const map, pair>& declaredArrays) { set> where_to_add; @@ -337,6 +351,7 @@ findParameters(ResultSet& foundParameters, for (auto& [func, bblocks] : fullIR) { for (const auto& block : bblocks) + { for (const auto& ir_block : block->getInstructions()) { auto instr = ir_block->getInstruction(); @@ -349,32 +364,37 @@ findParameters(ResultSet& foundParameters, call_sites[func_info->second].push_back(instr); } } - - - SAPFOR::buildDominatorTreeLT(bblocks); + } } - std::set alloc_statements; + set alloc_statements; for (const auto& [func, bblocks] : fullIR) + { for (const auto& block : bblocks) + { for (auto instr = block->getInstructions().begin(); instr != block->getInstructions().end(); ++instr) { auto op = (*instr)->getInstruction()->getOperator(); - if (op && op->variant() == ALLOCATE_STMT) { + if (op && op->variant() == ALLOCATE_STMT) alloc_statements.insert(op); - } } + } + } set for_statements; // Find all FOR statements in the program for (const auto& [func, bblocks] : fullIR) + { for (const auto& block : bblocks) + { for (auto instr = block->getInstructions().begin(); instr != block->getInstructions().end(); ++instr) { auto op = (*instr)->getInstruction()->getOperator(); if (op && op->variant() == FOR_NODE) for_statements.insert(op); } + } + } for (const auto& alloc_statement : alloc_statements) handle_single_allocate(where_to_add, alloc_statement, fullIR); diff --git a/src/ProjectParameters/projectParameters.h b/src/ProjectParameters/projectParameters.h index 1181560..83a69e3 100644 --- a/src/ProjectParameters/projectParameters.h +++ b/src/ProjectParameters/projectParameters.h @@ -1,42 +1,14 @@ #pragma once -#include "libSage++.h" #include #include #include #include +#include "..\GraphCall\graph_calls.h" + using ResultSet = std::set>; -enum class MODE -{ - BEFORE, - AFTER -}; - -static std::map> call_sites; - -template -void extract_vars_from_reg(std::set& worklist, - SAPFOR::Argument* reg, - Iterator instr, - Iterator first_instr); - - -template -void processArgument(std::set& worklist, - SAPFOR::Argument* arg, - Iterator instr, - Iterator first_instr); - -void lookup_for_vars(std::set>& where_to_add, - std::set& worklist, - SAPFOR::Instruction* instr, - SAPFOR::BasicBlock* bblock, - FuncInfo* cur_func, - const std::map>& fullIR); - -void -findParameters(ResultSet& foundParameters, - std::map>& fullIR, - const std::map, std::pair>& declaredArrays); +void findParameters(ResultSet& foundParameters, + std::map>& fullIR, + const std::map, std::pair>& declaredArrays); diff --git a/src/Sapfor.cpp b/src/Sapfor.cpp index 2bee6a5..e604e39 100644 --- a/src/Sapfor.cpp +++ b/src/Sapfor.cpp @@ -1894,9 +1894,7 @@ static bool runAnalysis(SgProject &project, const int curr_regime, const bool ne else if (curr_regime == RENAME_SYMBOLS) runRenameSymbols(&project, commonBlocks); else if (curr_regime == FIND_PARAMETERS) - { findParameters(parametersOfProject, fullIR, declaredArrays); - } else if (curr_regime == BUILD_IR) { auto CFG_forFile = buildCFG(commonBlocks, allFuncInfo_IR, SAPFOR::CFG_Settings(0)); diff --git a/src/Utils/CommonBlock.h b/src/Utils/CommonBlock.h index 196f3b9..7b89792 100644 --- a/src/Utils/CommonBlock.h +++ b/src/Utils/CommonBlock.h @@ -1,5 +1,7 @@ #pragma once +#include "../Distribution/Array.h" + enum varType { SCALAR, ARRAY, CONST, ANOTHER }; struct CommonVariableUse diff --git a/src/Utils/version.h b/src/Utils/version.h index 43758a9..6f49767 100644 --- a/src/Utils/version.h +++ b/src/Utils/version.h @@ -1,3 +1,3 @@ #pragma once -#define VERSION_SPF "2422" +#define VERSION_SPF "2423"