8sa1-gcc/gcc/coverage.c
Diego Novillo 0823efedd0 backport: As described in http://gcc.gnu.org/ml/gcc/2012-08/msg00015.html...
Merge from cxx-conversion branch (http://gcc.gnu.org/wiki/cxx-conversion).

As described in http://gcc.gnu.org/ml/gcc/2012-08/msg00015.html, this patch
changes the default bootstrap process so that stage 1 always builds with a C++
compiler.

Other than the bootstrap change, the patch makes no functional changes to the
compiler.  Everything should build as it does now in trunk.  The main
changes in this patch are:

1- Configuration changes.
2- Re-write of VEC.
3- Re-write of gengtype to support C++ templates and
   user-provided marking functions.
4- New hash table class.
5- Re-write double_int.
6- Implement tree macros as inline functions so they can be
   called from gdb.

As discussed before, several of these changes do not fully change
the call sites to use the new APIs.

The bootstrap changes have already been tested on a wide range of
targets (http://gcc.gnu.org/wiki/CppBuildStatus).  Additionally,
I have tested the merged trunk on: x86_64-unknown-linux-gnu,
mips64el-unknown-linux-gnu, powerpc64-unknown-linux-gnu,
i686-pc-linux-gnu, and ia64-unknown-linux-gnu.

ChangeLog
2012-08-14   Diego Novillo  <dnovillo@google.com>

	Merge from cxx-conversion branch.

	* Makefile.tpl (STAGE[+id+]_CXXFLAGS): Remove
	POSTSTAGE1_CONFIGURE_FLAGS.
	* Makefile.in: Regenerate.
	* configure.ac (ENABLE_BUILD_WITH_CXX): Remove.  Update all users.
	Force C++ when bootstrapping.
	* configure: Regenerate.


libcpp/ChangeLog
2012-08-14   Diego Novillo  <dnovillo@google.com>

	Merge from cxx-conversion branch.  Configury.

	* Makefile.in: Remove all handlers of ENABLE_BUILD_WITH_CXX.
	* configure.ac: Likewise.
	* configure: Regenerate.

2012-08-14   Lawrence Crowl  <crowl@google.com>

	Merge from cxx-conversion branch.  New C++ hash table.

	* include/symtab.h (typedef struct ht hash_table): Change the typedef
	name to cpp_hash_table.  Update all users of the typedef.

gcc/ChangeLog
2012-08-14   Diego Novillo  <dnovillo@google.com>

	Merge from cxx-conversion branch.  Configury.

	* configure.ac (CXX_FOR_BUILD): Define and substitute.
	(BUILD_CXXFLAGS): Define.
	Remove all handlers of ENABLE_BUILD_WITH_CXX.
	Force all build to be with C++.
	* Makefile.in (BUILD_CXXFLAGS): Use it.
	Remove all handlers of ENABLE_BUILD_WITH_CXX.
	* configure: Regenerate.
	* config.in: Regenerate.
	* doc/install.texi: Remove documentation for --enable-build-with-cxx
	and --enable-build-poststage1-with-cxx.

2012-08-14   Diego Novillo  <dnovillo@google.com>

	Merge from cxx-conversion branch.  Re-implement VEC in C++.

	* vec.c (vec_heap_free): Convert into a template function.
	(vec_gc_o_reserve_1): Make extern.
	(vec_gc_p_reserve): Remove.
	(vec_gc_p_reserve_exact): Remove.
	(vec_gc_o_reserve): Remove.
	(vec_gc_o_reserve_exact): Remove.
	(vec_heap_o_reserve_1): Make extern.
	(vec_heap_p_reserve): Remove.
	(vec_heap_p_reserve_exact): Remove.
	(vec_heap_o_reserve): Remove.
	(vec_heap_o_reserve_exact): Remove.
	(vec_stack_p_reserve): Remove.
	(vec_stack_p_reserve_exact): Remove.
	* vec.h (VEC_CHECK_INFO, VEC_CHECK_DECL, VEC_CHECK_PASS,
	VEC_ASSERT, VEC_ASSERT_FAIL, vec_assert_fail): Move earlier
	in the file.
	(VEC): Define to vec_t<T>.
	(vec_allocation_t): Define.
	(struct vec_prefix): Move earlier in the file.
	(vec_t<T>): New template.
	(DEF_VEC_I, DEF_VECL_ALLOC_I, DEF_VEC_P, DEF_VEC_ALLOC_P,
	DEF_VEC_O, DEF_VEC_ALLOC_P, DEF_VEC_O, DEF_VEC_ALLOC_O,
	DEF_VEC_ALLOC_P_STACK, DEF_VEC_ALLOC_O_STACK,
	DEF_VEC_ALLOC_I_STACK): Expand to 'struct vec_swallow_trailing_semi'.
	(DEF_VEC_A): Provide template instantiations for
	GC/PCH markers that do not traverse the vector.
	(vec_stack_p_reserve): Remove.
	(vec_stack_p_reserve_exact): Remove.
	(vec_stack_p_reserve_exact_1): Remove.
	(vec_stack_o_reserve): Remove.
	(vec_stack_o_reserve_exact): Remove.
	(vec_stack_free): Re-write as a template function.
	(vec_reserve): New template function.
	(vec_reserve_exact): New template function.
	(vec_heap_free): New template function if GATHER_STATISTICS is
	defined.  Otherwise, macro that expands to free().
	(VEC_length_1): New template function.
	(VEC_length): Call it.
	(VEC_empty_1): New template function.
	(VEC_empty): Call it.
	(VEC_address_1): New template function.
	(VEC_address): Call it.
	(VEC_last_1): New template function.
	(VEC_last): Call it.  Change return type to T&.
	Change all users that used VEC_Os.
	(VEC_index_1): New template function.
	(VEC_index): Call it.  Return a T& instead of a T*.
	Update all callers that were using VEC_O before.
	(VEC_iterate_1): New template function.
	(VEC_iterate): Call it.
	(VEC_embedded_size_1): New template function.
	(VEC_embedded_size): Call it.
	(VEC_embedded_init_1): New template function.
	(VEC_embedded_init): Call it.
	(VEC_alloc_1): New template function.
	(VEC_alloc): Call it.  If A is 'stack', call XALLOCAVAR to
	do the allocation.
	(VEC_free_1): New template function.
	(VEC_free): Call it.
	(VEC_copy_1): New template function.
	(VEC_copy): Call it.
	(VEC_space_1): New template function
	(VEC_space): Call it.
	(VEC_reserve_1): New template function.
	(VEC_reserve): Call it.
	(VEC_reserve_exact_1): New template function.
	(VEC_reserve_exact): Call it.
	(VEC_splice_1): New template function.
	(VEC_splice): Call it.
	(VEC_safe_splice_1): New template function.
	(VEC_safe_splice): Call it.
	(VEC_quick_push_1): New template function.  Create two overloads, one
	accepting T, the other accepting T *.  Update all callers
	where T and T * are ambiguous.
	(VEC_quick_push): Call it.
	(VEC_safe_push_1): New template function. Create two overloads, one
	accepting T, the other accepting T *.  Update all callers
	where T and T * are ambiguous.
	(VEC_safe_push): Call it.
	(VEC_pop_1): New template function.
	(VEC_pop): Call it.
	(VEC_truncate_1): New template function.
	(VEC_truncate): Call it.
	(VEC_safe_grow_1): New template function.
	(VEC_safe_grow): Call it.
	(VEC_safe_grow_cleared_1): New template function.
	(VEC_safe_grow_cleared): Call it.
	(VEC_replace_1): New template function.
	(VEC_replace): Call it.  Always accept T instead of T*.
	Update all callers that used VEC_Os.
	(VEC_quick_insert_1): New template function.
	(VEC_quick_insert): Call it.
	(VEC_safe_insert_1): New template function.
	(VEC_safe_insert): Call it.
	(VEC_ordered_remove_1): New template function.
	(VEC_ordered_remove): Call it.
	(VEC_unordered_remove_1): New template function.
	(VEC_unordered_remove): Call it.
	(VEC_block_remove_1): New template function.
	(VEC_block_remove): Call it.
	(VEC_lower_bound_1): New template function.
	(VEC_lower_bound): Call it.
	(VEC_OP): Remove.
	(DEF_VEC_FUNC_P): Remove.
	(DEF_VEC_ALLOC_FUNC_P): Remove.
	(DEF_VEC_NONALLOC_FUNCS_P): Remove.
	(DEF_VEC_FUNC_O): Remove.
	(DEF_VEC_ALLOC_FUNC_O): Remove.
	(DEF_VEC_NONALLOC_FUNCS_O): Remove.
	(DEF_VEC_ALLOC_FUNC_I): Remove.
	(DEF_VEC_NONALLOC_FUNCS_I): Remove.
	(DEF_VEC_ALLOC_FUNC_P_STACK): Remove.
	(DEF_VEC_ALLOC_FUNC_O_STACK): Remove.
	(DEF_VEC_ALLOC_FUNC_I_STACK): Remove.
	(vec_reserve_exact): New template function.

	* gengtype-lex.l (DEF_VEC_ALLOC_[IOP]/{EOID}): Remove.
	* gengtype-parse.c (token_names): Remove DEF_VEC_ALLOC_[IOP].
	(typedef_name): Emit vec_t<C1> instead of VEC_C1_C2.
	(def_vec_alloc): Remove.  Update all callers.
	* gengtype.c (filter_type_name): New.
	(output_mangled_typename): Call it.
	(write_func_for_structure): Likewise.
	(write_types): Likewise.
	(write_root): Likewise.
	(write_typed_alloc_def): Likewise.
	(note_def_vec): Emit vec_t<TYPE_NAME> instead of VEC_TYPE_NAME_base.
	(note_def_vec_alloc): Remove.
	* gengtype.h (note_def_vec_alloc): Remove.
	(DEFVEC_ALLOC): Remove token code.

	* df-scan.c (df_bb_verify): Remove call to df_free_collection_rec
	inside the insn traversal loop.
	* gimplify.c (gimplify_compound_lval): Rename STACK to EXPR_STACK.
	* ipa-inline.c (inline_small_functions): Rename HEAP to EDGE_HEAP.
	* reg-stack.c (stack): Rename to STACK_PTR.  Update all users.
	* tree-vrp.c (stack): Rename to EQUIV_STACK.  Update all users.

	* config/bfin/bfin.c (hwloop_optimize): Update some calls to
	VEC_* for vectors of non-pointers.
	* config/c6x/c6x.c (try_rename_operands): Likewise.
	(reshuffle_units): Likewise.
	* config/mips/mips.c (mips_multi_start): Likewise.
	(mips_multi_add): Likewise.
	(mips_multi_copy_insn): Likewise.
	(mips_multi_set_operand): Likewise.
	* hw-doloop.c (discover_loop): Likewise.
	(discover_loops): Likewise.
	(reorg_loops): Likewise.

2012-08-14   Diego Novillo  <dnovillo@google.com>

	Merge from cxx-conversion branch.  C++ support in gengtype.

	* coretypes.h (gt_pointer_operator): Move from ...
	* ggc.h: ... here.
	* doc/gty.texi: Document support for C++ templates and
	user-provided markers.
	* gcc/gengtype-lex.l: Update copyright year.
	Remove support for recognizing DEF_VEC_O, DEF_VEC_P and
	DEFVEC_I.
	* gengtype-parse.c: Update copyright year.
	(token_names): Remove DEF_VEC_O, DEF_VEC_P and DEF_VEC_I.
	(require_template_declaration): New.
	(typedef_name): Call it.
	(type): Replace IS_UNION with KIND. Replace all users.
	(def_vec): Remove.  Update all users.
	* gengtype-state.c (type_lineloc): Handle TYPE_USER_STRUCT.
	(write_state_user_struct_type): New.
	(write_state_type): Call it.
	(read_state_user_struct_type): New.
	(read_state_type): Call it.
	* gengtype.c: Update copyright year.
	(dump_pair): Move declaration to the top.
	(dump_type): Likewise.
	(dump_type_list): Likewise.
	(dbgprint_count_type_at): Handle TYPE_USER_STRUCT.
	(create_user_defined_type): New.
	(resolve_typedef): Call it.
	(new_structure): Replace argument ISUNION with KIND.
	Change users to refer to KIND directly.
	Update all callers.
	(find_structure): Likewise.
	(set_gc_used_type): Handle TYPE_USER_STRUCT.
	(create_file): Update HDR to include new copyright year.
	(struct walk_type_data): Add field IN_PTR_FIELD.
	(output_mangled_typename): Handle TYPE_USER_STRUCT.
	(walk_type): Set D->IN_PTR_FIELD when walking a TYPE_POINTER.
	Clear it afterwards.
	Handle TYPE_USER_STRUCT.
	(write_types_process_field): Handle TYPE_USER_STRUCT.
	(get_type_specifier): Move earlier in the file.
	(write_type_decl): New.
	(write_marker_function_name): New.
	(write_user_func_for_structure_ptr): New.
	(write_user_func_for_structure_body): New.
	(write_user_marking_functions): New.
	(write_func_for_structure): Call write_marker_function_name
	and write_type_decl.
	Do not call walk_type for TYPE_USER_STRUCT. Emit a call to the user
	function directly.
	Call write_user_marking_functions on TYPE_USER_STRUCTs.
	(write_types_local_user_process_field): New.
	(write_pch_user_walking_for_structure_body): New.
	(write_pch_user_walking_functions): New.
	(write_types_local_process_field): Handle TYPE_USER_STRUCT.
	(write_local_func_for_structure): Do not call walk_type for
	TYPE_USER_STRUCT. Instead, emit the call to gt_pch_nx directly.
	Call write_pch_user_walking_functions for TYPE_USER_STRUCTs.
	(write_root): Handle TYPE_USER_STRUCT.
	(vec_prefix_type): Remove.  Update all users.
	(note_def_vec): Remove.  Update all users.
	(dump_typekind): Handle TYPE_USER_STRUCT.
	(dump_type): Initialize SEEN_TYPES, if needed.
	Handle TYPE_USER_STRUCT.
	(dump_everything): Do not initialize SEEN_TYPES.
	* gengtype.h: Update copyright year.
	(enum typekind): Add TYPE_USER_STRUCT.
	(union_or_struct_p): Rename from UNION_OR_STRUCT_P.
	Convert into function.
	Add an overload taking const_type_p.
	Update all callers.
	(new_structure): Change second field to type enum typekind.
	Update all users.
	(find_structure): Likewise.
	(note_def_vec): Remove.
	(DEFVEC_OP): Remove.
	(DEFVEC_I): Remove.
	* ggc-page.c (gt_ggc_mx): Add entry points for marking
	'const char *&', 'unsigned char *&' and 'unsigned char&'.
	* ggc-zone.c (gt_ggc_mx): Add entry points for marking
	'const char *&' and 'unsigned char *&'.
	* stringpool.c (gt_pch_nx): Add entry points for marking
	'const char *&', 'unsigned char *&' and 'unsigned char&'.
	Add an entry point for the overload taking arguments 'unsigned char
	*', 'gt_pointer_operator' and 'void *'.
	* vec.h (struct vec_prefix): Remove GTY marker.
	(struct vec_t): Remove GTY((length)) attribute from field 'vec'.
	(gt_ggc_mx (vec_t<T> *)): New template function.
	(gt_pch_nx (vec_t<T> *)): New template function.
	(gt_pch_nx (vec_t<T *> *, gt_pointer_operator, void *)): New template
	function.
	(gt_pch_nx (vec_t<T> *, gt_pointer_operator, void *)): New template
	function.

	* basic-block.h (struct edge_def): Mark GTY((user)).
	Remove all GTY markers from fields.
	(gt_ggc_mx): Declare.
	(gt_pch_nx): Declare.
	* tree-cfg.c (gt_ggc_mx): New.
	(gt_pch_nx): New.

	* gengtype-lex.l (USER_GTY): Add pattern for "user".
	* gengtype-parse.c (option): Handle USER_GTY.
	(opts_have): New.
	(type): Call it.
	If the keyword 'user' is used, do not walk the fields
	of the structure.
	* gengtype.h (USER_GTY): Add.
	* doc/gty.texi: Update.

2012-08-14   Lawrence Crowl  <crowl@google.com>

	Merge cxx-conversion branch.  Implement C++ hash table.

	* hash-table.h: New. Implementation borrowed from libiberty/hashtab.c.
	* hash-table.c: Likewise.
	* tree-ssa-tail-merge.c: Include hash-table.h instead of hashtab.h.
	(static htab_t same_succ_htab): Change type to hash_table;
	move specification of helper functions from create call to declaration.
	Change users to invoke member functions.
	(same_succ_print_traverse): Make extern ssa_.... Change callers.
	Remove void* casting.
	(same_succ_hash): Likewise.
	(same_succ_equal): Likewise.
	(same_succ_delete): Likewise.
	* tree-ssa-threadupdate.c: Include hash-table.h.
	(struct local_info): Rename to ssa_local_info_t to avoid overloading
	the type name local_info with the variable name local_info.
	(static htab_t redirection_data): Change type to hash_table.
	Move specification of helper functions from create call to declaration.
	Change users to invoke member functions.
	(redirection_data_hash): Make extern ssa_.... Change callers.
	Remove void* casting.
	(redirection_data_eq): Likewise.
	(fix_duplicate_block_edges): Likewise.
	(create_duplicates): Likewise.
	(fixup_template_block): Likewise.
	(redirect_edges): Likewise.
	(lookup_redirection_data): Change types associated with the hash table
	from void* to their actual type. Remove unnecessary casts.
	* tree-ssa-ccp.c: Include hash-table.h.
	(typedef gimple_htab): New.  Uses hash_table.  Replace specific uses
	of htab_t with gimple_htab.  Change users to invoke member functions.
	Move specification of helper functions from create call to declaration.
	* tree-ssa-coalesce.c: Include hash-table.h instead of hashtab.h.
	(hash_ssa_name_by_var): Make extern. Remove void* casting.
	(eq_ssa_name_by_var): Likewise.
	(coalesce_ssa_name): Change type of local static htab_t ssa_name_hash
	to hash_table. Change users to invoke member functions.
	Move specification of helper functions from create call to declaration.
	* coverage.c: Include hash-table.h instead of hashtab.h.
	(static htab_t counts_hash): Change type to hash_table;
	move specification of helper functions from create call to declaration.
	Change users to invoke member functions.
	(htab_counts_entry_hash): Make extern. Rename with coverage_... instead
	of htab_... Remove void* casting.
	(htab_counts_entry_eq): Likewise.
	(htab_counts_entry_del): Likewise.
	* tree-ssa-pre.c: Include hash-table.h instead of hashtab.h.
	(static htab_t expression_to_id): Change type to hash_table.
	Move specification of helper functions from create call to declaration.
	Change users to invoke member functions.
	(static htab_t phi_translate_table): Likewise.
	(pre_expr_eq): Make extern ssa_.... Change callers.
	Remove void* casting.
	(pre_expr_hash): Likewise.
	(expr_pred_trans_hash): Likewise.
	(expr_pred_trans_eq): Likewise.
	(alloc_expression_id): Change types associated with the hash table
	from void* to their actual type. Remove unnecessary casts.
	(lookup_expression_id): Likewise.
	(phi_trans_lookup): Likewise.
	(phi_trans_add): Likewise.
	* stringpool.c: Rename uses of libcpp typedef hash_table to
	cpp_hash_table.
	* Makefile.in: Add hash-table.o to OBJS-libcommon-target.
	Add $(HASH_TABLE_H). Add new dependences on $(HASH_TABLE_H).

2012-08-14   Lawrence Crowl  <crowl@google.com>

	Merge from cxx-conversion branch.  Re-write double_int in C++.

	* hash-table.h
	(typedef double_int): Change to struct (POD).
	(double_int::make): New overloads for int to double-int conversion.
	(double_int::mask): New.
	(double_int::max_value): New.
	(double_int::min_value): New.
	(double_int::operator ++): New.
	(double_int::operator --): New.
	(double_int::operator *=): New.
	(double_int::operator +=): New.
	(double_int::operator -=): New.
	(double_int::to_signed): New.
	(double_int::to_unsigned): New.
	(double_int::fits_unsigned): New.
	(double_int::fits_signed): New.
	(double_int::fits): New.
	(double_int::trailing_zeros): New.
	(double_int::popcount): New.
	(double_int::multiple_of): New.
	(double_int::set_bit): New.
	(double_int::mul_with_sign): New.
	(double_int::operator * (binary)): New.
	(double_int::operator + (binary)): New.
	(double_int::operator - (binary)): New.
	(double_int::operator - (unary)): New.
	(double_int::operator ~ (unary)): New.
	(double_int::operator & (binary)): New.
	(double_int::operator | (binary)): New.
	(double_int::operator ^ (binary)): New.
	(double_int::and_not): New.
	(double_int::lshift): New.
	(double_int::rshift): New.
	(double_int::alshift): New.
	(double_int::arshift): New.
	(double_int::llshift): New.
	(double_int::lrshift): New.
	(double_int::lrotate): New.
	(double_int::rrotate): New.
	(double_int::div): New.
	(double_int::sdiv): New.
	(double_int::udiv): New.
	(double_int::mod): New.
	(double_int::smod): New.
	(double_int::umod): New.
	(double_int::divmod): New.
	(double_int::sdivmod): New.
	(double_int::udivmod): New.
	(double_int::ext): New.
	(double_int::zext): New.
	(double_int::sext): New.
	(double_int::is_zero): New.
	(double_int::is_one): New.
	(double_int::is_minus_one): New.
	(double_int::is_negative): New.
	(double_int::cmp): New.
	(double_int::ucmp): New.
	(double_int::scmp): New.
	(double_int::ult): New.
	(double_int::ugt): New.
	(double_int::slt): New.
	(double_int::sgt): New.
	(double_int::max): New.
	(double_int::smax): New.
	(double_int::umax): New.
	(double_int::min): New.
	(double_int::smin): New.
	(double_int::umin): New.
	(double_int::operator ==): New.
	(double_int::operator !=): New.
	(shwi_to_double_int): Change implementation to use member function.
	(double_int_minus_one): Likewise.
	(double_int_zero): Likewise.
	(double_int_one): Likewise.
	(double_int_two): Likewise.
	(double_int_ten): Likewise.
	(uhwi_to_double_int): Likewise.
	(double_int_to_shwi): Likewise.
	(double_int_to_uhwi): Likewise.
	(double_int_fits_in_uhwi_p): Likewise.
	(double_int_fits_in_shwi_p): Likewise.
	(double_int_fits_in_hwi_p): Likewise.
	(double_int_mul): Likewise.
	(double_int_mul_with_sign): Likewise.
	(double_int_add): Likewise.
	(double_int_sub): Likewise.
	(double_int_neg): Likewise.
	(double_int_div): Likewise.
	(double_int_sdiv): Likewise.
	(double_int_udiv): Likewise.
	(double_int_mod): Likewise.
	(double_int_smod): Likewise.
	(double_int_umod): Likewise.
	(double_int_divmod): Likewise.
	(double_int_sdivmod): Likewise.
	(double_int_udivmod): Likewise.
	(double_int_multiple_of): Likewise.
	(double_int_setbit): Likewise.
	(double_int_ctz): Likewise.
	(double_int_not): Likewise.
	(double_int_ior): Likewise.
	(double_int_and): Likewise.
	(double_int_and_not): Likewise.
	(double_int_xor): Likewise.
	(double_int_lshift): Likewise.
	(double_int_rshift): Likewise.
	(double_int_lrotate): Likewise.
	(double_int_rrotate): Likewise.
	(double_int_cmp): Likewise.
	(double_int_scmp): Likewise.
	(double_int_ucmp): Likewise.
	(double_int_max): Likewise.
	(double_int_smax): Likewise.
	(double_int_umax): Likewise.
	(double_int_min): Likewise.
	(double_int_smin): Likewise.
	(double_int_umin): Likewise.
	(double_int_ext): Likewise.
	(double_int_sext): Likewise.
	(double_int_zext): Likewise.
	(double_int_mask): Likewise.
	(double_int_max_value): Likewise.
	(double_int_min_value): Likewise.
	(double_int_zero_p): Likewise.
	(double_int_one_p): Likewise.
	(double_int_minus_one_p): Likewise.
	(double_int_equal_p): Likewise.
	(double_int_popcount): Likewise.
	* hash-table.c
	(double_int_mask): Reuse implementation for double_int::mask.
	(double_int_max_value): Likewise.
	(double_int_min_value): Likewise.
	(double_int_ext): Likewise.
	(double_int_zext): Likewise.
	(double_int_sext): Likewise.
	(double_int_mul_with_sign): Likewise.
	(double_int_divmod): Likewise.
	(double_int_sdivmod): Likewise.
	(double_int_udivmod): Likewise.
	(double_int_div): Likewise.
	(double_int_sdiv): Likewise.
	(double_int_udiv): Likewise.
	(double_int_mod): Likewise.
	(double_int_smod): Likewise.
	(double_int_umod): Likewise.
	(double_int_multiple_of): Likewise.
	(double_int_lshift): Likewise.
	(double_int_rshift): Likewise.
	(double_int_lrotate): Likewise.
	(double_int_rrotate): Likewise.
	(double_int_cmp): Likewise.
	(double_int_ucmp): Likewise.
	(double_int_scmp): Likewise.
	(double_int_max): Likewise.
	(double_int_smax): Likewise.
	(double_int_umax): Likewise.
	(double_int_min): Likewise.
	(double_int_smin): Likewise.
	(double_int_umin): Likewise.
	(double_int_min): Likewise.
	(double_int_min): Likewise.
	(double_int_min): Likewise.
	(double_int_min): Likewise.
	(double_int_min): Likewise.
	(double_int_min): Likewise.
	(double_int::alshift): New.
	(double_int::arshift): New.
	(double_int::llshift): New.
	(double_int::lrshift): New.
	(double_int::ult): New.
	(double_int::ugt): New.
	(double_int::slt): New.
	(double_int::sgt): New.
	(double_int_setbit): Reuse implementation for double_int::set_bit,
	which avoids a name conflict with a macro.
	(double_int_double_int_ctz): Reuse implementation for
	double_int::trailing_zeros.
	(double_int_fits_in_shwi_p): Reuse implementation for
	double_int::fits_signed.
	(double_int_fits_in_hwi_p): Reuse implementation for double_int::fits.
	(double_int_mul): Reuse implementation for binary
	double_int::operator *.
	(double_int_add): Likewise.
	(double_int_sub): Likewise.
	(double_int_neg): Reuse implementation for unary
	double_int::operator -.
	(double_int_max_value): Likewise.
	* fixed-value.c: Change to use member functions introduced above.

2012-08-14   Lawrence Crowl  <crowl@google.com>

	Merge cxx-conversion branch.  Support tree macro calling
	from gdb.

	* tree.h (tree_check): New.
	(TREE_CHECK): Use inline function above instead of __extension__.
	(tree_not_check): New.
	(TREE_NOT_CHECK): Use inline function above instead of __extension__.
	(tree_check2): New.
	(TREE_CHECK2): Use inline function above instead of __extension__.
	(tree_not_check2): New.
	(TREE_NOT_CHECK2): Use inline function above instead of __extension__.
	(tree_check3): New.
	(TREE_CHECK3): Use inline function above instead of __extension__.
	(tree_not_check3): New.
	(TREE_NOT_CHECK3): Use inline function above instead of __extension__.
	(tree_check4): New.
	(TREE_CHECK4): Use inline function above instead of __extension__.
	(tree_not_check4): New.
	(TREE_NOT_CHECK4): Use inline function above instead of __extension__.
	(tree_check5): New.
	(TREE_CHECK5): Use inline function above instead of __extension__.
	(tree_not_check5): New.
	(TREE_NOT_CHECK5): Use inline function above instead of __extension__.
	(contains_struct_check): New.
	(CONTAINS_STRUCT_CHECK): Use inline function above instead of
	__extension__.
	(tree_class_check): New.
	(TREE_CLASS_CHECK): Use inline function above instead of __extension__.
	(tree_range_check): New.
	(TREE_RANGE_CHECK): Use inline function above instead of __extension__.
	(omp_clause_subcode_check): New.
	(OMP_CLAUSE_SUBCODE_CHECK): Use inline function above instead of
	__extension__.
	(omp_clause_range_check): New.
	(OMP_CLAUSE_RANGE_CHECK): Use inline function above instead of
	__extension__.
	(expr_check): New.
	(EXPR_CHECK): Use inline function above instead of __extension__.
	(non_type_check): New.
	(NON_TYPE_CHECK): Use inline function above instead of __extension__.
	(tree_vec_elt_check): New.
	(TREE_VEC_ELT_CHECK): Use inline function above instead of
	__extension__.
	(omp_clause_elt_check): New.
	(OMP_CLAUSE_ELT_CHECK): Use inline function above instead of
	__extension__.
	(tree_operand_check): New.
	(TREE_OPERAND_CHECK): Use inline function above instead of
	__extension__.
	(tree_operand_check_code): New.
	(TREE_OPERAND_CHECK_CODE): Use inline function above instead of
	__extension__.
	(TREE_CHAIN): Simplify implementation.
	(TREE_TYPE): Simplify implementation.
	(tree_operand_length): Move for compilation dependences.
	* gdbinit.in: (macro define __FILE__): New.
	(macro define __LINE__): New.
	(skip "tree.h"): New.

gcc/cp/ChangeLog
2012-08-14   Diego Novillo  <dnovillo@google.com>

	Merge from cxx-conversion branch.  Re-write VEC in C++.

	* call.c (add_function_candidate): Remove const qualifier
	from call to VEC_index.

2012-08-14   Diego Novillo  <dnovillo@google.com>

	Merge from cxx-conversion branch.  Configury.

	* go-c.h: Remove all handlers of ENABLE_BUILD_WITH_CXX.
	* go-gcc.cc: Likewise.
	* go-system.h: Likewise.

From-SVN: r190402
2012-08-14 21:56:07 -04:00

1153 lines
33 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Read and write coverage files, and associated functionality.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
2000, 2001, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
based on some ideas from Dain Samples of UC Berkeley.
Further mangling by Bob Manson, Cygnus Support.
Further mangled by Nathan Sidwell, CodeSourcery
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define GCOV_LINKAGE
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "output.h"
#include "regs.h"
#include "expr.h"
#include "function.h"
#include "basic-block.h"
#include "toplev.h"
#include "tm_p.h"
#include "ggc.h"
#include "coverage.h"
#include "langhooks.h"
#include "hash-table.h"
#include "tree-iterator.h"
#include "cgraph.h"
#include "dumpfile.h"
#include "diagnostic-core.h"
#include "intl.h"
#include "filenames.h"
#include "target.h"
#include "gcov-io.h"
#include "gcov-io.c"
struct GTY((chain_next ("%h.next"))) coverage_data
{
struct coverage_data *next; /* next function */
unsigned ident; /* function ident */
unsigned lineno_checksum; /* function lineno checksum */
unsigned cfg_checksum; /* function cfg checksum */
tree fn_decl; /* the function decl */
tree ctr_vars[GCOV_COUNTERS]; /* counter variables. */
};
/* Counts information for a function. */
typedef struct counts_entry
{
/* We hash by */
unsigned ident;
unsigned ctr;
/* Store */
unsigned lineno_checksum;
unsigned cfg_checksum;
gcov_type *counts;
struct gcov_ctr_summary summary;
} counts_entry_t;
static GTY(()) struct coverage_data *functions_head = 0;
static struct coverage_data **functions_tail = &functions_head;
static unsigned no_coverage = 0;
/* Cumulative counter information for whole program. */
static unsigned prg_ctr_mask; /* Mask of counter types generated. */
/* Counter information for current function. */
static unsigned fn_ctr_mask; /* Mask of counters used. */
static GTY(()) tree fn_v_ctrs[GCOV_COUNTERS]; /* counter variables. */
static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated. */
static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base. */
/* Coverage info VAR_DECL and function info type nodes. */
static GTY(()) tree gcov_info_var;
static GTY(()) tree gcov_fn_info_type;
static GTY(()) tree gcov_fn_info_ptr_type;
/* Name of the notes (gcno) output file. The "bbg" prefix is for
historical reasons, when the notes file contained only the
basic block graph notes.
If this is NULL we're not writing to the notes file. */
static char *bbg_file_name;
/* File stamp for notes file. */
static unsigned bbg_file_stamp;
/* Name of the count data (gcda) file. */
static char *da_file_name;
/* The names of merge functions for counters. */
static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
/* Forward declarations. */
static void read_counts_file (void);
static tree build_var (tree, tree, int);
static void build_fn_info_type (tree, unsigned, tree);
static void build_info_type (tree, tree);
static tree build_fn_info (const struct coverage_data *, tree, tree);
static tree build_info (tree, tree);
static bool coverage_obj_init (void);
static VEC(constructor_elt,gc) *coverage_obj_fn
(VEC(constructor_elt,gc) *, tree, struct coverage_data const *);
static void coverage_obj_finish (VEC(constructor_elt,gc) *);
/* Return the type node for gcov_type. */
tree
get_gcov_type (void)
{
enum machine_mode mode = smallest_mode_for_size (GCOV_TYPE_SIZE, MODE_INT);
return lang_hooks.types.type_for_mode (mode, false);
}
/* Return the type node for gcov_unsigned_t. */
static tree
get_gcov_unsigned_t (void)
{
enum machine_mode mode = smallest_mode_for_size (32, MODE_INT);
return lang_hooks.types.type_for_mode (mode, true);
}
inline hashval_t
coverage_counts_entry_hash (const counts_entry_t *entry)
{
return entry->ident * GCOV_COUNTERS + entry->ctr;
}
inline int
coverage_counts_entry_eq (const counts_entry_t *entry1,
const counts_entry_t *entry2)
{
return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
}
inline void
coverage_counts_entry_del (counts_entry_t *entry)
{
free (entry->counts);
free (entry);
}
/* Hash table of count data. */
static hash_table <counts_entry_t, coverage_counts_entry_hash,
coverage_counts_entry_eq, coverage_counts_entry_del>
counts_hash;
/* Read in the counts file, if available. */
static void
read_counts_file (void)
{
gcov_unsigned_t fn_ident = 0;
struct gcov_summary summary;
unsigned new_summary = 1;
gcov_unsigned_t tag;
int is_error = 0;
unsigned lineno_checksum = 0;
unsigned cfg_checksum = 0;
if (!gcov_open (da_file_name, 1))
return;
if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
{
warning (0, "%qs is not a gcov data file", da_file_name);
gcov_close ();
return;
}
else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
{
char v[4], e[4];
GCOV_UNSIGNED2STRING (v, tag);
GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
warning (0, "%qs is version %q.*s, expected version %q.*s",
da_file_name, 4, v, 4, e);
gcov_close ();
return;
}
/* Read the stamp, used for creating a generation count. */
tag = gcov_read_unsigned ();
bbg_file_stamp = crc32_unsigned (bbg_file_stamp, tag);
counts_hash.create (10);
while ((tag = gcov_read_unsigned ()))
{
gcov_unsigned_t length;
gcov_position_t offset;
length = gcov_read_unsigned ();
offset = gcov_position ();
if (tag == GCOV_TAG_FUNCTION)
{
if (length)
{
fn_ident = gcov_read_unsigned ();
lineno_checksum = gcov_read_unsigned ();
cfg_checksum = gcov_read_unsigned ();
}
else
fn_ident = lineno_checksum = cfg_checksum = 0;
new_summary = 1;
}
else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
{
struct gcov_summary sum;
unsigned ix;
if (new_summary)
memset (&summary, 0, sizeof (summary));
gcov_read_summary (&sum);
for (ix = 0; ix != GCOV_COUNTERS_SUMMABLE; ix++)
{
summary.ctrs[ix].runs += sum.ctrs[ix].runs;
summary.ctrs[ix].sum_all += sum.ctrs[ix].sum_all;
if (summary.ctrs[ix].run_max < sum.ctrs[ix].run_max)
summary.ctrs[ix].run_max = sum.ctrs[ix].run_max;
summary.ctrs[ix].sum_max += sum.ctrs[ix].sum_max;
}
new_summary = 0;
}
else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
{
counts_entry_t **slot, *entry, elt;
unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
unsigned ix;
elt.ident = fn_ident;
elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
slot = counts_hash.find_slot (&elt, INSERT);
entry = *slot;
if (!entry)
{
*slot = entry = XCNEW (counts_entry_t);
entry->ident = fn_ident;
entry->ctr = elt.ctr;
entry->lineno_checksum = lineno_checksum;
entry->cfg_checksum = cfg_checksum;
entry->summary = summary.ctrs[elt.ctr];
entry->summary.num = n_counts;
entry->counts = XCNEWVEC (gcov_type, n_counts);
}
else if (entry->lineno_checksum != lineno_checksum
|| entry->cfg_checksum != cfg_checksum)
{
error ("Profile data for function %u is corrupted", fn_ident);
error ("checksum is (%x,%x) instead of (%x,%x)",
entry->lineno_checksum, entry->cfg_checksum,
lineno_checksum, cfg_checksum);
counts_hash.dispose ();
break;
}
else if (entry->summary.num != n_counts)
{
error ("Profile data for function %u is corrupted", fn_ident);
error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
counts_hash.dispose ();
break;
}
else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
{
error ("cannot merge separate %s counters for function %u",
ctr_names[elt.ctr], fn_ident);
goto skip_merge;
}
else
{
entry->summary.runs += summary.ctrs[elt.ctr].runs;
entry->summary.sum_all += summary.ctrs[elt.ctr].sum_all;
if (entry->summary.run_max < summary.ctrs[elt.ctr].run_max)
entry->summary.run_max = summary.ctrs[elt.ctr].run_max;
entry->summary.sum_max += summary.ctrs[elt.ctr].sum_max;
}
for (ix = 0; ix != n_counts; ix++)
entry->counts[ix] += gcov_read_counter ();
skip_merge:;
}
gcov_sync (offset, length);
if ((is_error = gcov_is_error ()))
{
error (is_error < 0 ? "%qs has overflowed" : "%qs is corrupted",
da_file_name);
counts_hash.dispose ();
break;
}
}
gcov_close ();
}
/* Returns the counters for a particular tag. */
gcov_type *
get_coverage_counts (unsigned counter, unsigned expected,
unsigned cfg_checksum, unsigned lineno_checksum,
const struct gcov_ctr_summary **summary)
{
counts_entry_t *entry, elt;
/* No hash table, no counts. */
if (!counts_hash.is_created ())
{
static int warned = 0;
if (!warned++)
inform (input_location, (flag_guess_branch_prob
? "file %s not found, execution counts estimated"
: "file %s not found, execution counts assumed to be zero"),
da_file_name);
return NULL;
}
elt.ident = current_function_funcdef_no + 1;
elt.ctr = counter;
entry = counts_hash.find (&elt);
if (!entry || !entry->summary.num)
/* The function was not emitted, or is weak and not chosen in the
final executable. Silently fail, because there's nothing we
can do about it. */
return NULL;
if (entry->cfg_checksum != cfg_checksum
|| entry->summary.num != expected)
{
static int warned = 0;
bool warning_printed = false;
tree id = DECL_ASSEMBLER_NAME (current_function_decl);
warning_printed =
warning_at (input_location, OPT_Wcoverage_mismatch,
"the control flow of function %qE does not match "
"its profile data (counter %qs)", id, ctr_names[counter]);
if (warning_printed)
{
inform (input_location, "use -Wno-error=coverage-mismatch to tolerate "
"the mismatch but performance may drop if the function is hot");
if (!seen_error ()
&& !warned++)
{
inform (input_location, "coverage mismatch ignored");
inform (input_location, flag_guess_branch_prob
? G_("execution counts estimated")
: G_("execution counts assumed to be zero"));
if (!flag_guess_branch_prob)
inform (input_location,
"this can result in poorly optimized code");
}
}
return NULL;
}
else if (entry->lineno_checksum != lineno_checksum)
{
warning (0, "source locations for function %qE have changed,"
" the profile data may be out of date",
DECL_ASSEMBLER_NAME (current_function_decl));
}
if (summary)
*summary = &entry->summary;
return entry->counts;
}
/* Allocate NUM counters of type COUNTER. Returns nonzero if the
allocation succeeded. */
int
coverage_counter_alloc (unsigned counter, unsigned num)
{
if (no_coverage)
return 0;
if (!num)
return 1;
if (!fn_v_ctrs[counter])
{
tree array_type = build_array_type (get_gcov_type (), NULL_TREE);
fn_v_ctrs[counter]
= build_var (current_function_decl, array_type, counter);
}
fn_b_ctrs[counter] = fn_n_ctrs[counter];
fn_n_ctrs[counter] += num;
fn_ctr_mask |= 1 << counter;
return 1;
}
/* Generate a tree to access COUNTER NO. */
tree
tree_coverage_counter_ref (unsigned counter, unsigned no)
{
tree gcov_type_node = get_gcov_type ();
gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
no += fn_b_ctrs[counter];
/* "no" here is an array index, scaled to bytes later. */
return build4 (ARRAY_REF, gcov_type_node, fn_v_ctrs[counter],
build_int_cst (integer_type_node, no), NULL, NULL);
}
/* Generate a tree to access the address of COUNTER NO. */
tree
tree_coverage_counter_addr (unsigned counter, unsigned no)
{
tree gcov_type_node = get_gcov_type ();
gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
no += fn_b_ctrs[counter];
/* "no" here is an array index, scaled to bytes later. */
return build_fold_addr_expr (build4 (ARRAY_REF, gcov_type_node,
fn_v_ctrs[counter],
build_int_cst (integer_type_node, no),
NULL, NULL));
}
/* Generate a checksum for a string. CHKSUM is the current
checksum. */
static unsigned
coverage_checksum_string (unsigned chksum, const char *string)
{
int i;
char *dup = NULL;
/* Look for everything that looks if it were produced by
get_file_function_name and zero out the second part
that may result from flag_random_seed. This is not critical
as the checksums are used only for sanity checking. */
for (i = 0; string[i]; i++)
{
int offset = 0;
if (!strncmp (string + i, "_GLOBAL__N_", 11))
offset = 11;
if (!strncmp (string + i, "_GLOBAL__", 9))
offset = 9;
/* C++ namespaces do have scheme:
_GLOBAL__N_<filename>_<wrongmagicnumber>_<magicnumber>functionname
since filename might contain extra underscores there seems
to be no better chance then walk all possible offsets looking
for magicnumber. */
if (offset)
{
for (i = i + offset; string[i]; i++)
if (string[i]=='_')
{
int y;
for (y = 1; y < 9; y++)
if (!(string[i + y] >= '0' && string[i + y] <= '9')
&& !(string[i + y] >= 'A' && string[i + y] <= 'F'))
break;
if (y != 9 || string[i + 9] != '_')
continue;
for (y = 10; y < 18; y++)
if (!(string[i + y] >= '0' && string[i + y] <= '9')
&& !(string[i + y] >= 'A' && string[i + y] <= 'F'))
break;
if (y != 18)
continue;
if (!dup)
string = dup = xstrdup (string);
for (y = 10; y < 18; y++)
dup[i + y] = '0';
}
break;
}
}
chksum = crc32_string (chksum, string);
free (dup);
return chksum;
}
/* Compute checksum for the current function. We generate a CRC32. */
unsigned
coverage_compute_lineno_checksum (void)
{
expanded_location xloc
= expand_location (DECL_SOURCE_LOCATION (current_function_decl));
unsigned chksum = xloc.line;
chksum = coverage_checksum_string (chksum, xloc.file);
chksum = coverage_checksum_string
(chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
return chksum;
}
/* Compute cfg checksum for the current function.
The checksum is calculated carefully so that
source code changes that doesn't affect the control flow graph
won't change the checksum.
This is to make the profile data useable across source code change.
The downside of this is that the compiler may use potentially
wrong profile data - that the source code change has non-trivial impact
on the validity of profile data (e.g. the reversed condition)
but the compiler won't detect the change and use the wrong profile data. */
unsigned
coverage_compute_cfg_checksum (void)
{
basic_block bb;
unsigned chksum = n_basic_blocks;
FOR_EACH_BB (bb)
{
edge e;
edge_iterator ei;
chksum = crc32_byte (chksum, bb->index);
FOR_EACH_EDGE (e, ei, bb->succs)
{
chksum = crc32_byte (chksum, e->dest->index);
}
}
return chksum;
}
/* Begin output to the notes file for the current function.
Writes the function header. Returns nonzero if data should be output. */
int
coverage_begin_function (unsigned lineno_checksum, unsigned cfg_checksum)
{
expanded_location xloc;
unsigned long offset;
/* We don't need to output .gcno file unless we're under -ftest-coverage
(e.g. -fprofile-arcs/generate/use don't need .gcno to work). */
if (no_coverage || !bbg_file_name)
return 0;
xloc = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
/* Announce function */
offset = gcov_write_tag (GCOV_TAG_FUNCTION);
gcov_write_unsigned (current_function_funcdef_no + 1);
gcov_write_unsigned (lineno_checksum);
gcov_write_unsigned (cfg_checksum);
gcov_write_string (IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl)));
gcov_write_string (xloc.file);
gcov_write_unsigned (xloc.line);
gcov_write_length (offset);
return !gcov_is_error ();
}
/* Finish coverage data for the current function. Verify no output
error has occurred. Save function coverage counts. */
void
coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum)
{
unsigned i;
if (bbg_file_name && gcov_is_error ())
{
warning (0, "error writing %qs", bbg_file_name);
unlink (bbg_file_name);
bbg_file_name = NULL;
}
if (fn_ctr_mask)
{
struct coverage_data *item = 0;
/* If the function is extern (i.e. extern inline), then we won't
be outputting it, so don't chain it onto the function
list. */
if (!DECL_EXTERNAL (current_function_decl))
{
item = ggc_alloc_coverage_data ();
item->ident = current_function_funcdef_no + 1;
item->lineno_checksum = lineno_checksum;
item->cfg_checksum = cfg_checksum;
item->fn_decl = current_function_decl;
item->next = 0;
*functions_tail = item;
functions_tail = &item->next;
}
for (i = 0; i != GCOV_COUNTERS; i++)
{
tree var = fn_v_ctrs[i];
if (item)
item->ctr_vars[i] = var;
if (var)
{
tree array_type = build_index_type (size_int (fn_n_ctrs[i] - 1));
array_type = build_array_type (get_gcov_type (), array_type);
TREE_TYPE (var) = array_type;
DECL_SIZE (var) = TYPE_SIZE (array_type);
DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (array_type);
varpool_finalize_decl (var);
}
fn_b_ctrs[i] = fn_n_ctrs[i] = 0;
fn_v_ctrs[i] = NULL_TREE;
}
prg_ctr_mask |= fn_ctr_mask;
fn_ctr_mask = 0;
}
}
/* Build a coverage variable of TYPE for function FN_DECL. If COUNTER
>= 0 it is a counter array, otherwise it is the function structure. */
static tree
build_var (tree fn_decl, tree type, int counter)
{
tree var = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL_TREE, type);
const char *fn_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn_decl));
char *buf;
size_t fn_name_len, len;
fn_name = targetm.strip_name_encoding (fn_name);
fn_name_len = strlen (fn_name);
buf = XALLOCAVEC (char, fn_name_len + 8 + sizeof (int) * 3);
if (counter < 0)
strcpy (buf, "__gcov__");
else
sprintf (buf, "__gcov%u_", counter);
len = strlen (buf);
#ifndef NO_DOT_IN_LABEL
buf[len - 1] = '.';
#elif !defined NO_DOLLAR_IN_LABEL
buf[len - 1] = '$';
#endif
memcpy (buf + len, fn_name, fn_name_len + 1);
DECL_NAME (var) = get_identifier (buf);
TREE_STATIC (var) = 1;
TREE_ADDRESSABLE (var) = 1;
DECL_ALIGN (var) = TYPE_ALIGN (type);
return var;
}
/* Creates the gcov_fn_info RECORD_TYPE. */
static void
build_fn_info_type (tree type, unsigned counters, tree gcov_info_type)
{
tree ctr_info = lang_hooks.types.make_type (RECORD_TYPE);
tree field, fields;
tree array_type;
gcc_assert (counters);
/* ctr_info::num */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
get_gcov_unsigned_t ());
fields = field;
/* ctr_info::values */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
build_pointer_type (get_gcov_type ()));
DECL_CHAIN (field) = fields;
fields = field;
finish_builtin_struct (ctr_info, "__gcov_ctr_info", fields, NULL_TREE);
/* key */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
build_pointer_type (build_qualified_type
(gcov_info_type, TYPE_QUAL_CONST)));
fields = field;
/* ident */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
get_gcov_unsigned_t ());
DECL_CHAIN (field) = fields;
fields = field;
/* lineno_checksum */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
get_gcov_unsigned_t ());
DECL_CHAIN (field) = fields;
fields = field;
/* cfg checksum */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
get_gcov_unsigned_t ());
DECL_CHAIN (field) = fields;
fields = field;
array_type = build_index_type (size_int (counters - 1));
array_type = build_array_type (ctr_info, array_type);
/* counters */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, array_type);
DECL_CHAIN (field) = fields;
fields = field;
finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
}
/* Returns a CONSTRUCTOR for a gcov_fn_info. DATA is
the coverage data for the function and TYPE is the gcov_fn_info
RECORD_TYPE. KEY is the object file key. */
static tree
build_fn_info (const struct coverage_data *data, tree type, tree key)
{
tree fields = TYPE_FIELDS (type);
tree ctr_type;
unsigned ix;
VEC(constructor_elt,gc) *v1 = NULL;
VEC(constructor_elt,gc) *v2 = NULL;
/* key */
CONSTRUCTOR_APPEND_ELT (v1, fields,
build1 (ADDR_EXPR, TREE_TYPE (fields), key));
fields = DECL_CHAIN (fields);
/* ident */
CONSTRUCTOR_APPEND_ELT (v1, fields,
build_int_cstu (get_gcov_unsigned_t (),
data->ident));
fields = DECL_CHAIN (fields);
/* lineno_checksum */
CONSTRUCTOR_APPEND_ELT (v1, fields,
build_int_cstu (get_gcov_unsigned_t (),
data->lineno_checksum));
fields = DECL_CHAIN (fields);
/* cfg_checksum */
CONSTRUCTOR_APPEND_ELT (v1, fields,
build_int_cstu (get_gcov_unsigned_t (),
data->cfg_checksum));
fields = DECL_CHAIN (fields);
/* counters */
ctr_type = TREE_TYPE (TREE_TYPE (fields));
for (ix = 0; ix != GCOV_COUNTERS; ix++)
if (prg_ctr_mask & (1 << ix))
{
VEC(constructor_elt,gc) *ctr = NULL;
tree var = data->ctr_vars[ix];
unsigned count = 0;
if (var)
count
= tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (var))), 0)
+ 1;
CONSTRUCTOR_APPEND_ELT (ctr, TYPE_FIELDS (ctr_type),
build_int_cstu (get_gcov_unsigned_t (),
count));
if (var)
CONSTRUCTOR_APPEND_ELT (ctr, DECL_CHAIN (TYPE_FIELDS (ctr_type)),
build_fold_addr_expr (var));
CONSTRUCTOR_APPEND_ELT (v2, NULL, build_constructor (ctr_type, ctr));
}
CONSTRUCTOR_APPEND_ELT (v1, fields,
build_constructor (TREE_TYPE (fields), v2));
return build_constructor (type, v1);
}
/* Create gcov_info struct. TYPE is the incomplete RECORD_TYPE to be
completed, and FN_INFO_PTR_TYPE is a pointer to the function info type. */
static void
build_info_type (tree type, tree fn_info_ptr_type)
{
tree field, fields = NULL_TREE;
tree merge_fn_type;
/* Version ident */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
get_gcov_unsigned_t ());
DECL_CHAIN (field) = fields;
fields = field;
/* next pointer */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
build_pointer_type (build_qualified_type
(type, TYPE_QUAL_CONST)));
DECL_CHAIN (field) = fields;
fields = field;
/* stamp */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
get_gcov_unsigned_t ());
DECL_CHAIN (field) = fields;
fields = field;
/* Filename */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
build_pointer_type (build_qualified_type
(char_type_node, TYPE_QUAL_CONST)));
DECL_CHAIN (field) = fields;
fields = field;
/* merge fn array */
merge_fn_type
= build_function_type_list (void_type_node,
build_pointer_type (get_gcov_type ()),
get_gcov_unsigned_t (), NULL_TREE);
merge_fn_type
= build_array_type (build_pointer_type (merge_fn_type),
build_index_type (size_int (GCOV_COUNTERS - 1)));
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
merge_fn_type);
DECL_CHAIN (field) = fields;
fields = field;
/* n_functions */
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
get_gcov_unsigned_t ());
DECL_CHAIN (field) = fields;
fields = field;
/* function_info pointer pointer */
fn_info_ptr_type = build_pointer_type
(build_qualified_type (fn_info_ptr_type, TYPE_QUAL_CONST));
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
fn_info_ptr_type);
DECL_CHAIN (field) = fields;
fields = field;
finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
}
/* Returns a CONSTRUCTOR for the gcov_info object. INFO_TYPE is the
gcov_info structure type, FN_ARY is the array of pointers to
function info objects. */
static tree
build_info (tree info_type, tree fn_ary)
{
tree info_fields = TYPE_FIELDS (info_type);
tree merge_fn_type, n_funcs;
unsigned ix;
tree filename_string;
int da_file_name_len;
VEC(constructor_elt,gc) *v1 = NULL;
VEC(constructor_elt,gc) *v2 = NULL;
/* Version ident */
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
build_int_cstu (TREE_TYPE (info_fields),
GCOV_VERSION));
info_fields = DECL_CHAIN (info_fields);
/* next -- NULL */
CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
info_fields = DECL_CHAIN (info_fields);
/* stamp */
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
build_int_cstu (TREE_TYPE (info_fields),
bbg_file_stamp));
info_fields = DECL_CHAIN (info_fields);
/* Filename */
da_file_name_len = strlen (da_file_name);
filename_string = build_string (da_file_name_len + 1, da_file_name);
TREE_TYPE (filename_string) = build_array_type
(char_type_node, build_index_type (size_int (da_file_name_len)));
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
build1 (ADDR_EXPR, TREE_TYPE (info_fields),
filename_string));
info_fields = DECL_CHAIN (info_fields);
/* merge fn array -- NULL slots indicate unmeasured counters */
merge_fn_type = TREE_TYPE (TREE_TYPE (info_fields));
for (ix = 0; ix != GCOV_COUNTERS; ix++)
{
tree ptr = null_pointer_node;
if ((1u << ix) & prg_ctr_mask)
{
tree merge_fn = build_decl (BUILTINS_LOCATION,
FUNCTION_DECL,
get_identifier (ctr_merge_functions[ix]),
TREE_TYPE (merge_fn_type));
DECL_EXTERNAL (merge_fn) = 1;
TREE_PUBLIC (merge_fn) = 1;
DECL_ARTIFICIAL (merge_fn) = 1;
TREE_NOTHROW (merge_fn) = 1;
/* Initialize assembler name so we can stream out. */
DECL_ASSEMBLER_NAME (merge_fn);
ptr = build1 (ADDR_EXPR, merge_fn_type, merge_fn);
}
CONSTRUCTOR_APPEND_ELT (v2, NULL, ptr);
}
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
build_constructor (TREE_TYPE (info_fields), v2));
info_fields = DECL_CHAIN (info_fields);
/* n_functions */
n_funcs = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (fn_ary)));
n_funcs = fold_build2 (PLUS_EXPR, TREE_TYPE (info_fields),
n_funcs, size_one_node);
CONSTRUCTOR_APPEND_ELT (v1, info_fields, n_funcs);
info_fields = DECL_CHAIN (info_fields);
/* functions */
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
build1 (ADDR_EXPR, TREE_TYPE (info_fields), fn_ary));
info_fields = DECL_CHAIN (info_fields);
gcc_assert (!info_fields);
return build_constructor (info_type, v1);
}
/* Create the gcov_info types and object. Generate the constructor
function to call __gcov_init. Does not generate the initializer
for the object. Returns TRUE if coverage data is being emitted. */
static bool
coverage_obj_init (void)
{
tree gcov_info_type, ctor, stmt, init_fn;
unsigned n_counters = 0;
unsigned ix;
struct coverage_data *fn;
struct coverage_data **fn_prev;
char name_buf[32];
no_coverage = 1; /* Disable any further coverage. */
if (!prg_ctr_mask)
return false;
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "Using data file %s\n", da_file_name);
/* Prune functions. */
for (fn_prev = &functions_head; (fn = *fn_prev);)
if (DECL_STRUCT_FUNCTION (fn->fn_decl))
fn_prev = &fn->next;
else
/* The function is not being emitted, remove from list. */
*fn_prev = fn->next;
for (ix = 0; ix != GCOV_COUNTERS; ix++)
if ((1u << ix) & prg_ctr_mask)
n_counters++;
/* Build the info and fn_info types. These are mutually recursive. */
gcov_info_type = lang_hooks.types.make_type (RECORD_TYPE);
gcov_fn_info_type = lang_hooks.types.make_type (RECORD_TYPE);
gcov_fn_info_ptr_type = build_pointer_type
(build_qualified_type (gcov_fn_info_type, TYPE_QUAL_CONST));
build_fn_info_type (gcov_fn_info_type, n_counters, gcov_info_type);
build_info_type (gcov_info_type, gcov_fn_info_ptr_type);
/* Build the gcov info var, this is referred to in its own
initializer. */
gcov_info_var = build_decl (BUILTINS_LOCATION,
VAR_DECL, NULL_TREE, gcov_info_type);
TREE_STATIC (gcov_info_var) = 1;
ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0);
DECL_NAME (gcov_info_var) = get_identifier (name_buf);
/* Build a decl for __gcov_init. */
init_fn = build_pointer_type (gcov_info_type);
init_fn = build_function_type_list (void_type_node, init_fn, NULL);
init_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
get_identifier ("__gcov_init"), init_fn);
TREE_PUBLIC (init_fn) = 1;
DECL_EXTERNAL (init_fn) = 1;
DECL_ASSEMBLER_NAME (init_fn);
/* Generate a call to __gcov_init(&gcov_info). */
ctor = NULL;
stmt = build_fold_addr_expr (gcov_info_var);
stmt = build_call_expr (init_fn, 1, stmt);
append_to_statement_list (stmt, &ctor);
/* Generate a constructor to run it. */
cgraph_build_static_cdtor ('I', ctor, DEFAULT_INIT_PRIORITY);
return true;
}
/* Generate the coverage function info for FN and DATA. Append a
pointer to that object to CTOR and return the appended CTOR. */
static VEC(constructor_elt,gc) *
coverage_obj_fn (VEC(constructor_elt,gc) *ctor, tree fn,
struct coverage_data const *data)
{
tree init = build_fn_info (data, gcov_fn_info_type, gcov_info_var);
tree var = build_var (fn, gcov_fn_info_type, -1);
DECL_INITIAL (var) = init;
varpool_finalize_decl (var);
CONSTRUCTOR_APPEND_ELT (ctor, NULL,
build1 (ADDR_EXPR, gcov_fn_info_ptr_type, var));
return ctor;
}
/* Finalize the coverage data. Generates the array of pointers to
function objects from CTOR. Generate the gcov_info initializer. */
static void
coverage_obj_finish (VEC(constructor_elt,gc) *ctor)
{
unsigned n_functions = VEC_length(constructor_elt, ctor);
tree fn_info_ary_type = build_array_type
(build_qualified_type (gcov_fn_info_ptr_type, TYPE_QUAL_CONST),
build_index_type (size_int (n_functions - 1)));
tree fn_info_ary = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL_TREE,
fn_info_ary_type);
char name_buf[32];
TREE_STATIC (fn_info_ary) = 1;
ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 1);
DECL_NAME (fn_info_ary) = get_identifier (name_buf);
DECL_INITIAL (fn_info_ary) = build_constructor (fn_info_ary_type, ctor);
varpool_finalize_decl (fn_info_ary);
DECL_INITIAL (gcov_info_var)
= build_info (TREE_TYPE (gcov_info_var), fn_info_ary);
varpool_finalize_decl (gcov_info_var);
}
/* Perform file-level initialization. Read in data file, generate name
of notes file. */
void
coverage_init (const char *filename)
{
int len = strlen (filename);
int prefix_len = 0;
if (!profile_data_prefix && !IS_ABSOLUTE_PATH (filename))
profile_data_prefix = getpwd ();
if (profile_data_prefix)
prefix_len = strlen (profile_data_prefix);
/* Name of da file. */
da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX)
+ prefix_len + 2);
if (profile_data_prefix)
{
memcpy (da_file_name, profile_data_prefix, prefix_len);
da_file_name[prefix_len++] = '/';
}
memcpy (da_file_name + prefix_len, filename, len);
strcpy (da_file_name + prefix_len + len, GCOV_DATA_SUFFIX);
bbg_file_stamp = local_tick;
if (flag_branch_probabilities)
read_counts_file ();
/* Name of bbg file. */
if (flag_test_coverage && !flag_compare_debug)
{
bbg_file_name = XNEWVEC (char, len + strlen (GCOV_NOTE_SUFFIX) + 1);
memcpy (bbg_file_name, filename, len);
strcpy (bbg_file_name + len, GCOV_NOTE_SUFFIX);
if (!gcov_open (bbg_file_name, -1))
{
error ("cannot open %s", bbg_file_name);
bbg_file_name = NULL;
}
else
{
gcov_write_unsigned (GCOV_NOTE_MAGIC);
gcov_write_unsigned (GCOV_VERSION);
gcov_write_unsigned (bbg_file_stamp);
}
}
}
/* Performs file-level cleanup. Close notes file, generate coverage
variables and constructor. */
void
coverage_finish (void)
{
if (bbg_file_name && gcov_close ())
unlink (bbg_file_name);
if (!flag_branch_probabilities && flag_test_coverage
&& (!local_tick || local_tick == (unsigned)-1))
/* Only remove the da file, if we're emitting coverage code and
cannot uniquely stamp it. If we can stamp it, libgcov will DTRT. */
unlink (da_file_name);
if (coverage_obj_init ())
{
VEC(constructor_elt,gc) *fn_ctor = NULL;
struct coverage_data *fn;
for (fn = functions_head; fn; fn = fn->next)
fn_ctor = coverage_obj_fn (fn_ctor, fn->fn_decl, fn);
coverage_obj_finish (fn_ctor);
}
}
#include "gt-coverage.h"