d5e254e19c
gcc/ 2014-11-05 Ilya Enkovich <ilya.enkovich@intel.com> * ipa-chkp.c: New. * ipa-chkp.h: New. * tree-chkp.c: New. * tree-chkp.h: New. * tree-chkp-opt.c: New. * rtl-chkp.c: New. * rtl-chkp.h: New. * Makefile.in (OBJS): Add ipa-chkp.o, rtl-chkp.o, tree-chkp.o tree-chkp-opt.o. (GTFILES): Add tree-chkp.c. * mode-classes.def (MODE_POINTER_BOUNDS): New. * tree.def (POINTER_BOUNDS_TYPE): New. * genmodes.c (complete_mode): Support MODE_POINTER_BOUNDS. (POINTER_BOUNDS_MODE): New. (make_pointer_bounds_mode): New. * machmode.h (POINTER_BOUNDS_MODE_P): New. * stor-layout.c (int_mode_for_mode): Support MODE_POINTER_BOUNDS. (layout_type): Support POINTER_BOUNDS_TYPE. * tree-pretty-print.c (dump_generic_node): Support POINTER_BOUNDS_TYPE. * tree-core.h (tree_index): Add TI_POINTER_BOUNDS_TYPE. * tree.c (build_int_cst_wide): Support POINTER_BOUNDS_TYPE. (type_contains_placeholder_1): Likewise. (build_common_tree_nodes): Initialize pointer_bounds_type_node. * tree.h (POINTER_BOUNDS_TYPE_P): New. (pointer_bounds_type_node): New. (POINTER_BOUNDS_P): New. (BOUNDED_TYPE_P): New. (BOUNDED_P): New. (CALL_WITH_BOUNDS_P): New. * gimple.h (gf_mask): Add GF_CALL_WITH_BOUNDS. (gimple_call_with_bounds_p): New. (gimple_call_set_with_bounds): New. (gimple_return_retbnd): New. (gimple_return_set_retbnd): New * gimple.c (gimple_build_return): Increase number of ops for return statement. (gimple_build_call_from_tree): Propagate CALL_WITH_BOUNDS_P flag. * gimple-pretty-print.c (dump_gimple_return): Print second op. * rtl.h (CALL_EXPR_WITH_BOUNDS_P): New. * gimplify.c (gimplify_init_constructor): Avoid infinite loop during gimplification of bounds initializer. * calls.c: Include tree-chkp.h, rtl-chkp.h, bitmap.h. (special_function_p): Use original decl name when analyzing instrumentation clone. (arg_data): Add fields special_slot, pointer_arg and pointer_offset. (store_bounds): New. (emit_call_1): Propagate instrumentation flag for CALL. (initialize_argument_information): Compute pointer_arg, pointer_offset and special_slot for pointer bounds arguments. (finalize_must_preallocate): Preallocate when storing bounds in bounds table. (compute_argument_addresses): Skip pointer bounds. (expand_call): Store bounds into tables separately. Return result joined with resulting bounds. * cfgexpand.c: Include tree-chkp.h, rtl-chkp.h. (expand_call_stmt): Propagate bounds flag for CALL_EXPR. (expand_return): Add returned bounds arg. Handle returned bounds. (expand_gimple_stmt_1): Adjust to new expand_return signature. (gimple_expand_cfg): Reset rtx bounds map. * expr.c: Include tree-chkp.h, rtl-chkp.h. (expand_assignment): Handle returned bounds. (store_expr_with_bounds): New. Replaces store_expr with new bounds target argument. Handle bounds returned by calls. (store_expr): Now wraps store_expr_with_bounds. * expr.h (store_expr_with_bounds): New. * function.c: Include tree-chkp.h, rtl-chkp.h. (bounds_parm_data): New. (use_register_for_decl): Do not registerize decls used for bounds stores and loads. (assign_parms_augmented_arg_list): Add bounds of the result structure pointer as the second argument. (assign_parm_find_entry_rtl): Mark bounds are never passed on the stack. (assign_parm_is_stack_parm): Likewise. (assign_parm_load_bounds): New. (assign_bounds): New. (assign_parms): Load bounds and determine a location for returned bounds. (diddle_return_value_1): New. (diddle_return_value): Handle returned bounds. * function.h (rtl_data): Add field for returned bounds. * varasm.c: Include tree-chkp.h. (output_constant): Support POINTER_BOUNDS_TYPE. (output_constant_pool_2): Support MODE_POINTER_BOUNDS. (ultimate_transparent_alias_target): Move up. (make_decl_rtl): For instrumented function use name of the original decl. (assemble_start_function): Mark function as global in case it is instrumentation clone of the global function. (do_assemble_alias): Follow transparent alias chain for identifier. Check if original alias is public. (maybe_assemble_visibility): Use visibility of the original function for instrumented version. (default_unique_section): Likewise. * emit-rtl.c (immed_double_const): Support MODE_POINTER_BOUNDS. (init_emit_once): Build pointer bounds zero constants. * explow.c (trunc_int_for_mode): Support MODE_POINTER_BOUNDS. * target.def (builtin_chkp_function): New. (chkp_bound_type): New. (chkp_bound_mode): New. (chkp_make_bounds_constant): New. (chkp_initialize_bounds): New. (load_bounds_for_arg): New. (store_bounds_for_arg): New. (load_returned_bounds): New. (store_returned_bounds): New. (chkp_function_value_bounds): New. (setup_incoming_vararg_bounds): New. (function_arg): Update hook description with new possible return value CONST_INT. * targhooks.h (default_load_bounds_for_arg): New. (default_store_bounds_for_arg): New. (default_load_returned_bounds): New. (default_store_returned_bounds): New. (default_chkp_bound_type): New. (default_chkp_bound_mode): New. (default_builtin_chkp_function): New. (default_chkp_function_value_bounds): New. (default_chkp_make_bounds_constant): New. (default_chkp_initialize_bounds): New. (default_setup_incoming_vararg_bounds): New. * targhooks.c (default_load_bounds_for_arg): New. (default_store_bounds_for_arg): New. (default_load_returned_bounds): New. (default_store_returned_bounds): New. (default_chkp_bound_type): New. (default_chkp_bound_mode); New. (default_builtin_chkp_function): New. (default_chkp_function_value_bounds): New. (default_chkp_make_bounds_constant): New. (default_chkp_initialize_bounds): New. (default_setup_incoming_vararg_bounds): New. * builtin-types.def (BT_BND): New. (BT_FN_PTR_CONST_PTR): New. (BT_FN_CONST_PTR_CONST_PTR): New. (BT_FN_BND_CONST_PTR): New. (BT_FN_CONST_PTR_BND): New. (BT_FN_PTR_CONST_PTR_SIZE): New. (BT_FN_PTR_CONST_PTR_CONST_PTR): New. (BT_FN_VOID_PTRPTR_CONST_PTR): New. (BT_FN_VOID_CONST_PTR_SIZE): New. (BT_FN_VOID_PTR_BND): New. (BT_FN_CONST_PTR_CONST_PTR_CONST_PTR): New. (BT_FN_BND_CONST_PTR_SIZE): New. (BT_FN_PTR_CONST_PTR_CONST_PTR_SIZE): New. (BT_FN_VOID_CONST_PTR_BND_CONST_PTR): New. * chkp-builtins.def: New. * builtins.def: include chkp-builtins.def. (DEF_CHKP_BUILTIN): New. * builtins.c: Include tree-chkp.h and rtl-chkp.h. (expand_builtin): Support BUILT_IN_CHKP_INIT_PTR_BOUNDS, BUILT_IN_CHKP_NULL_PTR_BOUNDS, BUILT_IN_CHKP_COPY_PTR_BOUNDS, BUILT_IN_CHKP_CHECK_PTR_LBOUNDS, BUILT_IN_CHKP_CHECK_PTR_UBOUNDS, BUILT_IN_CHKP_CHECK_PTR_BOUNDS, BUILT_IN_CHKP_SET_PTR_BOUNDS, BUILT_IN_CHKP_NARROW_PTR_BOUNDS, BUILT_IN_CHKP_STORE_PTR_BOUNDS, BUILT_IN_CHKP_GET_PTR_LBOUND, BUILT_IN_CHKP_GET_PTR_UBOUND, BUILT_IN_CHKP_BNDMK, BUILT_IN_CHKP_BNDSTX, BUILT_IN_CHKP_BNDCL, BUILT_IN_CHKP_BNDCU, BUILT_IN_CHKP_BNDLDX, BUILT_IN_CHKP_BNDRET, BUILT_IN_CHKP_INTERSECT, BUILT_IN_CHKP_NARROW, BUILT_IN_CHKP_EXTRACT_LOWER, BUILT_IN_CHKP_EXTRACT_UPPER. (std_expand_builtin_va_start): Init bounds for va_list. * cppbuiltin.c (define_builtin_macros_for_compilation_flags): Add __CHKP__ macro when Pointer Bounds Checker is on. * params.def (PARAM_CHKP_MAX_CTOR_SIZE): New. * passes.def (pass_ipa_chkp_versioning): New. (pass_early_local_passes): Renamed to pass_build_ssa_passes. (pass_fixup_cfg): Moved to pass_chkp_instrumentation_passes. (pass_chkp_instrumentation_passes): New. (pass_ipa_chkp_produce_thunks): New. (pass_local_optimization_passes): New. (pass_chkp_opt): New. * tree-pass.h (make_pass_ipa_chkp_versioning): New. (make_pass_ipa_chkp_produce_thunks): New. (make_pass_chkp): New. (make_pass_chkp_opt): New. (make_pass_early_local_passes): Renamed to ... (make_pass_build_ssa_passes): This. (make_pass_chkp_instrumentation_passes): New. (make_pass_local_optimization_passes): New. * passes.c (pass_manager::execute_early_local_passes): Execute early passes in three steps. (execute_all_early_local_passes): Renamed to ... (execute_build_ssa_passes): This. (pass_data_early_local_passes): Renamed to ... (pass_data_build_ssa_passes): This. (pass_early_local_passes): Renamed to ... (pass_build_ssa_passes): This. (pass_data_chkp_instrumentation_passes): New. (pass_chkp_instrumentation_passes): New. (pass_data_local_optimization_passes): New. (pass_local_optimization_passes): New. (make_pass_early_local_passes): Renamed to ... (make_pass_build_ssa_passes): This. (make_pass_chkp_instrumentation_passes): New. (make_pass_local_optimization_passes): New. * c-family/c.opt (fcheck-pointer-bounds): New. (fchkp-check-incomplete-type): New. (fchkp-zero-input-bounds-for-main): New. (fchkp-first-field-has-own-bounds): New. (fchkp-narrow-bounds): New. (fchkp-narrow-to-innermost-array): New. (fchkp-optimize): New. (fchkp-use-fast-string-functions): New. (fchkp-use-nochk-string-functions): New. (fchkp-use-static-bounds): New. (fchkp-use-static-const-bounds): New. (fchkp-treat-zero-dynamic-size-as-infinite): New. (fchkp-check-read): New. (fchkp-check-write): New. (fchkp-store-bounds): New. (fchkp-instrument-calls): New. (fchkp-instrument-marked-only): New. (Wchkp): New. * c-family/c-common.c (handle_bnd_variable_size_attribute): New. (handle_bnd_legacy): New. (handle_bnd_instrument): New. (c_common_attribute_table): Add bnd_variable_size, bnd_legacy and bnd_instrument. Fix documentation. (c_common_format_attribute_table): Likewsie. * toplev.c: include tree-chkp.h. (process_options): Check Pointer Bounds Checker is supported. (compile_file): Add chkp_finish_file call. * ipa-cp.c (initialize_node_lattices): Use cgraph_local_p to handle instrumentation clones properly. (propagate_constants_accross_call): Do not propagate through instrumentation thunks. * ipa-pure-const.c (propagate_pure_const): Support IPA_REF_CHKP. * ipa-inline.c (early_inliner): Check edge has summary allocated. * ipa-split.c: Include tree-chkp.h. (find_retbnd): New. (split_part_set_ssa_name_p): New. (consider_split): Do not split retbnd and retval producers. (insert_bndret_call_after): new. (split_function): Propagate Pointer Bounds Checker instrumentation marks and handle returned bounds. * tree-ssa-sccvn.h (vn_reference_op_struct): Transform opcode into bit field and add with_bounds field. * tree-ssa-sccvn.c (copy_reference_ops_from_call): Set with_bounds field for instrumented calls. * tree-ssa-pre.c (create_component_ref_by_pieces_1): Restore CALL_WITH_BOUNDS_P flag for calls. * tree-ssa-ccp.c: Include tree-chkp.h. (insert_clobber_before_stack_restore): Handle BUILT_IN_CHKP_BNDRET calls. * tree-ssa-dce.c: Include tree-chkp.h. (propagate_necessity): For free call fed by alloc check bounds are also provided by the same alloc. (eliminate_unnecessary_stmts): Handle BUILT_IN_CHKP_BNDRET used by free calls. * tree-inline.c: Include tree-chkp.h. (declare_return_variable): Add arg holding returned bounds slot. Create and initialize returned bounds var. (remap_gimple_stmt): Handle returned bounds. Return sequence of statements instead of a single statement. (insert_init_stmt): Add declaration. (remap_gimple_seq): Adjust to new remap_gimple_stmt signature. (copy_bb): Adjust to changed return type of remap_gimple_stmt. Properly handle bounds in va_arg_pack and va_arg_pack_len. (expand_call_inline): Handle returned bounds. Add bounds copy for generated mem to mem assignments. * tree-inline.h (copy_body_data): Add fields retbnd and assign_stmts. * value-prof.c: Include tree-chkp.h. (gimple_ic): Support returned bounds. * ipa.c (cgraph_build_static_cdtor_1): Support contructors with "chkp ctor" and "bnd_legacy" attributes. (symtab_remove_unreachable_nodes): Keep initial values for pointer bounds to be used for checks eliminations. (process_references): Handle IPA_REF_CHKP. (walk_polymorphic_call_targets): Likewise. * ipa-visibility.c (cgraph_externally_visible_p): Mark instrumented 'main' as externally visible. (function_and_variable_visibility): Filter instrumentation thunks. * cgraph.h (cgraph_thunk_info): Add add_pointer_bounds_args field. (cgraph_node): Add instrumented_version, orig_decl and instrumentation_clone fields. (symtab_node::get_alias_target): Allow IPA_REF_CHKP reference. (varpool_node): Add need_bounds_init field. (cgraph_local_p): New. * cgraph.c: Include tree-chkp.h. (cgraph_node::remove): Fix instrumented_version of the referenced node if any. (cgraph_node::dump): Dump instrumentation_clone and instrumented_version fields. (cgraph_node::verify_node): Check correctness of IPA_REF_CHKP references and instrumentation thunks. (cgraph_can_remove_if_no_direct_calls_and_refs_p): Keep all not instrumented instrumentation clones alive. (cgraph_redirect_edge_call_stmt_to_callee): Support returned bounds. * cgraphbuild.c (rebuild_cgraph_edges): Rebuild IPA_REF_CHKP reference. (cgraph_rebuild_references): Likewise. * cgraphunit.c: Include tree-chkp.h. (assemble_thunks_and_aliases): Skip thunks calling instrumneted function version. (varpool_finalize_decl): Register statically initialized decls in Pointer Bounds Checker. (walk_polymorphic_call_targets): Do not mark generated call to __builtin_unreachable as with_bounds. (output_weakrefs): If there are both instrumented and original versions, output only one of them. (cgraph_node::expand_thunk): Set with_bounds flag for created call statement. * ipa-ref.h (ipa_ref_use): Add IPA_REF_CHKP. (ipa_ref): increase size of use field. * symtab.c (ipa_ref_use_name): Add element for IPA_REF_CHKP. * varpool.c (dump_varpool_node): Dump need_bounds_init field. (ctor_for_folding): Do not fold constant bounds vars. * lto-streamer.h (LTO_minor_version): Change minor version from 0 to 1. * lto-cgraph.c (compute_ltrans_boundary): Keep initial values for pointer bounds. (lto_output_node): Output instrumentation_clone, thunk.add_pointer_bounds_args and orig_decl field. (lto_output_ref): Adjust to new ipa_ref::use field size. (input_overwrite_node): Read instrumentation_clone field. (input_node): Read thunk.add_pointer_bounds_args and orig_decl fields. (input_ref): Adjust to new ipa_ref::use field size. (input_cgraph_1): Compute instrumented_version fields and restore IDENTIFIER_TRANSPARENT_ALIAS chains. (lto_output_varpool_node): Output need_bounds_init value. (input_varpool_node): Read need_bounds_init value. * lto-partition.c (add_symbol_to_partition_1): Keep original and instrumented versions together. (privatize_symbol_name): Restore transparent alias chain if required. (add_references_to_partition): Add references to pointer bounds vars. * dbxout.c (dbxout_type): Ignore POINTER_BOUNDS_TYPE. * dwarf2out.c (gen_subprogram_die): Ignore bound args. (gen_type_die_with_usage): Skip pointer bounds. (dwarf2out_global_decl): Likewise. (is_base_type): Support POINTER_BOUNDS_TYPE. (gen_formal_types_die): Skip pointer bounds. (gen_decl_die): Likewise. * var-tracking.c (vt_add_function_parameters): Skip bounds parameters. * ipa-icf.c (sem_function::merge): Do not merge when instrumentation thunk still exists. (sem_variable::merge): Reset need_bounds_init flag. * doc/extend.texi: Document Pointer Bounds Checker built-in functions and attributes. * doc/tm.texi.in (TARGET_LOAD_BOUNDS_FOR_ARG): New. (TARGET_STORE_BOUNDS_FOR_ARG): New. (TARGET_LOAD_RETURNED_BOUNDS): New. (TARGET_STORE_RETURNED_BOUNDS): New. (TARGET_CHKP_FUNCTION_VALUE_BOUNDS): New. (TARGET_SETUP_INCOMING_VARARG_BOUNDS): New. (TARGET_BUILTIN_CHKP_FUNCTION): New. (TARGET_CHKP_BOUND_TYPE): New. (TARGET_CHKP_BOUND_MODE): New. (TARGET_CHKP_MAKE_BOUNDS_CONSTANT): New. (TARGET_CHKP_INITIALIZE_BOUNDS): New. * doc/tm.texi: Regenerated. * doc/rtl.texi (MODE_POINTER_BOUNDS): New. (BND32mode): New. (BND64mode): New. * doc/invoke.texi (-mmpx): New. (-mno-mpx): New. (chkp-max-ctor-size): New. * config/i386/constraints.md (w): New. (Ti): New. (Tb): New. * config/i386/i386-c.c (ix86_target_macros_internal): Add __MPX__. * config/i386/i386-modes.def (BND32): New. (BND64): New. * config/i386/i386-protos.h (ix86_bnd_prefixed_insn_p): New. * config/i386/i386.c: Include tree-chkp.h, rtl-chkp.h, tree-iterator.h. (regclass_map): Add bound registers. (dbx_register_map): Likewise. (dbx64_register_map): Likewise. (svr4_dbx_register_map): Likewise. (isa_opts): Add -mmpx. (PTA_MPX): New. (ix86_option_override_internal): Support MPX ISA. (ix86_conditional_register_usage): Support bound registers. (ix86_code_end): Add MPX bnd prefix. (output_set_got): Likewise. (print_reg): Avoid prefixes for bound registers. (ix86_print_operand): Add '!' (MPX bnd) print prefix support. (ix86_print_operand_punct_valid_p): Likewise. (ix86_print_operand_address): Support UNSPEC_BNDMK_ADDR and UNSPEC_BNDLDX_ADDR. (ix86_output_call_insn): Add MPX bnd prefix to branch instructions. (ix86_class_likely_spilled_p): Add bound regs support. (ix86_hard_regno_mode_ok): Likewise. (x86_order_regs_for_local_alloc): Likewise. (ix86_bnd_prefixed_insn_p): New. (ix86_builtins): Add IX86_BUILTIN_BNDMK, IX86_BUILTIN_BNDSTX, IX86_BUILTIN_BNDLDX, IX86_BUILTIN_BNDCL, IX86_BUILTIN_BNDCU, IX86_BUILTIN_BNDRET, IX86_BUILTIN_BNDNARROW, IX86_BUILTIN_BNDINT, IX86_BUILTIN_SIZEOF, IX86_BUILTIN_BNDLOWER, IX86_BUILTIN_BNDUPPER. (builtin_isa): Add leaf_p and nothrow_p fields. (def_builtin): Initialize leaf_p and nothrow_p. (ix86_add_new_builtins): Handle leaf_p and nothrow_p flags. (bdesc_mpx): New. (bdesc_mpx_const): New. (ix86_init_mpx_builtins): New. (ix86_init_builtins): Call ix86_init_mpx_builtins. (ix86_emit_cmove): New. (ix86_emit_move_max): New. (ix86_expand_builtin): Expand IX86_BUILTIN_BNDMK, IX86_BUILTIN_BNDSTX, IX86_BUILTIN_BNDLDX, IX86_BUILTIN_BNDCL, IX86_BUILTIN_BNDCU, IX86_BUILTIN_BNDRET, IX86_BUILTIN_BNDNARROW, IX86_BUILTIN_BNDINT, IX86_BUILTIN_SIZEOF, IX86_BUILTIN_BNDLOWER, IX86_BUILTIN_BNDUPPER. (ix86_function_value_bounds): New. (ix86_builtin_mpx_function): New. (ix86_get_arg_address_for_bt): New. (ix86_load_bounds): New. (ix86_store_bounds): New. (ix86_load_returned_bounds): New. (ix86_store_returned_bounds): New. (ix86_mpx_bound_mode): New. (ix86_make_bounds_constant): New. (ix86_initialize_bounds): (TARGET_LOAD_BOUNDS_FOR_ARG): New. (TARGET_STORE_BOUNDS_FOR_ARG): New. (TARGET_LOAD_RETURNED_BOUNDS): New. (TARGET_STORE_RETURNED_BOUNDS): New. (TARGET_CHKP_BOUND_MODE): New. (TARGET_BUILTIN_CHKP_FUNCTION): New. (TARGET_CHKP_FUNCTION_VALUE_BOUNDS): New. (TARGET_CHKP_MAKE_BOUNDS_CONSTANT): New. (TARGET_CHKP_INITIALIZE_BOUNDS): New. (ix86_option_override_internal): Do not support x32 with MPX. (init_cumulative_args): Init stdarg, bnd_regno, bnds_in_bt and force_bnd_pass. (function_arg_advance_32): Return number of used integer registers. (function_arg_advance_64): Likewise. (function_arg_advance_ms_64): Likewise. (ix86_function_arg_advance): Handle pointer bounds. (ix86_function_arg): Likewise. (ix86_function_value_regno_p): Mark fisrt bounds registers as possible function value. (ix86_function_value_1): Handle pointer bounds type/mode (ix86_return_in_memory): Likewise. (ix86_print_operand): Analyse insn to decide abounf "bnd" prefix. (ix86_expand_call): Generate returned bounds. (ix86_setup_incoming_vararg_bounds): New. (ix86_va_start): Initialize bounds for pointers in va_list. (TARGET_SETUP_INCOMING_VARARG_BOUNDS): New. * config/i386/i386.h (TARGET_MPX): New. (TARGET_MPX_P): New. (FIRST_PSEUDO_REGISTER): Fix to new value. (FIXED_REGISTERS): Add bound registers. (CALL_USED_REGISTERS): Likewise. (REG_ALLOC_ORDER): Likewise. (HARD_REGNO_NREGS): Likewise. (VALID_BND_REG_MODE): New. (FIRST_BND_REG): New. (LAST_BND_REG): New. (reg_class): Add BND_REGS. (REG_CLASS_NAMES): Likewise. (REG_CLASS_CONTENTS): Likewise. (BND_REGNO_P): New. (ANY_BND_REG_P): New. (BNDmode): New. (HI_REGISTER_NAMES): Add bound registers. (ix86_args): Add bnd_regno, bnds_in_bt, force_bnd_pass and stdarg fields. * config/i386/i386.md (UNSPEC_BNDMK): New. (UNSPEC_BNDMK_ADDR): New. (UNSPEC_BNDSTX): New. (UNSPEC_BNDLDX): New. (UNSPEC_BNDLDX_ADDR): New. (UNSPEC_BNDCL): New. (UNSPEC_BNDCU): New. (UNSPEC_BNDCN): New. (UNSPEC_MPX_FENCE): New. (UNSPEC_SIZEOF): New. (BND0_REG): New. (BND1_REG): New. (type): Add mpxmov, mpxmk, mpxchk, mpxld, mpxst. (length_immediate): Support mpxmov, mpxmk, mpxchk, mpxld, mpxst. (prefix_rep): Check for bnd prefix. (prefix_0f): Support mpxmov, mpxmk, mpxchk, mpxld, mpxst. (length_nobnd): New. (length): Use length_nobnd when specified. (memory): Support mpxmov, mpxmk, mpxchk, mpxld, mpxst. (BND): New. (bnd_ptr): New. (BNDCHECK): New. (bndcheck): New. (*jcc_1): Add MPX bnd prefix. (*jcc_2): Likewise. (jump): Likewise. (*indirect_jump): Likewise. (*tablejump_1): Likewise. (simple_return_internal): Likewise. (simple_return_internal_long): Likewise. (simple_return_pop_internal): Likewise. (simple_return_indirect_internal): Likewise. (<mode>_mk): New. (*<mode>_mk): New. (mov<mode>): New. (*mov<mode>_internal_mpx): New. (<mode>_<bndcheck>): New. (*<mode>_<bndcheck>): New. (<mode>_ldx): New. (*<mode>_ldx): New. (<mode>_stx): New. (*<mode>_stx): New. move_size_reloc_<mode>): New. * config/i386/predicates.md (address_mpx_no_base_operand): New. (address_mpx_no_index_operand): New. (bnd_mem_operator): New. (symbol_operand): New. (x86_64_immediate_size_operand): New. * config/i386/i386.opt (mmpx): New. * config/i386/i386-builtin-types.def (BND): New. (ULONG): New. (BND_FTYPE_PCVOID_ULONG): New. (VOID_FTYPE_BND_PCVOID): New. (VOID_FTYPE_PCVOID_PCVOID_BND): New. (BND_FTYPE_PCVOID_PCVOID): New. (BND_FTYPE_PCVOID): New. (BND_FTYPE_BND_BND): New. (PVOID_FTYPE_PVOID_PVOID_ULONG): New. (PVOID_FTYPE_PCVOID_BND_ULONG): New. (ULONG_FTYPE_VOID): New. (PVOID_FTYPE_BND): New. gcc/testsuite/ 2014-11-05 Ilya Enkovich <ilya.enkovich@intel.com> * gcc.target/i386/chkp-builtins-1.c: New. * gcc.target/i386/chkp-builtins-2.c: New. * gcc.target/i386/chkp-builtins-3.c: New. * gcc.target/i386/chkp-builtins-4.c: New. * gcc.target/i386/chkp-remove-bndint-1.c: New. * gcc.target/i386/chkp-remove-bndint-2.c: New. * gcc.target/i386/chkp-const-check-1.c: New. * gcc.target/i386/chkp-const-check-2.c: New. * gcc.target/i386/chkp-lifetime-1.c: New. * gcc.dg/pr37858.c: Replace early_local_cleanups pass name with build_ssa_passes. From-SVN: r217125
855 lines
27 KiB
C
855 lines
27 KiB
C
/* IPA visibility pass
|
|
Copyright (C) 2003-2014 Free Software Foundation, Inc.
|
|
|
|
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/>. */
|
|
|
|
/* This file implements two related passes:
|
|
|
|
- pass_data_ipa_function_and_variable_visibility run just after
|
|
symbol table, references and callgraph are built
|
|
|
|
- pass_data_ipa_function_and_variable_visibility run as first
|
|
proper IPA pass (that is after early optimization, or, (with LTO)
|
|
as a first pass done at link-time.
|
|
|
|
Purpose of both passes is to set correctly visibility properties
|
|
of all symbols. This includes:
|
|
|
|
- Symbol privatization:
|
|
|
|
Some symbols that are declared public by frontend may be
|
|
turned local (either by -fwhole-program flag, by linker plugin feedback
|
|
or by other reasons)
|
|
|
|
- Discovery of local functions:
|
|
|
|
A local function is one whose calls can occur only in the current
|
|
compilation unit and all its calls are explicit, so we can change
|
|
its calling convention. We simply mark all static functions whose
|
|
address is not taken as local.
|
|
|
|
externally_visible flag is set for symbols that can not be privatized.
|
|
For privatized symbols we clear TREE_PUBLIC flag and dismantle comdat
|
|
group.
|
|
|
|
- Dismantling of comdat groups:
|
|
|
|
Comdat group represent a section that may be replaced by linker by
|
|
a different copy of the same section from other unit.
|
|
If we have resolution information (from linker plugin) and we know that
|
|
a given comdat gorup is prevailing, we can dismantle it and turn symbols
|
|
into normal symbols. If the resolution information says that the
|
|
section was previaled by copy from non-LTO code, we can also dismantle
|
|
it and turn all symbols into external.
|
|
|
|
- Local aliases:
|
|
|
|
Some symbols can be interposed by dynamic linker. Refering to these
|
|
symbols is expensive, since it needs to be overwritable by the dynamic
|
|
linker. In some cases we know that the interposition does not change
|
|
semantic and we can always refer to a local copy (as in the case of
|
|
inline function). In this case we produce a local alias and redirect
|
|
calls to it.
|
|
|
|
TODO: This should be done for references, too.
|
|
|
|
- Removal of static ocnstructors and destructors that have no side effects.
|
|
|
|
- Regularization of several oddities introduced by frontends that may
|
|
be impractical later in the optimization queue. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "tm.h"
|
|
#include "tree.h"
|
|
#include "hash-map.h"
|
|
#include "is-a.h"
|
|
#include "plugin-api.h"
|
|
#include "vec.h"
|
|
#include "hashtab.h"
|
|
#include "hash-set.h"
|
|
#include "machmode.h"
|
|
#include "hard-reg-set.h"
|
|
#include "input.h"
|
|
#include "function.h"
|
|
#include "ipa-ref.h"
|
|
#include "cgraph.h"
|
|
#include "tree-pass.h"
|
|
#include "calls.h"
|
|
#include "gimple-expr.h"
|
|
#include "varasm.h"
|
|
|
|
/* Return true when NODE can not be local. Worker for cgraph_local_node_p. */
|
|
|
|
bool
|
|
cgraph_node::non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
|
|
{
|
|
/* FIXME: Aliases can be local, but i386 gets thunks wrong then. */
|
|
return !(node->only_called_directly_or_aliased_p ()
|
|
&& !node->has_aliases_p ()
|
|
&& node->definition
|
|
&& !DECL_EXTERNAL (node->decl)
|
|
&& !node->externally_visible
|
|
&& !node->used_from_other_partition
|
|
&& !node->in_other_partition);
|
|
}
|
|
|
|
/* Return true when function can be marked local. */
|
|
|
|
bool
|
|
cgraph_node::local_p (void)
|
|
{
|
|
cgraph_node *n = ultimate_alias_target ();
|
|
|
|
/* FIXME: thunks can be considered local, but we need prevent i386
|
|
from attempting to change calling convention of them. */
|
|
if (n->thunk.thunk_p)
|
|
return false;
|
|
return !n->call_for_symbol_thunks_and_aliases (cgraph_node::non_local_p,
|
|
NULL, true);
|
|
|
|
}
|
|
|
|
/* Return true when there is a reference to node and it is not vtable. */
|
|
|
|
bool
|
|
symtab_node::address_taken_from_non_vtable_p (void)
|
|
{
|
|
int i;
|
|
struct ipa_ref *ref = NULL;
|
|
|
|
for (i = 0; iterate_referring (i, ref); i++)
|
|
if (ref->use == IPA_REF_ADDR)
|
|
{
|
|
varpool_node *node;
|
|
if (is_a <cgraph_node *> (ref->referring))
|
|
return true;
|
|
node = dyn_cast <varpool_node *> (ref->referring);
|
|
if (!DECL_VIRTUAL_P (node->decl))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* A helper for comdat_can_be_unshared_p. */
|
|
|
|
static bool
|
|
comdat_can_be_unshared_p_1 (symtab_node *node)
|
|
{
|
|
if (!node->externally_visible)
|
|
return true;
|
|
/* When address is taken, we don't know if equality comparison won't
|
|
break eventually. Exception are virutal functions, C++
|
|
constructors/destructors and vtables, where this is not possible by
|
|
language standard. */
|
|
if (!DECL_VIRTUAL_P (node->decl)
|
|
&& (TREE_CODE (node->decl) != FUNCTION_DECL
|
|
|| (!DECL_CXX_CONSTRUCTOR_P (node->decl)
|
|
&& !DECL_CXX_DESTRUCTOR_P (node->decl)))
|
|
&& node->address_taken_from_non_vtable_p ())
|
|
return false;
|
|
|
|
/* If the symbol is used in some weird way, better to not touch it. */
|
|
if (node->force_output)
|
|
return false;
|
|
|
|
/* Explicit instantiations needs to be output when possibly
|
|
used externally. */
|
|
if (node->forced_by_abi
|
|
&& TREE_PUBLIC (node->decl)
|
|
&& (node->resolution != LDPR_PREVAILING_DEF_IRONLY
|
|
&& !flag_whole_program))
|
|
return false;
|
|
|
|
/* Non-readonly and volatile variables can not be duplicated. */
|
|
if (is_a <varpool_node *> (node)
|
|
&& (!TREE_READONLY (node->decl)
|
|
|| TREE_THIS_VOLATILE (node->decl)))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/* COMDAT functions must be shared only if they have address taken,
|
|
otherwise we can produce our own private implementation with
|
|
-fwhole-program.
|
|
Return true when turning COMDAT functoin static can not lead to wrong
|
|
code when the resulting object links with a library defining same COMDAT.
|
|
|
|
Virtual functions do have their addresses taken from the vtables,
|
|
but in C++ there is no way to compare their addresses for equality. */
|
|
|
|
static bool
|
|
comdat_can_be_unshared_p (symtab_node *node)
|
|
{
|
|
if (!comdat_can_be_unshared_p_1 (node))
|
|
return false;
|
|
if (node->same_comdat_group)
|
|
{
|
|
symtab_node *next;
|
|
|
|
/* If more than one function is in the same COMDAT group, it must
|
|
be shared even if just one function in the comdat group has
|
|
address taken. */
|
|
for (next = node->same_comdat_group;
|
|
next != node; next = next->same_comdat_group)
|
|
if (!comdat_can_be_unshared_p_1 (next))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* Return true when function NODE should be considered externally visible. */
|
|
|
|
static bool
|
|
cgraph_externally_visible_p (struct cgraph_node *node,
|
|
bool whole_program)
|
|
{
|
|
if (!node->definition)
|
|
return false;
|
|
if (!TREE_PUBLIC (node->decl)
|
|
|| DECL_EXTERNAL (node->decl))
|
|
return false;
|
|
|
|
/* Do not try to localize built-in functions yet. One of problems is that we
|
|
end up mangling their asm for WHOPR that makes it impossible to call them
|
|
using the implicit built-in declarations anymore. Similarly this enables
|
|
us to remove them as unreachable before actual calls may appear during
|
|
expansion or folding. */
|
|
if (DECL_BUILT_IN (node->decl))
|
|
return true;
|
|
|
|
/* If linker counts on us, we must preserve the function. */
|
|
if (node->used_from_object_file_p ())
|
|
return true;
|
|
if (DECL_PRESERVE_P (node->decl))
|
|
return true;
|
|
if (lookup_attribute ("externally_visible",
|
|
DECL_ATTRIBUTES (node->decl)))
|
|
return true;
|
|
if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
|
|
&& lookup_attribute ("dllexport",
|
|
DECL_ATTRIBUTES (node->decl)))
|
|
return true;
|
|
if (node->resolution == LDPR_PREVAILING_DEF_IRONLY)
|
|
return false;
|
|
/* When doing LTO or whole program, we can bring COMDAT functoins static.
|
|
This improves code quality and we know we will duplicate them at most twice
|
|
(in the case that we are not using plugin and link with object file
|
|
implementing same COMDAT) */
|
|
if ((in_lto_p || whole_program)
|
|
&& DECL_COMDAT (node->decl)
|
|
&& comdat_can_be_unshared_p (node))
|
|
return false;
|
|
|
|
/* When doing link time optimizations, hidden symbols become local. */
|
|
if (in_lto_p
|
|
&& (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN
|
|
|| DECL_VISIBILITY (node->decl) == VISIBILITY_INTERNAL)
|
|
/* Be sure that node is defined in IR file, not in other object
|
|
file. In that case we don't set used_from_other_object_file. */
|
|
&& node->definition)
|
|
;
|
|
else if (!whole_program)
|
|
return true;
|
|
|
|
if (MAIN_NAME_P (DECL_NAME (node->decl)))
|
|
return true;
|
|
|
|
if (node->instrumentation_clone
|
|
&& MAIN_NAME_P (DECL_NAME (node->orig_decl)))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Return true when variable should be considered externally visible. */
|
|
|
|
bool
|
|
varpool_node::externally_visible_p (void)
|
|
{
|
|
if (DECL_EXTERNAL (decl))
|
|
return true;
|
|
|
|
if (!TREE_PUBLIC (decl))
|
|
return false;
|
|
|
|
/* If linker counts on us, we must preserve the function. */
|
|
if (used_from_object_file_p ())
|
|
return true;
|
|
|
|
/* Bringing TLS variables local may cause dynamic linker failures
|
|
on limits of static TLS vars. */
|
|
if (DECL_THREAD_LOCAL_P (decl)
|
|
&& (DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED
|
|
&& DECL_TLS_MODEL (decl) != TLS_MODEL_INITIAL_EXEC))
|
|
return true;
|
|
|
|
if (DECL_HARD_REGISTER (decl))
|
|
return true;
|
|
if (DECL_PRESERVE_P (decl))
|
|
return true;
|
|
if (lookup_attribute ("externally_visible",
|
|
DECL_ATTRIBUTES (decl)))
|
|
return true;
|
|
if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
|
|
&& lookup_attribute ("dllexport",
|
|
DECL_ATTRIBUTES (decl)))
|
|
return true;
|
|
|
|
/* See if we have linker information about symbol not being used or
|
|
if we need to make guess based on the declaration.
|
|
|
|
Even if the linker clams the symbol is unused, never bring internal
|
|
symbols that are declared by user as used or externally visible.
|
|
This is needed for i.e. references from asm statements. */
|
|
if (used_from_object_file_p ())
|
|
return true;
|
|
if (resolution == LDPR_PREVAILING_DEF_IRONLY)
|
|
return false;
|
|
|
|
/* As a special case, the COMDAT virtual tables can be unshared.
|
|
In LTO mode turn vtables into static variables. The variable is readonly,
|
|
so this does not enable more optimization, but referring static var
|
|
is faster for dynamic linking. Also this match logic hidding vtables
|
|
from LTO symbol tables. */
|
|
if ((in_lto_p || flag_whole_program)
|
|
&& DECL_COMDAT (decl)
|
|
&& comdat_can_be_unshared_p (this))
|
|
return false;
|
|
|
|
/* When doing link time optimizations, hidden symbols become local. */
|
|
if (in_lto_p
|
|
&& (DECL_VISIBILITY (decl) == VISIBILITY_HIDDEN
|
|
|| DECL_VISIBILITY (decl) == VISIBILITY_INTERNAL)
|
|
/* Be sure that node is defined in IR file, not in other object
|
|
file. In that case we don't set used_from_other_object_file. */
|
|
&& definition)
|
|
;
|
|
else if (!flag_whole_program)
|
|
return true;
|
|
|
|
/* Do not attempt to privatize COMDATS by default.
|
|
This would break linking with C++ libraries sharing
|
|
inline definitions.
|
|
|
|
FIXME: We can do so for readonly vars with no address taken and
|
|
possibly also for vtables since no direct pointer comparsion is done.
|
|
It might be interesting to do so to reduce linking overhead. */
|
|
if (DECL_COMDAT (decl) || DECL_WEAK (decl))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/* Return true if reference to NODE can be replaced by a local alias.
|
|
Local aliases save dynamic linking overhead and enable more optimizations.
|
|
*/
|
|
|
|
bool
|
|
can_replace_by_local_alias (symtab_node *node)
|
|
{
|
|
return (node->get_availability () > AVAIL_INTERPOSABLE
|
|
&& !decl_binds_to_current_def_p (node->decl)
|
|
&& !node->can_be_discarded_p ());
|
|
}
|
|
|
|
/* Return true if we can replace refernece to NODE by local alias
|
|
within a virtual table. Generally we can replace function pointers
|
|
and virtual table pointers. */
|
|
|
|
bool
|
|
can_replace_by_local_alias_in_vtable (symtab_node *node)
|
|
{
|
|
if (is_a <varpool_node *> (node)
|
|
&& !DECL_VIRTUAL_P (node->decl))
|
|
return false;
|
|
return can_replace_by_local_alias (node);
|
|
}
|
|
|
|
/* walk_tree callback that rewrites initializer references. */
|
|
|
|
static tree
|
|
update_vtable_references (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
|
|
{
|
|
if (TREE_CODE (*tp) == VAR_DECL
|
|
|| TREE_CODE (*tp) == FUNCTION_DECL)
|
|
{
|
|
if (can_replace_by_local_alias_in_vtable (symtab_node::get (*tp)))
|
|
*tp = symtab_node::get (*tp)->noninterposable_alias ()->decl;
|
|
*walk_subtrees = 0;
|
|
}
|
|
else if (IS_TYPE_OR_DECL_P (*tp))
|
|
*walk_subtrees = 0;
|
|
return NULL;
|
|
}
|
|
|
|
/* In LTO we can remove COMDAT groups and weak symbols.
|
|
Either turn them into normal symbols or external symbol depending on
|
|
resolution info. */
|
|
|
|
static void
|
|
update_visibility_by_resolution_info (symtab_node * node)
|
|
{
|
|
bool define;
|
|
|
|
if (!node->externally_visible
|
|
|| (!DECL_WEAK (node->decl) && !DECL_ONE_ONLY (node->decl))
|
|
|| node->resolution == LDPR_UNKNOWN)
|
|
return;
|
|
|
|
define = (node->resolution == LDPR_PREVAILING_DEF_IRONLY
|
|
|| node->resolution == LDPR_PREVAILING_DEF
|
|
|| node->resolution == LDPR_UNDEF
|
|
|| node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP);
|
|
|
|
/* The linker decisions ought to agree in the whole group. */
|
|
if (node->same_comdat_group)
|
|
for (symtab_node *next = node->same_comdat_group;
|
|
next != node; next = next->same_comdat_group)
|
|
gcc_assert (!next->externally_visible
|
|
|| define == (next->resolution == LDPR_PREVAILING_DEF_IRONLY
|
|
|| next->resolution == LDPR_PREVAILING_DEF
|
|
|| next->resolution == LDPR_UNDEF
|
|
|| next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP));
|
|
|
|
if (node->same_comdat_group)
|
|
for (symtab_node *next = node->same_comdat_group;
|
|
next != node; next = next->same_comdat_group)
|
|
{
|
|
next->set_comdat_group (NULL);
|
|
DECL_WEAK (next->decl) = false;
|
|
if (next->externally_visible
|
|
&& !define)
|
|
DECL_EXTERNAL (next->decl) = true;
|
|
}
|
|
node->set_comdat_group (NULL);
|
|
DECL_WEAK (node->decl) = false;
|
|
if (!define)
|
|
DECL_EXTERNAL (node->decl) = true;
|
|
node->dissolve_same_comdat_group_list ();
|
|
}
|
|
|
|
/* Decide on visibility of all symbols. */
|
|
|
|
static unsigned int
|
|
function_and_variable_visibility (bool whole_program)
|
|
{
|
|
struct cgraph_node *node;
|
|
varpool_node *vnode;
|
|
|
|
/* All aliases should be procssed at this point. */
|
|
gcc_checking_assert (!alias_pairs || !alias_pairs->length ());
|
|
|
|
FOR_EACH_FUNCTION (node)
|
|
{
|
|
int flags = flags_from_decl_or_type (node->decl);
|
|
|
|
/* Optimize away PURE and CONST constructors and destructors. */
|
|
if (optimize
|
|
&& (flags & (ECF_CONST | ECF_PURE))
|
|
&& !(flags & ECF_LOOPING_CONST_OR_PURE))
|
|
{
|
|
DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
|
|
DECL_STATIC_DESTRUCTOR (node->decl) = 0;
|
|
}
|
|
|
|
/* Frontends and alias code marks nodes as needed before parsing is finished.
|
|
We may end up marking as node external nodes where this flag is meaningless
|
|
strip it. */
|
|
if (DECL_EXTERNAL (node->decl) || !node->definition)
|
|
{
|
|
node->force_output = 0;
|
|
node->forced_by_abi = 0;
|
|
}
|
|
|
|
/* C++ FE on lack of COMDAT support create local COMDAT functions
|
|
(that ought to be shared but can not due to object format
|
|
limitations). It is necessary to keep the flag to make rest of C++ FE
|
|
happy. Clear the flag here to avoid confusion in middle-end. */
|
|
if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl))
|
|
DECL_COMDAT (node->decl) = 0;
|
|
|
|
/* For external decls stop tracking same_comdat_group. It doesn't matter
|
|
what comdat group they are in when they won't be emitted in this TU. */
|
|
if (node->same_comdat_group && DECL_EXTERNAL (node->decl))
|
|
{
|
|
#ifdef ENABLE_CHECKING
|
|
symtab_node *n;
|
|
|
|
for (n = node->same_comdat_group;
|
|
n != node;
|
|
n = n->same_comdat_group)
|
|
/* If at least one of same comdat group functions is external,
|
|
all of them have to be, otherwise it is a front-end bug. */
|
|
gcc_assert (DECL_EXTERNAL (n->decl));
|
|
#endif
|
|
node->dissolve_same_comdat_group_list ();
|
|
}
|
|
gcc_assert ((!DECL_WEAK (node->decl)
|
|
&& !DECL_COMDAT (node->decl))
|
|
|| TREE_PUBLIC (node->decl)
|
|
|| node->weakref
|
|
|| DECL_EXTERNAL (node->decl));
|
|
if (cgraph_externally_visible_p (node, whole_program))
|
|
{
|
|
gcc_assert (!node->global.inlined_to);
|
|
node->externally_visible = true;
|
|
}
|
|
else
|
|
{
|
|
node->externally_visible = false;
|
|
node->forced_by_abi = false;
|
|
}
|
|
if (!node->externally_visible
|
|
&& node->definition && !node->weakref
|
|
&& !DECL_EXTERNAL (node->decl))
|
|
{
|
|
gcc_assert (whole_program || in_lto_p
|
|
|| !TREE_PUBLIC (node->decl));
|
|
node->unique_name = ((node->resolution == LDPR_PREVAILING_DEF_IRONLY
|
|
|| node->unique_name
|
|
|| node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
|
|
&& TREE_PUBLIC (node->decl));
|
|
node->resolution = LDPR_PREVAILING_DEF_IRONLY;
|
|
if (node->same_comdat_group && TREE_PUBLIC (node->decl))
|
|
{
|
|
symtab_node *next = node;
|
|
|
|
/* Set all members of comdat group local. */
|
|
if (node->same_comdat_group)
|
|
for (next = node->same_comdat_group;
|
|
next != node;
|
|
next = next->same_comdat_group)
|
|
{
|
|
next->set_comdat_group (NULL);
|
|
if (!next->alias)
|
|
next->set_section (NULL);
|
|
next->make_decl_local ();
|
|
next->unique_name = ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
|
|
|| next->unique_name
|
|
|| next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
|
|
&& TREE_PUBLIC (next->decl));
|
|
}
|
|
/* cgraph_externally_visible_p has already checked all other nodes
|
|
in the group and they will all be made local. We need to
|
|
dissolve the group at once so that the predicate does not
|
|
segfault though. */
|
|
node->dissolve_same_comdat_group_list ();
|
|
}
|
|
if (TREE_PUBLIC (node->decl))
|
|
node->set_comdat_group (NULL);
|
|
if (DECL_COMDAT (node->decl) && !node->alias)
|
|
node->set_section (NULL);
|
|
node->make_decl_local ();
|
|
}
|
|
|
|
if (node->thunk.thunk_p
|
|
&& !node->thunk.add_pointer_bounds_args
|
|
&& TREE_PUBLIC (node->decl))
|
|
{
|
|
struct cgraph_node *decl_node = node;
|
|
|
|
decl_node = decl_node->callees->callee->function_symbol ();
|
|
|
|
/* Thunks have the same visibility as function they are attached to.
|
|
Make sure the C++ front end set this up properly. */
|
|
if (DECL_ONE_ONLY (decl_node->decl))
|
|
{
|
|
gcc_checking_assert (DECL_COMDAT (node->decl)
|
|
== DECL_COMDAT (decl_node->decl));
|
|
gcc_checking_assert (node->in_same_comdat_group_p (decl_node));
|
|
gcc_checking_assert (node->same_comdat_group);
|
|
}
|
|
node->forced_by_abi = decl_node->forced_by_abi;
|
|
if (DECL_EXTERNAL (decl_node->decl))
|
|
DECL_EXTERNAL (node->decl) = 1;
|
|
}
|
|
|
|
update_visibility_by_resolution_info (node);
|
|
}
|
|
FOR_EACH_DEFINED_FUNCTION (node)
|
|
{
|
|
node->local.local |= node->local_p ();
|
|
|
|
/* If we know that function can not be overwritten by a different semantics
|
|
and moreover its section can not be discarded, replace all direct calls
|
|
by calls to an noninterposable alias. This make dynamic linking
|
|
cheaper and enable more optimization.
|
|
|
|
TODO: We can also update virtual tables. */
|
|
if (node->callers
|
|
&& can_replace_by_local_alias (node))
|
|
{
|
|
cgraph_node *alias = dyn_cast<cgraph_node *>
|
|
(node->noninterposable_alias ());
|
|
|
|
if (alias && alias != node)
|
|
{
|
|
while (node->callers)
|
|
{
|
|
struct cgraph_edge *e = node->callers;
|
|
|
|
e->redirect_callee (alias);
|
|
if (gimple_has_body_p (e->caller->decl))
|
|
{
|
|
push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
|
|
e->redirect_call_stmt_to_callee ();
|
|
pop_cfun ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FOR_EACH_VARIABLE (vnode)
|
|
{
|
|
/* weak flag makes no sense on local variables. */
|
|
gcc_assert (!DECL_WEAK (vnode->decl)
|
|
|| vnode->weakref
|
|
|| TREE_PUBLIC (vnode->decl)
|
|
|| DECL_EXTERNAL (vnode->decl));
|
|
/* In several cases declarations can not be common:
|
|
|
|
- when declaration has initializer
|
|
- when it is in weak
|
|
- when it has specific section
|
|
- when it resides in non-generic address space.
|
|
- if declaration is local, it will get into .local common section
|
|
so common flag is not needed. Frontends still produce these in
|
|
certain cases, such as for:
|
|
|
|
static int a __attribute__ ((common))
|
|
|
|
Canonicalize things here and clear the redundant flag. */
|
|
if (DECL_COMMON (vnode->decl)
|
|
&& (!(TREE_PUBLIC (vnode->decl)
|
|
|| DECL_EXTERNAL (vnode->decl))
|
|
|| (DECL_INITIAL (vnode->decl)
|
|
&& DECL_INITIAL (vnode->decl) != error_mark_node)
|
|
|| DECL_WEAK (vnode->decl)
|
|
|| DECL_SECTION_NAME (vnode->decl) != NULL
|
|
|| ! (ADDR_SPACE_GENERIC_P
|
|
(TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
|
|
DECL_COMMON (vnode->decl) = 0;
|
|
}
|
|
FOR_EACH_DEFINED_VARIABLE (vnode)
|
|
{
|
|
if (!vnode->definition)
|
|
continue;
|
|
if (vnode->externally_visible_p ())
|
|
vnode->externally_visible = true;
|
|
else
|
|
{
|
|
vnode->externally_visible = false;
|
|
vnode->forced_by_abi = false;
|
|
}
|
|
if (lookup_attribute ("no_reorder",
|
|
DECL_ATTRIBUTES (vnode->decl)))
|
|
vnode->no_reorder = 1;
|
|
if (!vnode->externally_visible
|
|
&& !vnode->weakref)
|
|
{
|
|
gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl));
|
|
vnode->unique_name = ((vnode->resolution == LDPR_PREVAILING_DEF_IRONLY
|
|
|| vnode->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
|
|
&& TREE_PUBLIC (vnode->decl));
|
|
if (vnode->same_comdat_group && TREE_PUBLIC (vnode->decl))
|
|
{
|
|
symtab_node *next = vnode;
|
|
|
|
/* Set all members of comdat group local. */
|
|
if (vnode->same_comdat_group)
|
|
for (next = vnode->same_comdat_group;
|
|
next != vnode;
|
|
next = next->same_comdat_group)
|
|
{
|
|
next->set_comdat_group (NULL);
|
|
if (!next->alias)
|
|
next->set_section (NULL);
|
|
next->make_decl_local ();
|
|
next->unique_name = ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
|
|
|| next->unique_name
|
|
|| next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
|
|
&& TREE_PUBLIC (next->decl));
|
|
}
|
|
vnode->dissolve_same_comdat_group_list ();
|
|
}
|
|
if (TREE_PUBLIC (vnode->decl))
|
|
vnode->set_comdat_group (NULL);
|
|
if (DECL_COMDAT (vnode->decl) && !vnode->alias)
|
|
vnode->set_section (NULL);
|
|
vnode->make_decl_local ();
|
|
vnode->resolution = LDPR_PREVAILING_DEF_IRONLY;
|
|
}
|
|
update_visibility_by_resolution_info (vnode);
|
|
|
|
/* Update virtual tables to point to local aliases where possible. */
|
|
if (DECL_VIRTUAL_P (vnode->decl)
|
|
&& !DECL_EXTERNAL (vnode->decl))
|
|
{
|
|
int i;
|
|
struct ipa_ref *ref;
|
|
bool found = false;
|
|
|
|
/* See if there is something to update. */
|
|
for (i = 0; vnode->iterate_referring (i, ref); i++)
|
|
if (ref->use == IPA_REF_ADDR
|
|
&& can_replace_by_local_alias_in_vtable (ref->referred))
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
if (found)
|
|
{
|
|
hash_set<tree> visited_nodes;
|
|
|
|
vnode->get_constructor ();
|
|
walk_tree (&DECL_INITIAL (vnode->decl),
|
|
update_vtable_references, NULL, &visited_nodes);
|
|
vnode->remove_all_references ();
|
|
record_references_in_initializer (vnode->decl, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dump_file)
|
|
{
|
|
fprintf (dump_file, "\nMarking local functions:");
|
|
FOR_EACH_DEFINED_FUNCTION (node)
|
|
if (node->local.local)
|
|
fprintf (dump_file, " %s", node->name ());
|
|
fprintf (dump_file, "\n\n");
|
|
fprintf (dump_file, "\nMarking externally visible functions:");
|
|
FOR_EACH_DEFINED_FUNCTION (node)
|
|
if (node->externally_visible)
|
|
fprintf (dump_file, " %s", node->name ());
|
|
fprintf (dump_file, "\n\n");
|
|
fprintf (dump_file, "\nMarking externally visible variables:");
|
|
FOR_EACH_DEFINED_VARIABLE (vnode)
|
|
if (vnode->externally_visible)
|
|
fprintf (dump_file, " %s", vnode->name ());
|
|
fprintf (dump_file, "\n\n");
|
|
}
|
|
symtab->function_flags_ready = true;
|
|
return 0;
|
|
}
|
|
|
|
/* Local function pass handling visibilities. This happens before LTO streaming
|
|
so in particular -fwhole-program should be ignored at this level. */
|
|
|
|
namespace {
|
|
|
|
const pass_data pass_data_ipa_function_and_variable_visibility =
|
|
{
|
|
SIMPLE_IPA_PASS, /* type */
|
|
"visibility", /* name */
|
|
OPTGROUP_NONE, /* optinfo_flags */
|
|
TV_CGRAPHOPT, /* tv_id */
|
|
0, /* properties_required */
|
|
0, /* properties_provided */
|
|
0, /* properties_destroyed */
|
|
0, /* todo_flags_start */
|
|
( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */
|
|
};
|
|
|
|
/* Bring functions local at LTO time with -fwhole-program. */
|
|
|
|
static unsigned int
|
|
whole_program_function_and_variable_visibility (void)
|
|
{
|
|
function_and_variable_visibility (flag_whole_program);
|
|
if (optimize)
|
|
ipa_discover_readonly_nonaddressable_vars ();
|
|
return 0;
|
|
}
|
|
|
|
} // anon namespace
|
|
|
|
namespace {
|
|
|
|
const pass_data pass_data_ipa_whole_program_visibility =
|
|
{
|
|
IPA_PASS, /* type */
|
|
"whole-program", /* name */
|
|
OPTGROUP_NONE, /* optinfo_flags */
|
|
TV_CGRAPHOPT, /* tv_id */
|
|
0, /* properties_required */
|
|
0, /* properties_provided */
|
|
0, /* properties_destroyed */
|
|
0, /* todo_flags_start */
|
|
( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */
|
|
};
|
|
|
|
class pass_ipa_whole_program_visibility : public ipa_opt_pass_d
|
|
{
|
|
public:
|
|
pass_ipa_whole_program_visibility (gcc::context *ctxt)
|
|
: ipa_opt_pass_d (pass_data_ipa_whole_program_visibility, ctxt,
|
|
NULL, /* generate_summary */
|
|
NULL, /* write_summary */
|
|
NULL, /* read_summary */
|
|
NULL, /* write_optimization_summary */
|
|
NULL, /* read_optimization_summary */
|
|
NULL, /* stmt_fixup */
|
|
0, /* function_transform_todo_flags_start */
|
|
NULL, /* function_transform */
|
|
NULL) /* variable_transform */
|
|
{}
|
|
|
|
/* opt_pass methods: */
|
|
|
|
virtual bool gate (function *)
|
|
{
|
|
/* Do not re-run on ltrans stage. */
|
|
return !flag_ltrans;
|
|
}
|
|
virtual unsigned int execute (function *)
|
|
{
|
|
return whole_program_function_and_variable_visibility ();
|
|
}
|
|
|
|
}; // class pass_ipa_whole_program_visibility
|
|
|
|
} // anon namespace
|
|
|
|
ipa_opt_pass_d *
|
|
make_pass_ipa_whole_program_visibility (gcc::context *ctxt)
|
|
{
|
|
return new pass_ipa_whole_program_visibility (ctxt);
|
|
}
|
|
|
|
class pass_ipa_function_and_variable_visibility : public simple_ipa_opt_pass
|
|
{
|
|
public:
|
|
pass_ipa_function_and_variable_visibility (gcc::context *ctxt)
|
|
: simple_ipa_opt_pass (pass_data_ipa_function_and_variable_visibility,
|
|
ctxt)
|
|
{}
|
|
|
|
/* opt_pass methods: */
|
|
virtual unsigned int execute (function *)
|
|
{
|
|
return function_and_variable_visibility (flag_whole_program && !flag_lto);
|
|
}
|
|
|
|
}; // class pass_ipa_function_and_variable_visibility
|
|
|
|
simple_ipa_opt_pass *
|
|
make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt)
|
|
{
|
|
return new pass_ipa_function_and_variable_visibility (ctxt);
|
|
}
|