StatementAssign * StatementAssign::make_possible_compound_assign(CGContext &cg_context, const Type *type, const Lhs &l, eAssignOps op, const Expression &e) { eBinaryOps bop = compound_to_binary_ops(op); const Expression *rhs = NULL; SafeOpFlags *fs = NULL; std::string tmp1; std::string tmp2; if (bop != MAX_BINARY_OP) { SafeOpFlags *local_fs = NULL; FunctionInvocation* fi = NULL; if (safe_assign(op)) { local_fs = SafeOpFlags::make_dummy_flags(); fi = new FunctionInvocationBinary(bop, local_fs); } else { local_fs = SafeOpFlags::make_random_binary(type, &(l.get_type()), &(l.get_type()), sOpAssign, bop); ERROR_GUARD(NULL); fi = FunctionInvocationBinary::CreateFunctionInvocationBinary(cg_context, bop, local_fs); tmp1 = dynamic_cast<FunctionInvocationBinary*>(fi)->get_tmp_var1(); tmp2 = dynamic_cast<FunctionInvocationBinary*>(fi)->get_tmp_var2(); } fs = local_fs->clone(); fi->add_operand(new ExpressionVariable(*(l.get_var()), &l.get_type())); fi->add_operand(e.clone()); rhs = new ExpressionFuncall(*fi); } else { rhs = &e; #if 0 if (e.term_type == eFunction) { const ExpressionFuncall* func = dynamic_cast<const ExpressionFuncall*>(&e); if (!func->get_invoke().safe_invocation()) { fs = SafeOpFlags::make_dummy_flags(); fs = NULL; } } #endif if (op != eSimpleAssign) { fs = SafeOpFlags::make_random_binary(type, &(l.get_type()), &(rhs->get_type()), sOpAssign, bop); bool op1 = fs->get_op1_sign(); bool op2 = fs->get_op2_sign(); enum SafeOpSize size = fs->get_op_size(); eSimpleType type1 = SafeOpFlags::flags_to_type(op1, size); eSimpleType type2 = SafeOpFlags::flags_to_type(op2, size); const Block *blk = cg_context.get_current_block(); assert(blk); tmp1 = blk->create_new_tmp_var(type1); tmp2 = blk->create_new_tmp_var(type2); ERROR_GUARD(NULL); } } StatementAssign *sa = new StatementAssign(cg_context.get_current_block(), l, op, e, rhs, fs, tmp1, tmp2); return sa; }
FunctionInvocation * FunctionInvocation::make_random_binary(CGContext &cg_context, const Type* type) { DEPTH_GUARD_BY_TYPE_RETURN(dtFunctionInvocationRandomBinary, NULL); if (rnd_flipcoin(10) && Type::has_pointer_type()) { ERROR_GUARD(NULL); return make_random_binary_ptr_comparison(cg_context); } eBinaryOps op; do { op = (eBinaryOps)(rnd_upto(MAX_BINARY_OP, BINARY_OPS_PROB_FILTER)); } while (type->is_float() && !BinaryOpWorksForFloat(op)); ERROR_GUARD(NULL); assert(type); SafeOpFlags *flags = SafeOpFlags::make_random_binary(type, NULL, NULL, sOpBinary, op); assert(flags); ERROR_GUARD(NULL); FunctionInvocationBinary *fi = FunctionInvocationBinary::CreateFunctionInvocationBinary(cg_context, op, flags); Effect lhs_eff_accum; CGContext lhs_cg_context(cg_context, cg_context.get_effect_context(), &lhs_eff_accum); // Generate an expression with the correct type required by safe math operands const Type* lhs_type = flags->get_lhs_type(); const Type* rhs_type = flags->get_rhs_type(); assert(lhs_type && rhs_type); if (!BinaryOpWorksForFloat(op)) { assert(!lhs_type->is_float() && "lhs_type is float!"); assert(!rhs_type->is_float() && "rhs_type is float!"); } Expression *lhs = Expression::make_random(lhs_cg_context, lhs_type); ERROR_GUARD_AND_DEL1(NULL, fi); Expression *rhs = 0; cg_context.merge_param_context(lhs_cg_context, true); FactMgr* fm = get_fact_mgr(&cg_context); vector<const Fact*> facts_copy = fm->global_facts; #if 0 if (lhs->term_type == eVariable) { lhs_eff_accum.read_deref_volatile((ExpressionVariable*)lhs); } #endif // If we are guaranteed that the LHS will be evaluated before the RHS, // or if the LHS is pure (not merely side-effect-free), // then we can generate the RHS under the original effect context. if (IsOrderedStandardFunc(op)) { // || lhs_eff_accum.is_pure()) { TODO: need more thoughts on the purity issue. rhs = Expression::make_random(cg_context, rhs_type); } else { // Otherwise, the RHS must be generated under the combined effect // of the original effect and the LHS effect. Effect rhs_eff_context(cg_context.get_effect_context()); rhs_eff_context.add_effect(lhs_eff_accum, true); Effect rhs_eff_accum; CGContext rhs_cg_context(cg_context, rhs_eff_context, &rhs_eff_accum); if (op == eLShift || op == eRShift) { eTermType tt = MAX_TERM_TYPES; bool not_constant = rnd_flipcoin(ShiftByNonConstantProb); // avoid shifting negative or too much if (!not_constant) { rhs = Constant::make_random_upto(lhs_type->SizeInBytes() * 8); } else { rhs = Expression::make_random(rhs_cg_context, rhs_type, NULL, false, true, tt); } } else { rhs = Expression::make_random(rhs_cg_context, rhs_type); // avoid divide by zero or possible zero (reached by pointer comparison) if ((op == eMod || op == eDiv) && (rhs->equals(0) || rhs->is_0_or_1()) && !lhs_type->is_float() && !rhs_type->is_float()) { VectorFilter f; f.add(eMod).add(eDiv).add(eLShift).add(eRShift); op = (eBinaryOps)(rnd_upto(MAX_BINARY_OP, &f)); fi->set_operation(op); } } cg_context.merge_param_context(rhs_cg_context, true); } ERROR_GUARD_AND_DEL2(NULL, fi, lhs); if (!BinaryOpWorksForFloat(op)) { assert(!lhs->get_type().is_float() && "lhs is of float!"); assert(!rhs->get_type().is_float() && "rhs is of float!"); } if (CompatibleChecker::compatible_check(lhs, rhs)) { Error::set_error(COMPATIBLE_CHECK_ERROR); delete lhs; delete rhs; delete fi; return NULL; } // ordered operators such as "||" or "&&" may skip the 2nd parameter if (IsOrderedStandardFunc(op)) { fm->makeup_new_var_facts(facts_copy, fm->global_facts); merge_facts(fm->global_facts, facts_copy); } // TODO: fix `rhs' for eLShift and eRShift and ... // Currently, the "fix" is handled in `FunctionInvocationBinary::Output'. fi->param_value.push_back(lhs); fi->param_value.push_back(rhs); return fi; }