From e7e49454c6c42625ab967223ee7061eddca7110d Mon Sep 17 00:00:00 2001 From: Xuejun Yang Date: Sat, 4 Jun 2011 15:52:14 -0600 Subject: [PATCH] Support Unions in random programs to the extend Structs were supported Note the unspecified behavior: writing to one field of an union, then reading the value of another field, is not avoided currently. They are supposed to be handled by an updated generation time analyzer that I will check in soon. --- src/ArrayVariable.cpp | 18 +- src/Bookkeeper.cpp | 7 +- src/Bookkeeper.h | 2 +- src/CGContext.cpp | 2 +- src/CGOptions.cpp | 8 + src/CGOptions.h | 17 ++ src/CVQualifiers.cpp | 2 +- src/Constant.cpp | 20 +- src/DFSOutputMgr.cpp | 4 +- src/DFSOutputMgr.h | 2 +- src/DFSProgramGenerator.cpp | 2 +- src/DefaultOutputMgr.cpp | 4 +- src/Effect.cpp | 24 +-- src/Expression.cpp | 34 ++-- src/ExpressionFuncall.cpp | 3 +- src/Function.cpp | 6 +- src/FunctionInvocation.cpp | 3 +- src/OutputMgr.h | 2 +- src/Probabilities.cpp | 6 +- src/Probabilities.h | 4 + src/RandomProgramGenerator.cpp | 46 ++++- src/ReducerOutputMgr.cpp | 12 +- src/ReducerOutputMgr.h | 2 +- src/StatementArrayOp.cpp | 6 +- src/Type.cpp | 340 ++++++++++++++++----------------- src/Type.h | 44 ++--- src/Variable.cpp | 48 ++--- src/Variable.h | 6 +- src/VariableSelector.cpp | 64 ++----- src/VariableSelector.h | 4 +- 30 files changed, 384 insertions(+), 358 deletions(-) diff --git a/src/ArrayVariable.cpp b/src/ArrayVariable.cpp index dc8f2f5a8..65312fdb1 100644 --- a/src/ArrayVariable.cpp +++ b/src/ArrayVariable.cpp @@ -157,7 +157,7 @@ ArrayVariable::CreateArrayVariable(Block* blk, const std::string &name, const Ty } ArrayVariable *var = new ArrayVariable(blk, name, type, init, qfer, sizes, isFieldVarOf); ERROR_GUARD_AND_DEL1(NULL, var); - if (type->eType == eStruct) { + if (type->is_aggregate()) { var->create_field_vars(type); } // create a list of alternative initial values. now only support integer arrays @@ -257,8 +257,8 @@ ArrayVariable::itemize(void) const av->add_index(new Constant(get_int_type(), StringUtils::int2str(index))); } av->collective = this; - // only expand struct for itemized array variable - if (type->eType == eStruct) { + // only expand struct/union for itemized array variable + if (type->is_aggregate()) { av->create_field_vars(type); } return av; @@ -277,8 +277,8 @@ ArrayVariable::itemize(const vector& const_indices) const av->add_index(new Constant(get_int_type(), StringUtils::int2str(index))); } av->collective = this; - // only expand struct for itemized array variable - if (type->eType == eStruct) { + // only expand struct/union for itemized array variable + if (type->is_aggregate()) { av->create_field_vars(type); } return av; @@ -296,8 +296,8 @@ ArrayVariable::itemize(const std::vector& indices, Block* blk) } av->collective = this; av->parent = blk; - // only expand struct for itemized array variable - if (type->eType == eStruct) { + // only expand struct/union for itemized array variable + if (type->is_aggregate()) { av->create_field_vars(type); } blk->local_vars.push_back(av); @@ -316,8 +316,8 @@ ArrayVariable::itemize(const std::vector& indices, Block* blk } av->collective = this; av->parent = blk; - // only expand struct for itemized array variable - if (type->eType == eStruct) { + // only expand struct/union for itemized array variable + if (type->is_aggregate()) { av->create_field_vars(type); } blk->local_vars.push_back(av); diff --git a/src/Bookkeeper.cpp b/src/Bookkeeper.cpp index 79d5cf208..865a3b9c9 100644 --- a/src/Bookkeeper.cpp +++ b/src/Bookkeeper.cpp @@ -382,7 +382,7 @@ Bookkeeper::record_vars_with_bitfields(const Type *type) { assert(type); const Type *base_type = type->get_base_type(); - if ((base_type->eType != eStruct) || + if (!base_type->is_aggregate() || (!base_type->has_bitfields())) return; @@ -393,10 +393,9 @@ Bookkeeper::record_vars_with_bitfields(const Type *type) } void -Bookkeeper::record_bitfields_structs(const Type *typ) +Bookkeeper::record_type_with_bitfields(const Type *typ) { - if (typ->eType != eStruct) - return; + if (!typ->is_aggregate()) return; if (typ->has_bitfields()) { Bookkeeper::structs_with_bitfields++; diff --git a/src/Bookkeeper.h b/src/Bookkeeper.h index ad5fd2342..f31175b4d 100644 --- a/src/Bookkeeper.h +++ b/src/Bookkeeper.h @@ -73,7 +73,7 @@ class Bookkeeper static void record_volatile_access(const Variable* var, int deref_level, bool write); - static void record_bitfields_structs(const Type* typ); + static void record_type_with_bitfields(const Type* typ); static void record_vars_with_bitfields(const Type *type); diff --git a/src/CGContext.cpp b/src/CGContext.cpp index 97943e298..67f9201dc 100644 --- a/src/CGContext.cpp +++ b/src/CGContext.cpp @@ -541,7 +541,7 @@ CGContext::allow_const(Effect::Access access) const bool CGContext::accept_type(const Type* t) const { - return get_effect_context().is_side_effect_free() || !t->is_volatile_struct(); + return get_effect_context().is_side_effect_free() || !t->is_volatile_struct_union(); } /* return true if an incoming effect is in conflict with current context */ diff --git a/src/CGOptions.cpp b/src/CGOptions.cpp index 967277960..e859fdf3c 100644 --- a/src/CGOptions.cpp +++ b/src/CGOptions.cpp @@ -83,11 +83,13 @@ DEFINE_GETTER_SETTER_BOOL(wrap_volatiles) DEFINE_GETTER_SETTER_BOOL(allow_const_volatile) DEFINE_GETTER_SETTER_BOOL(avoid_signed_overflow) DEFINE_GETTER_SETTER_INT (max_struct_fields) +DEFINE_GETTER_SETTER_INT (max_union_fields) DEFINE_GETTER_SETTER_INT (max_nested_struct_level) DEFINE_GETTER_SETTER_STRING_REF(struct_output) DEFINE_GETTER_SETTER_BOOL (fixed_struct_fields) DEFINE_GETTER_SETTER_BOOL (expand_struct) DEFINE_GETTER_SETTER_BOOL (use_struct) +DEFINE_GETTER_SETTER_BOOL (use_union) DEFINE_GETTER_SETTER_INT (max_indirect_level) DEFINE_GETTER_SETTER_INT (max_array_dimensions) DEFINE_GETTER_SETTER_INT (max_array_length_per_dimension) @@ -131,6 +133,8 @@ DEFINE_GETTER_SETTER_BOOL(strict_const_arrays) DEFINE_GETTER_SETTER_BOOL(jumps) DEFINE_GETTER_SETTER_BOOL(return_structs) DEFINE_GETTER_SETTER_BOOL(arg_structs) +DEFINE_GETTER_SETTER_BOOL(return_unions) +DEFINE_GETTER_SETTER_BOOL(arg_unions) DEFINE_GETTER_SETTER_BOOL(volatiles) DEFINE_GETTER_SETTER_BOOL(volatile_pointers) DEFINE_GETTER_SETTER_BOOL(enable_vol_tests) @@ -168,6 +172,7 @@ CGOptions::set_default_settings(void) max_stmt_depth(CGOPTIONS_DEFAULT_MAX_STMT_DEPTH); max_expr_depth(CGOPTIONS_DEFAULT_MAX_EXPR_DEPTH); max_struct_fields(CGOPTIONS_DEFAULT_MAX_STRUCT_FIELDS); + max_union_fields(CGOPTIONS_DEFAULT_MAX_UNION_FIELDS); max_nested_struct_level(CGOPTIONS_DEFAULT_MAX_NESTED_STRUCT_LEVEL); fixed_struct_fields(false); expand_struct(false); @@ -186,6 +191,7 @@ CGOptions::set_default_settings(void) CGOptions::nomain(false); random_based(true); use_struct(true); + use_union(true); compact_output(false); msp(false); func1_max_params(CGOPTIONS_DEFAULT_FUNC1_MAX_PARAMS); @@ -210,6 +216,8 @@ CGOptions::set_default_settings(void) jumps(true); return_structs(true); arg_structs(true); + return_unions(true); + arg_unions(true); volatiles(true); volatile_pointers(true); vol_addr_file(CGOPTIONS_DEFAULT_VOL_ADDR_FILE); diff --git a/src/CGOptions.h b/src/CGOptions.h index 81a510d71..4b367d74b 100644 --- a/src/CGOptions.h +++ b/src/CGOptions.h @@ -50,6 +50,7 @@ using namespace std; #define CGOPTIONS_DEFAULT_MAX_STMT_DEPTH (5) #define CGOPTIONS_DEFAULT_MAX_EXPR_DEPTH (5) #define CGOPTIONS_DEFAULT_MAX_STRUCT_FIELDS (10) +#define CGOPTIONS_DEFAULT_MAX_UNION_FIELDS (5) #define CGOPTIONS_DEFAULT_MAX_NESTED_STRUCT_LEVEL (0) #define CGOPTIONS_DEFAULT_MAX_INDIRECT_LEVEL (2) #define CGOPTIONS_DEFAULT_MAX_ARRAY_DIMENSIONS (3) @@ -110,6 +111,9 @@ class CGOptions { static int max_struct_fields(); static int max_struct_fields(int p); + static int max_union_fields(); + static int max_union_fields(int p); + static int max_nested_struct_level(); static int max_nested_struct_level(int p); @@ -125,6 +129,9 @@ class CGOptions { static bool use_struct(); static bool use_struct(bool p); + static bool use_union(); + static bool use_union(bool p); + static int max_indirect_level(); static int max_indirect_level(int p); @@ -254,9 +261,15 @@ class CGOptions { static bool return_structs(void); static bool return_structs(bool p); + static bool return_unions(void); + static bool return_unions(bool p); + static bool arg_structs(void); static bool arg_structs(bool p); + static bool arg_unions(void); + static bool arg_unions(bool p); + static bool volatiles(void); static bool volatiles(bool p); @@ -380,11 +393,13 @@ class CGOptions { static bool allow_const_volatile_; static bool avoid_signed_overflow_; static int max_struct_fields_; + static int max_union_fields_; static int max_nested_struct_level_; static std::string struct_output_; static bool fixed_struct_fields_; static bool expand_struct_; static bool use_struct_; + static bool use_union_; static int max_indirect_level_; static int max_array_dimensions_; static int max_array_length_per_dimension_; @@ -433,6 +448,8 @@ class CGOptions { static bool jumps_; static bool return_structs_; static bool arg_structs_; + static bool return_unions_; + static bool arg_unions_; static bool volatiles_; static bool volatile_pointers_; static bool enable_vol_tests_; diff --git a/src/CVQualifiers.cpp b/src/CVQualifiers.cpp index 4c2fb8901..91881b0be 100644 --- a/src/CVQualifiers.cpp +++ b/src/CVQualifiers.cpp @@ -347,7 +347,7 @@ CVQualifiers::random_qualifiers(const Type* t) /* * be careful to use it because it will generate volatile without knowing the context. - * Only used to generate qulifiers for structs + * Only used to generate qulifiers for struct/unions */ CVQualifiers CVQualifiers::random_qualifiers(const Type* t, unsigned int const_prob, unsigned int volatile_prob) diff --git a/src/Constant.cpp b/src/Constant.cpp index 9628eca68..d0489945b 100644 --- a/src/Constant.cpp +++ b/src/Constant.cpp @@ -230,6 +230,20 @@ GenerateRandomStructConstant(const Type* type) return value; } +// -------------------------------------------------------------- + /* generate an union initializer: unlike struct, initializing + the first field is enough + *************************************************************/ +static string +GenerateRandomUnionConstant(const Type* type) +{ + string value = "{"; + assert(type->eType == eUnion && type->fields.size() == type->bitfields_length_.size()); + value += GenerateRandomConstant(type->fields[0]); + value += "}"; + return value; +} + static string GenerateRandomConstant(const Type* type) { @@ -239,7 +253,11 @@ GenerateRandomConstant(const Type* type) } else if (type->eType == eStruct) { v = GenerateRandomStructConstant(type); - ERROR_GUARD(""); + ERROR_GUARD(""); + } + else if (type->eType == eUnion) { + v = GenerateRandomUnionConstant(type); + ERROR_GUARD(""); } // the only possible constant for a pointer is "0" else if (type->eType == ePointer) { diff --git a/src/DFSOutputMgr.cpp b/src/DFSOutputMgr.cpp index 3e7c110a7..7f92ead94 100644 --- a/src/DFSOutputMgr.cpp +++ b/src/DFSOutputMgr.cpp @@ -75,10 +75,10 @@ DFSOutputMgr::OutputHeader(int argc, char *argv[], unsigned long seed) } void -DFSOutputMgr::OutputStructs(ostream& /*out*/) +DFSOutputMgr::OutputStructUnions(ostream& /*out*/) { ofstream o_struct(struct_output_.c_str()); - OutputStructDeclarations(o_struct); + OutputStructUnionDeclarations(o_struct); o_struct.close(); } diff --git a/src/DFSOutputMgr.h b/src/DFSOutputMgr.h index 22c67d761..9f468a6fb 100644 --- a/src/DFSOutputMgr.h +++ b/src/DFSOutputMgr.h @@ -42,7 +42,7 @@ class DFSOutputMgr : public OutputMgr { virtual void OutputHeader(int argc, char *argv[], unsigned long seed); - virtual void OutputStructs(ostream& /*out*/); + virtual void OutputStructUnions(ostream& /*out*/); virtual void Output(); diff --git a/src/DFSProgramGenerator.cpp b/src/DFSProgramGenerator.cpp index e03ce9dae..e9822e29e 100644 --- a/src/DFSProgramGenerator.cpp +++ b/src/DFSProgramGenerator.cpp @@ -83,7 +83,7 @@ DFSProgramGenerator::goGenerator() dynamic_cast(RandomNumber::GetRndNumGenerator()); //unsigned long long count = 0; GenerateAllTypes(); - output_mgr_->OutputStructs(cout); + output_mgr_->OutputStructUnions(cout); while(!impl->get_all_done()) { Error::set_error(SUCCESS); GenerateFunctions(); diff --git a/src/DefaultOutputMgr.cpp b/src/DefaultOutputMgr.cpp index 04d1dda74..c24d45150 100644 --- a/src/DefaultOutputMgr.cpp +++ b/src/DefaultOutputMgr.cpp @@ -121,7 +121,7 @@ DefaultOutputMgr::OutputGlobals() string prefix = "extern "; OutputGlobalVariablesDecls(ofile, prefix); - OutputStructDeclarations(ofile); + OutputStructUnionDeclarations(ofile); ofile << "#endif" << std::endl; ofile.close(); } @@ -204,7 +204,7 @@ DefaultOutputMgr::Output() RandomOutputDefs(); } else { - OutputStructDeclarations(out); + OutputStructUnionDeclarations(out); OutputGlobalVariables(out); OutputForwardDeclarations(out); OutputFunctions(out); diff --git a/src/Effect.cpp b/src/Effect.cpp index 784f9baa3..34af7709b 100644 --- a/src/Effect.cpp +++ b/src/Effect.cpp @@ -129,12 +129,6 @@ Effect::read_var(const Variable *v) { if (!is_read(v)) { read_vars.push_back(v); - //if (v->type->eType == eStruct) { - // for (size_t i=0; ifield_vars.size(); i++) { - // read_var(v->field_vars[i]); - // } - // //read_vars.insert(read_vars.end(), v->field_vars.begin(), v->field_vars.end()); - //} } pure &= (v->is_const() && !v->is_volatile()); side_effect_free &= !v->is_volatile(); @@ -148,12 +142,6 @@ Effect::write_var(const Variable *v) { if (!is_written(v)) { write_vars.push_back(v); - //if (v->type->eType == eStruct) { - // for (size_t i=0; ifield_vars.size(); i++) { - // write_var(v->field_vars[i]); - // } - // //write_vars.insert(write_vars.end(), v->field_vars.begin(), v->field_vars.end()); - //} } // pure = pure; // TODO: not quite correct below --- @@ -300,7 +288,7 @@ Effect::is_read(const Variable *v) const return true; } } - // if we read a struct, presumingly all the fields are read too + // if we read a struct/union, presumingly all the fields are read too if (v->isFieldVarOf_) { return is_read(v->isFieldVarOf_); } @@ -362,7 +350,7 @@ Effect::is_written(const Variable *v) const return true; } } - // if we write a struct, presumingly all the fields are written too + // if we write a struct/union, presumingly all the fields are written too if (v->isFieldVarOf_) { return is_written(v->isFieldVarOf_); } @@ -411,13 +399,13 @@ Effect::is_written(string vname) const } /* - * whether any field of a struct is been read + * whether any field of a struct/union is been read */ bool Effect::field_is_read(const Variable *v) const { size_t j; - if (v->type->eType == eStruct) { + if (v->is_aggregate()) { for (j=0; jfield_vars.size(); j++) { Variable* field_var = v->field_vars[j]; if (is_read(field_var) || field_is_read(field_var)) { @@ -429,13 +417,13 @@ Effect::field_is_read(const Variable *v) const } /* - * whether any field of a struct is been written + * whether any field of a struct/union is been written */ bool Effect::field_is_written(const Variable *v) const { size_t j; - if (v->type->eType == eStruct) { + if (v->is_aggregate()) { for (j=0; jfield_vars.size(); j++) { Variable* field_var = v->field_vars[j]; if (is_written(field_var) || field_is_written(field_var)) { diff --git a/src/Expression.cpp b/src/Expression.cpp index 5e2b554c5..03b2a32f0 100644 --- a/src/Expression.cpp +++ b/src/Expression.cpp @@ -164,6 +164,8 @@ DefaultExpressionFilter::filter(int v) const eTermType tt = number_to_termtype(v, Expression::exprTable_); if (!CGOptions::return_structs() && tt == eFunction && type_.eType == eStruct) return true; + if (!CGOptions::return_unions() && tt == eFunction && type_.eType == eUnion) + return true; if (tt == eConstant && no_const_) { return true; } @@ -177,23 +179,12 @@ DefaultExpressionFilter::filter(int v) const /////////////////////////////////////////////////// class ParamExpressionFilter : public ExpressionFilter { public: - ParamExpressionFilter(); - - virtual ~ParamExpressionFilter(); - + ParamExpressionFilter(const Type* t) : type_(t) {} virtual bool filter(int v) const; +private: + const Type* type_; }; -ParamExpressionFilter::ParamExpressionFilter() -{ - -} - -ParamExpressionFilter::~ParamExpressionFilter() -{ - -} - bool ParamExpressionFilter::filter(int v) const { @@ -204,12 +195,14 @@ ParamExpressionFilter::filter(int v) const return true; eTermType tt = number_to_termtype(v, Expression::exprTable_); - // constant struct variables can not be a parameters if (tt == eConstant) { return true; } - if (!CGOptions::return_structs() && tt == eFunction) - return true; + if (tt == eFunction) { + if (type_->eType == eStruct && !CGOptions::return_structs() || + type_->eType == eUnion && !CGOptions::return_unions()) + return true; + } return false; } @@ -346,12 +339,7 @@ Expression::make_random_param(CGContext &cg_context, const Type* type, const CVQ assert(type); // if a term type is provided, no need to choose random term type if (tt == MAX_TERM_TYPES) { - tt = ParameterTypeProbability(cg_context); - } - ERROR_GUARD(NULL); - - if (type->eType == eStruct) { - ParamExpressionFilter filter; + ParamExpressionFilter filter(type); tt = ExpressionTypeProbability(cg_context, &filter); } diff --git a/src/ExpressionFuncall.cpp b/src/ExpressionFuncall.cpp index d6dbeb2a7..83968c576 100644 --- a/src/ExpressionFuncall.cpp +++ b/src/ExpressionFuncall.cpp @@ -71,8 +71,7 @@ ExpressionFuncall::make_random(CGContext &cg_context, const Type* type, const CV ++cg_context.stmt_depth; bool std_func = ExpressionFunctionProbability(cg_context); ERROR_GUARD(NULL); - // unary/binary "functions" don't yield void or struct type, - // therefore they are taken out of consideration + // unary/binary "functions" produce scalar types only if (type && (type->eType != eSimple || type->simple_type == eVoid)) std_func = false; diff --git a/src/Function.cpp b/src/Function.cpp index 569f03e8e..c802d9069 100644 --- a/src/Function.cpp +++ b/src/Function.cpp @@ -225,7 +225,7 @@ RandomFunctionName(void) } /*------------------------------------------------------------- - * choose a random return type. only structs and integer types + * choose a random return type. only struct/unions and integer types * (not incl. void) are qualified, (no arrays) *************************************************************/ static const Type* @@ -423,6 +423,8 @@ OutputFormalParam(Variable *var, std::ostream *pOut) //var->type->Output( out ); if (!CGOptions::arg_structs() && var->type) assert(var->type->eType != eStruct); + if (!CGOptions::arg_unions() && var->type) + assert(var->type->eType != eUnion); var->output_qualified_type(out); out << " " << var->name; @@ -454,6 +456,8 @@ Function::OutputHeader(std::ostream &out) { if (!CGOptions::return_structs() && return_type) assert(return_type->eType != eStruct); + if (!CGOptions::return_unions() && return_type) + assert(return_type->eType != eUnion); // force functions to be static if necessary if (CGOptions::force_globals_static()) { out << "static "; diff --git a/src/FunctionInvocation.cpp b/src/FunctionInvocation.cpp index 741420b7e..358d34ddc 100644 --- a/src/FunctionInvocation.cpp +++ b/src/FunctionInvocation.cpp @@ -96,8 +96,7 @@ FunctionInvocation::make_random(bool is_std_func, else if (FuncListSize() < CGOptions::max_funcs()) { fi = FunctionInvocationUser::build_invocation_and_function(cg_context, type, qfer); } else { - // we can not find/create a function for struct/pointer type, - // and we can not do binary/unary operation on them either, so give up + // we can not find/create a function because we reach the limit, so give up fi = new FunctionInvocationUser(NULL, false, NULL); fi->failed = true; return fi; diff --git a/src/OutputMgr.h b/src/OutputMgr.h index a0f13a112..0352e5d7e 100644 --- a/src/OutputMgr.h +++ b/src/OutputMgr.h @@ -81,7 +81,7 @@ class OutputMgr { virtual void OutputHeader(int argc, char *argv[], unsigned long seed) = 0; - virtual void OutputStructs(ostream& /* out */) {}; + virtual void OutputStructUnions(ostream& /* out */) {}; virtual void Output() = 0; diff --git a/src/Probabilities.cpp b/src/Probabilities.cpp index 3cf9ad09d..ed54637fc 100644 --- a/src/Probabilities.cpp +++ b/src/Probabilities.cpp @@ -420,7 +420,7 @@ Probabilities::set_single_name_maps() // for single field in exhaustive mode set_single_name("exhaustive_bitfield_prob", pExhaustiveBitFieldsProb); - // for signed flag of struct fields. + // for signed flag of struct/union fields. set_single_name("bitfields_signed_prob", pBitFieldsSignedProb); // for signed flag of safe ops @@ -459,6 +459,9 @@ Probabilities::set_single_name_maps() // for choosing struct as LType set_single_name("struct_as_ltype_prob", pStructAsLTypeProb); + // for choosing union as LType + set_single_name("union_as_ltype_prob", pUnionAsLTypeProb); + // for creating new array var set_single_name("new_array_var_prob", pNewArrayVariableProb); @@ -549,6 +552,7 @@ Probabilities::initialize_single_probs() m[pStdUnaryFuncProb] = 5; m[pShiftByNonConstantProb] = 50; m[pStructAsLTypeProb] = 30; + m[pUnionAsLTypeProb] = 25; if (CGOptions::arrays()) m[pNewArrayVariableProb] = 20; else diff --git a/src/Probabilities.h b/src/Probabilities.h index e875591cc..c5dcde713 100644 --- a/src/Probabilities.h +++ b/src/Probabilities.h @@ -58,6 +58,7 @@ enum ProbName { pShiftByNonConstantProb, pPointerAsLTypeProb, pStructAsLTypeProb, + pUnionAsLTypeProb, pNewArrayVariableProb, // group for statement @@ -188,6 +189,9 @@ enum ProbName { #define StructAsLTypeProb \ Probabilities::get_prob(pStructAsLTypeProb) +#define UnionAsLTypeProb \ + Probabilities::get_prob(pUnionAsLTypeProb) + #define NewArrayVariableProb \ Probabilities::get_prob(pNewArrayVariableProb) diff --git a/src/RandomProgramGenerator.cpp b/src/RandomProgramGenerator.cpp index cb8a62315..e0e16ca97 100644 --- a/src/RandomProgramGenerator.cpp +++ b/src/RandomProgramGenerator.cpp @@ -163,6 +163,7 @@ static void print_help() cout << " --main | --nomain: enable | disable to generate main function (enabled by default)." << endl << endl; cout << " --compound-assignment | --no-compound-assignment: enable | disable compound assignments (enabled by default)." << endl << endl; cout << " --structs | --no-structs: enable | disable to generate structs (enable by default)." << endl << endl; + cout << " --unions | --no-unions: enable | disable to generate unions (enable by default)." << endl << endl; cout << " --packed-struct | --no-packed-struct: enable | disable packed structs by adding #pragma pack(1) before struct definition (disabled by default)." << endl << endl; cout << " --bitfields | --no-bitfields: enable | disable full-bitfields structs (disabled by default)." << endl << endl; cout << " --argc | --no-argc: genereate main function with/without argv and argc being passed (enabled by default)." << endl << endl; @@ -171,6 +172,7 @@ static void print_help() cout << " --max-block-size : limit the number of non-return statements in a block to (default 4)." << endl << endl; cout << " --max-funcs : limit the number of functions (besides main) to (default 10)." << endl << endl; cout << " --max-struct-fields : limit the number of struct fields to (default 10). " << endl << endl; + cout << " --max-union-fields : limit the number of union fields to (default 5). " << endl << endl; cout << " --max-pointer-depth : limit the indirect depth of pointers to (default 2)." << endl << endl; cout << " --max-array-dim : limit array dimensions to . (default 3)" << endl << endl; cout << " --max-array-len-per-dim : limit array length per dimension to (default 10)." << endl << endl; @@ -224,10 +226,12 @@ static void print_advanced_help() cout << " --func1_max_params : specify the number of symbolic variables passed to func_1 (default 3). "; cout << "Only used when --splat | --crest | --klee | --coverage-test is enabled." << endl << endl; - // struct related options + // struct/union related options cout << " --fixed-struct-fields: fix the size of struct fields to max-struct-fields (default 10)." << endl << endl; cout << " --return-structs | --no-return-structs: enable | disable return structs from a function (enabled by default)." << endl << endl; cout << " --arg-structs | --no-arg-structs: enable | disable structs being used as args (enabled by default)." << endl << endl; + cout << " --return-unions | --no-return-unions: enable | disable return unions from a function (enabled by default)." << endl << endl; + cout << " --arg-unions | --no-arg-unions: enable | disable unions being used as args (enabled by default)." << endl << endl; // delta related options cout << " --delta-monitor [simple]: specify the type of delta monitor. Only [simple] type is supported now." << endl << endl; @@ -521,6 +525,16 @@ main(int argc, char **argv) continue; } + if (strcmp (argv[i], "--unions") == 0) { + CGOptions::use_union(true); + continue; + } + + if (strcmp (argv[i], "--no-unions") == 0) { + CGOptions::use_union(false); + continue; + } + if (strcmp (argv[i], "--argc") == 0) { CGOptions::accept_argc(true); continue; @@ -551,6 +565,16 @@ main(int argc, char **argv) continue; } + if (strcmp (argv[i], "--max-union-fields") ==0 ) { + unsigned long ret; + i++; + arg_check(argc, i); + if (!parse_int_arg(argv[i], &ret)) + exit(-1); + CGOptions::max_union_fields(ret); + continue; + } + if (strcmp (argv[i], "--max-nested-struct-level") ==0 ) { unsigned long ret; i++; @@ -753,6 +777,26 @@ main(int argc, char **argv) continue; } + if (strcmp (argv[i], "--return-unions") == 0) { + CGOptions::return_unions(true); + continue; + } + + if (strcmp (argv[i], "--no-return-unions") == 0) { + CGOptions::return_unions(false); + continue; + } + + if (strcmp (argv[i], "--arg-unions") == 0) { + CGOptions::arg_unions(true); + continue; + } + + if (strcmp (argv[i], "--no-arg-unions") == 0) { + CGOptions::arg_unions(false); + continue; + } + if (strcmp (argv[i], "--volatiles") == 0) { CGOptions::volatiles(true); continue; diff --git a/src/ReducerOutputMgr.cpp b/src/ReducerOutputMgr.cpp index 7df3248ab..75b162536 100644 --- a/src/ReducerOutputMgr.cpp +++ b/src/ReducerOutputMgr.cpp @@ -783,8 +783,8 @@ ReducerOutputMgr::rewrite_func_calls(const Statement* stm, std::ostream &out, in if (!calls.empty()) { size_t i; for (i=0; iget_type().eType == eStruct) { + // exclude calls that return struct/union for now because struct const is not accepted as parameter value + if (calls[i]->get_type().is_aggregate()) { continue; } output_tab(out, indent); @@ -919,15 +919,15 @@ ReducerOutputMgr::output_global_values(string header, std::ostream& out, int ind } void -ReducerOutputMgr::OutputStructs(ostream& out) +ReducerOutputMgr::OutputStructUnions(ostream& out) { size_t i; for (i=0; iused_vars.size(); i++) { const Type* t = reducer->used_vars[i]->type; - if (t->eType == eStruct) { + if (t->is_aggregate()) { Type* type = Type::find_type(t); assert(type); - OutputStruct(type, out); + OutputStructUnion(type, out); } } } @@ -984,7 +984,7 @@ ReducerOutputMgr::Output() reducer->expand_used_vars(); std::ostream &out = get_main_out(); - OutputStructs(out); + OutputStructUnions(out); output_vars(*VariableSelector::GetGlobalVariables(), out, 0); output_artificial_globals(out); size_t i; diff --git a/src/ReducerOutputMgr.h b/src/ReducerOutputMgr.h index b6f683f60..e1e2e05ad 100644 --- a/src/ReducerOutputMgr.h +++ b/src/ReducerOutputMgr.h @@ -84,7 +84,7 @@ class ReducerOutputMgr : public OutputMgr { void output_global_state_for_func(const Function* f, std::ostream &out, int indent); void output_artificial_globals(ostream& out); - virtual void OutputStructs(ostream& out); + virtual void OutputStructUnions(ostream& out); void OutputGlobals(ostream& out); private: diff --git a/src/StatementArrayOp.cpp b/src/StatementArrayOp.cpp index 9d308e2d6..9e9488f8b 100644 --- a/src/StatementArrayOp.cpp +++ b/src/StatementArrayOp.cpp @@ -118,7 +118,7 @@ StatementArrayOp::make_random_array_init(CGContext &cg_context) // JYTODO: initialize only field(s) of array members if they are of type struct Block* b = cg_context.get_current_block()->random_parent_block(); - Expression* init = VariableSelector::make_init_value(Effect::READ, cg_context, av->type, &av->qfer, b);//Expression::make_random(cg_context, av->type, true); + Expression* init = VariableSelector::make_init_value(Effect::READ, cg_context, av->type, &av->qfer, b); if (CGOptions::strict_const_arrays()) assert(av->type->eType != ePointer); assert(init->visit_facts(fm->global_facts, cg_context)); @@ -226,8 +226,8 @@ StatementArrayOp::Output(std::ostream &out, FactMgr* fm, int indent) const output_tab(out, indent); out << "{"; outputln(out); - // cannot assign array members to a struct constant directly, has to create a "fake" struct var first - if (init_value->term_type == eConstant && array_var->type->eType == eStruct) { + // cannot assign array members to a struct/union constant directly, has to create a "fake" struct var first + if (init_value->term_type == eConstant && array_var->is_aggregate()) { output_tab(out, indent+1); array_var->type->Output(out); out << " tmp = "; diff --git a/src/Type.cpp b/src/Type.cpp index 05750157b..8bf3aeae2 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -103,7 +103,7 @@ NonVoidTypeFilter::filter(int v) const return true; if (!type->used) { - Bookkeeper::record_bitfields_structs(type); + Bookkeeper::record_type_with_bitfields(type); type->used = true; } @@ -158,15 +158,19 @@ NonVoidNonVolatileTypeFilter::filter(int v) const if (type->eType == eSimple && type->simple_type == eVoid) return true; - if (type->eType == eStruct && !Type::is_nonvolatile_struct(type)) + if (type->is_aggregate() && type->is_volatile_struct_union()) return true; if ((type->eType == eStruct) && (!CGOptions::arg_structs())) { return true; } + if ((type->eType == eUnion) && (!CGOptions::arg_unions())) { + return true; + } + if (!type->used) { - Bookkeeper::record_bitfields_structs(type); + Bookkeeper::record_type_with_bitfields(type); type->used = true; } @@ -396,97 +400,64 @@ Type::find_pointer_type(const Type* t, bool add) return 0; } -/* - * flag == 0, test const; - * flag == 1, test volatile; - */ bool -Type::is_nonconst_or_nonvolatile_struct(const Type *ty, const int flag) +Type::is_const_struct_union() const { - if (ty->eType != eStruct) - return false; - assert(ty->fields.size() == ty->qfers_.size()); - - for (size_t i = 0; i < ty->fields.size(); ++i) { - const Type *field = ty->fields[i]; - if (field->eType == eStruct) { - bool flag2 = Type::is_nonconst_or_nonvolatile_struct(field, flag); - if (!flag2) - return false; - } + if (!is_aggregate()) return false; + assert(fields.size() == qfers_.size()); - CVQualifiers cf = ty->qfers_[i]; - if (flag == 0) { - if (cf.is_const()) - return false; - } - else if (flag == 1) { - if (cf.is_volatile()) - return false; - } - else { - assert(0); + for (size_t i = 0; i < fields.size(); ++i) { + const Type *field = fields[i]; + if (field->is_const_struct_union()) { + return true; } + const CVQualifiers& cf = qfers_[i]; + if (cf.is_const()) return true; } - return true; + return false; } bool -Type::is_nonconst_struct(const Type *ty) +Type::is_volatile_struct_union() const { - return Type::is_nonconst_or_nonvolatile_struct(ty, 0); -} + if (!is_aggregate()) return false; + assert(fields.size() == qfers_.size()); -bool -Type::is_nonvolatile_struct(const Type *ty) -{ - return Type::is_nonconst_or_nonvolatile_struct(ty, 1); -} - -bool -Type::is_const_struct() const -{ - return eType==eStruct && !Type::is_nonconst_or_nonvolatile_struct(this, 0); -} - -bool -Type::is_volatile_struct() const -{ - return eType==eStruct && !Type::is_nonconst_or_nonvolatile_struct(this, 1); + for (size_t i = 0; i < fields.size(); ++i) { + const Type *field = fields[i]; + if (field->is_volatile_struct_union()) { + return true; + } + const CVQualifiers& cf = qfers_[i]; + if (cf.is_volatile()) + return true; + } + return false; } bool -Type::struct_has_int_field() const +Type::has_int_field() const { - assert(eType == eStruct); - vector::const_iterator i; - for (i = fields.begin(); i != fields.end(); ++i) { - if (((*i)->eType == eSimple) && ((*i)->simple_type != eVoid)) - return true; - else if ((*i)->eType == eStruct) { - bool rv = false; - vector::const_iterator j; - for (j = fields.begin(); j != fields.begin(); ++j) { - rv = (*j)->struct_has_int_field(); - if (rv) - return true; - } - } + if (!is_aggregate()) return false; + for (size_t i=0; iis_int()) return true; + if (t->has_int_field()) return true; } return false; } void -Type::get_all_ok_struct_types(vector &ok_types, bool no_const, bool no_volatile, bool need_int_field) +Type::get_all_ok_struct_union_types(vector &ok_types, bool no_const, bool no_volatile, bool need_int_field, bool bStruct) { - vector::iterator i; - + vector::iterator i; for(i = AllTypes.begin(); i != AllTypes.end(); ++i) { Type* t = (*i); - if ((t->eType != eStruct) || - (no_const && t->is_const_struct()) || - (no_volatile && t->is_volatile_struct()) || - (need_int_field && (!t->struct_has_int_field()))) { + if (bStruct && t->eType != eStruct) continue; + if (!bStruct && t->eType != eUnion) continue; + if ((no_const && t->is_const_struct_union()) || + (no_volatile && t->is_volatile_struct_union()) || + (need_int_field && (!t->has_int_field()))) { continue; } ok_types.push_back(t); @@ -494,7 +465,7 @@ Type::get_all_ok_struct_types(vector &ok_types, bool no_const, bool no_v } const Type* -Type::choose_random_struct_type(vector &ok_types) +Type::choose_random_struct_union_type(vector &ok_types) { size_t sz = ok_types.size(); assert(sz > 0); @@ -504,7 +475,7 @@ Type::choose_random_struct_type(vector &ok_types) assert(index >= 0); Type *rv_type = ok_types[index]; if (!rv_type->used) { - Bookkeeper::record_bitfields_structs(rv_type); + Bookkeeper::record_type_with_bitfields(rv_type); rv_type->used = true; } return rv_type; @@ -524,6 +495,7 @@ Type::has_pointer_type(void) return derived_types.size() > 0; } +/* for exhaustive mode only */ const Type* Type::choose_random_struct_from_type(const Type* type, bool no_volatile) { @@ -531,14 +503,13 @@ Type::choose_random_struct_from_type(const Type* type, bool no_volatile) return NULL; const Type* t = type; - vector ok_struct_types; - get_all_ok_struct_types(ok_struct_types, no_volatile, false, true); + get_all_ok_struct_union_types(ok_struct_types, no_volatile, false, true, true); if (ok_struct_types.size() > 0) { DEPTH_GUARD_BY_DEPTH_RETURN(1, NULL); - t = Type::choose_random_struct_type(ok_struct_types); + t = Type::choose_random_struct_union_type(ok_struct_types); ERROR_GUARD(NULL); } return t; @@ -597,35 +568,27 @@ Type::choose_random_nonvoid_simple(void) } void -Type::make_one_bitfield(size_t index, bool &last_is_zero, - vector &random_fields, - vector &qualifiers, - vector &fields_length) +Type::make_one_bitfield(vector &random_fields, vector &qualifiers, vector &fields_length) { int max_length = CGOptions::bitfields_length(); - bool sign = rnd_flipcoin(BitFieldsSignedProb); ERROR_RETURN(); + const Type *type = sign ? &Type::get_simple_type(eInt) : &Type::get_simple_type(eUInt); - random_fields.push_back(type); + random_fields.push_back(type); CVQualifiers qual = CVQualifiers::random_qualifiers(type, FieldConstProb, FieldVolatileProb); ERROR_RETURN(); qualifiers.push_back(qual); - int length = rnd_upto(CGOptions::bitfields_length()); - //while (i == 0 && length == 0) - //length = rnd_upto(CGOptions::bitfields_length()); - ERROR_RETURN(); - if (index==0 || last_is_zero) { - if (max_length <= 2) - length = 1; - else - length = rnd_upto(max_length - 1) + 1; - } - else { - length = rnd_upto(max_length); - } + int length = rnd_upto(max_length); ERROR_RETURN(); - last_is_zero = (length == 0) ? true : false; + + bool no_zero_len = fields_length.empty() || (fields_length.back() == 0); + // force length to be non-zero is required + if (length == 0 && no_zero_len) { + if (max_length <= 2) length = 1; + else length = rnd_upto(max_length - 1) + 1; + } + ERROR_RETURN(); fields_length.push_back(length); } @@ -635,30 +598,27 @@ Type::make_full_bitfields_struct_fields(size_t field_cnt, vector &r vector &qualifiers, vector &fields_length) { - bool last_is_zero = false; - for (size_t i=0; i &random_fields, +Type::make_one_struct_field(vector &random_fields, vector &qualifiers, vector &fields_length) { ChooseRandomTypeFilter f; unsigned int i = rnd_upto(AllTypes.size(), &f); ERROR_RETURN(); - const Type* type = AllTypes[i]; - random_fields.push_back(type); + const Type* type = AllTypes[i]; + random_fields.push_back(type); CVQualifiers qual = CVQualifiers::random_qualifiers(type, FieldConstProb, FieldVolatileProb); ERROR_RETURN(); qualifiers.push_back(qual); @@ -666,33 +626,50 @@ Type::make_one_struct_field(size_t, vector &random_fields, } void -Type::make_normal_struct_fields(size_t field_cnt, vector &random_fields, - vector &qualifiers, - vector &fields_length) +Type::make_one_union_field(vector &fields, vector &qfers, vector &lens) { - bool last_is_zero = false; - - for (size_t i=0; i ok_types = AllTypes; + ok_types.insert(ok_types.end(), derived_types.begin(), derived_types.end()); + const Type* type = NULL; + do { + unsigned int i = pure_rnd_upto(ok_types.size()); + const Type* t = ok_types[i]; + // no union in union? + if (t->eType == eUnion || t->eType == eSimple && SIMPLE_TYPES_PROB_FILTER->filter(t->simple_type)) { + continue; + } + type = t; + } while (type == NULL); + + fields.push_back(type); + CVQualifiers qual = CVQualifiers::random_qualifiers(type, FieldConstProb, FieldVolatileProb); + ERROR_RETURN(); + qfers.push_back(qual); + lens.push_back(-1); } - } } void -Type::make_all_full_bitfields_struct_types() +Type::make_normal_struct_fields(size_t field_cnt, vector &random_fields, + vector &qualifiers, + vector &fields_length) { -/* - bool sign = false; - if (Probabilities::zero_probability(BitFieldsSignedProb)) -*/ -} + for (size_t i=0; i fields; + vector qfers; + vector lens; + + for (size_t i=0; iused) { - Bookkeeper::record_bitfields_structs(rv_type); + Bookkeeper::record_type_with_bitfields(rv_type); rv_type->used = true; } return rv_type; @@ -1167,12 +1158,10 @@ bool Type::is_unamed_padding(size_t index) const { size_t sz = bitfields_length_.size(); - if (sz == 0) return false; assert(index < sz); - return (bitfields_length_[index] == 0); } @@ -1197,7 +1186,7 @@ Type::has_bitfields() const bool Type::is_full_bitfields_struct() const { - //return (bitfields_length_.size() > 0); + if (eType != eStruct) return false; size_t i; for (i = 0; i < bitfields_length_.size(); ++i) { if (bitfields_length_[i] < 0) @@ -1386,13 +1375,16 @@ Type::SizeInBytes(void) const case eUnion: { unsigned int max_size = 0; for (i=0; iSizeInBytes() > max_size) { - max_size = fields[i]->SizeInBytes(); + unsigned int sz = fields[i]->SizeInBytes(); + if (sz == SIZE_UNKNOWN) return sz; + if (sz > max_size) { + max_size = sz; } } return max_size; } case eStruct: { + if (!this->packed_) return SIZE_UNKNOWN; unsigned int total_size = 0; for (i=0; iSizeInBytes(); @@ -1405,7 +1397,7 @@ Type::SizeInBytes(void) const } // -------------------------------------------------------------- - /* Select a left hand type + /* Select a left hand type for assignments ************************************************************/ const Type * Type::SelectLType(bool no_volatile, eAssignOps op) @@ -1419,23 +1411,29 @@ Type::SelectLType(bool no_volatile, eAssignOps op) ERROR_GUARD(NULL); type = Type::make_random_pointer_type(); } - ERROR_GUARD(NULL); - // allow struct as LValue - vector ok_struct_types; - get_all_ok_struct_types(ok_struct_types, true, no_volatile, false); - if ((ok_struct_types.size() > 0) && !type && (op == eSimpleAssign) && rnd_flipcoin(StructAsLTypeProb)) { - ERROR_GUARD(NULL); - type = Type::choose_random_struct_type(ok_struct_types); + // JYTODO: choose a union type as LHS type, this mean RHS can't be constant + /*if (!type) { + vector ok_union_types; + get_all_ok_struct_union_types(ok_union_types, true, no_volatile, false, false); + if ((ok_union_types.size() > 0) && (op == eSimpleAssign) && rnd_flipcoin(UnionAsLTypeProb)) { + type = Type::choose_random_struct_union_type(ok_union_types); + } + }*/ + // choose a struct type as LHS type + if (!type) { + vector ok_struct_types; + get_all_ok_struct_union_types(ok_struct_types, true, no_volatile, false, true); + if ((ok_struct_types.size() > 0) && (op == eSimpleAssign) && rnd_flipcoin(StructAsLTypeProb)) { + type = Type::choose_random_struct_union_type(ok_struct_types); + } } - ERROR_GUARD(NULL); // default is any integer type - if (!type) + if (!type) { type = get_int_type(); - ERROR_GUARD(NULL); - + } return type; } @@ -1445,7 +1443,7 @@ Type::get_int_subfield_names(string prefix, vector& names) const if (eType == eSimple) { names.push_back(prefix); } - else if (eType == eStruct) { + else if (is_aggregate()) { size_t i; size_t j = 0; for (i=0; ieType==eStruct || type->eType==eUnion); + assert (type->is_aggregate()); if (!type->printed) { // output dependent structs, if any for (i=0; ifields.size(); i++) { - if (type->fields[i]->eType==eStruct || type->fields[i]->eType==eUnion) { - OutputStruct((Type*)type->fields[i], out); + if (type->fields[i]->is_aggregate()) { + OutputStructUnion((Type*)type->fields[i], out); } } // output myself @@ -1517,10 +1515,8 @@ void OutputStruct(Type* type, std::ostream &out) out << " {"; really_outputln(out); - assert(type->fields.size() == type->qfers_.size()); - //if (is_full_bitfields) - //assert(type->fields.size() == type->bitfields_length_.size()); - size_t j = 0; + assert(type->fields.size() == type->qfers_.size()); + unsigned int j = 0; for (i=0; ifields.size(); i++) { out << " "; const Type *field = type->fields[i]; @@ -1563,7 +1559,7 @@ void OutputStruct(Type* type, std::ostream &out) /* print all struct definitions (fields etc) *************************************************************/ void -OutputStructDeclarations(std::ostream &out) +OutputStructUnionDeclarations(std::ostream &out) { size_t i; output_comment_line(out, "--- Struct/Union Declarations ---"); @@ -1571,7 +1567,7 @@ OutputStructDeclarations(std::ostream &out) { Type* t = AllTypes[i]; if (t->used && (t->eType == eStruct || t->eType == eUnion)) { - OutputStruct(AllTypes[i], out); + OutputStructUnion(AllTypes[i], out); } } } diff --git a/src/Type.h b/src/Type.h index 949534c6d..03ca8c3d1 100644 --- a/src/Type.h +++ b/src/Type.h @@ -49,9 +49,10 @@ #include "CVQualifiers.h" template class Enumerator; - using namespace std; +#define SIZE_UNKNOWN 0xFFFF + /* * */ @@ -114,20 +115,14 @@ class Type static const Type *choose_random_struct_from_type(const Type* type, bool no_volatile); - static void get_all_ok_struct_types(vector &ok_types, bool no_const, bool no_volatile, bool need_int_field); + static void get_all_ok_struct_union_types(vector &ok_types, bool no_const, bool no_volatile, bool need_int_field, bool bStruct); - bool struct_has_int_field() const; + bool has_int_field() const; - static const Type* choose_random_struct_type(vector &ok_types); + static const Type* choose_random_struct_union_type(vector &ok_types); static const Type * choose_random_nonvoid_nonvolatile(void); - static bool is_nonconst_struct(const Type *ty); - - static bool is_nonvolatile_struct(const Type *ty); - - static bool is_nonconst_or_nonvolatile_struct(const Type *ty, const int flag); - static bool has_pointer_type(void); static const Type* random_type_from_type(const Type* type, bool no_volatile=false, bool strict_simple_type=false); @@ -166,22 +161,21 @@ class Type vector &accum_types, vector &all_types, vector &all_quals, vector &all_bitfield_quals); - static void make_all_full_bitfields_struct_types(); - static void make_all_struct_types(int level, vector &accum_types); static void make_all_struct_union_types(); // make a random struct or union type - static Type* make_random_struct_union_type(void); + static Type* make_random_struct_type(void); + static Type* make_random_union_type(void); - static void make_one_bitfield(size_t index, bool &last_is_zero, - vector &random_fields, + static void make_one_bitfield(vector &random_fields, vector &qualifiers, vector &fields_length); - static void make_one_struct_field(size_t index, vector &random_fields, + static void make_one_struct_field(vector &random_fields, vector &qualifiers, vector &fields_length); + static void make_one_union_field(vector &fields, vector &qfers, vector &lens); static void make_full_bitfields_struct_fields(size_t field_cnt, vector &random_fields, vector &qualifiers, @@ -230,8 +224,9 @@ class Type bool is_full_bitfields_struct() const; bool is_bitfield(size_t index) const ; bool has_bitfields() const; - bool is_const_struct() const; - bool is_volatile_struct() const; + bool is_const_struct_union() const; + bool is_volatile_struct_union() const; + bool is_int(void) const { return eType == eSimple && simple_type != eVoid;} bool is_aggregate(void) const { return eType == eStruct || eType == eUnion;} bool match(const Type* t, enum eMatchType mt) const; unsigned long SizeInBytes(void) const; @@ -244,18 +239,17 @@ class Type eTypeDesc eType; const Type *ptr_type; eSimpleType simple_type; - vector dimensions; // for array types + vector dimensions; // for array types vector fields; // for struct/union types unsigned int sid; // sequence id, for struct/union types bool used; // whether any variable declared with this type bool printed; // whether this struct/union has been printed in the random program - const bool packed_; // whether this struct/union should be packed - vector qfers_; // conresponds to each element of fields + const bool packed_; // whether this struct/union should be packed + vector qfers_; // conresponds to each element of fields // It's a tradeoff between the current implementation and the // need of struct's level type qualifiers. - // -1 means it's a regular field - vector bitfields_length_; + vector bitfields_length_; // -1 means it's a regular field static Type *void_type; private: @@ -269,8 +263,8 @@ class Type void GenerateAllTypes(void); const Type * get_int_type(void); -void OutputStructDeclarations(std::ostream &); -void OutputStruct(Type* type, std::ostream &out); +void OutputStructUnionDeclarations(std::ostream &); +void OutputStructUnion(Type* type, std::ostream &out); /////////////////////////////////////////////////////////////////////////////// diff --git a/src/Variable.cpp b/src/Variable.cpp index 035b85904..431afc68a 100644 --- a/src/Variable.cpp +++ b/src/Variable.cpp @@ -96,7 +96,7 @@ int find_variable_in_set(const vector& set, const Variable* v) int find_field_variable_in_set(const vector& set, const Variable* v) { size_t i; - if (v->type->eType == eStruct) { + if (v->is_aggregate()) { for (i=0; ifield_vars.size(); i++) { const Variable* field = v->field_vars[i]; int pos = find_variable_in_set(set, field); @@ -217,7 +217,7 @@ Variable::loose_match(const Variable* v) const bool Variable::match(const Variable* v) const { - if (type && v->type && type->eType == eStruct) { + if (type && v->type && type->is_aggregate()) { return (this == v) || has_field_var(v); } return this == v; @@ -263,7 +263,7 @@ Variable::is_virtual(void) const ************************************************************************/ bool Variable::has_field_var(const Variable* v) const { - if (type->eType == eStruct) { + if (type->is_aggregate()) { const Variable* tmp = v; while (tmp) { if (tmp == this) { @@ -280,12 +280,14 @@ bool Variable::has_field_var(const Variable* v) const ************************************************************************/ void Variable::create_field_vars(const Type *type) { - assert(type->eType == eStruct); + assert(type->is_aggregate()); size_t i, j; assert(type->fields.size() == type->qfers_.size()); j = 0; - bool is_vol_struct = qfer.is_volatile_after_deref(0); - bool is_const_struct = qfer.is_const_after_deref(0); + if (name == "g_371") + j = 0; + bool is_vol_var = qfer.is_volatile(); + bool is_const_var = qfer.is_const(); for (i=0; ifields.size(); i++) { if (type->is_unamed_padding(i)) continue; @@ -297,15 +299,13 @@ void Variable::create_field_vars(const Type *type) ss << name; } ss << ".f" << j++; - CVQualifiers quals = type->qfers_[i]; - //bool isConst = is_const() || quals.is_const(); - //bool isVolatile = is_volatile() || quals.is_volatile(); - bool isConst = is_const_struct || quals.is_const(); - bool isVolatile = is_vol_struct || quals.is_volatile(); + CVQualifiers quals = type->qfers_[i]; + quals.set_const(is_const_var || quals.is_const()); + quals.set_volatile(is_vol_var || quals.is_volatile()); bool isBitfield = type->is_bitfield(i); Variable *var = Variable::CreateVariable(ss.str(), type->fields[i], - isConst, isVolatile, false, false, false, isBitfield, this); - ERROR_RETURN(); + quals.get_consts(), quals.get_volatiles(), false, false, false, isBitfield, this); + assert(var->qfer.sanity_check(var->type)); field_vars.push_back(var); } } @@ -336,7 +336,7 @@ Variable::CreateVariable(const std::string &name, const Type *type, var->init = Constant::make_random(type); ERROR_GUARD_AND_DEL1(NULL, var); - if (type->eType == eStruct) { + if (type->is_aggregate()) { var->create_field_vars(type); } ERROR_GUARD_AND_DEL1(NULL, var); @@ -351,7 +351,7 @@ Variable::CreateVariable(const std::string &name, const Type *type, const Expres assert(type->simple_type != eVoid); Variable *var = new Variable(name, type, init, qfer); - if (type->eType == eStruct) { + if (type->is_aggregate()) { var->create_field_vars(type); } ERROR_GUARD_AND_DEL1(NULL, var); @@ -488,14 +488,14 @@ Variable::is_const_after_deref(int deref_level) const return true; } if (type) { - // check struct type + // check struct/union type int i; const Type* t = type; for (i=0; iptr_type; } assert(t); - return t->is_const_struct(); + return t->is_const_struct_union(); } return false; } @@ -511,14 +511,14 @@ Variable::is_volatile_after_deref(int deref_level) const return true; } if (type) { - // check struct type + // check struct/union type int i; const Type* t = type; for (i=0; iptr_type; } assert(t); - return t->is_volatile_struct(); + return t->is_volatile_struct_union(); } return false; } @@ -958,7 +958,7 @@ Variable::compatible(const Variable *v) const void Variable::hash(std::ostream& out) const { - if (type->eType == eStruct) { + if (type->is_aggregate()) { size_t i; for (i=0; ihash(out); @@ -1175,7 +1175,7 @@ Variable::output_volatile_address(ostream &out, int indent, const string &fp_str output_volatile_fprintf(out, indent, name, sizeof_string, fp_string); // } } - else if (type->eType == eStruct) { + else if (type->is_aggregate()) { #if 0 if (is_vol && is_global()) { std::string name = "&" + get_actual_name(); @@ -1217,11 +1217,13 @@ Variable::output_addressable_name(ostream &out, int indent) const output_print_str(out, str, str_value, indent); outputln(out); } - else if (type->eType == eStruct) { + else if (type->eType == eStruct || type->eType == eUnion) { for (i=0; iisBitfield_) { field_vars[i]->output_addressable_name(out, indent); + // Unions fields all start from the same location + if (type->eType == eUnion) break; } } } @@ -1246,7 +1248,7 @@ Variable::output_value_dump(ostream &out, string prefix, int indent) const output_print_str(out, prefix + to_string() + " = " + type->printf_directive() + "\\n", to_string(), indent); outputln(out); } - else if (type->eType == eStruct) { + else if (type->eType == eStruct || type->eType == eUnion) { for (i=0; ioutput_value_dump(out, prefix, indent); diff --git a/src/Variable.h b/src/Variable.h index b1bd44dc2..a4b550882 100644 --- a/src/Variable.h +++ b/src/Variable.h @@ -54,7 +54,6 @@ using namespace std; class CGContext; class Expression; class Function; -class Type; class Block; class Lhs; class ArrayVariable; @@ -90,6 +89,7 @@ class Variable bool is_field_var(void) const { return isFieldVarOf_ != 0; }; bool is_array_field(void) const; bool is_virtual(void) const; + bool is_aggregate(void) const { return type && type->is_aggregate(); } bool match(const Variable* v) const; bool loose_match(const Variable* v) const; bool is_pointer(void) const { return type && type->eType == ePointer;} @@ -129,7 +129,7 @@ class Variable static size_t GetMaxArrayDimension(const vector& vars); - vector field_vars; // field variables for structs + vector field_vars; // field variables for struct/unions const std::string name; const Type *type; const Expression *init; @@ -140,7 +140,7 @@ class Variable const bool isStatic; const bool isRegister; const bool isBitfield_; // expanded from a full-bitfield struct var - const Variable* isFieldVarOf_; //expanded from a struct + const Variable* isFieldVarOf_; //expanded from a struct/union const bool isArray; const CVQualifiers qfer; static std::vector ctrl_vars; diff --git a/src/VariableSelector.cpp b/src/VariableSelector.cpp index 668ea86e0..4aa2eca5d 100644 --- a/src/VariableSelector.cpp +++ b/src/VariableSelector.cpp @@ -161,10 +161,10 @@ VariableSelector::new_variable(const std::string &name, const Type *type, const } /* - *expand each struct field to a single variable + *expand each struct/union field to a single variable */ void -VariableSelector::expand_struct_vars(vector& vars, const Type* type) +VariableSelector::expand_struct_union_vars(vector& vars, const Type* type) { size_t i; size_t len = vars.size(); @@ -173,7 +173,7 @@ VariableSelector::expand_struct_vars(vector& vars, const Type* type) // don't expand virtual variables if (tmpvar->is_virtual()) continue; // don't break up a struct if it matches the given type - if (tmpvar->type->eType == eStruct && (tmpvar->type != type)) { + if (tmpvar->is_aggregate() && (tmpvar->type != type)) { vars.erase(vars.begin() + i); vars.insert(vars.end(), tmpvar->field_vars.begin(), tmpvar->field_vars.end()); i--; @@ -186,7 +186,7 @@ VariableSelector::expand_struct_vars(vector& vars, const Type* type) *expand each struct field to a single variable */ void -VariableSelector::expand_struct_vars(vector& vars, const Type* type) +VariableSelector::expand_struct_union_vars(vector& vars, const Type* type) { size_t i; size_t len = vars.size(); @@ -195,7 +195,7 @@ VariableSelector::expand_struct_vars(vector& vars, const Type* // don't expand virtual variables if (tmpvar->is_virtual()) continue; // don't break up a struct if it matches the given type - if (tmpvar->type->eType == eStruct && (tmpvar->type != type)) { + if (tmpvar->is_aggregate() && (tmpvar->type != type)) { vars.erase(vars.begin() + i); vars.insert(vars.end(), tmpvar->field_vars.begin(), tmpvar->field_vars.end()); i--; @@ -365,7 +365,7 @@ VariableSelector::choose_visible_written_var(const Block* b, vector ok_vars; // include the fields of structs - expand_struct_vars(written_vars, type); + expand_struct_union_vars(written_vars, type); for (i=0; i vars, eMatchType mt, const vector& invalid_vars, bool no_bitfield, - bool no_expand_struct) + bool no_expand_struct_union) { vector ok_vars; vector::iterator i; - if (!no_expand_struct && type && (type->eType == eSimple || type->eType == eStruct)) - expand_struct_vars(vars, type); + if (!no_expand_struct_union && type && (type->eType == eSimple || type->is_aggregate())) + expand_struct_union_vars(vars, type); bool found = has_dereferenceable_var(vars, type, cg_context); if (found) { @@ -908,8 +908,8 @@ VariableSelector::GenerateNewParentLocal(Block &block, { ERROR_GUARD(NULL); assert(t); - // if this is for a struct with volatile field(s), create a global variable instead - if (t->eType==eStruct && !Type::is_nonvolatile_struct(t)) { + // if this is for a struct/union with volatile field(s), create a global variable instead + if (t->is_aggregate() && t->is_volatile_struct_union()) { return GenerateNewGlobal(access, cg_context, t, qfer); } // if there are "goto" in block (and sub-blocks), find the jump source statement, @@ -1321,7 +1321,7 @@ VariableSelector::create_random_array(const CGContext& cg_context) // don't make life complicated, restrict local variables to non-volatile type = as_global ? Type::choose_random_nonvoid() : Type::choose_random_nonvoid_nonvolatile(); ERROR_GUARD(NULL); - } while (type->is_const_struct() || !cg_context.accept_type(type)); + } while (type->is_const_struct_union() || !cg_context.accept_type(type)); CVQualifiers qfer; qfer.add_qualifiers(false, false); @@ -1361,7 +1361,7 @@ VariableSelector::select_array(const CGContext &cg_context) (cg_context.get_effect_context().is_side_effect_free() || !av->is_volatile()) && !av->is_const() && !cg_context.is_nonwritable(av) && - !av->type->is_const_struct()) { + !av->type->is_const_struct_union()) { array_vars.push_back(av); } } @@ -1377,44 +1377,6 @@ VariableSelector::select_array(const CGContext &cg_context) return array_vars[index]; } -/****************************************************************************** - * focus variable is used to direct the generation of array operations. A focus - * variable denotes which member of which array when are interested to read and/or - * write. - * - * focus var can be selected with choices: - * - * 1) For focus var "ary[i]", we could select neighboring array members, or - * any member whose index depends on i, for example "ary[i-1]" - * - * 2) for focus var that is a struct, we can select any field of it - *******************************************************************************/ -//const ArrayVariable* -//VariableSelector::select_random_focus_var(Effect::Access access, -// const CGContext &cg_context, -// const Type* type, -// const CVQualifiers* /*qfer*/, -// const vector& invalid_vars, -// eMatchType /*mt*/) -//{ -// ArrayVariable* av = cg_context.focus_var; -// int deref_level = av->type->get_indirect_level() - type->get_indirect_level(); -// // check with constraints on const and volatile qualification of the array variable -// if (access == Effect::WRITE && av->is_const_after_deref(deref_level)) { -// return 0; -// } -// if (!cg_context.get_effect_context().is_side_effect_free() && av->is_volatile_after_deref(deref_level)) { -// return 0; -// } -// if (find_variable_in_set(invalid_vars, av->get_collective()) != -1) { -// return 0; -// } -// if (av) { -// return av->rnd_mutate(); -// } -// return 0; -//} - /* given a collective array, create a member out of induction variables in the context */ ArrayVariable* VariableSelector::itemize_array(CGContext& cg_context, const ArrayVariable* av) diff --git a/src/VariableSelector.h b/src/VariableSelector.h index 3cc3c2cd4..845d7eb9f 100644 --- a/src/VariableSelector.h +++ b/src/VariableSelector.h @@ -96,7 +96,7 @@ class VariableSelector static Variable* GenerateParameterVariable(const Type *type, const CVQualifiers *qfer); static std::vector* GetGlobalVariables(void) {return &GlobalList;} static void doFinalization(void); - static void expand_struct_vars(vector& vars, const Type* type); + static void expand_struct_union_vars(vector& vars, const Type* type); static ProbabilityTable * scopeTable_; static void InitScopeTable(); @@ -140,7 +140,7 @@ class VariableSelector static void find_all_non_array_visible_vars(const Block* b, vector &vars); - static void expand_struct_vars(vector& vars, const Type* type); + static void expand_struct_union_vars(vector& vars, const Type* type); static bool has_dereferenceable_var(const vector& vars, const Type* type, const CGContext& cg_context);