const Variable* StatementFor::make_iteration(CGContext& cg_context, StatementAssign*& init, Expression*& test, StatementAssign*& incr, unsigned int& bound) { FactMgr* fm = get_fact_mgr(&cg_context); assert(fm); Block* blk = cg_context.get_current_block(); assert(blk); // save a copy of facts env and context vector<const Fact*> facts_copy = fm->global_facts; cg_context.get_effect_stm().clear(); // Select the loop control variable, avoid volatile vector<const Variable*> invalid_vars; Variable *var = NULL; do { var = VariableSelector::SelectLoopCtrlVar(cg_context, invalid_vars); ERROR_GUARD(NULL); if (var->is_volatile()) { invalid_vars.push_back(var); } else { break; } } while (true); bool read = cg_context.read_indices(var, fm->global_facts); assert(read); cg_context.write_var(var); cg_context.read_var(var); // Select the loop parameters: init, limit, increment, etc. int init_n, limit_n, incr_n; eBinaryOps test_op; eAssignOps incr_op; bound = INVALID_BOUND; // choose a random array from must use variables, and find the dimension with shortest length // JYTODO: be more aggressive? if (cg_context.rw_directive) { vector<const Variable*> arrays; cg_context.rw_directive->find_must_use_arrays(arrays); if (!arrays.empty()) { const ArrayVariable* av = dynamic_cast<const ArrayVariable*>(VariableSelector::choose_ok_var(arrays)); assert(av); for (size_t i=0; i<av->get_dimension(); i++) { if (av->get_sizes()[i] < bound) { bound = av->get_sizes()[i]; } } } } if (bound != INVALID_BOUND) { bound = make_random_array_control(--bound, init_n, limit_n, incr_n, test_op, incr_op, var->type->is_signed()); } else { assert(var->type); make_random_loop_control(init_n, limit_n, incr_n, test_op, incr_op, var->type->is_signed()); } ERROR_GUARD(NULL); // Build the IR for the subparts of the loop. Constant * c_init = Constant::make_int(init_n); ERROR_GUARD(NULL); // if we chose control variable wisely, this should never return false assert(var); Lhs* lhs = new Lhs(*var); ERROR_GUARD_AND_DEL1(NULL, c_init); eBinaryOps bop = StatementAssign::compound_to_binary_ops(incr_op); SafeOpFlags *flags1 = SafeOpFlags::make_random_binary(var->type, var->type, var->type, sOpAssign, bop); ERROR_GUARD_AND_DEL2(NULL, c_init, lhs); init = new StatementAssign(cg_context.get_current_block(), *lhs, *c_init, eSimpleAssign, flags1); ERROR_GUARD_AND_DEL3(NULL, c_init, lhs, flags1); bool visited = init->visit_facts(fm->global_facts, cg_context); assert(visited); assert(var); ExpressionVariable *v = new ExpressionVariable(*var); Bookkeeper::record_volatile_access(v->get_var(), v->get_indirect_level(), false); Bookkeeper::record_volatile_access(v->get_var(), v->get_indirect_level(), true); Constant *c_limit = Constant::make_int(limit_n); ERROR_GUARD_AND_DEL2(NULL, init, v); FunctionInvocation *invocation = FunctionInvocation::make_binary(cg_context, test_op, v, c_limit); ERROR_GUARD_AND_DEL3(NULL, init, v, c_limit); test = new ExpressionFuncall(*invocation); // canonize before validation //const ExpressionVariable exp_var(*var); //const FunctionInvocationBinary fb(eAdd, &exp_var, c_incr); //const ExpressionFuncall funcall(fb); Lhs *lhs1 = dynamic_cast<Lhs*>(lhs->clone()); //SafeOpFlags *flags2 = SafeOpFlags::make_random(sOpAssign); ERROR_GUARD_AND_DEL3(NULL, init, test, lhs1); Constant * c_incr = Constant::make_int(incr_n); ERROR_GUARD_AND_DEL3(NULL, init, test, lhs1); if (bound != INVALID_BOUND) { incr = new StatementAssign(cg_context.get_current_block(), *lhs1, *c_incr, incr_op); } else { incr = StatementAssign::make_possible_compound_assign(cg_context, &(v->get_type()), *lhs1, incr_op, *c_incr); } return var; }
ExpressionVariable * ExpressionVariable::make_random(CGContext &cg_context, const Type* type, const CVQualifiers* qfer, bool as_param, bool as_return) { DEPTH_GUARD_BY_TYPE_RETURN(dtExpressionVariable, NULL); Function *curr_func = cg_context.get_current_func(); FactMgr* fm = get_fact_mgr_for_func(curr_func); vector<const Variable*> dummy; // save current effects, in case we need to reset Effect eff_accum = cg_context.get_accum_effect(); Effect eff_stmt = cg_context.get_effect_stm(); ExpressionVariable *ev = 0; do { const Variable* var = 0; // try to use one of must_read_vars in CGContext var = VariableSelector::select_must_use_var(Effect::READ, cg_context, type, qfer); if (var == NULL) { var = VariableSelector::select(Effect::READ, cg_context, type, qfer, dummy, eFlexible); } ERROR_GUARD(NULL); if (!var) continue; if (!type->is_float() && var->type->is_float()) continue; // forbid a parameter to take the address of an argument // this is to simplify the path shortcutting delta if (as_param && var->is_argument() && var->type->is_dereferenced_from(type)) { continue; } if (!CGOptions::addr_taken_of_locals() && var->type->is_dereferenced_from(type) && (var->is_argument() || var->is_local())) { continue; } // forbid a escaping pointer to take the address of an argument or a local variable int indirection = var->type->get_indirect_level() - type->get_indirect_level(); if (as_return && CGOptions::no_return_dead_ptr() && FactPointTo::is_pointing_to_locals(var, cg_context.get_current_block(), indirection, fm->global_facts)) { continue; } int valid = FactPointTo::opportunistic_validate(var, type, fm->global_facts); if (valid) { ExpressionVariable tmp(*var, type); if (tmp.visit_facts(fm->global_facts, cg_context)) { ev = tmp.get_indirect_level() == 0 ? new ExpressionVariable(*var) : new ExpressionVariable(*var, type); cg_context.curr_blk = cg_context.get_current_block(); break; } else { cg_context.reset_effect_accum(eff_accum); cg_context.reset_effect_stm(eff_stmt); } } dummy.push_back(var); } while (true); // statistics int deref_level = ev->get_indirect_level(); if (deref_level > 0) { incr_counter(Bookkeeper::read_dereference_cnts, deref_level); } if (deref_level < 0) { Bookkeeper::record_address_taken(ev->get_var()); } Bookkeeper::record_volatile_access(ev->get_var(), deref_level, false); return ev; }