/*************************************************************************************** * for a given input env, abstract a given statement, generate an output env, and * update both input/output env for this statement * * shortcut: if this input env matches previous input env, use previous output env directly ***************************************************************************************/ bool Statement::validate_and_update_facts(vector<const Fact*>& inputs, CGContext& cg_context) const { FactMgr* fm = get_fact_mgr_for_func(func); int shortcut = shortcut_analysis(inputs, cg_context); if (shortcut==0) { /* mark the goto statements inside this statement as visited this is to fix scenario like the following: lbl: s1 for (...) { goto lbl; } where the "for" statement is bypassed, but the output from "goto lbl" must be feed into s1 in order to achieve a fixed point */ for (size_t i=0; i<fm->cfg_edges.size(); i++) { const Statement* s = fm->cfg_edges[i]->src; if (s->eType == eGoto && contains_stmt(s)) { fm->map_visited[s] = true; } } return true; } if (shortcut==1) return false; vector<const Fact*> inputs_copy = inputs; if (!stm_visit_facts(inputs, cg_context)) { return false; } fm->set_fact_in(this, inputs_copy); fm->set_fact_out(this, inputs); return true; }
/**************************************************************************** * Entry point to pointer analysis and other DFA analysis for newly * created statement. remember some analysis has already been done during the * statement generation, some analysis work is only possible with a complete * statement, we do it here ****************************************************************************/ void Statement::post_creation_analysis(vector<const Fact*>& pre_facts, const Effect& pre_effect, CGContext& cg_context) const { FactMgr* fm = get_fact_mgr_for_func(func); if (eType == eIfElse) { ((const StatementIf*)this)->combine_branch_facts(pre_facts); } else { fm->makeup_new_var_facts(pre_facts, fm->global_facts); } // save the effect for this statement if this is a simple statement // for compound statements, it's effect is saved in make_random if (!is_compound(eType)) { fm->map_stm_effect[this] = cg_context.get_effect_stm(); } bool special_handled = false; // special handling for non-looping statements in func_1, which we never re-visit to // save run-time if (cg_context.get_current_func()->name == "func_1" && !(cg_context.flags & IN_LOOP) ) { if (has_uncertain_call_recursive()) { FactVec outputs = pre_facts; cg_context.reset_effect_accum(pre_effect); //if (stm_id == 573) /*if (this->eType == eAssign) { ((const StatementAssign*)this)->get_rhs()->indented_output(cout, 0); } cout << endl; Output(cout, fm);*/ //} if (!validate_and_update_facts(outputs, cg_context)) { assert(0); } fm->global_facts = outputs; special_handled = true; } } if (!special_handled) { // for if...else..., we don't want to walk through the true branch and false branch again // compute the output with consideration of return statement(s) in both branches if (eType == eAssign) { const StatementAssign* sa = (const StatementAssign*)this; // abstract fact for assignment itself. No analysis on function calls // on RHS since they are already handled during statement generation FactMgr::update_fact_for_assign(sa, fm->global_facts); } else if (eType == eReturn) { const StatementReturn* sr = (const StatementReturn*)this; FactMgr::update_fact_for_return(sr, fm->global_facts); } } fm->remove_rv_facts(fm->global_facts); fm->set_fact_in(this, pre_facts); fm->set_fact_out(this, fm->global_facts); fm->map_accum_effect[this] = *(cg_context.get_effect_accum()); fm->map_visited[this] = true; }
/************************************************************************************************** * DFA analysis for a block: * * we must considers all kinds of blocks: block for for-loops; block for if-true and if-false; block for * function body; block that loops; block has jump destination insdie; block being a jump destination itself * (in the case of "continue" in for-loops). All of them must be taken care in this function. * * params: * inputs: the inputs env before entering block * cg_context: code generation context * fail_index: records which statement in this block caused analyzer to fail * visit_one: when is true, the statements in this block must be visited at least once ****************************************************************************************************/ bool Block::find_fixed_point(vector<const Fact*> inputs, vector<const Fact*>& post_facts, CGContext& cg_context, int& fail_index, bool visit_once) const { FactMgr* fm = get_fact_mgr(&cg_context); // include outputs from all back edges leading to this block size_t i; static int g = 0; vector<const CFGEdge*> edges; int cnt = 0; do { // if we have never visited the block, force the visitor to go through all statements at least once if (fm->map_visited[this]) { if (cnt++ > 7) { // takes too many iterations to reach a fixed point, must be something wrong assert(0); } find_edges_in(edges, false, true); for (i=0; i<edges.size(); i++) { const Statement* src = edges[i]->src; //assert(fm->map_visited[src]); merge_facts(inputs, fm->map_facts_out[src]); } } if (!visit_once) { int shortcut = shortcut_analysis(inputs, cg_context); if (shortcut == 0) return true; } //if (shortcut == 1) return false; FactVec outputs = inputs; // add facts for locals for (i=0; i<local_vars.size(); i++) { const Variable* v = local_vars[i]; FactMgr::add_new_var_fact(v, outputs); } // revisit statements with new inputs for (i=0; i<stms.size(); i++) { int h = g++; if (h == 2585) BREAK_NOP; // for debugging if (!stms[i]->analyze_with_edges_in(outputs, cg_context)) { fail_index = i; return false; } } fm->set_fact_in(this, inputs); post_facts = outputs; FactMgr::update_facts_for_oos_vars(local_vars, outputs); fm->set_fact_out(this, outputs); fm->map_visited[this] = true; // compute accumulated effect set_accumulated_effect(cg_context); visit_once = false; } while (true); return true; }
Block * Block::make_dummy_block(CGContext &cg_context) { Function *curr_func = cg_context.get_current_func(); assert(curr_func); Block *b = new Block(cg_context.get_current_block(), 0); b->func = curr_func; b->in_array_loop = !(cg_context.iv_bounds.empty()); curr_func->blocks.push_back(b); curr_func->stack.push_back(b); FactMgr* fm = get_fact_mgr_for_func(curr_func); fm->set_fact_in(b, fm->global_facts); Effect pre_effect = cg_context.get_accum_effect(); b->post_creation_analysis(cg_context, pre_effect); curr_func->stack.pop_back(); return b; }
Statement* Block::append_return_stmt(CGContext& cg_context) { FactMgr* fm = get_fact_mgr_for_func(func); FactVec pre_facts = fm->global_facts; cg_context.get_effect_stm().clear(); Statement* sr = Statement::make_random(cg_context, eReturn); ERROR_GUARD(NULL); stms.push_back(sr); fm->makeup_new_var_facts(pre_facts, fm->global_facts); assert(sr->visit_facts(fm->global_facts, cg_context)); fm->set_fact_in(sr, pre_facts); fm->set_fact_out(sr, fm->global_facts); fm->map_accum_effect[sr] = *(cg_context.get_effect_accum()); fm->map_visited[sr] = true; //sr->post_creation_analysis(pre_facts, cg_context); fm->map_accum_effect[this] = *(cg_context.get_effect_accum()); fm->map_stm_effect[this].add_effect(fm->map_stm_effect[sr]); return sr; }
Statement* Block::append_nested_loop(CGContext& cg_context) { FactMgr* fm = get_fact_mgr_for_func(func); FactVec pre_facts = fm->global_facts; cg_context.get_effect_stm().clear(); Statement* sf = HYPOTHESIS_DRAW(Statement, cg_context, eFor); ERROR_GUARD(NULL); stms.push_back(sf); fm->makeup_new_var_facts(pre_facts, fm->global_facts); //assert(sf->visit_facts(fm->global_facts, cg_context)); fm->set_fact_in(sf, pre_facts); fm->set_fact_out(sf, fm->global_facts); fm->map_accum_effect[sf] = *(cg_context.get_effect_accum()); fm->map_visited[sf] = true; //sf->post_creation_analysis(pre_facts, cg_context); fm->map_accum_effect[this] = *(cg_context.get_effect_accum()); fm->map_stm_effect[this].add_effect(fm->map_stm_effect[sf]); return sf; }
Block * Block::make_random(CGContext &cg_context, bool looping) { //static int bid = 0; DEPTH_GUARD_BY_TYPE_RETURN(dtBlock, NULL); Function *curr_func = cg_context.get_current_func(); assert(curr_func); Block *b = new Block(cg_context.get_current_block(), CGOptions::max_block_size()); b->func = curr_func; b->looping = looping; // if there are induction variables, we are in a loop that traverses array(s) b->in_array_loop = !(cg_context.iv_bounds.empty()); //b->stm_id = bid++; // Push this block onto the variable scope stack. curr_func->stack.push_back(b); curr_func->blocks.push_back(b); // record global facts at this moment so that subsequent statement // inside the block doesn't ruin it FactMgr* fm = get_fact_mgr_for_func(curr_func); fm->set_fact_in(b, fm->global_facts); Effect pre_effect = cg_context.get_accum_effect(); unsigned int max = BlockProbability(*b); if (Error::get_error() != SUCCESS) { curr_func->stack.pop_back(); delete b; return NULL; } unsigned int i; if (b->stm_id == 1) BREAK_NOP; // for debugging for (i = 0; i <= max; ++i) { Statement *s = HYPOTHESIS_DRAW(Statement, cg_context); // In the exhaustive mode, Statement::make_random could return NULL; if (!s) break; b->stms.push_back(s); if (s->must_return()) { break; } } if (Error::get_error() != SUCCESS) { curr_func->stack.pop_back(); delete b; return NULL; } // append nested loop if some must-read/write variables hasn't been accessed if (b->need_nested_loop(cg_context) && cg_context.blk_depth < CGOptions::max_blk_depth()) { b->append_nested_loop(cg_context); } // perform DFA analysis after creation b->post_creation_analysis(cg_context, pre_effect); if (Error::get_error() != SUCCESS) { curr_func->stack.pop_back(); delete b; return NULL; } curr_func->stack.pop_back(); if (Error::get_error() != SUCCESS) { //curr_func->stack.pop_back(); delete b; return NULL; } // ISSUE: in the exhaustive mode, do we need a return statement here // if the last statement is not? Error::set_error(SUCCESS); return b; }