From 14219cdfd58e96cb6d34f086d7a25de115739d29 Mon Sep 17 00:00:00 2001 From: mkoch Date: Tue, 9 Jan 2024 18:28:50 +0300 Subject: [PATCH] add REMOVE_DEAD_CODE_AND_UNPARSE (debug) pass --- sapfor/experts/Sapfor_2017/CMakeLists.txt | 6 +- .../Sapfor_2017/_src/CFGraph/CFGraph.h | 4 + .../_src/CFGraph/live_variable_analysis.cpp | 31 ++ sapfor/experts/Sapfor_2017/_src/Sapfor.cpp | 8 + sapfor/experts/Sapfor_2017/_src/Sapfor.h | 2 + .../_src/Transformations/dead_code.cpp | 436 ++++++++++++++++++ .../_src/Transformations/dead_code.h | 14 + .../Sapfor_2017/_src/Utils/PassManager.h | 2 + 8 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 sapfor/experts/Sapfor_2017/_src/Transformations/dead_code.cpp create mode 100644 sapfor/experts/Sapfor_2017/_src/Transformations/dead_code.h diff --git a/sapfor/experts/Sapfor_2017/CMakeLists.txt b/sapfor/experts/Sapfor_2017/CMakeLists.txt index 0ad33fe..94433f2 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} @@ -414,6 +417,7 @@ 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..dbe790d 100644 --- a/sapfor/experts/Sapfor_2017/_src/CFGraph/CFGraph.h +++ b/sapfor/experts/Sapfor_2017/_src/CFGraph/CFGraph.h @@ -33,6 +33,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); @@ -71,6 +72,9 @@ namespace SAPFOR */ 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); }; 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 ba8a0ae..ccd933e 100644 --- a/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.cpp +++ b/sapfor/experts/Sapfor_2017/_src/CFGraph/live_variable_analysis.cpp @@ -97,6 +97,37 @@ namespace SAPFOR return inserted; }; + 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; 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..3c9c548 --- /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,