diff --git a/sapfor/experts/Sapfor_2017/CMakeLists.txt b/sapfor/experts/Sapfor_2017/CMakeLists.txt index fd246f3..be43305 100644 --- a/sapfor/experts/Sapfor_2017/CMakeLists.txt +++ b/sapfor/experts/Sapfor_2017/CMakeLists.txt @@ -160,7 +160,9 @@ set(PARALLEL_REG _src/ParallelizationRegions/ParRegions.cpp _src/ParallelizationRegions/expand_extract_reg.h _src/ParallelizationRegions/resolve_par_reg_conflicts.cpp _src/ParallelizationRegions/resolve_par_reg_conflicts.h) - + +set(TR_DEAD_CODE _src/Transformations/dead_code.cpp + _src/Transformations/dead_code.h) set(TR_CP _src/Transformations/checkpoints.cpp _src/Transformations/checkpoints.h) set(TR_VECTOR _src/Transformations/array_assign_to_loop.cpp @@ -191,6 +193,7 @@ set(TR_CONV _src/Transformations/convert_to_c.cpp _src/Transformations/convert_to_c.h) set(TRANSFORMS + ${TR_DEAD_CODE} ${TR_CP} ${TR_VECTOR} ${TR_ENDDO_LOOP} @@ -218,6 +221,13 @@ set(CFG _src/CFGraph/IR.cpp _src/CFGraph/private_variables_analysis.h ) +set(DATA_FLOW + _src/CFGraph/DataFlow/data_flow.h + _src/CFGraph/DataFlow/data_flow_impl.h + _src/CFGraph/DataFlow/backward_data_flow.h + _src/CFGraph/DataFlow/backward_data_flow_impl.h + ) + set(CREATE_INTER_T _src/CreateInterTree/CreateInterTree.cpp _src/CreateInterTree/CreateInterTree.h) @@ -377,6 +387,7 @@ set(ZLIB ${zlib_sources}/src/adler32.c set(SOURCE_EXE ${CFG} + ${DATA_FLOW} ${CREATE_INTER_T} ${DIRA} ${DISTR} @@ -406,7 +417,9 @@ set(SOURCE_EXE add_executable(Sapfor_F ${SOURCE_EXE}) source_group (CFGraph FILES ${CFG}) +source_group (CFGraph\\DataFlow FILES ${DATA_FLOW}) +source_group (Transformations\\DeadCodeRemoving FILES ${TR_DEAD_CODE}) source_group (Transformations\\ExpressionSubstitution FILES ${EXPR_TRANSFORM}) source_group (Transformations\\CheckPoints FILES ${TR_CP}) source_group (Transformations\\LoopEndDoConverter FILES ${TR_ENDDO_LOOP}) diff --git a/sapfor/experts/Sapfor_2017/_src/CFGraph/CFGraph.h b/sapfor/experts/Sapfor_2017/_src/CFGraph/CFGraph.h index 99b98dd..e47447c 100644 --- a/sapfor/experts/Sapfor_2017/_src/CFGraph/CFGraph.h +++ b/sapfor/experts/Sapfor_2017/_src/CFGraph/CFGraph.h @@ -31,8 +31,9 @@ namespace SAPFOR //live variables [arg -> blocks with usages] std::map> live_in, live_out, live_inout; - bool addLive(const std::map>& to_add, bool in); - std::map> getLive(bool in) const; + 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); @@ -69,11 +70,14 @@ namespace SAPFOR /* * FOR LIVE ANALYSIS */ - bool addLiveIn(const std::map>& to_add) { return addLive(to_add, true); }; - bool addLiveOut(const std::map>& to_add) { return addLive(to_add, false); }; + bool addLiveIn(const std::map>& to_add) { return addLive(to_add, true); }; + bool addLiveOut(const std::map>& to_add) { return addLive(to_add, false); }; + + bool removeLiveIn(SAPFOR::Argument* to_remove) { return removeLive(to_remove, true); }; + bool removeLiveOut(SAPFOR::Argument* to_remove) { return removeLive(to_remove, false); }; - std::map> getLiveIn() const { return getLive(true); }; - std::map> getLiveOut() const { return getLive(false); }; + std::map> getLiveIn() const { return getLive(true); }; + std::map> getLiveOut() const { return getLive(false); }; void compressLives(); /* diff --git a/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/backward_data_flow.h b/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/backward_data_flow.h new file mode 100644 index 0000000..58009c9 --- /dev/null +++ b/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/backward_data_flow.h @@ -0,0 +1,20 @@ +#pragma once +#include "data_flow.h" + +#include +#include +#include + +#include "../../Utils/SgUtils.h" +#include "../CFGraph.h" +#include "../IR.h" + +template +class BackwardDataFlowAnalysis : public DataFlowAnalysis { + std::vector reorderSequence(const std::vector& blocks, + const std::set back_edge_sources); +public: + void fit(const std::vector& blocks); +}; + +#include "backward_data_flow_impl.h" \ No newline at end of file diff --git a/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/backward_data_flow_impl.h b/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/backward_data_flow_impl.h new file mode 100644 index 0000000..d1d4486 --- /dev/null +++ b/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/backward_data_flow_impl.h @@ -0,0 +1,103 @@ +#pragma once +#include "backward_data_flow.h" + +#include +#include +#include + +#include "../../Utils/SgUtils.h" +#include "../CFGraph.h" +#include "../IR.h" +#include "../RD_subst.h" + +/* Note: this file should be included in backward_data_flow.h to provide template definitions */ + +// minimizes the number of blocks beween the ends of back edges +template +std::vector +BackwardDataFlowAnalysis::reorderSequence(const std::vector& blocks, + const std::set back_edge_sources) +{ + std::vector res = { }; + + auto blocks_end = blocks.rend(); + for (auto it = blocks.rbegin(); it < blocks_end; it++) + { + SAPFOR::BasicBlock* curr = *it; + auto res_end = res.end(); + auto inserter = res.begin(); + if (back_edge_sources.count(curr) == 0) + { + auto curr_next_begin = curr->getNext().begin(); + auto curr_next_end = curr->getNext().end(); + while (inserter < res_end && std::find(curr_next_begin, curr_next_end, *inserter) == curr_next_end) + inserter++; + } + + res.insert(inserter, curr); + } + + return res; +} + +template +void BackwardDataFlowAnalysis::fit(const std::vector& blocks) +{ + std::set> back_edges = {}; + + bool returned = false; + std::map> back_edges_by_src; + + auto blocks_sorted = sortCfgNodes(blocks, &back_edges); + + std::set back_edge_sources; + + for (auto& edge : back_edges) + { + back_edges_by_src[edge.first].insert(edge.second); + back_edge_sources.insert(edge.first); + } + + back_edges.clear(); + + blocks_sorted = reorderSequence(blocks_sorted, back_edge_sources); + back_edge_sources.clear(); + + std::reverse(blocks_sorted.begin(), blocks_sorted.end()); + + nodes.clear(); + std::map node_by_block; + + for (auto block : blocks_sorted) + { + NodeType* node = createNode(block); + nodes.push_back(node); + node_by_block[block] = node; + } + + int nodes_size = nodes.size(); + + for (int i = 0; i < nodes_size; i++) + { + NodeType* node = nodes[i]; + + auto back_edges_by_src_it = back_edges_by_src.find(node->getBlock()); + if (back_edges_by_src_it != back_edges_by_src.end()) + { + // This node is a source for back edge + for (auto dest : back_edges_by_src_it->second) + { + auto node_by_block_it = node_by_block.find(dest); + if (node_by_block_it != node_by_block.end()) + node_by_block_it->second->getRollback().insert(i); + } + } + + for (auto next : node->getBlock()->getNext()) + { + auto node_by_block_it = node_by_block.find(next); + if (node_by_block_it != node_by_block.end()) + node->getPrevBlocks().insert(node_by_block_it->second); + } + } +} \ No newline at end of file diff --git a/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/data_flow.h b/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/data_flow.h new file mode 100644 index 0000000..11493a0 --- /dev/null +++ b/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/data_flow.h @@ -0,0 +1,67 @@ +#pragma once +#include +#include + +#include "../../Utils/SgUtils.h" +#include "../CFGraph.h" +#include "../IR.h" + +template +class DataFlowAnalysisNode { + static const int CNT_NOTINIT = 0; + + int in_cnt = CNT_NOTINIT, out_cnt = CNT_NOTINIT; + + std::set rollback; + std::set ignore_rollback; + + std::set*> prev_blocks; + + SAPFOR::BasicBlock* bb; +public: + DataFlowAnalysisNode(); + + void doStep(); + + virtual DataType getIn() = 0; + virtual DataType getOut() = 0; + + virtual bool addIn(const DataType& data) = 0; + virtual bool addOut(const DataType& data) = 0; + + virtual bool forwardData(const DataType& data) = 0; + + bool newerThan(const DataFlowAnalysisNode* block) const { return out_cnt > block->in_cnt; } + + int getInCnt() { return in_cnt; } + int getOutCnt() { return out_cnt; } + + void setInCnt(int cnt) { in_cnt = cnt; } + void setOutCnt(int cnt) { out_cnt = cnt; } + static int getStartCounter() { return CNT_NOTINIT; } + + std::set& getRollback() { return rollback; } + std::set& getIgnoreRollback() { return ignore_rollback; } + + std::set*>& getPrevBlocks() { return prev_blocks; } + + SAPFOR::BasicBlock* getBlock() { return bb; } + void setBlock(SAPFOR::BasicBlock* b) { bb = b; } +}; + +template +class DataFlowAnalysis { +protected: + std::vector nodes; + + virtual NodeType* createNode(SAPFOR::BasicBlock* block) = 0; +public: + virtual void fit(const std::vector& blocks) = 0; + void analyze(); + + const std::vector& getNodes() { return nodes; } + + ~DataFlowAnalysis(); +}; + +#include "data_flow_impl.h" \ No newline at end of file diff --git a/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/data_flow_impl.h b/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/data_flow_impl.h new file mode 100644 index 0000000..da5a5fb --- /dev/null +++ b/sapfor/experts/Sapfor_2017/_src/CFGraph/DataFlow/data_flow_impl.h @@ -0,0 +1,113 @@ +#pragma once +#include "data_flow.h" + +#include +#include + +#include "../../Utils/SgUtils.h" +#include "../CFGraph.h" +#include "../IR.h" + +/* Note: this file should be included in data_flow.h to provide template definitions */ + +/* definitions for DataFlowAnalysisNode class */ + +template +const int DataFlowAnalysisNode::CNT_NOTINIT; + +template +DataFlowAnalysisNode::DataFlowAnalysisNode() +{ + getRollback() = {}; + getIgnoreRollback() = {}; + prev_blocks = {}; +} + +template +void DataFlowAnalysisNode::doStep() +{ + int in_max_cnt = CNT_NOTINIT, out_max_cnt = CNT_NOTINIT; + for (auto next : prev_blocks) + { + if (in_cnt < next->out_cnt) + { + for (const auto& byOut : next->getOut()) + { + bool inserted = addIn({ byOut }); + + if (inserted) + { + if (next->out_cnt > in_max_cnt) + in_max_cnt = next->out_cnt; + + inserted = forwardData({ byOut }); + + if (inserted && next->out_cnt > out_max_cnt) + out_max_cnt = next->out_cnt; + } + } + } + } + + bool was_notinit = (out_cnt == CNT_NOTINIT); + + if (out_max_cnt != CNT_NOTINIT) + out_cnt = out_max_cnt; + + if (in_max_cnt != CNT_NOTINIT) + in_cnt = in_max_cnt; + + // TODO: fix counter overflow + if (was_notinit) + { + out_cnt++; + in_cnt++; + } +} + +/* definitions for DataFlowAnalysis class */ + +template +void DataFlowAnalysis::analyze() { + auto curr = 0; + auto stop = nodes.size(); + + while (curr != stop) + { + auto curr_bb = nodes[curr]; + curr_bb->doStep(); + + const auto& jumps = curr_bb->getRollback(); + if (jumps.size() != 0) + { + auto& ignored_jumps = curr_bb->getIgnoreRollback(); + + bool jump = false; + for (const auto& jump_to : jumps) + { + if (ignored_jumps.insert(jump_to).second && curr_bb->newerThan(nodes[jump_to])) + { + jump = true; + curr = jump_to; + break; + } + } + + if (!jump) + curr_bb->getIgnoreRollback().clear(); + else + continue; + } + + curr++; + } +} + +template +DataFlowAnalysis::~DataFlowAnalysis() +{ + for (DataFlowAnalysisNode* node : nodes) + delete node; + + nodes.clear(); +} \ No newline at end of file diff --git a/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.cpp b/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.cpp index 4b40ff9..48bdff8 100644 --- a/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.cpp +++ b/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.cpp @@ -1,5 +1,6 @@ #include "live_variable_analysis.h" #include "RD_subst.h" +#include "DataFlow/backward_data_flow.h" #include #include @@ -16,18 +17,20 @@ using std::set; using std::unordered_map; using std::list; +using LIVE_VARIABLES::LiveDeadVarsForCall; + namespace SAPFOR { - bool BasicBlock::addLive(const map>& to_add, bool in) { + bool BasicBlock::addLive(const map>& to_add, bool in) { std::map>& current_set = (in ? live_in : live_out); std::map>& opposite_set = (!in ? live_in : live_out); bool inserted = false; for (const auto& byNew : to_add) { - const set& add_in_live = byNew.second; - set new_in_live = {}; - + const vector& add_in_live = byNew.second; + vector new_in_live = {}; + auto current_set_iter = current_set.find(byNew.first); if (current_set_iter == current_set.end()) @@ -94,18 +97,54 @@ namespace SAPFOR return inserted; }; - map> BasicBlock::getLive(bool in) const { + bool BasicBlock::removeLive(SAPFOR::Argument* to_remove, bool in) + { + std::map>& current_set = (in ? live_in : live_out); + std::map>& opposite_set = (!in ? live_in : live_out); + + bool removed = false; + + removed |= (current_set.erase(to_remove) != 0); + + if (!removed) + { + auto it = live_inout.find(to_remove); + + if (it != live_inout.end()) + { + auto& dest = opposite_set[to_remove]; + for (SAPFOR::BasicBlock* bb : it->second) + { + auto find_bb_from_dest = std::lower_bound(dest.begin(), dest.end(), bb); + + if (find_bb_from_dest == dest.end() || *find_bb_from_dest != bb) + dest.insert(find_bb_from_dest, bb); + } + + removed = true; + } + } + + return removed; + }; + + map> BasicBlock::getLive(bool in) const { auto& current_set = in ? live_in : live_out; - map> res; + map> res; for (auto& by_source : { current_set, live_inout }) + { for (auto& by_pair : by_source) - res[by_pair.first].insert(by_pair.second.begin(), by_pair.second.end()); + { + auto& dest = res[by_pair.first]; + dest.insert(dest.end(), by_pair.second.begin(), by_pair.second.end()); + } + } return res; } - + void BasicBlock::compressLives() { for (auto& bySrc : { &live_in, &live_out, &live_inout }) for (auto& byArg : *bySrc) @@ -113,403 +152,285 @@ namespace SAPFOR } } -struct fcall +bool LiveDeadVarsForCall::tryInsert(set& dest, SAPFOR::BasicBlock* b) { -private: - bool tryInsert(set& dest, SAPFOR::BasicBlock* b) + if (b == block || dest.find(block) == dest.end()) { - if (b == block || dest.find(block) == dest.end()) - { - dest.insert(b); - return true; - } - - return false; + dest.insert(b); + return true; } -public: - FuncInfo* func; - - map> live_after; - set dead_after; + return false; +} - map> commons_live_after; - set commons_dead_after; +LiveDeadVarsForCall::LiveDeadVarsForCall(FuncInfo* f, SAPFOR::BasicBlock* b, const vector& p) +{ + block = b; + func = f; - vector params; - SAPFOR::BasicBlock* block; + int param_size = p.size(); + params = vector(param_size, NULL); - fcall(FuncInfo* f, SAPFOR::BasicBlock* b, const vector& p) - { - block = b; - func = f; - - int param_size = p.size(); - params = vector(param_size, NULL); + for (int i = 0; i < param_size; i++) + if (f->funcParams.isArgOut(i)) + params[i] = p[i]; +} - for (int i = 0; i < param_size; i++) - if (f->funcParams.isArgOut(i)) - params[i] = p[i]; +void LiveDeadVarsForCall::make_live(SAPFOR::Argument* arg, SAPFOR::BasicBlock* b) +{ + if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::COMMON_ || arg->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_) + { + if (commons_dead_after.find(arg) == commons_dead_after.end()) + tryInsert(commons_live_after[arg], b); } - void make_live(SAPFOR::Argument* arg, SAPFOR::BasicBlock* b) + auto it = find(params.begin(), params.end(), arg); + if (it != params.end()) { - if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::COMMON_ || arg->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_) - { - if (commons_dead_after.find(arg) == commons_dead_after.end()) - tryInsert(commons_live_after[arg], b); - } - - auto it = find(params.begin(), params.end(), arg); - if (it != params.end()) - { - int idx = it - params.begin(); - if (dead_after.find(idx) == dead_after.end()) - tryInsert(live_after[idx], b); - } + int idx = it - params.begin(); + if (dead_after.find(idx) == dead_after.end()) + tryInsert(live_after[idx], b); } +} - void make_dead(SAPFOR::Argument* arg) +void LiveDeadVarsForCall::make_dead(SAPFOR::Argument* arg) +{ + if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::COMMON_ || arg->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_) { - if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::COMMON_ || arg->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_) + if (commons_live_after.find(arg) == commons_live_after.end()) commons_dead_after.insert(arg); - - auto it = find(params.begin(), params.end(), arg); - if (it != params.end()) - { - int idx = it - params.begin(); - dead_after.insert(idx); - } } - void updateFromOut() + auto it = find(params.begin(), params.end(), arg); + if (it != params.end()) { - for (const auto& p : block->getLiveOut()) - for (auto b : p.second) - make_live(p.first, b); + int idx = it - params.begin(); + if (live_after.find(idx) == live_after.end()) + dead_after.insert(idx); } -}; +} + +void LiveDeadVarsForCall::updateFromOut() +{ + for (const auto& p : block->getLiveOut()) + for (auto b : p.second) + make_live(p.first, b); +} static bool getLiveDead(const vector& params, const string& func_name, set& live, set& dead); static void buildUseDef(SAPFOR::BasicBlock* block, set& use, set& def, - vector& formal_parameters, vector& fcalls, - const map& funcByName); + vector& formal_parameters, vector& fcalls, + const map& funcByName, bool interprocedural); -enum -{ - CNT_NOTINIT = 0 -}; - -struct BasicBlockNode -{ - SAPFOR::BasicBlock* bb; +class LiveVarAnalysisNode : public DataFlowAnalysisNode>> { +private: set live, dead; - int in_cnt, out_cnt; - set next_blocks; - - set::reverse_iterator> rollback; - set::reverse_iterator> ignore_rollback; - - BasicBlockNode(SAPFOR::BasicBlock* block, vector& formal_parameters, - vector& fcalls, const map& funcByName) +public: + map> getIn() { - bb = block; - out_cnt = in_cnt = CNT_NOTINIT; + return getBlock()->getLiveOut(); + }; + + map> getOut() + { + return getBlock()->getLiveIn(); + }; + + bool addIn(const map>& data) + { + return getBlock()->addLiveOut(data); + }; + + bool addOut(const map>& data) + { + return getBlock()->addLiveIn(data); + }; + + bool forwardData(const map>& data) + { + bool inserted = false; + + for (const auto& byArg : data) + if (live.find(byArg.first) == live.end() && dead.find(byArg.first) == dead.end()) + inserted |= getBlock()->addLiveIn({ byArg }); + + return inserted; + }; + + LiveVarAnalysisNode(SAPFOR::BasicBlock* block, vector& formal_parameters, + vector& fcalls, const map& funcByName) + { + setBlock(block); + + buildUseDef(getBlock(), live, dead, formal_parameters, fcalls, funcByName, true); - buildUseDef(bb, live, dead, formal_parameters, fcalls, funcByName); for (SAPFOR::Argument* arg : live) - bb->addLiveIn({ { arg, { bb } } }); - - rollback = {}; - ignore_rollback = {}; - next_blocks = {}; + getBlock()->addLiveIn({ { arg, { getBlock() } } }); } - - void updateLive() - { - bool in_changed = false, out_changed = false; - int in_max_cnt = CNT_NOTINIT, out_max_cnt = CNT_NOTINIT; - for (auto next : next_blocks) - { - if (out_cnt < next->in_cnt) - { - for (const auto& byArg : next->bb->getLiveIn()) - { - bool inserted = bb->addLiveOut({ byArg }); - out_changed |= inserted; - - if (inserted) - { - if (next->in_cnt > out_max_cnt) - out_max_cnt = next->in_cnt; - - if (live.find(byArg.first) == live.end() && dead.find(byArg.first) == dead.end()) - { - inserted = bb->addLiveIn({ byArg }); - if (inserted && next->in_cnt > in_max_cnt) - { - in_max_cnt = next->in_cnt; - in_changed = true; - } - } - } - } - } - } - - bool was_notinit = (in_cnt == CNT_NOTINIT); - - if (in_max_cnt != CNT_NOTINIT) - in_cnt = in_max_cnt; - - if (out_max_cnt != CNT_NOTINIT) - out_cnt = out_max_cnt; - - // TODO: fix counter overflow - if (was_notinit) - { - out_cnt++; - in_cnt++; - } - } - - bool newerThan(const BasicBlockNode* block) const { return in_cnt > block->out_cnt; } }; +class LiveVarAnalysis : public BackwardDataFlowAnalysis>, LiveVarAnalysisNode> { +protected: + vector& formal_parameters; + vector& fcalls; + const map& funcByName; + + LiveVarAnalysisNode* createNode(SAPFOR::BasicBlock* block) override { + return new LiveVarAnalysisNode(block, formal_parameters, fcalls, funcByName); + }; +public: + LiveVarAnalysis(vector& formal_parameters, vector& fcalls, + const map& funcByName) : formal_parameters(formal_parameters), fcalls(fcalls), funcByName(funcByName) + { }; +}; + +void getUseDefForInstruction(SAPFOR::BasicBlock* block, SAPFOR::Instruction* instr, + set& use, set& def, + vector& formal_parameters, vector& fcalls, + vector& lastParamRef, int& last_param_ref_index, int& last_param_ref_size, + string& fName, const map& funcByName, bool interprocedural) +{ + for (auto arg : { instr->getArg1(), instr->getArg2(), instr->getResult() }) + if (arg && arg->getMemType() == SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_) + formal_parameters[getParamIndex(arg, formal_parameters.size())] = arg; + + SAPFOR::Argument* res_arg = NULL; + + static const set skip = { SAPFOR::CFG_OP::ENTRY }; + SAPFOR::CFG_OP instr_operation = instr->getOperation(); + if (hasStoreStructure(instr_operation)) + { + res_arg = instr->getArg1(); + set instr_args = { instr->getResult(), instr->getArg2() }; + use.insert(instr_args.begin(), instr_args.end()); + } + else if (instr_operation == SAPFOR::CFG_OP::PARAM) + { + lastParamRef[last_param_ref_index--] = instr->getArg1(); + } + else if (instr_operation == SAPFOR::CFG_OP::F_CALL) + { + res_arg = instr->getResult(); + + last_param_ref_size = stoi(instr->getArg2()->getValue()); + + lastParamRef.clear(); + lastParamRef.resize(last_param_ref_size); + + last_param_ref_index = last_param_ref_size - 1; + + fName = instr->getArg1()->getValue(); + } + else if (skip.find(instr_operation) == skip.end()) + { + //default + res_arg = instr->getResult(); + std::set intr_args = { instr->getArg1(), instr->getArg2() }; + use.insert(intr_args.begin(), intr_args.end()); + } + else + { + //skip + return; + } + + if ((instr_operation == SAPFOR::CFG_OP::F_CALL || instr_operation == SAPFOR::CFG_OP::PARAM) && last_param_ref_index < 0) { + auto func_it = funcByName.find(fName); + if (func_it != funcByName.end()) + { + fcalls.push_back(LiveDeadVarsForCall(func_it->second, block, lastParamRef)); + + auto r_it = fcalls.rbegin(); + auto r_end = fcalls.rend(); + + for (auto e : def) + r_it->make_dead(e); + + for (auto e : use) + r_it->make_live(e, block); + } + + set make_live, make_dead; + if (fName == "_READ") + def.insert(lastParamRef.begin(), lastParamRef.end()); + else if (interprocedural && getLiveDead(lastParamRef, fName, make_live, make_dead)) + { + use.insert(make_live.begin(), make_live.end()); + def.insert(make_dead.begin(), make_dead.end()); + } + else + use.insert(lastParamRef.begin(), lastParamRef.end()); + + last_param_ref_index = 0; + last_param_ref_size = 0; + + lastParamRef.clear(); + fName = ""; + } + + if (res_arg) + def.insert(res_arg); +} + +static void updateUseDefForInstruction(SAPFOR::BasicBlock* block, SAPFOR::Instruction* instr, + set& use, set& def, + vector& formal_parameters, vector& fcalls, + vector& lastParamRef, int& last_param_ref_index, int& last_param_ref_size, + string& fName, const map& funcByName, bool interprocedural) +{ + set res, args; + + getUseDefForInstruction(block, instr, + args, res, + formal_parameters, fcalls, + lastParamRef, last_param_ref_index, last_param_ref_size, + fName, funcByName, + interprocedural + ); + + for (auto e : res) + { + if (e && e->getType() == SAPFOR::CFG_ARG_TYPE::VAR) + { + def.insert(e); + use.erase(e); + } + } + + for (auto e : args) + { + if (e && e->getType() == SAPFOR::CFG_ARG_TYPE::VAR) + { + use.insert(e); + def.erase(e); + } + } +} + //Build use and def sets of block. Result are stored in use and def static void buildUseDef(SAPFOR::BasicBlock* block, set& use, set& def, - vector& formal_parameters, vector& fcalls, - const map& funcByName) + vector& formal_parameters, vector& fcalls, + const map& funcByName, bool interprocedural) { - set tmp_use, tmp_def; - vector lastParamRef; - bool fcall_added; + int last_param_ref_index = 0, last_param_ref_size = 0; + string fName; - for (auto ir_block : block->getInstructions()) + const auto& instructions = block->getInstructions(); + auto ir_block_it = instructions.rbegin(), ir_block_end = instructions.rend(); + + for (; ir_block_it != ir_block_end; ir_block_it++) { - fcall_added = false; - SAPFOR::Instruction* instr = ir_block->getInstruction(); - for (auto arg : { instr->getArg1(), instr->getArg2(), instr->getResult() }) - if (arg && arg->getMemType() == SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_) - formal_parameters[getParamIndex(arg, formal_parameters.size())] = arg; - - set res = {}, args = {}; - SAPFOR::Argument* res_arg = NULL; - - static const set skip = { SAPFOR::CFG_OP::ENTRY }; - SAPFOR::CFG_OP instr_operation = instr->getOperation(); - if (hasStoreStructure(instr_operation)) { - res_arg = instr->getArg1(); - std::set instr_args = { instr->getResult(), instr->getArg2()}; - insertIfVar(instr_args.begin(), instr_args.end(), args); - } - else if (instr_operation == SAPFOR::CFG_OP::PARAM) - lastParamRef.push_back(instr->getArg1()); - else if (instr_operation == SAPFOR::CFG_OP::F_CALL) - { - res_arg = instr->getResult(); - - int count = stoi(instr->getArg2()->getValue()); - if (lastParamRef.size() != count) - printInternalError(convertFileName(__FILE__).c_str(), __LINE__); - - const string& fName = instr->getArg1()->getValue(); - auto func_it = funcByName.find(fName); - if (func_it != funcByName.end()) - { - fcalls.push_back(fcall(func_it->second, block, lastParamRef)); - fcall_added = true; - } - - set make_live, make_dead; - if (fName == "_READ") - res.insert(lastParamRef.begin(), lastParamRef.end()); - else if (getLiveDead(lastParamRef, fName, make_live, make_dead)) - { - insertIfVar(make_live.begin(), make_live.end(), args); - insertIfVar(make_dead.begin(), make_dead.end(), res); - } - else - insertIfVar(lastParamRef.begin(), lastParamRef.end(), args); - - lastParamRef.clear(); - } - else if(skip.find(instr_operation) == skip.end()) - { - //default - res_arg = instr->getResult(); - std::set intr_args = { instr->getArg1(), instr->getArg2() }; - insertIfVar(intr_args.begin(), intr_args.end(), args); - } - else { - //skip - continue; - } - - if (res_arg && res_arg->getType() == SAPFOR::CFG_ARG_TYPE::VAR) - res.insert(res_arg); - - for (auto e : args) - if (!tmp_def.count(e)) - tmp_use.insert(e); - - for(auto e : res) - if (!tmp_use.count(e)) - tmp_def.insert(e); - - auto r_it = fcalls.rbegin(); - auto r_end = fcalls.rend(); - if (fcall_added && r_it != r_end) - r_it++; - - while (r_it != r_end && r_it->block == block) - { - for (auto e : args) - r_it->make_live(e, block); - - for (auto e : res) - r_it->make_dead(e); - - r_it++; - } + updateUseDefForInstruction(block, (*ir_block_it)->getInstruction(), + use, def, + formal_parameters, fcalls, + lastParamRef, last_param_ref_index, last_param_ref_size, + fName, funcByName, + interprocedural + ); } - - use = tmp_use; - def = tmp_def; -} - -// minimizes the number of blocks beween the ends of back edges -static vector reorderSequence(const vector& blocks, - const set back_edge_sources) -{ - vector res = { }; - - auto blocks_end = blocks.rend(); - for (auto it = blocks.rbegin(); it < blocks_end; it++) - { - SAPFOR::BasicBlock* curr = *it; - auto res_end = res.end(); - auto inserter = res.begin(); - if (back_edge_sources.count(curr) == 0) - { - auto curr_next_begin = curr->getNext().begin(); - auto curr_next_end = curr->getNext().end(); - while (inserter < res_end && std::find(curr_next_begin, curr_next_end, *inserter) == curr_next_end) - inserter++; - } - - res.insert(inserter, curr); - } - - return res; -} - -// finds back edges, reorders and converts blocks into vector of BasicBlockNode* -// fills vector of formal parameters for given function -// fills info about arguments which becomes live after calls of functions -static vector toBlocksWithCnt(const vector& blocks, - vector& formal_parameters, - vector& fcalls, const map& funcByName) -{ - set> back_edges = {}; - - bool returned = false; - map> back_edges_by_src; - - auto blocks_sorted = sortCfgNodes(blocks, &back_edges); - - set back_edge_sources; - - for (auto& edge : back_edges) - { - back_edges_by_src[edge.first].insert(edge.second); - back_edge_sources.insert(edge.first); - } - - back_edges.clear(); - - blocks_sorted = reorderSequence(blocks_sorted, back_edge_sources); - back_edge_sources.clear(); - - vector blocks_with_counters; - map node_by_block; - for (auto block : blocks_sorted) - { - BasicBlockNode* node = new BasicBlockNode(block, formal_parameters, fcalls, funcByName); - blocks_with_counters.push_back(node); - node_by_block[block] = node; - } - - for (auto r_it = blocks_with_counters.rbegin(); r_it != blocks_with_counters.rend(); r_it++) - { - auto back_edges_by_src_it = back_edges_by_src.find((*r_it)->bb); - if (back_edges_by_src_it != back_edges_by_src.end()) - { - // This node is a source for back edge - for (auto dest : back_edges_by_src_it->second) - { - auto node_by_block_it = node_by_block.find(dest); - if (node_by_block_it != node_by_block.end()) - node_by_block_it->second->rollback.insert(r_it); - } - } - - for (auto next : (*r_it)->bb->getNext()) - { - auto node_by_block_it = node_by_block.find(next); - if (node_by_block_it != node_by_block.end()) - (*r_it)->next_blocks.insert(node_by_block_it->second); - } - } - - return blocks_with_counters; -} - -// iterate over separated subset of blocks -static void analyzeSequence(const vector& blocks_with_counters) -{ - auto curr = blocks_with_counters.rbegin(); - auto stop = blocks_with_counters.rend(); - - while (curr != stop) - { - auto curr_bb = *curr; - curr_bb->updateLive(); - - const auto& jumps = curr_bb->rollback; - if (jumps.size() != 0) - { - auto& ignored_jumps = curr_bb->ignore_rollback; - - bool jump = false; - for (const auto& jump_to : jumps) - { - if (ignored_jumps.insert(jump_to).second && curr_bb->newerThan(*jump_to)) - { - jump = true; - curr = jump_to; - break; - } - } - - if (!jump) - curr_bb->ignore_rollback.clear(); - else - continue; - } - - curr++; - } -} - -// delete all nodes from vector -static void freeBlocksWithCnt(const vector& blocks_with_counters) -{ - for (auto to_free : blocks_with_counters) - delete to_free; } // prints info about live variables @@ -527,7 +448,7 @@ void doDumpLive(const map>& CFGraph_for_p for (const auto& live : byBB->getLiveIn()) { __spf_print(1, " %s:", live.first->getValue().c_str()); - for(auto use : live.second) + for (auto use : live.second) __spf_print(1, " %d", use->getNumber()); __spf_print(1, "\n"); } @@ -630,8 +551,8 @@ static void fillLiveDeadArgs(const FuncInfo* func, const vector& params, - const map, set>>& params_and_globals, - const string& func_name, set& result) + const map, set>>& params_and_globals, + const string& func_name, set& result) { auto globals_it = params_and_globals.find(func_name); @@ -646,7 +567,7 @@ bool joinGlobalsWithParameters(const vector& params, for (int idx : param_indexes) { if (idx < params_size) { - if(params[idx] && params[idx]->getType() == SAPFOR::CFG_ARG_TYPE::VAR) + if (params[idx] && params[idx]->getType() == SAPFOR::CFG_ARG_TYPE::VAR) result.insert(params[idx]); } else @@ -658,11 +579,11 @@ bool joinGlobalsWithParameters(const vector& params, } // fill sets of arguments wich becomes live or dead after call with parameters params -static bool getLiveDead(const vector& params, const string& func_name, - set& live, set& dead) +static bool getLiveDead(const vector& params, const string& func_name, + set& live, set& dead) { return joinGlobalsWithParameters(params, live_by_func, func_name, live) && - joinGlobalsWithParameters(params, dead_by_func, func_name, dead); + joinGlobalsWithParameters(params, dead_by_func, func_name, dead); } // entrypoint for live variable analysis pass @@ -682,14 +603,14 @@ void runLiveVariableAnalysis(const map>& callDeps[byFunc.first].insert(byFunc.first->callsFromV.begin(), byFunc.first->callsFromV.end()); funcByName[byFunc.first->funcName] = byFunc.first; } - + vector> scc; vector> callLvls = groupByCallDependencies(callDeps, scc); - map> func_to_blocks_with_cnt; + map func_to_analysis_object; map> func_to_parameters; - list> live_for_fcalls; + list> live_for_fcalls; //TODO: take into account ssc structure // main stage @@ -707,8 +628,9 @@ void runLiveVariableAnalysis(const map>& auto& params = func_to_parameters[byFunc->funcName] = vector(byFunc->funcParams.countOfPars, NULL); - auto& blocks_with_cnt = (func_to_blocks_with_cnt[byFunc->funcName] = toBlocksWithCnt(itCFG->second, params, curr_fcalls, funcByName)); - analyzeSequence(blocks_with_cnt); + LiveVarAnalysis* analysis_object = (func_to_analysis_object[byFunc->funcName] = new LiveVarAnalysis(params, curr_fcalls, funcByName)); + analysis_object->fit(itCFG->second); + analysis_object->analyze(); fillLiveDeadArgs(byFunc, itCFG->second); } @@ -717,7 +639,7 @@ void runLiveVariableAnalysis(const map>& // interprocedural analysis for (auto& calls_vector : live_for_fcalls) { - map assembled_fcalls; + map assembled_fcalls; for (auto& call : calls_vector) { call.updateFromOut(); @@ -727,8 +649,8 @@ void runLiveVariableAnalysis(const map>& auto it = assembled_fcalls.find(call.func); if (it == assembled_fcalls.end()) - it = assembled_fcalls.insert({ call.func, fcall(call.func, call.block, {}) }).first; - + it = assembled_fcalls.insert({ call.func, LiveDeadVarsForCall(call.func, call.block, {}) }).first; + for (const auto& p : call.live_after) it->second.live_after[p.first].insert(p.second.begin(), p.second.end()); @@ -738,12 +660,12 @@ void runLiveVariableAnalysis(const map>& for (const auto& func : assembled_fcalls) { - auto func_it = func_to_blocks_with_cnt.find(func.first->funcName); - if (func_it == func_to_blocks_with_cnt.end()) + auto func_it = func_to_analysis_object.find(func.first->funcName); + if (func_it == func_to_analysis_object.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); auto param_it = func_to_parameters.find(func.first->funcName); - if(param_it == func_to_parameters.end()) + if (param_it == func_to_parameters.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); const vector& params = param_it->second; @@ -761,14 +683,14 @@ void runLiveVariableAnalysis(const map>& } } - set exits; - int max_cnt = CNT_NOTINIT; - for (auto block : func_it->second) + set exits; + int max_cnt = LiveVarAnalysisNode::getStartCounter(); + for (auto block : func_it->second->getNodes()) { - if (block->bb->getNext().size() == 0) + if (block->getBlock()->getNext().size() == 0) exits.insert(block); - if (block->out_cnt > max_cnt) - max_cnt = block->out_cnt; + if (block->getInCnt() > max_cnt) + max_cnt = block->getInCnt(); } max_cnt++; @@ -777,23 +699,25 @@ void runLiveVariableAnalysis(const map>& { for (const auto& byArg : live_after) { - if (exit->bb->addLiveOut({ byArg })) + map> converted; + converted[byArg.first] = vector(byArg.second.begin(), byArg.second.end()); + + if (exit->addIn(converted)) { - exit->out_cnt = max_cnt; - if (exit->live.find(byArg.first) == exit->live.end() && exit->dead.find(byArg.first) == exit->dead.end()) - if (exit->bb->addLiveIn({ byArg })) - exit->in_cnt = max_cnt; + exit->setInCnt(max_cnt); + if (exit->forwardData(converted)) + exit->setOutCnt(max_cnt); } } } - + // now we can update live sets in all blocks - analyzeSequence(func_it->second); + func_it->second->analyze(); } } - for (const auto& nodeByFunc : func_to_blocks_with_cnt) - freeBlocksWithCnt(nodeByFunc.second); + for (const auto& byFunc : func_to_analysis_object) + delete byFunc.second; for (auto& byFunc : CFGraph_for_project) for (auto& byBlock : byFunc.second) diff --git a/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.h b/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.h index 52e183b..d4a2c6a 100644 --- a/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.h +++ b/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.h @@ -1,6 +1,37 @@ +#pragma once + #include "../Utils/SgUtils.h" #include "CFGraph.h" +namespace LIVE_VARIABLES +{ + /* Store information about live and dead variables after call operator */ + /* (needed for interprocedural part of live variable analysis) */ + class LiveDeadVarsForCall + { + private: + bool tryInsert(std::set& dest, SAPFOR::BasicBlock* b); + public: + FuncInfo* func; + + std::map> live_after; + std::set dead_after; + + std::map> commons_live_after; + std::set commons_dead_after; + + std::vector params; + SAPFOR::BasicBlock* block; + + LiveDeadVarsForCall(FuncInfo* f, SAPFOR::BasicBlock* b, const std::vector& p); + + void make_live(SAPFOR::Argument* arg, SAPFOR::BasicBlock* b); + void make_dead(SAPFOR::Argument* arg); + + void updateFromOut(); + }; +} + template void insertIfVar(IT begin, IT end, DEST& to) { for (auto it = begin; it != end; it++) @@ -8,6 +39,12 @@ void insertIfVar(IT begin, IT end, DEST& to) { to.insert(*it); }; +void getUseDefForInstruction(SAPFOR::BasicBlock* block, SAPFOR::Instruction* instr, + std::set& use, std::set& def, + std::vector& formal_parameters, std::vector& fcalls, + std::vector& lastParamRef, int& last_param_ref_index, int& last_param_ref_size, + std::string& fName, const std::map& funcByName, bool interprocedural); + void runLiveVariableAnalysis(const std::map>& CFGraph_for_project); void doDumpLive(const std::map>& CFGraph_for_project); diff --git a/sapfor/experts/Sapfor_2017/_src/Sapfor.cpp b/sapfor/experts/Sapfor_2017/_src/Sapfor.cpp index f64f5e8..4a006d0 100644 --- a/sapfor/experts/Sapfor_2017/_src/Sapfor.cpp +++ b/sapfor/experts/Sapfor_2017/_src/Sapfor.cpp @@ -79,6 +79,7 @@ #include "Transformations/private_removing.h" #include "Transformations/fix_common_blocks.h" #include "Transformations/convert_to_c.h" +#include "Transformations/dead_code.h" #include "RenameSymbols/rename_symbols.h" #include "ProjectParameters/projectParameters.h" @@ -1169,6 +1170,12 @@ static bool runAnalysis(SgProject &project, const int curr_regime, const bool ne covertToC(file); else if (curr_regime == INSERT_NO_DISTR_FLAGS_FROM_GUI) addPrivatesToArraysFromGUI(file, declaredArrays, distrStateFromGUI); + else if (curr_regime == REMOVE_DEAD_CODE_AND_UNPARSE) + { + auto funcsForFile = getObjectForFileFromMap(file_name, allFuncInfo_IR); + for (auto& func : funcsForFile) + removeDeadCode(func->funcPointer, allFuncInfo_IR, commonBlocks); + } else if (curr_regime == TEST_PASS) { //test pass @@ -2515,6 +2522,7 @@ void runPass(const int curr_regime, const char *proj_name, const char *folderNam findFunctionsToInclude(true); break; // all these cases run UNPARSE_FILE after + case REMOVE_DEAD_CODE_AND_UNPARSE: case RENAME_SYMBOLS: case RESOLVE_PAR_REGIONS: case CREATE_PARALLEL_REGIONS: diff --git a/sapfor/experts/Sapfor_2017/_src/Sapfor.h b/sapfor/experts/Sapfor_2017/_src/Sapfor.h index 670cd9c..a66f577 100644 --- a/sapfor/experts/Sapfor_2017/_src/Sapfor.h +++ b/sapfor/experts/Sapfor_2017/_src/Sapfor.h @@ -165,6 +165,7 @@ enum passes { BUILD_IR, LIVE_ANALYSIS_IR, PRIVATE_ANALYSIS_IR, + REMOVE_DEAD_CODE_AND_UNPARSE, FIX_COMMON_BLOCKS, REMOVE_OMP_DIRS, @@ -343,6 +344,7 @@ static void setPassValues() passNames[CALL_GRAPH_IR] = "CALL_GRAPH_IR"; passNames[LIVE_ANALYSIS_IR] = "LIVE_ANALYSIS_IR"; passNames[PRIVATE_ANALYSIS_IR] = "PRIVATE_ANALYSIS_IR"; + passNames[REMOVE_DEAD_CODE_AND_UNPARSE] = "REMOVE_DEAD_CODE_AND_UNPARSE"; passNames[FIX_COMMON_BLOCKS] = "FIX_COMMON_BLOCKS"; passNames[REMOVE_OMP_DIRS] = "REMOVE_OMP_DIRS"; diff --git a/sapfor/experts/Sapfor_2017/_src/Transformations/dead_code.cpp b/sapfor/experts/Sapfor_2017/_src/Transformations/dead_code.cpp new file mode 100644 index 0000000..f1ad920 --- /dev/null +++ b/sapfor/experts/Sapfor_2017/_src/Transformations/dead_code.cpp @@ -0,0 +1,436 @@ +#include "dead_code.h" + +#include +#include +#include +#include + +using std::map; +using std::string; +using std::vector; +using std::set; + +static void updateUseDefForInstruction(SAPFOR::BasicBlock* block, SAPFOR::Instruction* instr, + set& use, set& def, + vector& formal_parameters, + vector& lastParamRef, int& last_param_ref_index, int& last_param_ref_size, + string& fName, + bool& useful, bool& last_fcall_useful, + set& usedByThisBlock) +{ + set res, args; + + if (fName == "") + last_fcall_useful = false; + + vector fcalls; + + + getUseDefForInstruction(block, instr, + args, res, + formal_parameters, fcalls, + lastParamRef, last_param_ref_index, last_param_ref_size, + fName, {}, + false + ); + + if (!useful) + { + for (SAPFOR::Argument* r : res) + { + if (use.find(r) != use.end() || r->getMemType() != SAPFOR::CFG_MEM_TYPE::LOCAL_) + { + useful = true; + break; + } + } + } + + if (!useful) + { + set always_useful = + { + SAPFOR::CFG_OP::POINTER_ASS, + SAPFOR::CFG_OP::STORE, + SAPFOR::CFG_OP::REC_REF_STORE, + SAPFOR::CFG_OP::RANGE, + SAPFOR::CFG_OP::ENTRY, + SAPFOR::CFG_OP::EXIT, + SAPFOR::CFG_OP::DVM_DIR, + SAPFOR::CFG_OP::SPF_DIR, + + SAPFOR::CFG_OP::F_CALL //TODO: handle pure functions + }; + + if (always_useful.find(instr->getOperation()) != always_useful.end()) + useful = true; + else if(instr->getOperation() == SAPFOR::CFG_OP::PARAM && last_fcall_useful) + useful = true; + } + + if (useful) + { + if (instr->getOperation() == SAPFOR::CFG_OP::F_CALL) + last_fcall_useful = true; + + for (auto e : res) + { + def.insert(e); + use.erase(e); + } + + for (auto e : args) + { + use.insert(e); + def.erase(e); + } + + insertIfVar(args.begin(), args.end(), usedByThisBlock); + } +} + + +//Build use and def sets of block. Result are stored in use and def +static void buildUseDef(SAPFOR::BasicBlock* block, set& use, set& def, + vector& formal_parameters, vector& useful, + set& usedByThisBlock) +{ + set use_with_regs = use, def_with_regs = def; + + vector lastParamRef; + int last_param_ref_index = 0, last_param_ref_size = 0; + string fName = ""; + bool last_fcall_useful = false; + + const auto& instructions = block->getInstructions(); + int instr_size = instructions.size(); + + for (int i = instr_size - 1; i >= 0; i--) + { + bool u = useful[i]; + + updateUseDefForInstruction(block, instructions[i]->getInstruction(), + use_with_regs, def_with_regs, + formal_parameters, + lastParamRef, last_param_ref_index, last_param_ref_size, + fName, + u, last_fcall_useful, + usedByThisBlock + ); + + useful[i] = u; + } + + insertIfVar(use_with_regs.begin(), use_with_regs.end(), use); + insertIfVar(def_with_regs.begin(), def_with_regs.end(), def); +} + + +class DeadCodeAnalysisNode : public DataFlowAnalysisNode>> { +private: + vector useful; + bool useful_block = false; + set next_notempty_in, next_notempty_out; + bool useful_jump = false; + + vector& formal_parameters; +public: + bool updateJumpStatus() + { + bool res = false; + const auto& prev = getPrevBlocks(); + if (prev.size() > 1 && !useful.back() && + getBlock()->getInstructions().back()->getInstruction()->getOperation() == SAPFOR::CFG_OP::JUMP_IF) + { + const auto& example = dynamic_cast(*prev.begin())->next_notempty_out; + + for (auto p : prev) + { + DeadCodeAnalysisNode* next = dynamic_cast(p); + + if (next->next_notempty_out != example) + { + useful.back() = true; + res = true; + break; + } + } + } + + return res; + } + + bool updateNextNotEmpty() + { + bool updated = false; + + if(!useful_block) + { + set current = {}; + + for (auto nextP : getPrevBlocks()) + { + DeadCodeAnalysisNode* next = dynamic_cast(nextP); + + if(!next) + printInternalError(convertFileName(__FILE__).c_str(), __LINE__); + + current.insert(next->next_notempty_out.begin(), next->next_notempty_out.end()); + } + + if (current != next_notempty_in) + { + next_notempty_in = current; + updated = true; + } + } + + return updated; + } + + map> getIn() { + return getBlock()->getLiveOut(); + }; + + map> getOut() { + return getBlock()->getLiveIn(); + }; + + bool addIn(const map>& data) { + bool inserted = getBlock()->addLiveOut(data); + + if (!useful_block) + inserted |= updateNextNotEmpty(); + + inserted |= updateJumpStatus(); + + return inserted; + }; + + bool addOut(const map>& data) { + return getBlock()->addLiveIn(data); + }; + + bool forwardData(const map>& data) { + bool inserted = false; + SAPFOR::BasicBlock* bb= getBlock(); + + set use, def; + + for (const auto& byArg : data) + use.insert(byArg.first); + + set usedByThisBlock; + buildUseDef(bb, use, def, this->formal_parameters, useful, usedByThisBlock); + + auto in = bb->getLiveIn(), out = bb->getLiveOut(); + + for (SAPFOR::Argument* arg : use) + { + bool this_block = usedByThisBlock.find(arg) != usedByThisBlock.end(); + + if (!this_block) + { + auto data_it = data.find(arg); + + if (data_it == data.end()) + printInternalError(convertFileName(__FILE__).c_str(), __LINE__); + + inserted |= bb->addLiveIn({ *data_it }); + } + else + { + auto in_it = in.find(arg); + bool skip = false; + if (in_it != in.end()) + { + if (in_it->second.size() == 1 && *(in_it->second.begin()) == bb) + skip = true; // nothing to do, inserted = false + else + bb->removeLiveIn(arg); + } + if(!skip) + inserted |= bb->addLiveIn({ { arg, { bb } } }); + } + } + + if(!useful_block) + { + for(bool status : useful) + { + if (status) + { + useful_block = true; + + inserted = true; + next_notempty_out = { this }; + break; + } + } + } + + if (!useful_block) + { + if (next_notempty_in != next_notempty_out) + { + inserted = true; + next_notempty_out = next_notempty_in; + } + } + + return inserted; + }; + + DeadCodeAnalysisNode(SAPFOR::BasicBlock* block, vector& formal_parameters) : + formal_parameters(formal_parameters) + { + setBlock(block); + useful.resize(block->getInstructions().size(), false); + set use, def; + set usedByThisBlock; + + buildUseDef(getBlock(), use, def, this->formal_parameters, useful, usedByThisBlock); + + for (SAPFOR::Argument* arg : use) + getBlock()->addLiveIn({ { arg, { getBlock() } } }); + } + + const vector& getResult() { return useful; }; +}; + +class DeadCodeAnalysis : public BackwardDataFlowAnalysis>, DeadCodeAnalysisNode> { +protected: + vector& formal_parameters; + + DeadCodeAnalysisNode* createNode(SAPFOR::BasicBlock* block) override { + return new DeadCodeAnalysisNode(block, formal_parameters); + }; +public: + DeadCodeAnalysis(vector& formal_parameters) : + formal_parameters(formal_parameters) + { }; +}; + + +void removeDeadCode(SgStatement* func, + const map>& allFuncs, + const map& commonBlocks) +{ + SgProgHedrStmt* prog = isSgProgHedrStmt(func); + + if (prog) + __spf_print(1, "[analyze %s]\n", prog->name().identifier()); + else + __spf_print(1, "[cannot resolve name of function]\n"); + + + auto cfg = buildCFGforCurrentFunc(func, SAPFOR::CFG_Settings(true, false, false, false, false, false, false), commonBlocks, allFuncs); + + if(cfg.size() != 1) + printInternalError(convertFileName(__FILE__).c_str(), __LINE__); + + const auto& cfg_pair = *(cfg.begin()); + + vector func_parameters(cfg_pair.first->funcParams.countOfPars, NULL); + + DeadCodeAnalysis* analysis_object = new DeadCodeAnalysis(func_parameters); + + analysis_object->fit(cfg_pair.second); + analysis_object->analyze(); + + set useful; + + for (DeadCodeAnalysisNode* byNode : analysis_object->getNodes()) + { + const auto& instructions = byNode->getBlock()->getInstructions(); + const auto& statuses = byNode->getResult(); + + int size = instructions.size(); + + if(size != statuses.size()) + printInternalError(convertFileName(__FILE__).c_str(), __LINE__); + + for (int i = 0; i < size; i++) + { + if(statuses[i]) + { + SgStatement* stmt = instructions[i]->getInstruction()->getOperator(); + + while(stmt && useful.insert(stmt).second) + { + __spf_print(1, "[Useful statement '%s' on line %d]\n", stmt->unparse(), stmt->lineNumber()); + stmt = stmt->controlParent(); + } + } + } + } + + SgStatement* end = func->lastNodeOfStmt(), *st = func; + + set removable = + { + ASSIGN_STAT + }; + + SgStatement* enclosing = st->controlParent(); + SgStatement* encl_end = enclosing ? enclosing->lastNodeOfStmt() : NULL; + + while (st != end) + { + SgStatement* next = st->lexNext(); + SgStatement* parent = NULL; + + if (removable.find(st->variant()) != removable.end() && useful.find(st) == useful.end()) + { + __spf_print(1, "[Useless statement '%s' on line %d]\n", st->unparse(), st->lineNumber()); + + parent = st->controlParent(); + + st->extractStmt()->deleteStmt(); + st = NULL; + } + else + { + if (st == encl_end) + { + if (enclosing) + { + bool empty_parent = false; + + switch (enclosing->variant()) + { + case IF_NODE: + empty_parent = + enclosing->lexNext() == encl_end || // IF THEN ENDIF + enclosing->lexNext()->variant() == CONTROL_END && + enclosing->lexNext()->lexNext() == encl_end; // IF THEN ELSE ENDIF + break; + default: + empty_parent = enclosing->lexNext() == encl_end; + break; + } + + if(empty_parent) + { + parent = enclosing->controlParent(); + enclosing->extractStmt()->deleteStmt(); + st->extractStmt()->deleteStmt(); + st = NULL; + } + } + + } + } + + if(!parent) + parent = st->controlParent(); + + if (parent != enclosing) + { + enclosing = parent; + encl_end = enclosing ? enclosing->lastNodeOfStmt() : NULL; + } + + st = next; + } +} \ No newline at end of file diff --git a/sapfor/experts/Sapfor_2017/_src/Transformations/dead_code.h b/sapfor/experts/Sapfor_2017/_src/Transformations/dead_code.h new file mode 100644 index 0000000..7c83b1d --- /dev/null +++ b/sapfor/experts/Sapfor_2017/_src/Transformations/dead_code.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +#include "../Utils/SgUtils.h" +#include "../CFGraph/CFGraph.h" +#include "../CFGraph/live_variable_analysis.h" +#include "../CFGraph/DataFlow/data_flow.h" +#include "../CFGraph/DataFlow/backward_data_flow.h" + +void removeDeadCode(SgStatement* func, + const std::map>&allFuncs, + const std::map& commonBlocks); \ No newline at end of file diff --git a/sapfor/experts/Sapfor_2017/_src/Utils/PassManager.h b/sapfor/experts/Sapfor_2017/_src/Utils/PassManager.h index 3e68a6a..88ed1ba 100644 --- a/sapfor/experts/Sapfor_2017/_src/Utils/PassManager.h +++ b/sapfor/experts/Sapfor_2017/_src/Utils/PassManager.h @@ -306,6 +306,8 @@ void InitPassesDependencies(map> &passDepsIn, set Pass(REMOVE_OMP_DIRS) <= Pass(REMOVE_OMP_DIRS_TRANSFORM); + Pass(BUILD_IR) <= Pass(REMOVE_DEAD_CODE_AND_UNPARSE); + passesIgnoreStateDone.insert({ CREATE_PARALLEL_DIRS, INSERT_PARALLEL_DIRS, INSERT_SHADOW_DIRS, EXTRACT_PARALLEL_DIRS, EXTRACT_SHADOW_DIRS, CREATE_REMOTES, UNPARSE_FILE, REMOVE_AND_CALC_SHADOW, REVERSE_CREATED_NESTED_LOOPS, PREDICT_SCHEME, CALCULATE_STATS_SCHEME, REVERT_SPF_DIRS, CLEAR_SPF_DIRS, TRANSFORM_SHADOW_IF_FULL,