FunctionInvocation * FunctionInvocation::make_random_unary(CGContext &cg_context, const Type* type) { DEPTH_GUARD_BY_TYPE_RETURN(dtFunctionInvocationRandomUnary, NULL); assert(type); eUnaryOps op = (eUnaryOps)(rnd_upto(MAX_UNARY_OP, UNARY_OPS_PROB_FILTER)); ERROR_GUARD(NULL); SafeOpFlags *flags = NULL; if (op == eMinus && type->eType != eVector) { flags = SafeOpFlags::make_random(sOpUnary); ERROR_GUARD(NULL); type = flags->get_lhs_type(); assert(type); } // Type restirctions for vectors. if (type->eType == eVector) { // Not returns signed type. if (!type->is_signed() && op == eNot) { op = ePlus; } // Unlikely, but ++ and -- might overflow. if (type->is_signed() && (op == ePlus || op == eMinus)) { op = eNot; } } FunctionInvocation *fi = FunctionInvocationUnary::CreateFunctionInvocationUnary(cg_context, op, flags); Expression *operand = Expression::make_random(cg_context, type); ERROR_GUARD_AND_DEL1(NULL, fi); fi->param_value.push_back(operand); return fi; }
FunctionInvocation * FunctionInvocation::make_random_unary(CGContext &cg_context, const Type* type) { DEPTH_GUARD_BY_TYPE_RETURN(dtFunctionInvocationRandomUnary, NULL); assert(type); eUnaryOps op; do { op = (eUnaryOps)(rnd_upto(MAX_UNARY_OP, UNARY_OPS_PROB_FILTER)); } while (type->is_float() && !UnaryOpWorksForFloat(op)); ERROR_GUARD(NULL); SafeOpFlags *flags = NULL; flags = SafeOpFlags::make_random_unary(type, NULL, op); ERROR_GUARD(NULL); type = flags->get_lhs_type(); assert(type); FunctionInvocation *fi = FunctionInvocationUnary::CreateFunctionInvocationUnary(cg_context, op, flags); Expression *operand = Expression::make_random(cg_context, type); ERROR_GUARD_AND_DEL1(NULL, fi); fi->param_value.push_back(operand); return fi; }
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() && type->eType != eVector) { ERROR_GUARD(NULL); return make_random_binary_ptr_comparison(cg_context); } eBinaryOps op = (eBinaryOps)(rnd_upto(MAX_BINARY_OP, BINARY_OPS_PROB_FILTER)); ERROR_GUARD(NULL); assert(type); SafeOpFlags *flags = SafeOpFlags::make_random(sOpBinary, op); assert(flags); ERROR_GUARD(NULL); // Special stuff for vectors. if (type->eType == eVector) { // Only signed type can use logicals. Also no div or mod. // TODO: Instead of changing the op, flip the sign of the type. if (!type->is_signed() && ( op==eCmpGt || op==eCmpLt || op==eCmpGe || op==eCmpLe || op==eCmpEq || op==eCmpNe || op==eAnd || op==eOr || op==eDiv || op==eMod)) { op = eAdd; } // Only unsigned can use unsafe ops. if (type->is_signed() && ( op==eAdd || op==eSub || op==eMul || op==eDiv || op==eMod || op==eRShift || op==eLShift)) { op = eAnd; } delete flags; flags = SafeOpFlags::make_dummy_flags(); } 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(); // More special stuff for vectors. if (type->eType == eVector) { lhs_type = type; rhs_type = type; } assert(lhs_type && rhs_type); 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 = lhs_type->eType == eVector ? dynamic_cast<Expression*>(CLSmith::ExpressionVector::make_constant(rhs_type, lhs_type->SizeInBytes() * 8)) : dynamic_cast<Expression*>(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())) { 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 (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; }