#include "RD_subst.h" #include "IR.h" #include "CFGraph.h" #include #include #include #include #include #include "../Utils/SgUtils.h" #include "../Utils/CommonBlock.h" #include "../GraphCall/graph_calls.h" #include "../ExpressionTransform/expr_transform.h" #define PRINT_PROF_INFO 0 #define DEBUG_CHECKS 0 using std::string; using std::vector; using std::list; using std::map; using std::set; using std::pair; using std::unordered_map; using std::unordered_set; using std::cout; using std::endl; using SAPFOR::CFG_VAL; using SAPFOR::CFG_OP; using SAPFOR::CFG_OP_S; using SAPFOR::CFG_ARG_TYPE; using SAPFOR::CFG_MEM_TYPE; static bool substitutions_were_built = false; static bool substitutions_applied = false; static bool wereSubstitutionsBuilt() { return substitutions_were_built; } static void setSubstitutionsWereBuilt(bool new_state) { substitutions_were_built = new_state; } static bool wereSubstitutionsApplied() { return substitutions_applied; } static void setSubstitutionsApplied(bool new_state) { substitutions_applied = new_state; } static map>> oldExpressionsInFile; static map>> replacementsInFiles; static int substitution_counter = 0; static const map>>& getReplacementsInFiles() { return replacementsInFiles; } static const map>>& getOldExpressionsInFile() { return oldExpressionsInFile; } static bool storeExpression(map>>& place, const string& filename, SgStatement* stmt, int expr_index, SgExpression* expr, bool override_expr = true) { auto& by_curr_file = place[filename]; auto it = by_curr_file.find(stmt); if (it == by_curr_file.end()) it = by_curr_file.insert(it, make_pair(stmt, vector(3, NULL))); #if DEBUG_CHECKS if(override_expr && it->second[expr_index]) __spf_print(DEBUG_CHECKS, "lost pointer: %s:%d expr %d %s\n", filename.c_str(), stmt->lineNumber(), expr_index, expr->unparse()); #endif if (override_expr || !(it->second[expr_index])) { it->second[expr_index] = expr; return true; } return false; } static bool addOldExpression(const string& filename, SgStatement* stmt, int expr_index, SgExpression* old_expr, bool override_expr = true) { return storeExpression(oldExpressionsInFile, filename, stmt, expr_index, old_expr, override_expr); } static bool addReplacement(const string& filename, SgStatement* stmt, int expr_index, SgExpression* new_expr, bool override_expr = true) { return storeExpression(replacementsInFiles, filename, stmt, expr_index, new_expr, override_expr); } static bool addReplacementAndBackup(const string& filename, SgStatement* stmt, int expr_index, SgExpression* new_expr) { addReplacement(filename, stmt, expr_index, new_expr); SgExpression* original = stmt->expr(expr_index); addOldExpression(filename, stmt, expr_index, original, true); return true; } static void updateOldExpression() { for (auto& byFile : oldExpressionsInFile) { SgFile::switchToFile(byFile.first); for (auto& byStmt : byFile.second) { for (int i = 0; i < 3; i++) { auto& expr = byStmt.second[i]; if (byStmt.second[i] != NULL) byStmt.second[i] = byStmt.first->expr(i); } } } } static void applyReplacement(map>>& replacements) { for (auto& byFile : replacements) { SgFile::switchToFile(byFile.first); for (auto& byStmt : byFile.second) { for (int i = 0; i < 3; i++) { auto& expr = byStmt.second[i]; if (expr != NULL) byStmt.first->setExpression(i, expr); } } } } static void removeInfo(map>>& replacements, string filename, SgStatement* stmt, int i) { auto it_file = replacements.find(filename); if (it_file != replacements.end()) { auto it_stmt = it_file->second.find(stmt); if (it_stmt != it_file->second.end()) { it_stmt->second[i] = NULL; bool all_null = true; for (auto e : it_stmt->second) { if (e != NULL) { all_null = false; break; } } if (all_null) it_file->second.erase(it_stmt); } if (it_file->second.size() == 0) replacements.erase(it_file); } } static void dump_replacements_for_file(string filename) { cout << "substitutions for file " << filename << ":" << endl; for (auto& byStmt : replacementsInFiles[filename]) { for (int i = 0; i < 3; i++) { auto& expr = byStmt.second[i]; if (expr != NULL) cout << " stmt:" << byStmt.first->sunparse() << ", index: " << i << ", expr: " << expr->sunparse() << endl; } } } static int getSubstitutionCounter() { return substitution_counter; } static void incrementSubstitutionCounter() { ++substitution_counter; } static void resetSubstitutionCounter() { substitution_counter = 0; } const map& getCommonArgsByFunc(FuncInfo* func, map>& cache, const vector>& commonVars, unordered_map& globals_cache, unordered_map& locals_cache) { auto it = cache.find(func); if (it != cache.end()) return it->second; auto& res = cache[func]; for (const auto& byVar : commonVars) { string file = func->fileName; SgSymbol* s = NULL; for (const auto& varUse : byVar.first->getAllUse()) if (varUse.getFileName() == file && (s = varUse.getUseS())) break; if (!s) s = byVar.first->getSymbol(); if (s) res[getArgNameBySymbol(commonVars, func, s, globals_cache, locals_cache)] = s; } return res; } static bool getDependencies(SAPFOR::Argument* var, SAPFOR::Instruction* instr, const SAPFOR::BasicBlock* curr_BB, map>& dependencies) { map process_instr; process_instr[var] = instr; dependencies[var].clear(); while (process_instr.size() != 0) { map reg_decl; map to_add; for (const auto& byVar : process_instr) { if (byVar.second->getOperation() == SAPFOR::CFG_OP::F_CALL) return false; auto instr_type = byVar.second->getOperation(); int instr_num = byVar.second->getNumber(); set args; try { if (instr_type == CFG_OP::LOAD) { args.insert(byVar.second->getArg1()); int num_of_params = stoi(byVar.second->getArg2()->getValue()); int offset = instr_num - curr_BB->getInstructions().front()->getNumber() - num_of_params; auto start = curr_BB->getInstructions().begin() + offset; auto end = start + num_of_params; for (; start != end; start++) args.insert((*start)->getInstruction()->getArg1()); } else if (hasStoreStructure(instr_type)) { return false; } else args = { byVar.second->getArg1(), byVar.second->getArg2() }; } catch (std::invalid_argument e) { //cannot convert number of parameters into integer in LOAD or STORE instruction printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } for (const auto arg : args) { if (arg != NULL) { if (arg->getType() == CFG_ARG_TYPE::REG) { auto reg_decl_it = reg_decl.find(arg); if (reg_decl_it != reg_decl.end()) to_add.insert(*reg_decl_it); else { for (SAPFOR::IR_Block* byIR : curr_BB->getInstructions()) { auto instruction = byIR->getInstruction(); auto instr_res = instruction->getResult(); if (instr_res && instr_res->getType() == CFG_ARG_TYPE::REG && !hasStoreStructure(instruction->getOperation())) reg_decl[instr_res] = instruction; } reg_decl_it = reg_decl.find(arg); if (reg_decl_it != reg_decl.end()) to_add.insert(*reg_decl_it); else //printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return false; } } else if (arg->getType() == CFG_ARG_TYPE::VAR || arg->getType() == CFG_ARG_TYPE::ARRAY) dependencies[var].insert(arg); } } } process_instr = to_add; } return true; } static const set& func_affects(const FuncInfo* func, const vector& blocks) { static map> affects; auto func_affects_it = affects.find(func); if (func_affects_it == affects.end()) { func_affects_it = affects.insert({ func, { } }).first; for (auto block : blocks) if (block->getNext().size() == 0) for (const auto& out : block->getRD_Out()) /* if a function affects variable, than there is basic block, where OUT for that variable contains at least 1 valid index of instruction (index < 0 means that this variable has reaching definition otside of this function) */ if (out.second.size() != 1 || *out.second.begin() >= 0) func_affects_it->second.insert(out.first); } return func_affects_it->second; } static SgSymbol* findCommon(SgSymbol* symb, const FuncInfo* processed_function, const map& commonBlocks) { for (const auto& cb : processed_function->commonBlocks) { auto cb_it = commonBlocks.find(cb.first); if (cb_it != commonBlocks.end()) { for (auto& var_pos : cb_it->second->getGroupedVars()) { bool this_var = false; for (auto& var : var_pos.second) { for (auto& varUse : var->getAllUse()) { if (varUse.getUseS() == symb) { this_var = true; break; } } if (this_var) break; } if (this_var) for (auto& var : var_pos.second) for (auto& varUse : var->getAllUse()) if (varUse.getFunctionName() == processed_function->funcName) return varUse.getUseS(); } } } return NULL; } static SgExpression* copyExpr(SgExpression* exp_to_copy, const FuncInfo* processed_function, const map& commonBlocks, bool only_global = false) { SgExpression* copy = exp_to_copy->copyPtr(); set locals; map commons; //common symb from expr -> common symb from processed_func set exp_to_process = { copy }; while (exp_to_process.size() != 0) { set to_add; for (auto& exp : exp_to_process) { if (exp->lhs()) to_add.insert(exp->lhs()); if (exp->rhs()) to_add.insert(exp->lhs()); if (exp->symbol()) { SgSymbol* symb = exp->symbol(); if (locals.count(symb)) continue; auto it = commons.find(symb); if (it == commons.end()) { SgSymbol* found = findCommon(symb, processed_function, commonBlocks); if (!found) { if (only_global) return NULL; locals.insert(symb); continue; } it = commons.insert({ symb, found }).first; } exp->setSymbol(it->second); } } exp_to_process = to_add; } return copy; } static bool isBBlockFromCurrentFile(const map>& CFGraph, const SAPFOR::BasicBlock* bb) { const string curr = current_file->filename(); for (auto& byFunc : CFGraph) { if (count(byFunc.second.begin(), byFunc.second.end(), bb)) return byFunc.first->fileName == curr; } return false; } static bool isIfOrLoopFromBB(SgStatement* st, SAPFOR::BasicBlock* bb) { SAPFOR::Instruction* last = bb->getInstructions().back()->getInstruction(); int variant = st->variant(); bool if_or_loop_from_BB = last->getOperator() == st; switch (variant) { case IF_NODE: case LOGIF_NODE: case ELSEIF_NODE: return if_or_loop_from_BB && last->getOperation() == CFG_OP::JUMP_IF; case FOR_NODE: return if_or_loop_from_BB && (last->getOperation() != CFG_OP::JUMP && last->getOperation() != CFG_OP::JUMP_IF); case WHILE_NODE: return if_or_loop_from_BB && last->getOperation() == CFG_OP::JUMP_IF; default: return true; } return true; } static map func_makes_available(const FuncInfo* func, SgProject* project, map>& availableForFunc, map>>& dependenciesForFunc, const vector& blocks, const map>& CFGraph, map>& dependencies, const FuncInfo* processed_function, const map& commonBlocks) { if (string(current_file->filename()) != func->fileName) return { }; auto available_after_func_it = availableForFunc.find(func); if (available_after_func_it == availableForFunc.end()) { available_after_func_it = availableForFunc.insert({ func, { } }).first; auto& availableForCurrentFunc = available_after_func_it->second; auto& dependenciesForCurrentFunc = dependenciesForFunc[func]; bool first_out_block = true; vector> makes_available; for (auto block : blocks) { if (block->getNext().size() == 0) { if (first_out_block) { for (auto& out : block->getRD_Out()) { if ((out.first->getMemType() == SAPFOR::CFG_MEM_TYPE::COMMON_ /* || out.first->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_*/) && out.second.size() == 1 && *(out.second.begin()) >= 0) { makes_available.push_back(std::make_pair(out.first, *(out.second.begin()))); } } first_out_block = false; } else { makes_available.erase(std::remove_if(makes_available.begin(), makes_available.end(), [&block](const pair& p) { auto it = block->getRD_Out().find(p.first); return (it == block->getRD_Out().end()) || (it->second.size() != 1) || (*(it->second.begin()) != p.second); }), makes_available.end() ); } } } for (const auto& p : makes_available) { auto argument = p.first; int instr_number = p.second; pair instr_and_bb = getInstructionAndBlockByNumber(CFGraph, instr_number); if (!isBBlockFromCurrentFile(CFGraph, instr_and_bb.second)) continue; if (getDependencies(argument, instr_and_bb.first, instr_and_bb.second, dependenciesForCurrentFunc)) { //check if all variables with affect on definition could be used there bool can_use = true; auto dependencies_of_var = dependenciesForCurrentFunc.find(argument); if (dependencies_of_var == dependenciesForCurrentFunc.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (SAPFOR::Argument* dep : dependencies_of_var->second) { if (dep->getMemType() != SAPFOR::CFG_MEM_TYPE::COMMON_/* || dep->getMemType() == SAPFOR::CFG_MEM_TYPE::MODULE_*/) { can_use = false; break; } } if (can_use) availableForCurrentFunc[argument] = instr_and_bb.first->getOperator()->expr(1); } } } auto dependencies_after_func_it = dependenciesForFunc.find(func); if(dependencies_after_func_it == dependenciesForFunc.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); map available; for (const auto& byArgument : available_after_func_it->second) { auto dependencies_for_argument_it = dependencies_after_func_it->second.find(byArgument.first); if(dependencies_for_argument_it == dependencies_after_func_it->second.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgExpression* exp_of_def = copyExpr(byArgument.second, processed_function, commonBlocks, true); if (exp_of_def) { dependencies[byArgument.first] = dependencies_for_argument_it->second; available[byArgument.first] = exp_of_def; } } return available; } static unordered_map globals, locals; const string& getArgNameBySymbol(const vector>& commonVars, const FuncInfo* func, SgSymbol* s, unordered_map& globals_cache, unordered_map& locals_cache) { auto local_it = locals_cache.find(s); if (local_it != locals_cache.end()) return local_it->second; auto global_it = globals_cache.find(s); if (global_it != globals_cache.end()) return global_it->second; CFG_MEM_TYPE mType = CFG_MEM_TYPE::NONE_; SgStatement* scope = OriginalSymbol(s)->scope(); if (!scope) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); string name = createName(commonVars, func, s, scope, mType); if (mType == CFG_MEM_TYPE::LOCAL_) return locals_cache[s] = name; else return globals_cache[s] = name; } static SgExpression* expandSymbolToExpression(SgExpression* s, const map& name_to_expr, const vector>& commonVars, const FuncInfo* func) { while (s->variant() == VAR_REF && s->symbol() && s->symbol()->identifier()) { string argName = getArgNameBySymbol(commonVars, func, s->symbol(), globals, locals); auto it = name_to_expr.find(argName); if (it == name_to_expr.end() || it->second->type()->variant() != s->type()->variant()) break; incrementSubstitutionCounter(); __spf_print(PRINT_PROF_INFO, "%s -> ", s->unparse()); s = it->second; __spf_print(PRINT_PROF_INFO, "%s\n", s->unparse()); } return s; } static SgExpression* performExprSubstAndLink_(SgExpression* cur_exp, bool is_left, const map& name_to_expr, const map& available, const vector>& commonVars, const FuncInfo* func, SgExpression* exp, SgExpression*& backup) { SgExpression* sub_expr = is_left ? cur_exp->lhs() : cur_exp->rhs(); if (sub_expr) if (sub_expr->symbol() && sub_expr->variant() != PROC_CALL && sub_expr->variant() != FUNC_CALL) { SgArrayRefExp* array_expr = isSgArrayRefExp(sub_expr); if (array_expr) { if (array_expr->subscripts()) return array_expr->subscripts(); } else if (sub_expr->symbol()->identifier()) { SgExpression* replace_by = expandSymbolToExpression(sub_expr, name_to_expr, commonVars, func); if (replace_by != sub_expr) { if (backup == NULL) { backup = exp->copyPtr(); createLinksToCopy(backup, exp); } __spf_print(PRINT_PROF_INFO, "%s -> ", sub_expr->unparse()); is_left ? cur_exp->setLhs(replace_by->copy()) : cur_exp->setRhs(replace_by->copy()); sub_expr = is_left ? cur_exp->lhs() : cur_exp->rhs(); __spf_print(PRINT_PROF_INFO, "%s\n", sub_expr->unparse()); incrementSubstitutionCounter(); return sub_expr; } } } else return sub_expr; return NULL; } // iterate over function or procedure call arguments and sustitute if it possible static list performExprSubstInCall(const char* fname, SgExprListExp* actualArguments, const map& name_to_expr, const map& available, const vector>& commonVars, const FuncInfo* func, const map& funcByName, SgExpression* exp, SgExpression*& backup) { if (!fname || !actualArguments) return { }; // Step 1. Get indexes of arguments that can be substituted set possible_substitution; auto found_func = funcByName.find(fname); if (found_func != funcByName.end()) { FuncInfo* called_func = found_func->second; int count_of_params = called_func->funcParams.countOfPars; for (int i = 0; i < count_of_params; i++) if (!called_func->funcParams.isArgOut(i)) possible_substitution.insert(i); } else { if (isIntrinsicFunctionName(fname)) return { actualArguments }; // main loop can substitute all arguments indiscriminately } // Step 2. Perform possible substitutions list res; SgExpression* curr = actualArguments; int pos = 0; while (curr) { SgExpression* actual_param = curr->lhs(); if (actual_param) { if (actual_param->symbol() && actual_param->symbol()->identifier() && actual_param->variant() == VAR_REF) { if (possible_substitution.find(pos) != possible_substitution.end()) { SgExpression* to_add = performExprSubstAndLink_(curr, true, name_to_expr, available, commonVars, func, exp, backup); if (to_add) res.push_back(to_add); } } else { res.push_back(actual_param); } } pos++; curr = curr->rhs(); } return res; } // if replacement occurs, returns a new expression (the new expression is linked to the original one) // if there were no replacements, then returns NULL static SgExpression* performExprSubstAndLink(SgStatement* stmt, int i, const map& available, const vector>& commonVars, const FuncInfo* func, const map& funcByName) { SgExpression* expr_to_subst = stmt->expr(i); map name_to_expr; for (const auto& p : available) name_to_expr[p.first->getValue()] = p.second; SgExpression* backup = NULL; list to_process; SgCallStmt* call = isSgCallStmt(stmt); if (!call) { SgExpression* replace_symbol_by = expandSymbolToExpression(expr_to_subst, name_to_expr, commonVars, func); if (replace_symbol_by != expr_to_subst) { if (backup == NULL) { backup = expr_to_subst->copyPtr(); createLinksToCopy(backup, expr_to_subst); } expr_to_subst = replace_symbol_by->copyPtr(); stmt->setExpression(i, expr_to_subst); } to_process = { expr_to_subst }; } else { auto to_add = performExprSubstInCall(call->name()->identifier(), isSgExprListExp(call->expr(0)), name_to_expr, available, commonVars, func, funcByName, expr_to_subst, backup); for (auto e : to_add) to_process.push_back(e); } while (to_process.size() > 0) { SgExpression* cur_exp = to_process.front(), *sub_expr; to_process.pop_front(); SgFunctionCallExp* fcall = isSgFunctionCallExp(cur_exp); if (fcall) { auto to_add = performExprSubstInCall(fcall->funName()->identifier(), isSgExprListExp(fcall->args()), name_to_expr, available, commonVars, func, funcByName, expr_to_subst, backup); for (auto e : to_add) to_process.push_back(e); } else { sub_expr = performExprSubstAndLink_(cur_exp, true, name_to_expr, available, commonVars, func, expr_to_subst, backup); if (sub_expr) to_process.push_back(sub_expr); sub_expr = performExprSubstAndLink_(cur_exp, false, name_to_expr, available, commonVars, func, expr_to_subst, backup); if (sub_expr) to_process.push_back(sub_expr); } } if (backup) { stmt->setExpression(i, backup); return expr_to_subst; } return NULL; } // replace argument_to_replace by argument_value in expr. // if there were no replacements, then returns expr. // if substitution couldn't be applied due to type mismatch, return NULL // else returns substituted expression (note that argument_value can be returned) // argument value shouldn't contains argument_to_replace static SgExpression* substSingleSymb(SgExpression* expr, SAPFOR::Argument* argument_to_replace, SgExpression* argument_value, const vector>& commonVars, const FuncInfo* func) { string arg_to_replace_name = argument_to_replace->getValue(); if (expr->variant() == VAR_REF && expr->symbol()) { string arg_from_expr = getArgNameBySymbol(commonVars, func, expr->symbol(), globals, locals); if (arg_from_expr == arg_to_replace_name) return argument_value; else return expr; } // check if argument in expression bool symbol_in_expression = false; list to_process = { expr }; while (to_process.size() > 0) { SgExpression* cur_exp = to_process.front(); to_process.pop_front(); if (cur_exp && cur_exp->variant() != PROC_CALL && cur_exp->variant() != FUNC_CALL) if (cur_exp->symbol()) { SgArrayRefExp* array_expr = isSgArrayRefExp(cur_exp); if (array_expr) { if (array_expr->subscripts()) to_process.push_back(array_expr->subscripts()); } else if (cur_exp->variant() == VAR_REF && cur_exp->symbol()->identifier()) { string argName = getArgNameBySymbol(commonVars, func, cur_exp->symbol(), globals, locals); if (argName == arg_to_replace_name) { symbol_in_expression = true; to_process.clear(); break; } } } else { to_process.push_back(cur_exp->lhs()); to_process.push_back(cur_exp->rhs()); } } if (!symbol_in_expression) return expr; // perform substitution SgExpression* copy = expr->copyPtr(); to_process = { copy }; while (to_process.size() > 0) { SgExpression* cur_exp = to_process.front(); to_process.pop_front(); for (auto is_left : { true, false }) { SgExpression* sub_expr = is_left ? cur_exp->lhs() : cur_exp->rhs(); if (sub_expr && sub_expr->variant() != PROC_CALL && sub_expr->variant() != FUNC_CALL) if (sub_expr->symbol()) { SgArrayRefExp* array_expr = isSgArrayRefExp(sub_expr); if (array_expr) { if (array_expr->subscripts()) to_process.push_back(array_expr->subscripts()); } else if (sub_expr->variant() == VAR_REF && sub_expr->symbol()->identifier()) { string argName = getArgNameBySymbol(commonVars, func, sub_expr->symbol(), globals, locals); if (argName == arg_to_replace_name) if (sub_expr->type()->variant() == argument_value->type()->variant()) is_left ? cur_exp->setLhs(argument_value->copy()) : cur_exp->setRhs(argument_value->copy()); else return NULL; } } else to_process.push_back(sub_expr); } } return copy; } // replace chains like a->f(arg) by a->f(g()), where arg->g() // updates available and dependencies structures static bool joinChains(map& available, map>& dependencies, SAPFOR::Argument* arg, const vector>& commonVars, const FuncInfo* func) { auto arg_in_available = available.find(arg); if (arg_in_available == available.end()) return false; auto arg_in_dependencies = dependencies.find(arg); if (arg_in_dependencies == dependencies.end()) return false; SgExpression* arg_value = arg_in_available->second; // g() const auto& arg_dependencies = arg_in_dependencies->second; bool joined = false; for (auto& p : dependencies) { if (p.second.count(arg)) { SAPFOR::Argument* curr_var = p.first; // a variable auto available_it = available.find(curr_var); if (available_it != available.end()) { SgExpression* new_expr = substSingleSymb(available_it->second, arg, arg_value, commonVars, func); //f(g()) if (new_expr && new_expr != available_it->second) { p.second.erase(arg); p.second.insert(arg_dependencies.begin(), arg_dependencies.end()); available[curr_var] = new_expr; joined = true; } } } } return joined; } // sorts BasicBlocks from blocks in control flow order // pass ignored_edges for saving there back edges (used in live variable analysis) vector sortCfgNodes(const vector& blocks, set>* ignored_edges) { list seq_starts = { }; for (auto e : blocks) if (e->getInstructions().front()->isHeader()) seq_starts.push_front(e); else if(e->getPrev().size() == 0) seq_starts.push_back(e); if (blocks.size() == 0) return { }; // STEP 1: marks all back edges set> to_ignore; unordered_set in_process = { }; unordered_set visited = { }, all_visited = { }; unordered_set at_stack = { }; list processing_stack, processing_starts = seq_starts; at_stack.insert(seq_starts.begin(), seq_starts.end()); while (processing_starts.size() != 0) { auto start = processing_starts.front(); processing_starts.pop_front(); processing_stack = { start }; at_stack = { start }; while (processing_stack.size() != 0) { auto curr_it = processing_stack.end(); curr_it--; SAPFOR::BasicBlock* curr = *curr_it; in_process.insert(curr); bool next_added = false; for (auto next_node : curr->getNext()) { if (!to_ignore.count({ curr, next_node })) { if (in_process.count(next_node)) { // this is back edge to_ignore.insert({ curr, next_node }); } else if (!visited.count(next_node) && at_stack.insert(next_node).second) { processing_stack.push_back(next_node); next_added = true; } // if next_node has status visited then do nothing } } if (!next_added) { // mark as visited in_process.erase(curr); visited.insert(curr); processing_stack.erase(curr_it); at_stack.erase(curr); } } in_process.clear(); all_visited.insert(visited.begin(), visited.end()); visited.clear(); processing_stack.clear(); at_stack.clear(); if (processing_starts.size() == 0 && all_visited.size() < blocks.size()) { //find new entrypoint SAPFOR::BasicBlock* new_start = NULL; int linenum = 0; for (auto block : blocks) { if (all_visited.count(block) == 0) { int curr_line = block->getInstructions().front()->getInstruction()->getOperator()->lineNumber(); if (new_start == NULL || curr_line < linenum) { new_start = block; linenum = curr_line; } } } if(new_start == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); seq_starts.push_back(new_start); processing_starts.push_back(new_start); } } all_visited.clear(); // STEP 2: visit nodes and build sorted array vector result; for (const auto& start : seq_starts) processing_stack.push_back(start); in_process.insert(seq_starts.begin(), seq_starts.end()); while (processing_stack.size() != 0) { bool nodes_added = false; for (auto block_it = processing_stack.begin(); block_it != processing_stack.end();) { // check if block could be added to result bool add = true; auto block = *block_it; for (auto prev : block->getPrev()) if (!visited.count(prev) && !to_ignore.count({ prev, block })) add = false; if (add) { nodes_added = true; if (visited.insert(block).second) result.push_back(block); in_process.erase(block); block_it = processing_stack.erase(block_it); bool stack_empty = block_it == processing_stack.end(); for (auto next : block->getNext()) if (!visited.count(next) && in_process.insert(next).second) processing_stack.push_back(next); if (stack_empty) block_it = processing_stack.begin(); } else { block_it++; } } if (!nodes_added && processing_stack.size() != 0) { //there is some blocks in the stack but no one can be processed //this code should be unreachable #if DEBUG_CHECKS printInternalError(convertFileName(__FILE__).c_str(), __LINE__); #endif // DEBUG_CHECKS auto block = processing_stack.back(); processing_stack.pop_back(); in_process.erase(block); result.push_back(block); visited.insert(block); nodes_added = true; for (auto next : block->getNext()) if (!visited.count(next) && in_process.insert(next).second) processing_stack.push_back(next); } } #if DEBUG_CHECKS set verify_unique; verify_unique.insert(result.begin(), result.end()); if (verify_unique.size() != result.size()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); verify_unique.clear(); #endif // DEBUG_CHECKS #if DEBUG_CHECKS set all_blocks, res_blocks; all_blocks.insert(blocks.begin(), blocks.end()); res_blocks.insert(result.begin(), result.end()); if(res_blocks != all_blocks) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); #endif // DEBUG_CHECKS if (ignored_edges) ignored_edges->insert(to_ignore.begin(), to_ignore.end()); // return back edges if needed return result; } map> saved_available; map>> saved_dependencies; // save contents of available and dependencies for specified instruction. void save_chains(int instr_num, const map& available, const map>& dependencies, SAPFOR::Argument* arg) { map available_to_save; map> dependencies_to_save; set needed_vars, new_needed = { arg }; while (new_needed.size() != 0) { needed_vars = new_needed; new_needed = { }; for (auto e : needed_vars) { auto it_available = available.find(e); if (it_available == available.end()) continue; auto it_dependencies = dependencies.find(e); if (it_dependencies == dependencies.end()) continue; available_to_save.insert(*it_available); dependencies_to_save.insert(*it_dependencies); for (auto dep : it_dependencies->second) { if (!available_to_save.count(dep)) new_needed.insert(dep); } } } saved_available[instr_num] = available_to_save; saved_dependencies[instr_num] = dependencies_to_save; } // return number of instructions where we need to save data from available and dependencies set save_at_indexes(SAPFOR::BasicBlock* bb) { if (!bb || bb->getInstructions().size() == 0) return { }; int bb_start = bb->getInstructions().front()->getNumber(); int bb_end = bb->getInstructions().back()->getNumber(); set needed_indexes; for (auto p : bb->getRD_Out()) if (p.second.size() == 1 && *p.second.begin() >= bb_start && *p.second.begin() <= bb_end) needed_indexes.insert(*p.second.begin()); return needed_indexes; } bool isArgReaches(int decl_instr, SAPFOR::BasicBlock* decl_bb, SAPFOR::Argument* arg, SAPFOR::BasicBlock* dest_bb) { if (arg->getType() != CFG_ARG_TYPE::VAR) return false; const auto& RD_In_of_dest_bb = dest_bb->getRD_In(); auto dep_from_dest_bb_RD_In = RD_In_of_dest_bb.find(arg); if (dep_from_dest_bb_RD_In == RD_In_of_dest_bb.end()) return decl_bb->getRD_In().count(arg) == 0; const auto& RDs_for_arg = dep_from_dest_bb_RD_In->second; if (RDs_for_arg.size() == 1) { const int rd = *RDs_for_arg.begin(); if (rd >= decl_bb->getInstructions().front()->getNumber() && rd <= decl_bb->getInstructions().back()->getNumber()) return rd < decl_instr; } auto arg_in_from_decl_it = decl_bb->getRD_In().find(arg); if (arg_in_from_decl_it == decl_bb->getRD_In().end()) return false; if(arg_in_from_decl_it->second != RDs_for_arg) return false; set reachable = { decl_bb }; set banned_instructions; for (int instr_def : arg_in_from_decl_it->second) if (instr_def >= decl_instr || instr_def < decl_bb->getInstructions().front()->getNumber()) //try to find way [decl_bb] -> [dest_bb] with redefining of var (that means that var value from decl_bb could be overwrited) banned_instructions.insert(instr_def); set worklist = reachable, banned_blocks; bool way_found = false; while (worklist.size() != 0 && banned_instructions.size() != 0) { for (SAPFOR::BasicBlock* wl : worklist) { int start = wl->getInstructions().front()->getNumber(), end = wl->getInstructions().back()->getNumber(); for (auto banned_it = banned_instructions.begin(); banned_it != banned_instructions.end();) { if(start <= *banned_it && *banned_it <= end) { banned_it = banned_instructions.erase(banned_it); banned_blocks.insert(wl); } else { banned_it++; } } } set to_insert; for (auto b : worklist) for (auto next : b->getNext()) if (reachable.insert(next).second) to_insert.insert(next); worklist = to_insert; } reachable = banned_blocks; worklist = reachable; while (worklist.size() != 0 && banned_instructions.size() != 0) { if(worklist.find(dest_bb) != worklist.end()) return false; set to_insert; for (auto b : worklist) for (auto next : b->getNext()) if(next != decl_bb) if (reachable.insert(next).second) to_insert.insert(next); worklist = to_insert; } return true; } // return arg's definition if it really reaches dest_bb // else - return NULL. // dont alter returned expression. Otherwise Sage tree may change. // note: use this function only for decl_bb from the same routine as dest_bb SgExpression* getRd(int instr_num, SAPFOR::BasicBlock* decl_bb, SAPFOR::Argument* arg, SAPFOR::BasicBlock* dest_bb, map& available, map>& dependencies, const vector>& commonVars, FuncInfo* curr_func, const map& commonBlocks) { auto saved_available_it = saved_available.find(instr_num); auto saved_dependencies_it = saved_dependencies.find(instr_num); if (saved_available_it == saved_available.end() || saved_dependencies_it == saved_dependencies.end()) return NULL; map temp_available = saved_available_it->second; map> temp_dependencies = saved_dependencies_it->second; set arg_rd_dep; set prevents = { }; int joined = 0; bool all_dep_reaches = false; while (joined == prevents.size()) { prevents = { }; joined = 0; auto arg_rd_it = temp_available.find(arg); auto arg_dep_it = temp_dependencies.find(arg); if (arg_rd_it == temp_available.end() || arg_dep_it == temp_dependencies.end()) return NULL; for (auto e : arg_dep_it->second) if (!isArgReaches(instr_num, decl_bb, e, dest_bb)) prevents.insert(e); if (prevents.size() == 0) { all_dep_reaches = true; break; } for (auto e : prevents) if (joinChains(temp_available, temp_dependencies, e, commonVars, curr_func)) joined++; } if (!all_dep_reaches) return NULL; auto arg_rd_it = temp_available.find(arg); auto arg_dep_it = temp_dependencies.find(arg); if (arg_rd_it == temp_available.end() || arg_dep_it == temp_dependencies.end()) return NULL; SgExpression* new_exp = copyExpr(arg_rd_it->second, curr_func, commonBlocks); if (new_exp) { dependencies.insert(*arg_dep_it); available[arg] = new_exp; } return new_exp; } static SgExpression* replaceSingleConstRef(SgExpression* exp) { if (exp->variant() != CONST_REF) return NULL; SgExpression* ret = ReplaceParameter_(exp); int sign = 1; SgExpression* toCalc = ret; if (ret->variant() == UNARY_ADD_OP) toCalc = ret->lhs(); if (ret->variant() == MINUS_OP) { toCalc = ret->lhs(); sign = -1; } if (toCalc->isInteger()) return new SgValueExp(sign * toCalc->valueInteger()); else return exp; } static bool replaceConstantAndLink_(SgExpression* cur_exp, bool is_left, SgExpression* exp, SgExpression*& backup) { SgExpression* sub_expr = is_left ? cur_exp->lhs() : cur_exp->rhs(); SgExpression* after_subst; if (sub_expr) { if (after_subst = replaceSingleConstRef(sub_expr)) { if (after_subst != sub_expr) { if (backup == NULL) { backup = exp->copyPtr(); createLinksToCopy(backup, exp); } is_left ? cur_exp->setLhs(after_subst) : cur_exp->setRhs(after_subst); } return false; } return true; } return false; } static bool calculateAndLink_(SgExpression* cur_exp, bool is_left, SgExpression* exp, SgExpression*& backup) { int err, res; SgExpression* sub_expr = is_left ? cur_exp->lhs() : cur_exp->rhs(); if (sub_expr) { err = CalculateInteger(sub_expr, res); if (err != -1) { if (backup == NULL) { backup = exp->copyPtr(); createLinksToCopy(backup, exp); } is_left ? cur_exp->setLhs(new SgValueExp(res)) : cur_exp->setRhs(new SgValueExp(res)); return false; } return true; } return false; } // if replacement occurs, returns a new expression (the new expression is linked to the original one) // if there were no replacements, then returns NULL static SgExpression* replaceConstantAndLink(SgStatement* stmt, int i) { SgExpression* exp = stmt->expr(i); SgExpression* is_exp_constant = replaceSingleConstRef(exp); if (is_exp_constant != NULL) return is_exp_constant == exp ? NULL : is_exp_constant; SgExpression* backup = NULL; list to_process = { exp }; while (to_process.size() > 0) { SgExpression* cur_exp = to_process.front(); to_process.pop_front(); if (replaceConstantAndLink_(cur_exp, true, exp, backup)) to_process.push_back(cur_exp->lhs()); if (replaceConstantAndLink_(cur_exp, false, exp, backup)) to_process.push_back(cur_exp->rhs()); } int res; if (CalculateInteger(exp, res) != -1) { if (backup) stmt->setExpression(i, backup); return new SgValueExp(res); } to_process = { exp }; while (to_process.size() > 0) { SgExpression* cur_exp = to_process.front(); to_process.pop_front(); if (calculateAndLink_(cur_exp, true, exp, backup)) to_process.push_back(cur_exp->lhs()); if (calculateAndLink_(cur_exp, false, exp, backup)) to_process.push_back(cur_exp->rhs()); } if (backup) { stmt->setExpression(i, backup); return exp; } return NULL; } static void performExprSubstAndSave(SgStatement* stmt_to_subst, int i, const map& available, const vector>& commonVars, const FuncInfo* func, const map& funcByName) { SgExpression* expr_to_subst = stmt_to_subst->expr(i); SgExpression* expr_with_replacements = NULL; expr_with_replacements = performExprSubstAndLink(stmt_to_subst, i, available, commonVars, func, funcByName); if (expr_with_replacements != NULL) { replaceConstantRec(expr_with_replacements); calculate(expr_with_replacements); addReplacementAndBackup(current_file->filename(), stmt_to_subst, i, expr_with_replacements); } else { SgExpression* afterReplaceConstants = replaceConstantAndLink(stmt_to_subst, i); if (afterReplaceConstants != NULL) addReplacementAndBackup(current_file->filename(), stmt_to_subst, i, afterReplaceConstants); } } void buildSubstitutions(const map>& CFGraph_for_project, const map& commonBlocks, SgProject* project) { if (wereSubstitutionsBuilt()) return; resetSubstitutionCounter(); map funcByName; for (const auto& byFunc : CFGraph_for_project) funcByName[byFunc.first->funcName] = byFunc.first; map> commonArgsByFunc = { }; map> availableForFunc = { }; map>> dependenciesForFunc = { }; set analyzedFunctions = {}; for (auto& byFunc : CFGraph_for_project) { SgFile::switchToFile(byFunc.first->fileName); // skip ENTRY, analyze only original functions if (!(isSgProgHedrStmt(byFunc.first->funcPointer) || isSgProcHedrStmt(byFunc.first->funcPointer) || isSgFuncHedrStmt(byFunc.first->funcPointer)) || (analyzedFunctions.find(byFunc.first->funcName) != analyzedFunctions.end())) continue; analyzedFunctions.insert(byFunc.first->funcName); auto commonVars = getCommonsByFunction(current_file, byFunc.first->funcPointer, commonBlocks); const auto& commonArgs = getCommonArgsByFunc(byFunc.first, commonArgsByFunc, commonVars, globals, locals); unordered_set analyzedStmt; auto sortedCfgNodes = sortCfgNodes(byFunc.second); auto cfg_start_it = sortedCfgNodes.begin(); auto cfg_end_it = sortedCfgNodes.end(); for (auto cfg_it = cfg_start_it; cfg_it < cfg_end_it; cfg_it++) { SAPFOR::BasicBlock* cur_BB = *cfg_it; map available; //available definitions map> dependencies; set idx_to_save = save_at_indexes(cur_BB); auto idx_it = idx_to_save.begin(); auto idx_end_it = idx_to_save.end(); for (const auto& in_val : cur_BB->getRD_In()) { if (in_val.first->getType() == CFG_ARG_TYPE::VAR && in_val.second.size() == 1) { int instr_num = *(in_val.second.begin()); if (instr_num < 0) continue; auto cfg_find_bb = cfg_it + 1; SAPFOR::BasicBlock* in_val_bb = NULL; do { cfg_find_bb--; if ((*cfg_find_bb)->getInstructions().front()->getNumber() <= instr_num && (*cfg_find_bb)->getInstructions().back()->getNumber() >= instr_num) { in_val_bb = *cfg_find_bb; break; } } while (cfg_find_bb > cfg_start_it); if (in_val_bb) { SgExpression* rd = getRd(instr_num, in_val_bb, in_val.first, cur_BB, available, dependencies, commonVars, byFunc.first, commonBlocks); } else { pair instr_and_bb = getInstructionAndBlockByNumber(CFGraph_for_project, instr_num); if (getDependencies(in_val.first, instr_and_bb.first, instr_and_bb.second, dependencies)) { //check if all variables affecting the definition can be used there bool can_use = true; auto dependencies_of_var = dependencies.find(in_val.first); if (dependencies_of_var == dependencies.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (SAPFOR::Argument* dep : dependencies_of_var->second) { if (!isArgReaches(instr_num, instr_and_bb.second, dep, cur_BB)) { can_use = false; break; } if (dep->getMemType() == CFG_MEM_TYPE::COMMON_ && commonArgs.find(dep->getValue()) == commonArgs.end()) { can_use = false; break; } } if (can_use && isBBlockFromCurrentFile(CFGraph_for_project, instr_and_bb.second)) { SgExpression* expr_to_subst = copyExpr(instr_and_bb.first->getOperator()->expr(1), byFunc.first, commonBlocks); if (expr_to_subst) available[in_val.first] = expr_to_subst; } } } } } vector arguments_of_func_call = { }; SgStatement* prev_stmt = NULL; for (SAPFOR::IR_Block* byIR : cur_BB->getInstructions()) { SAPFOR::Instruction* instruction = byIR->getInstruction(); int instruction_number = instruction->getNumber(); SAPFOR::CFG_OP instr_type = instruction->getOperation(); SAPFOR::Argument* instr_res = hasStoreStructure(instr_type) ? instruction->getArg1() : instruction->getResult(); SgStatement* cur_stmt = instruction->getOperator(); bool stmt_has_result = cur_stmt ? cur_stmt->variant() == ASSIGN_STAT : false; if (cur_stmt && cur_stmt != prev_stmt && isIfOrLoopFromBB(cur_stmt, cur_BB) && cur_stmt->variant() != READ_STAT && analyzedStmt.insert(cur_stmt).second) { prev_stmt = cur_stmt; int start_with_expression = 0; if (stmt_has_result) { start_with_expression = 1; SgExpression* result_of_stmt = cur_stmt->expr(0); SgArrayRefExp* array_ref; if (result_of_stmt && (array_ref = isSgArrayRefExp(result_of_stmt)) && array_ref->subscripts()) performExprSubstAndSave(cur_stmt, 0, available, commonVars, byFunc.first, funcByName); } for (int i = start_with_expression; i < 3; i++) if (cur_stmt->expr(i)) performExprSubstAndSave(cur_stmt, i, available, commonVars, byFunc.first, funcByName); } if (instr_res) { if (instr_res->getType() == CFG_ARG_TYPE::VAR || instr_res->getType() == CFG_ARG_TYPE::ARRAY) { if (instr_res->getType() == CFG_ARG_TYPE::VAR) { joinChains(available, dependencies, instr_res, commonVars, byFunc.first); SgExpression* prev_expr = NULL; set prev_dep = {}; auto available_it = available.find(instr_res); if (available_it != available.end()) { prev_expr = available_it->second; auto dependencies_it = dependencies.find(instr_res); if (dependencies_it != dependencies.end()) prev_dep = dependencies_it->second; else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); available.erase(available_it); } if (cur_stmt && stmt_has_result && getDependencies(instr_res, instruction, cur_BB, dependencies)) { SgExpression* expr_to_subst = copyExpr(cur_stmt->expr(1), byFunc.first, commonBlocks); auto dependencies_it = dependencies.find(instr_res); if (dependencies_it != dependencies.end()) { if (dependencies_it->second.count(instr_res) && prev_expr != NULL) { SgExpression* next_expr_to_subst = substSingleSymb(expr_to_subst, instr_res, prev_expr, commonVars, byFunc.first); if (next_expr_to_subst && next_expr_to_subst != expr_to_subst) { expr_to_subst = next_expr_to_subst; dependencies_it->second.erase(instr_res); dependencies_it->second.insert(prev_dep.begin(), prev_dep.end()); } } } if (expr_to_subst) available[instr_res] = expr_to_subst; } } for (const auto& p : dependencies) if (p.second.count(instr_res)) available.erase(p.first); while (idx_it != idx_end_it && *idx_it < instruction_number) idx_it++; if (idx_it != idx_end_it && *idx_it == instruction_number) save_chains(instruction_number, available, dependencies, instr_res); } } if (instr_type == CFG_OP::PARAM) arguments_of_func_call.push_back(instruction->getArg1()); if (instr_type == CFG_OP::F_CALL) { string func_name = instruction->getArg1()->getValue(); auto func_to_call_it = CFGraph_for_project.begin(); auto end_of_CFG = CFGraph_for_project.end(); for (; func_to_call_it != end_of_CFG; func_to_call_it++) { const auto& p = func_to_call_it->first; if (p->funcName == func_name) break; } if (func_to_call_it != end_of_CFG) { FuncInfo* func = func_to_call_it->first; int number_of_params = arguments_of_func_call.size(); for (int i = 0; i < number_of_params; i++) { if (!func->funcParams.isArgOut(i)) arguments_of_func_call[i] = NULL; } const set& affected_vars = func_affects(func, func_to_call_it->second); for (auto& affected : affected_vars) { joinChains(available, dependencies, affected, commonVars, byFunc.first); for (const auto& p : dependencies) if (p.second.count(affected)) available.erase(p.first); if (available.count(affected)) available.erase(affected); } auto add_to_available = func_makes_available(func, project, availableForFunc, dependenciesForFunc, func_to_call_it->second, CFGraph_for_project, dependencies, byFunc.first, commonBlocks); available.insert(add_to_available.begin(), add_to_available.end()); } for (auto& func_arg : arguments_of_func_call) if (func_arg && func_arg->getType() != SAPFOR::CFG_ARG_TYPE::CONST && func_arg->getType() != SAPFOR::CFG_ARG_TYPE::CONST_STR) { joinChains(available, dependencies, func_arg, commonVars, byFunc.first); for (const auto& p : dependencies) if (p.second.count(func_arg)) available.erase(p.first); available.erase(func_arg); } arguments_of_func_call.clear(); } } } locals.clear(); saved_available.clear(); saved_dependencies.clear(); } setSubstitutionsWereBuilt(true); } void performRDSubst(const map>& CFGraph_for_project, const map& commonBlocks, SgProject* project) { if (!wereSubstitutionsBuilt()) buildSubstitutions(CFGraph_for_project, commonBlocks, project); else updateOldExpression(); __spf_print(PRINT_PROF_INFO, "total number of substitutions: %d\n", getSubstitutionCounter()); if (!wereSubstitutionsApplied()) { applyReplacement(replacementsInFiles); setSubstitutionsApplied(true); } } void revertSubstitutions() { if (wereSubstitutionsBuilt() && wereSubstitutionsApplied()) { applyReplacement(oldExpressionsInFile); setSubstitutionsApplied(false); } } void cancelRevertionForStatement(string filename, SgStatement* stmt, int i) { if (i < 0 || i > 2 || !stmt) return; removeInfo(oldExpressionsInFile, filename, stmt, i); removeInfo(replacementsInFiles, filename, stmt, i); } /*void destroyReplacementsInFiles() { replacementsInFiles.clear(); setSubstitutionsWereBuilt(false); } void destroyOldExpressionsInFile() { oldExpressionsInFile.clear(); setSubstitutionsWereBuilt(false); } void destroyAllSubstitutionsData() { destroyReplacementsInFiles(); destroyOldExpressionsInFile(); setSubstitutionsWereBuilt(false); setSubstitutionsApplied(false); }*/