diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-04-23 12:53:36 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-04-23 12:53:36 +0000 |
commit | 65cbf05437b8a57ff08846beb19407c9e0dd2553 (patch) | |
tree | 0b0bd391a56275bab5bf67e4094d9b7a24ade79c | |
parent | 381399a9fee786a047529a0f7de787de475ab97c (diff) | |
download | gcc-65cbf05437b8a57ff08846beb19407c9e0dd2553.tar.gz |
2012-04-23 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 186692 using svnmerge
[gcc/]
2012-04-23 Basile Starynkevitch <basile@starynkevitch.net>
{{improvements for merging with GCC 4.8 trunk svn rev 186692}}
* melt-run.proto.h (MELT_GCC_VERSION): Define, if unknown, in the
generated melt-run.h
* melt-runtime.c (melt_val2passflag): TODO_dump_func &
TODO_dump_cgraph don't exist in GCC 4.8.
* melt-build.tpl: Say flavor, not variant! Build first the
quicklybuilt application modules, to catch error in macro C
strings...
* melt-build.mk: Regenerate.
* melt/warmelt-base.melt (valdesc_strbuf): Check for MELT_GCC_VERSION also.
* melt/warmelt-genobj.melt (compilobj_nrep_citeration): Use
meltcit prefix in generated citerator names..
* melt/warmelt-outobj.melt (syntestgen_citerator): Use
meltcitstate prefix.
* melt/xtramelt-ana-base.melt (each_cgraph_fun_body)
(each_cgraph_fun_entryblock, each_cgraph_fun_call_flow_graph)
(each_bb_cfun, with_cfun_decl): Adapt to GCC 4.8, add
documentation.
(each_cgraph_decl): Only for GCC 4.6 & 4.7
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@186705 138bc75d-0d04-0410-961f-82ee72b054a4
570 files changed, 19467 insertions, 11741 deletions
diff --git a/ChangeLog b/ChangeLog index 45c3ef3d59a..5e2da40c97a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2012-04-11 Steve Ellcey <sellcey@mips.com> + + * MAINTAINERS: Changed email address. + 2012-03-28 Georg-Johann Lay <avr@gjlay.de> PR target/52737 diff --git a/ChangeLog.MELT b/ChangeLog.MELT index 4e32180211d..cd0a59ab2dc 100644 --- a/ChangeLog.MELT +++ b/ChangeLog.MELT @@ -1,4 +1,7 @@ +2012-04-23 Basile Starynkevitch <basile@starynkevitch.net> + MELT branch merged with trunk rev 186692 using svnmerge + 2012-04-12 Basile Starynkevitch <basile@starynkevitch.net> {{MELT 0.9.5 release}} * INSTALL/README-MELT-PLUGIN: Mention it. diff --git a/MAINTAINERS b/MAINTAINERS index 9514f70940d..99ed27e78f2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -67,7 +67,7 @@ i386 port Richard Henderson rth@redhat.com i386 port Jan Hubicka jh@suse.cz i386 port Uros Bizjak ubizjak@gmail.com ia64 port Jim Wilson wilson@tuliptree.org -ia64 port Steve Ellcey sje@cup.hp.com +ia64 port Steve Ellcey sellcey@mips.com iq2000 port Nick Clifton nickc@redhat.com lm32 port Sebastien Bourdeauducq sebastien@milkymist.org m32c port DJ Delorie dj@redhat.com @@ -121,7 +121,7 @@ DJGPP DJ Delorie dj@delorie.com freebsd Loren J. Rittle ljrittle@acm.org GNU/Hurd Thomas Schwinge thomas@schwinge.name hpux John David Anglin dave.anglin@nrc-cnrc.gc.ca -hpux Steve Ellcey sje@cup.hp.com +hpux Steve Ellcey sellcey@mips.com solaris Rainer Orth ro@CeBiTec.Uni-Bielefeld.DE netbsd Jason Thorpe thorpej@netbsd.org netbsd Krister Walfridsson krister.walfridsson@gmail.com diff --git a/contrib/ChangeLog b/contrib/ChangeLog index fb59f6692e0..97b86454d6c 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,8 @@ +2012-04-16 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * testsuite-management/validate_failures.py (GetBuildData): Use + target_alias. + 2012-04-06 Doug Evans <dje@google.com> * dg-extract-results.sh: Handle KFAILs. diff --git a/contrib/testsuite-management/validate_failures.py b/contrib/testsuite-management/validate_failures.py index 7bc50896a66..c0436e5811d 100755 --- a/contrib/testsuite-management/validate_failures.py +++ b/contrib/testsuite-management/validate_failures.py @@ -5,7 +5,7 @@ # Contributed by Diego Novillo <dnovillo@google.com> # -# Copyright (C) 2011 Free Software Foundation, Inc. +# Copyright (C) 2011, 2012 Free Software Foundation, Inc. # # This file is part of GCC. # @@ -241,7 +241,7 @@ def CompareResults(manifest, actual): def GetBuildData(options): - target = GetMakefileValue('%s/Makefile' % options.build_dir, 'target=') + target = GetMakefileValue('%s/Makefile' % options.build_dir, 'target_alias=') srcdir = GetMakefileValue('%s/Makefile' % options.build_dir, 'srcdir =') if not ValidBuildDirectory(options.build_dir, target): Error('%s is not a valid GCC top level build directory.' % diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7ad65218c5c..88968a07b15 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,1593 @@ +2012-04-22 Jan Hubicka <jh@suse.cz> + + * lto-symtab.c (lto_varpool_replace_node): Do not merge needed flags. + * cgraphbuild.c (record_reference, record_type_list, mark_address, + mark_load, mark_store): Do not mark varpool nodes as needed. + * cgraph.c (cgraph_new_nodes): Remove. + (cgraph_create_function_alias): Do not mark nodes as reachable. + (cgraph_add_thunk): Likewise. + (cgraph_mark_reachable_node): Do not manage the queue. + * cgraph.h (cgraph_node): Remove next_needed. + (varpool_nodes_queue): Remove next_needed and prev_needed. + (x_cgraph_nodes_queue, x_cgraph_nodes_queue, cgraph_new_nodes): Remove. + (cgraph_new_nodes): Declare. + (x_varpool_nodes_queue, varpool_nodes_queue); Remove. + (varpool_analyze_pending_decls): Remove. + (varpool_analyze_node): New. + (varpool_mark_needed_node): Remove. + (varpool_first_variable, varpool_next_variable): New inlines. + (varpool_first_static_initializer, varpool_next_static_initializer): Update. + (FOR_EACH_STATIC_VARIABLE): Remove unused walker. + (varpool_first_defined_variable): New inline. + (varpool_next_defined_variable): New inline + (FOR_EACH_VARIABLE): Reimplement. + (FOR_EACH_DEFINED_VARIABLE): Reimplement. + * toplev.c (wrapup_global_declaration_2): Use analyzed instead of + needed flag. + * cgraphunit.c (cgraph_new_nodes): Declare here. + (enqueue_node): New function. + (cgraph_process_new_functions): update for new + node set; when constructing cgraph enqueue node for processing. + (cgraph_add_new_function): Use new node set. + (process_function_and_variable_attributes): Do not set varpool needed + flags. + (referred_to_p): New function. + (varpool_finalize_decl): Move here from varpool.c; enqueue needed node + when varpool is in construction. + (cgraph_analyze_functions): Rewrite. + (cgraph_expand_all_functions): Update. + (cgraph_output_in_order): Do not analyze pending decls; do not set needed flags. + (cgraph_optimize): Do not analyze pending decls. + * lto-cgraph.c (input_varpool_node): Clear analyzed flag for objects in other + partition; do not mark node as needed. + * dwarf2out.c (reference_to_unused): Use analyzed flag. + (premark_types_used_by_global_vars_helper): Likewise. + * ipa.c (process_references): Do not call varpool_mark_needed_node. + (cgraph_remove_unreachable_nodes): Do not rely on varpool and + cgrpah queues. + (function_and_variable_visibility): Do not mark node as needed. + (whole_program_function_and_variable_visibility): Likewise. + * Makefile.in (gt-varpool.h): No longer needed. + * passes.c (execute_one_pass, execute_ipa_pass_list): Update. + (ipa_write_summaries): Do not use needed flag. + * varpool.c: Do not include gt-varpool.h + (x_varpool_nodes_queue, x_varpool_last_needed_node, + x_varpool_last_needed_node, x_varpool_first_unanalyzed_node, + x_varpool_first_unanalyzed_node, varpool_assembled_nodes_queue): + Remove. + (varpool_remove_node): Do not update the lists. + (dump_varpool_node): Do not dump needed flag. + (varpool_enqueue_needed_node): Remove. + (varpool_mark_needed_node): Remove. + (varpool_reset_queue): Remove. + (varpool_finalize_decl): Move to cgraphunit.c + (varpool_analyze_node): New functions based on former + varpool_analyze_pending_decls. + (varpool_analyze_pending_decls): Remove. + (varpool_assemble_decl): Do not update the lists. + (enqueue_node): New function. + (varpool_remove_unreferenced_decls): Rewrite. + (varpool_empty_needed_queue): Remove. + (add_new_static_var): Do not mark node as needed. + (varpool_create_variable_alias): Handle expansion state + creation. + * except.c (output_ttype): Do not mark node as needed. + * varasm.c (mark_decl_referenced): Do not use mark_needed_node. + * tree-profile.c (init_ic_make_global_vars, init_ic_make_global_vars): + Likewise. + * tree-switch-conversion.c (build_one_array): Likewise. + +2012-04-22 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR c/44774 + * doc/invoke.texi (pedantic): Rename to Wpedantic. + * common.opt (Wpedantic): New. + (pedantic): Alias Wpedantic. + * diagnostic.c (warning_at): Likewise. + * c-decl.c (diagnose_mismatched_decls): Likewise. + (build_array_declarator): Likewise. + (mark_forward_parm_decls): + (check_bitfield_type_and_width): Likewise. + (grokdeclarator): Likewise. + (grokfield): Likewise. + (finish_struct): Likewise. + (build_enumerator): Likewise. + (store_parm_decls_oldstyle): Likewise. + (declspecs_add_qual): Likewise. + (declspecs_add_type): Likewise. + (finish_declspecs): Likewise. + * c-typeck.c (composite_type): Likewise. + (comp_target_types): Likewise. + (build_array_ref): Likewise. + (pointer_diff): Likewise. + (build_unary_op): Likewise. + (build_conditional_expr): Likewise. + (build_c_cast): Likewise. + (convert_for_assignment): Likewise. + (maybe_warn_string_init): Likewise. + (digest_init): Likewise. + (pop_init_level): Likewise. + (set_init_index): Likewise. + (c_finish_goto_label): Likewise. + (c_finish_return): Likewise. + (do_case): Likewise. + (build_binary_op): Likewise. + * c-parser.c (static): Likewise. + (c_parser_external_declaration): Likewise. + (c_parser_declaration_or_fndef): Likewise. + (c_parser_static_assert_declaration_no_se): Likewise. + (c_parser_enum_specifier): Likewise. + (c_parser_struct_or_union_specifier): Likewise. + (c_parser_struct_declaration): Likewise. + (c_parser_alignas_specifier): Likewise. + (c_parser_braced_init): Likewise. + (c_parser_initelt): Likewise. + (c_parser_compound_statement_nostart): Likewise. + (c_parser_conditional_expression): Likewise. + (c_parser_alignof_expression): Likewise. + (c_parser_postfix_expression): Likewise. + (c_parser_postfix_expression_after_paren_): Likewise. + (c_parser_objc_class_instance_variables): Likewise. + (c_parser_objc_method_definition): Likewise. + (c_parser_objc_methodprotolist): Likewise. + +2012-04-22 Ian Lance Taylor <iant@google.com> + + * godump.c (go_output_typedef): Dump size of structs. + +2012-04-22 Razya Ladelsky <razya@il.ibm.com> + + Correcting transform_to_exit_first_loop + fix to PR46886 + * tree-parloops.c (transform_to_exit_first_loop): Remove + setting of number of iterations according to the loop pattern. + Duplicate from entry to exit->src instead of loop->latch. + (pallelize_loops): Remove the condition preventing do-while loops. + * tree-cfg.c (bool bb_in_region_p): New. + (gimple_duplicate_sese_tail): Adjust duplication of the the subloops. + Adjust redirection of the duplicated iteration. + +2012-04-21 Richard Sandiford <rdsandiford@googlemail.com> + + PR bootstrap/53021 + * rtl.def (ADDRESS): Use "i" rather than "w". + * rtl.h (find_base_term): Delete. + (may_be_sp_based_p): Declare. + * rtl.c (rtx_code_size): Remove ADDRESS special case. + * alias.h (UNIQUE_BASE_VALUE_SP, UNIQUE_BASE_VALUE_ARGP) + (UNIQUE_BASE_VALUE_FP, UNIQUE_BASE_VALUE_HFP): Move to... + * alias.c: ...here. + (find_base_term): Make static. + (may_be_sp_based_p): New function. + * dse.c (record_store): Use it. + * store-motion.c (store_killed_in_insn): Likewise. + +2012-04-21 Richard Sandiford <rdsandiford@googlemail.com> + + * fold-const.c (fold_checksum_tree): Fix VECTOR_CST case. + +2012-04-21 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR 35441 + * c-typeck.c (inform_declaration): New. + (build_function_call_vec): Do not pretty-print + expressions when caret is enabled. + (convert_arguments): Use inform_declaration. + +2012-04-20 Jim Meyering <meyering@redhat.com> + + * genmodes.c (make_complex_modes): Don't truncate a mode name of + length 7 or more when prepending a "C". Suggested by Richard Guenther. + +2012-04-20 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR rtl-optimization/44214 + * fold-const.c (exact_inverse): New function. + (fold_binary_loc): Fold vector and complex division by constant into + multiply by recripocal with flag_reciprocal_math; fold vector division + by constant into multiply by reciprocal with exact inverse. + +2012-04-20 Jan Hubicka <jh@suse.cz> + + * lto-symtab.c (lto_cgraph_replace_node): Merge needed instead of + force flags. + * cgraph.c (cgraph_add_thunk): Use mark_reachable_node. + (cgraph_remove_node): Update. + (cgraph_mark_needed_node): Remove. + (cgraph_mark_force_output_node): New. + (dump_cgraph_node): Do not dump needed flag. + (cgraph_node_cannot_be_local_p_1): Update. + (cgraph_can_remove_if_no_direct_calls_and_refs): Update. + * cgraph.h (symtab_node_base): Add force_output flag. + (cgraph_node): Remove needed flag. + (varpool_node): Remove force_output flag. + (cgraph_mark_needed_node): Remove. + (cgraph_mark_force_output_node): New. + (cgraph_only_called_directly_or_aliased_p, + varpool_can_remove_if_no_refs, varpool_all_refs_explicit_p): Update. + * ipa-cp.c (ipcp_generate_summary): Remove out of date assert. + * cgraphunit.c (cgraph_decide_is_function_needed): rewrite. + (cgraph_add_new_function): Update. + (cgraph_mark_if_needed): Update. + (verify_cgraph_node): Update. + (cgraph_analyze_function): Alias target is reachable. + (process_function_and_variable_attributes): Update: externally_visible + flag makes function reachable. + (cgraph_analyze_functions): Update dumping. + * lto-cgraph.c (lto_output_node, lto_output_varpool_node, + input_overwrite_node, input_varpool_node): Update streaming. + * lto-streamer-out.c (produce_symtab): Use force_output. + * ipa.c (process_references): Weakrefs must be processed. + (cgraph_remove_unreachable_nodes): Likewise; update for new + force_output flag. + (varpool_externally_visible_p): Weakrefs are externally visible + even if they are not. + (function_and_variable_visibility): Update; when processing alias + pair force the targets to be output. + (whole_program_function_and_variable_visility): Use + mark_reachable_node. + * trans-mem.c (ipa_tm_mark_needed_node): Remove + (ipa_tm_mark_force_output_node): New function. + (ipa_tm_create_version_alias, ipa_tm_create_version): Update. + * gimple-fold.c (can_refer_decl_in_current_unit_p): Be lax about + aliases. + * varasm.c (mark_decl_referenced): Update. + (find_decl_and_mark_needed): Remove. + (find_decl): New function. + (weak_finish, finish_aliases_1, assemble_alias): Update; do not mark + alias targets as needed. + (dump_tm_clone_pairs): Update. + * tree-inline.c (copy_bb): Update check. + * symtab.c (dump_symtab_base): Dump force_output. + * tree-ssa-structalias.c (ipa_pta_execute): Use force_output. + * passes.c (execute_todo): Fix dumping. + * varpool.c (decide_is_variable_needed, varpool_finalize_decl): Update. + (varpool_analyze_pending_decls): Alias target is reachable. + (varpool_create_variable_alias): Finalize weakrefs. + +2012-04-20 Jakub Jelinek <jakub@redhat.com> + + PR bootstrap/53021 + * alias.h (UNIQUE_BASE_VALUE_SP, UNIQUE_BASE_VALUE_ARGP, + UNIQUE_BASE_VALUE_FP, UNIQUE_BASE_VALUE_HFP): Define. + * alias.c (init_alias_targets): Use UNIQUE_BASE_VALUE_* + macros instead of constants. + * dse.c (record_store): Check for SP ADDRESS by comparing + XWINT to UNIQUE_BASE_VALUE_SP instead of expecting + XEXP to be stack_pointer_rtx. + +2012-04-20 Richard Guenther <rguenther@suse.de> + + * tree-ssa-copy.c (propagate_tree_value_into_stmt): Use + update_call_from_tree when propagating into a call. + +2012-04-20 Alan Modra <amodra@gmail.com> + + * config/rs6000/rs6000.c (rs6000_emit_savres_rtx): Formatting. + (rs6000_emit_prologue, rs6000_emit_epilogue): Likewise. Rename + sp_offset to frame_off. Move world save code earlier. + +2012-04-20 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/53050 + * tree-ssa-forwprop.c (ssa_forward_propagate_and_combine): + Do only one transform on COND_EXPRs at the same time. + +2012-04-19 Jan Hubicka <jh@suse.cz> + + * symtab.c (dump_symtab_base): Revert accidental checkin. + +2012-04-20 Alan Modra <amodra@gmail.com> + + PR target/53040 + * config/rs6000/rs6000.c (rs6000_savres_strategy): When using + static chain, set REST_INLINE_FPRS too. + +2012-04-20 Thomas Schwinge <thomas@codesourcery.com> + + * tree-dump.c (dequeue_and_dump) <BIT_FIELD_REF>: Dump the three child + nodes. + +2012-04-20 Richard Guenther <rguenther@suse.de> + + * tree-vect-loop.c (vect_analyze_loop_operations): Do not vectorize + loops that can never run more often than the vectorization factor. + +2012-04-19 Jan Hubicka <jh@suse.cz> + + * symtab.c (dump_symtab_base): Fix dumping of asm lists. + +2012-04-19 David Edelsohn <dje.gcc@gmail.com> + + * config/rs6000/sync.md (fetchop_name): Change ior attribute to "or". + +2012-04-19 Jim Meyering <meyering@redhat.com> + + * genmodes.c (make_complex_modes): Avoid unnecessary use of strncpy. + We verified above that the string(including trailing NUL) fits in buf, + so just use memcpy. + +2012-04-19 Richard Guenther <rguenther@suse.de> + + * symtab.c (dump_symtab_base): Use TREE_STRING_POINTER + for dumping DECL_SECTION_NAME. + +2012-04-19 Michael Matz <matz@suse.de> + + PR middle-end/52977 + * tree.h (VECTOR_CST_NELTS): Use part number of types again. + (struct tree_vector): Adjust GTY length. + * tree.c (make_vector_stat): Don't set VECTOR_CST_NELTS. + + * gengtype.c (struct walk_type_data): Add in_record_p and loopcounter + members. + (walk_type, <TYPE_POINTER, TYPE_ARRAY>): Handle case where our + caller emitted the length calulation already. + (walk_type, <TYPE_UNION, TYPE_STRUCT>): Emit length calculations + before handling any of the fields for structs. + +2012-04-19 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/53031 + * tree-vrp.c (adjust_range_with_scev): Revert back to + using max_loop_iterations. + +2012-04-19 Michael Matz <matz@suse.de> + + * diagnostic.c (emit_diagnostic): Move va_end call after user + of the va_list. + (warning, warning_at, pedwarn, permerror): Ditto. + +2012-04-19 Richard Guenther <rguenther@suse.de> + + * ira-int.h (ira_allocno_object_iter_cond): Avoid out-of-bound + array access. + +2012-04-19 Georg-Johann Lay <avr@gjlay.de> + + PR target/53033 + * config/avr/avr.c (avr_out_load_psi): Fix assembler template for + the case *(X+const). + +2012-04-19 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org> + + * config/arm/sync.md (sync_optab): Change ior attribute to "or". + +2012-04-19 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR c/52283/37985 + * stmt.c (warn_if_unused_value): Skip NOP_EXPR. + * convert.c (convert_to_integer): Don't set TREE_NO_WARNING. + +2012-04-19 Richard Guenther <rguenther@suse.de> + + PR rtl-optimization/44688 + * loop-iv.c (determine_max_iter): Only return max_iter. + (iv_number_of_iterations): Also use the recorded loop bound + on the maximum number of iterations. + * loop-unroll.c (decide_unroll_runtime_iterations): Use + max_iter to avoid unrolling loops that do not roll. + (decide_unroll_stupid): Likewise. + +2012-04-18 Steven Bosscher <steven@gcc.gnu.org> + + * targhooks.c (default_case_values_threshold): Fix code style nit. + + * stmt.c (add_case_node, expand_case): Move logic to remove/reduce + case range and type folding from here... + * gimplify.c (gimplify_switch_expr): ... to here. Expect NULL_TREE + type, as documented in tree.def. + +2012-04-18 Jan Hubicka <jh@suse.cz> + + * cgraph.h (verify_symtab, verify_symtab_node, verify_symtab_base): + Declare. + * cgraphunit.c (verify_cgraph_node): Verify symtab base; do not verify + cgraph hash and same comdat groups. + (cgraph_optimize): Verify symbol table. + * ipa.c (cgraph_remove_unreachable_nodes): Verify symbol table. + (dissolve_same_comdat_group_list): Work on symtab nodes. + (function_and_variable_visibility): Dissolve variable same comdat group + lists, too. + * symtab.c: Include timevar.h + (verify_symtab_base, verify_symtab_node, verify_symtab): New functions. + +2012-04-18 Steven Bosscher <steven@gcc.gnu.org> + + * tree-switch-conversion.c (info): Remove global pass info. + (check_range, check_process_case, check_final_bb, create_temp_arrays, + free_temp_arrays, gather_default_values, build_constructors, + array_value_type, build_one_array, build_arrays, gen_def_assigns, + fix_phi_nodes, gen_inbound_check): Pass info around from ... + (process_switch): ... here. Unify message format. Return a const + char pointer to the failure reason message. + (do_switchconv): Unify message format. Update process_switch usage. + + * tree.def (CASE_LABEL_EXPR): Fix documentation, mention all operands. + * tree-cfg.c (edge_to_cases): Fix documentation. + +2012-04-18 Uros Bizjak <ubizjak@gmail.com> + + * config/alpha/sync.md (fetchop_name): Change ior attribute to "or". + +2012-04-18 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR tree-optimization/52976 + * tree-ssa-reassoc.c (add_to_ops_vec_max_rank): Delete. + (possibly_move_powi): New function. + (rewrite_expr_tree): Call possibly_move_powi. + (rewrite_expr_tree_parallel): Likewise. + (attempt_builtin_powi): Change call of add_to_ops_vec_max_rank to + call add_to_ops_vec instead. + +2012-04-18 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR tree-optimization/52976 + * tree-ssa-reassoc.c (stmt_is_power_of_op): New function. + (decrement_power): Likewise. + (propagate_op_to_single_use): Likewise. + (zero_one_operation): Handle __builtin_pow* calls in linearized + expression trees; factor logic into propagate_op_to_single_use. + (undistribute_ops_list): Allow operands with repeat counts > 1. + +2012-04-18 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/44688 + * cfgloop.h (record_niter_bound): Declare. + * tree-ssa-loop-niter.c (record_niter_bound): Export. + Update the estimation with the upper bound here... + (estimate_numbers_of_iterations_loop): ... instead of here. + Do not forcefully reset a recorded upper bound. + * tree-vect-loop-manip.c (vect_do_peeling_for_alignment): + Record the maximum number of loop iterations of the prologue loop. + +2012-04-18 Jan Hubicka <jh@suse.cz> + + * lto-symtab.c (lto_cgraph_replace_node): Update. + * cgraphbuild.c (record_reference, record_type_list, + record_eh_tables, mark_address, mark_load, mark_store): Update. + * cgraph.c (cgraph_same_body_alias, dump_cgraph_node, + cgraph_create_virtual_clone, cgraph_for_node_thunks_and_aliases): + Update. + * cgraph.h (symtab_node_def, symtab_node, const_symtab_node): Remove. + (cgraph_alias_aliased_node, varpool_alias_aliased_node): Update. + * reload.c: Fix typo in comment. + * rtlanal.c: Likewise. + * tree-emultls.c (gen_emutls_addr): Update. + * ipa-reference.c (analyze_function): Update. + * cgraphunit.c (cgraph_analyze_function, + cgraph_process_same_body_aliases, assemble_thunks_and_aliases): + Update. + * ipa-ref.c (ipa_record_reference): Reorg to avoid reference types. + (ipa_remove_reference): Likewise. + (ipa_remove_all_refering): Rename to ... + (ipa_remove_all_referring): ... this one; update. + (ipa_dump_references): Update. + (ipa_dump_referring): Update. + (ipa_clone_references): Update. + (ipa_clone_refering): Rename to ... + (ipa_clone_referring): ... this one; update. + (ipa_ref_cannot_lead_to_return): Update. + (ipa_ref_has_aliases_p): Update. + * ipa-ref.h (symtab_node_def, symtab_node, const_symtab_node): New + forward typedefs. + (ipa_ref_type): Remove. + (ipa_ref_ptr_u): Remove. + (ipa_ref): Remove referencing, refered, refered_index, refering_type + and refered_type; add referring, referred and referred_index. + (ipa_ref_list): Rename refering to referring. + (ipa_record_reference, ipa_remove_all_referring, ipa_dump_referring, + ipa_clone_references, ipa_clone_referring): Update prototypes. + * lto-cgraph.c (referenced_from_other_partition_p): Update. + (lto_output_ref): Update. + (add_references): Update. + (input_varpool_node): Update. + (input_refs): Update. + * ipa-ref-inline.h (ipa_ref_node): Update. + (ipa_ref_varpool_node): Update. + (ipa_ref_referring_node): Update. + (ipa_ref_referring_varpool_node): Update. + (ipa_ref_referring_ref_list): Update. + (ipa_ref_referred_ref_list): Update. + (ipa_ref_list_first_referring): Update. + (ipa_empty_ref_list): Update. + (ipa_ref_list_refering_iterate): Rename to ... + (ipa_ref_list_referring_iterate): ... this one. + * cse.c: Update comment. + * ipa-utils.c (ipa_reverse_postorder): Update. + * tree-ssa-alias.c: Update. + * ipa-inline.c (reset_edge_caches): Update. + (update_caller_keys): Update. + * ipa-inline.h: Update comments. + * jump.c: Update comment. + * alias.c: Likewise. + * ipa.c (process_references): Update. + (cgraph_remove_unreachable_nodes): Likewise. + (ipa_discover_readonly_nonaddressable_var): Likewise. + (cgraph_address_taken_from_non_vtable_p): Likewise. + * trans-mem.c (ipa_tm_execute): Update. + * simplify-rtx.c: Fix comment. + * rtl.c: Fix comment. + * symtab.c (symtab_unregister_node): Update. + * varpool.c (dump_varpool_node): Update. + (varpool_analyze_pending_decls): Update. + (assemble_aliases): Update. + (varpool_for_node_and_aliases): Update. + +2012-04-18 Richard Guenther <rguenther@suse.de> + + * cfgloop.h (estimate_numbers_of_iterations_loop): Remove + use_undefined_p parameter. + * tree-flow.h (estimate_numbers_of_iterations): Likewise. + * tree-ssa-loop-niter.c (estimate_numbers_of_iterations_loop): + Likewise. + (estimate_numbers_of_iterations): Likewise. + (estimated_loop_iterations): Adjust. + (max_loop_iterations): Likewise. + (scev_probably_wraps_p): Likewise. + * tree-ssa-loop.c (tree_ssa_loop_bounds): Likewise. + * tree-vrp.c (adjust_range_with_scev): Use max_stmt_executions, + not max_loop_iterations. + (execute_vrp): Remove explicit number of iterations estimation. + +2012-04-18 Enkovich Ilya <ilya.enkovich@intel.com> + + * config/i386/linux-common.h: New. + + * config.gcc: Add i386/linux-common.h before + all i386/linux.h and i386/linux64.h usages. + + * config/i386/gnu-user.h (GNU_USER_TARGET_LINK_SPEC): New. + (LINK_SPEC): Use GNU_USER_TARGET_LINK_SPEC. + * config/i386/gnu-user64.h: Likewise. + + * config/i386/gnu-user.common.h (GNU_USER_TARGET_CC1_SPEC): New. + (CC1_SPEC): Use GNU_USER_TARGET_CC1_SPEC. + (GNU_USER_TARGET_MATHFILE_SPEC): New. + (ENDFILE_SPEC): Use GNU_USER_TARGET_MATHFILE_SPEC. + +2012-04-18 Jan Hubicka <jh@suse.cz> + + * cgraph.c (cgraph_node_name): Remove. + (dump_cgraph_node): Use dump_symtab_base; reformat. + * cgraph.h (symtab_node_asm_name, symtab_node_name, dump_symtab, + debug_symtab, dump_symtab_node, debug_symtab_node, dump_symtab_base): + Declare. + (cgraph_node_name, varpool_node_name): Remove. + (cgraph_node_asm_name, varpool_node_asm_name, + cgraph_node_name, varpool_node_name): New. + * tree-pass.h (TODO_dump_cgraph): Rename to ... + (TODO_dump_symtab): ... this one. + * ipa-cp (pass_ipa_cp): Update. + * ia-reference.c (generate_summary, read_write_all_from_decl, + propagate, ipa_reference_read_optimization_summary): Update. + * cgraphunit.c (cgraph_analyze_functions): Update. + (cgraph_optimize): Update. + * ipa-ref.c (ipa_dump_references): Update. + (ipa_dump_refering): Update. + * ipa-inline.c (pass_ipa_inline): Update. + * matrix-reorg.c (pass_ipa_matrix_reorg): Update. + * ipa.c (pass_ipa_function_visibility, + pass_ipa_whole_program_visibility): Update. + * tree-sra.c (pass_early_ipa_sra): Update. + * symtab.c: Include langhooks.h + (symtab_node_asm_name): New. + (symtab_node_name): New. + (symtab_type_names): New static var. + (dump_symtab_base): New. + (dump_symtab_node, dump_symtab): New. + (debug_symtab_node, debug_symtab): New. + * tree-ssa-structalias.c: Dump symbol table. + * pases.c (execute_todo): Handle TODO_dump_symtab instead + of TODO_dump_cgraph. + * varpoo.c (varpool_node_name): Remove. + (dump_varpool_node): Use dump_symtab_base; reformat. + +2012-04-18 Manuel López-Ibáñez <manu@gcc.gnu.org> + + * doc/invoke.texi (Language Independent Options): @item should be + before @opindex. + +2012-04-17 Richard Sandiford <rdsandiford@googlemail.com> + + PR bootstrap/53021 + * rtl.c (rtx_code_size): Handle ADDRESS. + +2012-04-17 Tom de Vries <tom@codesourcery.com> + + * tree-iterator.c (append_to_statement_list_1): Handle case that *list_p + is not a STMT_LIST. + +2012-04-17 Uros Bizjak <ubizjak@gmail.com> + + PR target/53020 + * config/i386/sync.md (atomic_<code><mode>): Rename to + atomic_<logic><mode>. + +2012-04-17 Richard Sandiford <rdsandiford@googlemail.com> + + * rtl.def (ADDRESS): Turn operand into a HOST_WIDE_INT. + * alias.c (reg_base_value): Expand and update comment. + (arg_base_value): New variable. + (unique_id): Move up file. + (unique_base_value, unique_base_value_p, known_base_value_p): New. + (find_base_value): Use arg_base_value and known_base_value_p. + (record_set): Document REG_NOALIAS handling. Use unique_base_value. + (find_base_term): Use known_base_value_p. + (base_alias_check): Use unique_base_value_p. + (init_alias_target): Initialize arg_base_value. Use unique_base_value. + (init_alias_analysis): Use 1 as the first id for REG_NOALIAS bases. + +2012-04-17 Pat Haugen <pthaugen@us.ibm.com> + + * config/rs6000/rs6000.h (SLOW_UNALIGNED_ACCESS): Remove DImode. + +2012-04-17 Michael Matz <matz@suse.de> + + PR tree-optimization/18437 + * tree-vectorizer.h (_stmt_vec_info.stride_load_p): New member. + (STMT_VINFO_STRIDE_LOAD_P): New accessor. + (vect_check_strided_load): Declare. + * tree-vect-data-refs.c (vect_check_strided_load): New function. + (vect_analyze_data_refs): Use it to accept strided loads. + * tree-vect-stmts.c (vectorizable_load): Ditto and handle them. + +2012-04-17 Richard Guenther <rguenther@suse.de> + + PR middle-end/53011 + * tree-eh.c (cleanup_empty_eh_merge_phis): Properly discard + loops when redirecting an entry or latch edge. + +2012-04-17 Bernd Schmidt <bernds@codesourcery.com> + + * sel-sched.c (sel_global_init): Revert previous change. + +2012-04-17 Richard Guenther <rguenther@suse.de> + + * tree-flow.h (array_at_struct_end_p): Move declaration ... + * tree.h (array_at_struct_end_p): ... here. + * tree-ssa-loop-niter.c (array_at_struct_end_p): Move ... + * expr.c (array_at_struct_end_p): ... here. Rewrite. + +2012-04-17 Steven Bosscher <steven@gcc.gnu.org> + + * stmt.c (cost_table_, use_cost_table, cost_table_initialize, + COST_TABLE): Remove. + (estimate_case_costs): Remove. + (expand_case): Do not call estimate_case_costs + to set use_cost_table. + (balance_case_nodes): Do not use use_cost_table. + +2012-04-16 Jan Hubicka <jh@suse.cz> + + * cgraph.c (cgraph_hash, assembler_name_hash): Remove. + (hash_node, eq_node): Remove. + (cgraph_create_node): Do not handle hashtable. + (cgraph_get_node): Remove. + (cgraph_insert_node_to_hashtable): Remove. + (hash_node_by_assembler_name): Remove. + (eq_assembler_name): Remove. + (cgraph_node_for_asm): Rewrite. + (cgraph_find_replacement_node): Break out from ... + (cgraph_remove_node): ... here; do not maintain hashtables. + (change_decl_assembler_name): Remove. + (cgraph_clone_node): Do not maintain hashtables. + * cgraph.h (const_symtab_node): New typedef. + (cgraph_insert_node_to_hashtable): Remove. + (symtab_get_node, symtab_node_for_asm, + symtab_insert_node_to_hashtable): Declare. + (cgraph_find_replacement_node): Declare. + (cgraph_get_node, varpool_get_node): Turn into inlines. + (cgraph, varpool): Work sanely on NULL pointers. + (FOR_EACH_SYMBOL): New walker. + * ipa-inline-transform.c (save_inline_function_body): Use + symtab_insert_node_to_hashtable. + * symtab.c: Include ggc.h and diagnostics.h + (symtab_hash, assembler_name_hash): New static vars; + (hash_node, eq_node, hash_node_by_assembler_name, + eq_assembler_name, insert_to_assembler_name_hash, + unlink_from_assembler_name_hash): New. + (symtab_register_node): Update hashtables. + (symtab_insert_node_to_hashtable): New. + (symtab_unregister_node): Update hashtables. + (symtab_get_node): New. + (symtab_node_for_asm): New. + (change_decl_assembler_name): New. + * Makefile.in (symtab.o): Needs GTY. + * varpool.c (varpool_hash): Remove. + (hash_varpool_node, eq_varpool_node, varpool_get_node): Remove. + (varpool_node): Rewrite using varpool_get_node. + (varpool_remove_node): DO not maintain hashtables. + (varpool_node_for_asm): Rewrite. + +2012-04-16 Sandra Loosemore <sandra@codesourcery.com> + + * doc/invoke.texi: Copy-edit to put verbs in the present tense + when describing the current behavior of GCC. + +2012-04-16 Richard Sandiford <rdsandiford@googlemail.com> + + * genemit.c (gen_exp): Remove ADDRESS handling. + * genoutput.c (scan_operands): Likewise. + * genpeep.c (match_rtx): Likewise. + * genrecog.c (add_to_sequence): Likewise. + +2012-04-16 David Edelsohn <dje.gcc@gmail.com> + + * doc/install.texi (Specific, *-ibm-aix*): Update assembler bug status. + +2012-04-16 Martin Jambor <mjambor@suse.cz> + + * tree-sra.c (build_ref_for_model): Create COMPONENT_REFs only for + bit-fields. + +2012-04-16 Ulrich Weigand <ulrich.weigand@linaro.org> + + PR target/51819 + * config/arm/arm.c (arm_print_operand): Fix invalid alignment + hints for 'A' operand types. + +2012-04-16 Jan Hubicka <jh@suse.cz> + + * cgraph.h (symtab_node_base): Add next and previous pointers. + (cgraph_node): Remove next and preivous pointers. + (varpool_node): Likewise; remove next/previous GTY marker; + it is not type safe. + (symtab_node_def): Update GTY marker + (x_cgraph_nodes, cgraph_nodes): Remove. + (symtab_nodes): New function. + (cgraph_order): Rename to ... + (symtab_order): ... this one. + (symtab_register_node, symtab_unregister_node, symtab_remove_node): + Declare. + (x_varpool_nodes, varpool_nodes): Remove. + (FOR_EACH_STATIC_VARIABLE): Update. + (symtab_function_p, symtab_variable_p): New function. + (FOR_EACH_VARIABLE): Update. + (varpool_first_variable, varpool_next_variable): New functions. + (FOR_EACH_VARIABLE): Update. + (cgraph_first_defined_function): Update. + (cgraph_next_defined_function, cgraph_next_defined_function): Update. + (FOR_EACH_DEFINED_FUNCTION, FOR_EACH_FUNCTION): Update. + (cgraph_first_function, cgraph_next_function): New. + (FOR_EACH_FUNCTION): Update. + (cgraph_first_function_with_gimple_body, + cgraph_next_function_with_gimple_body): Update. + * symtab.c: New file. + * cgraph.c: Update copyright dates. + (x_cgraph_nodes, cgraph_order): Remove. + (NEXT_FREE_NODE): Update. + (SET_NEXT_FREE_NODE): New. + (cgraph_create_node_1): Remove common code. + (cgraph_create_node): Remove common code; call symtab_register_node. + (cgraph_remove_node): Remove common code; call symtab_unregister-node. + (cgraph_add_asm_node): Update. + (cgraph_clone_node): Register new node. + * cgraphunit.c (process_function_and_variable_attributes): Update. + (cgraph_analyze_functions): Update. + (cgraph_analyze_functions): Update. + (cgraph_output_in_order): Update. + * lto-cgraph.c (input_node, input_varpool_node, input_cgraph_1): + Update. + * ipa-inline.c (recursive_inlining): Update. + * lto-streamer-in.c (lto_input_toplevel_asms): Update. + * ipa.c (cgraph_remove_unreachable_nodes): Update. + * Makefile.in: Add symtab.o + * varpool.c (x_varpool_nodes): Remove + (varpool_node): Remove common code; call symtab_register_node. + (varpool_remove_node): Remove common code; call symtab_unregister_node. + +2012-04-16 Richard Guenther <rguenther@suse.de> + + PR middle-end/52977 + * tree.h (VECTOR_CST_NELTS): Adjust. + (struct tree_vector): Add explicit length field. + (make_vector_stat): Declare. + (make_vector): Define. + * tree.c (make_vector_stat): New function. + (build_vector_stat): Use it. + * tree-streamer-in.c (streamer_alloc_tree): Likewise. + +2012-04-16 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR tree-optimization/52976 + * tree-ssa-reassoc.c (add_to_ops_vec_max_rank): New function. + (undistribute_ops_list): Ops with repeat counts aren't eligible for + undistribution. + (attempt_builtin_powi): Call add_to_ops_vec_max_rank. + +2012-04-16 Jan Hubicka <jh@suse.cz> + + * cgraph.h (FOR_EACH_VARIABLE, FOR_EACH_VARIABLE, FOR_EACH_FUNCTION): + New macros. + * lto-symtab.c (lto_symtab_merge_cgraph_nodes): Use FOR_EACH + walkers to walk cgraph and varpool. + * cgraph.c (cgraph_node_for_asm): Likewise. + (dump_cgraph): Likewise. + * value-prof.c (init_node_map): Likewise. + * tree.c (free_lang_data_in_cgraph): Likewise. + * tree-emutls.c: (ipa_lower_emutls): Likewise. + * ipa-reference.c (generate_summary, propagate): Likewise. + * cgraphunit.c (verify_cgraph, cgraph_process_same_body_aliases, + cgraph_mark_functions_to_output, cgraph_output_in_order, + output_weakrefs, cgraph_materialize_all_clones, + cgraph_optimize): Likewise. + * lto-cgraph.c (merge_profile_summaries): Likewise. + (input_cgraph): Likewise. + * ipa-pure-const.c (generate_summary): Likewise. + (propagate): Likwise. + * ipa-utils.c (ipa_reduced_postorder): Likewise. + (ipa_free_postorder_info): Likewise. + (ipa_reverse_postorder): Likewise. + * ipa-inline.c (ipa_inline): Likewise. + * matrix-reorg.c (find_matrices_decl): Likewise. + (matrix_reorg): Likewise. + * tree-vectorizer.c (increase_alignment): Likewise. + * ipa.c (cgraph_remove_unreachable_nodes): Likewise. + (function_and_variable_visibility): Likewise. + (whole_program_function_and_variable_visibility): Likewise. + (ipa_cdtor_merge): Likewise. + * trans-mem.c (ipa_tm_execute): Likewise. + * ipa-inline-analysis.c (dump_inline_summaries): Likewise. + * ipa-prop.c (ipa_print_all_jump_functions): Likewise. + (ipa_print_all_params): Likewise. + (ipa_update_after_lto_read): Likewise. + * tree-profie.c (tree_profiling): Likewise. + * tree-ssa-structalias.c (ipa_pta_execute): Likewise. + * passes.c (dump_passes): Likewise. + (do_per_function): Likewise. + (ipa_write_summaries): Likewise. + * varpool.c (dump_varpool): Likewise. + (varpool_node_for_asm): Likewise. + (varpool_assemble_pending_decls): Likewise. + +2012-04-16 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/52975 + * tree-if-conv.c (predicate_bbs): Do not simplify inverted + condition but always mark it with TRUTH_NOT_EXPR. + +2012-04-16 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/52975 + * tree-ssa-forwprop.c (combine_cond_exprs): New function. + (ssa_forward_propagate_and_combine): Call it for COND_EXPRs + and VEC_COND_EXPRs. Also combine into VEC_COND_EXPRs condition. + * fold-const.c (operand_equal_p): Handle TARGET_MEM_REF. + +2012-04-14 Uros Bizjak <ubizjak@gmail.com> + + * config/i386/sse.md (ssse3_plusminus): New code iterator. + (avx2_ph<plusminus_mnemonic>wv16hi3): Macroize insn from + avx2_ph{add,adds,sub,subs}wv16hi3 using ssse3_plusminus code iterator. + (ssse3_ph<plusminus_mnemonic>wv8hi3): Macroize insn from + ssse3_ph{add,adds,sub,subs}wv8hi3 using ssse3_plusminus code iterator. + (ssse3_ph<plusminus_mnemonic>wv4hi3): Macroize insn from + ssse3_ph{add,adds,sub,subs}wv4hi3 using ssse3_plusminus code iterator. + + (avx2_ph<plusminus_mnemonic>dv8si3): Macroize insn from + avx2_ph{add,adds,sub,subs}dv8si3 using plusminus code iterator. + (ssse3_ph<plusminus_mnemonic>dv4si3): Macroize insn from + ssse3_ph{add,adds,sub,subs}dv4si3 using plusminus code iterator. + (ssse3_ph<plusminus_mnemonic>dv2si3): Macroize insn from + ssse3_ph{add,adds,sub,subs}dv2si3 using plusminus code iterator. + + (xop_plus): New code iterator. + (macs): New code attribute. + (macds): Ditto. + (xop_p<macs><ssemodesuffix><ssemodesuffix>): Macroize insn from + xop_pmacs{,s}{ww,dd} using xop_plus code iterator and VI24_128 mode + iterator. + (xop_p<macs>dql): Macroize insn from xop_pmacs{,s}dql using + xop_plus code iterator. + (xop_p<macs>dqh): Macroize insn from xop_pmacs{,s}dqh using + xop_plus code iterator. + (xop_p<macs>wd): Macroize insn from xop_pmacs{,s}wd using + xop_plus code iterator. + (xop_p<madcs>wd): Macroize insn from xop_pmadcs{,s}wd using + xop_plus code iterator. + + (xop_phadd<u>bw): Macroize insn from xop_phadd{,u}bw usign + any_extend code iterator. + (xop_phadd<u>bd): Macroize insn from xop_phadd{,u}bd usign + any_extend code iterator. + (xop_phadd<u>bq): Macroize insn from xop_phadd{,u}bq usign + any_extend code iterator. + (xop_phadd<u>wd): Macroize insn from xop_phadd{,u}wd usign + any_extend code iterator. + (xop_phadd<u>wq): Macroize insn from xop_phadd{,u}wq usign + any_extend code iterator. + (xop_phadd<u>dq): Macroize insn from xop_phadd{,u}dq usign + any_extend code iterator. + +2012-04-14 Tom de Vries <tom@codesourcery.com> + + * cfgcleanup.c (try_optimize_cfg): Replace call to delete_insn_chain by + call to delete_insn. Remove code to reorder BASIC_BLOCK note and + DELETED_LABEL note, and move it to ... + * cfgrtl.c (delete_insn): ... here. Change return type to void. + (delete_insn_and_edges): Likewise. + (delete_insn_chain): Handle new return type of delete_insn. Delete + chain backwards rather than forwards. + * rtl.h (delete_insn, delete_insn_and_edges): Change return type to + void. + * cfglayout.c (fixup_reorder_chain): Delete unused label. + +2012-04-14 Jan Hubicka <jh@suse.cz> + + * cgraph.h: Update copyrights; + (symtab_node): Turn to union typedef. + (symtab_node_base): New structure. + (symtab_type): Add SYMTAB_SYMBOL tag. + (cgraph_node): Annotate some pinters with nested_ptr. + (varpool_node): Likewise. + (cgraph_local_info): Remove lto_file_data + and externally_visible. + (cgraph_node): Remove decl; same_comdat_group list; + aux; ref_list; order; address_taken; reachable_from_other_parittion, + in_other_partition; resolution. + (varpool_node): Remove decl; same_comdat_group; + ref_list; lto_file_data; aux; order; resolution; externally_visible; + used_from_other_partition; in_other_partition. + (symtab_node_def): New union. + (cgraph, varpool): Update. + (varpool_first_static_initializer, varpool_next_static_initializer, + cgraph_only_called_directly_or_aliased_p, + varpool_can_remove_if_no_refs, varpool_can_remove_if_no_refs, + varpool_all_refs_explicit_p, cgraph_alias_aliased_node, + varpool_alias_aliased_node, cgraph_edge_recursive_p): Update + field references. + * cgraph.c: Likewise. + (cgraph_hash, assembler_name_hash): Turn into symtab_node. + * cgraphbuild.c: Likewise. + * lto-symtab.c: Likewise. + * c-gimplify.c: Likewise. + * value-prof.c: Likewise. + * tree.c: Likewise. + * ipa-cp.c: Likewise. + * tree-emutls.c: Likewise. + * ipa-inline-transform.c: Likwise. + * ipa-reference.c: Likewise. + * cgraphunit.c: Likewise. + * ipa-ref.c: Likewise. + * lto-cgraph.c: Likewise. + * ipa-ref-inline.h: Likewise. + * ipa-pure-const.c: Likewise. + * lto-streamer-out.c: Likewise. + * ipa-utils.c: Likewise. + * ipa-inline.c: Likewise. + * matrix-reorg.c: Likewise. + * tree-eh.c: Likewise. + * tree-vectorizer.c: Likewise. + * ipa-split.c: Likewise. + * ipa.c: Likewise. + * trans-mem.c: Likewise. + * ipa-inline-analysis.c: Likewise. + * gimplify.c: Likewise. + * cfgexpand.c: Likewise. + * tree-sra.c: Likewise. + * ipa-prop.c: Likewise. + * varasm.c: Likewise. + * tree-nested.c: Likewise. + * tree-inline.c: Likewise. + * tree-profile.c: Likewise. + * tree-ssa-structalias.c: Likewise. + * passes.c: Likewise. + * varpool.c: Likewise. + +2012-04-14 Tom de Vries <tom@codesourcery.com> + + * tree-ssa-tail-merge.c (stmt_local_def): New function, factored out of + same_succ_hash, with local_def inlined. Use SINGLE_SSA_DEF_OPERAND. + Use FOR_EACH_IMM_USE_FAST instead of FOR_EACH_IMM_USE_STMT. Remove use + of find_edge. + (gsi_advance_fw_nondebug_nonlocal): New function. + (local_def): Removed function. + (same_succ_hash): Use stmt_local_def. + (same_succ_equal): Use gsi_advance_fw_nondebug_nonlocal. + (gsi_advance_bw_nondebug_nonlocal): Use stmt_local_def. + +2012-04-13 H.J. Lu <hongjiu.lu@intel.com> + + * config/i386/i386-c.c (ix86_target_macros): Define _ILP32 + and __ILP32__ for x32. + +2012-04-13 Martin Jambor <mjambor@suse.cz> + + PR middle-end/52939 + * gimple-fold.c (gimple_get_virt_method_for_binfo): Bail out if + fold_ctor_reference returns a zero constant. + +2012-04-13 Enkovich Ilya <ilya.enkovich@intel.com> + + * config.gcc: Add i386/gnu-user-common.h before all + i386/gnu-user.h and i386/gnu-user64.h usages. + + * config/i386/gnu-user-common.h: New. + + * config/i386/gnu-user.h (CPP_SPEC): Moved to gnu-user-common.h. + (CC1_SPEC): Likewise. + (ENDFILE_SPEC): Likewise. + (DEFAULT_PCC_STRUCT_RETURN): Likewise. + (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Likewise. + (TARGET_OS_CPP_BUILTINS): Likewise. + (LIBGCC2_HAS_TF_MODE): Likewise. + (LIBGCC2_TF_CEXT): Likewise. + (TF_SIZE): Likewise. + (TARGET_ASM_FILE_END): Likewise. + (STACK_CHECK_MOVING_SP): Likewise. + (STACK_CHECK_STATIC_BUILTIN): Likewise. + * config/i386/gnu-user64.h: Likewise. + +2012-04-13 Martin Jambor <mjambor@suse.cz> + + * expr.c (expand_expr_real_1): Pass type, not the expression, to + set_mem_attributes for a memory temporary. Do not call the function + for the memory temporary created for a bitfield. + +2012-04-13 Alexandre Oliva <aoliva@redhat.com> + + PR debug/48866 + * df.h (enum debug_temp_where): New. + (dead_debug_init, dead_debug_finish) Declare. + (dead_debug_add, dead_debug_insert_temp): Declare. + (struct dead_debug_use, struct dead_debug): Moved from... + * df-problems.c: ... here. + (df_set_unused_notes_for_mw): Bind debug uses of unused regno + to a debug temp. + (df_create_unused_note): Likewise. + (df_set_dead_notes_for_mw): Move comment where it belongs. + (dead_debug_init): Export. + (dead_debug_reset_uses): New, factored out of... + (dead_debug_finish): ...this. Export. + (dead_debug_reset): Remove. + (dead_debug_add): Export. + (dead_debug_insert_before): Rename to... + (dead_debug_insert_temp): ... this. Add where argument. Export. + Locate stored value for BEFORE_WITH_VALUE. Avoid repeat inserts. + Return insertion count. + (df_note_bb_compute): Adjust. + * dce.c (word_dce_process_block): Adjust dead debug uses. + (dce_process_block): Likewise. + +2012-04-13 Alexandre Oliva <aoliva@redhat.com> + + * df-problems.c (df_note_bb_compute): Do not take note of + debug uses for whose REGs we won't emit DEAD or UNUSED notes. + +2012-04-13 Alexandre Oliva <aoliva@redhat.com> + + PR debug/51570 + * var-tracking.c (expand_depth): New type. + (onepart_aux, expand_loc_callback_data): Change depth type to it. + (loc_exp_dep_alloc): Adjust initializer. + (update_depth): Use new type. Add entryvals. + (vt_expand_var_loc_chain): Take note of expansions with + ENTRY_VALUEs, but don't accept them right away. Run an optional + second pass accepting the minimum ENTRY_VALUE count found in the + first pass. + (vt_expand_loc_callback, INIT_ELCD): Adjust. + +2012-04-13 Tom de Vries <tom@codesourcery.com> + + * tree-ssa-tail-merge.c (gsi_advance_bw_nondebug_nonlocal): Add + parameters vuse and vuse_escaped. + (find_duplicate): Init vuse1, vuse2 and vuse_escaped. Pass to + gsi_advance_bw_nondebug_nonlocal. Return if vuse_escaped and + vuse1 != vuse2. + +2012-04-13 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/52969 + * tree-if-conv.c (predicate_mem_writes): Properly gimplify + the condition for the COND_EXPR and handle predicate negation + by swapping the COND_EXPR arms. + +2012-04-13 Nick Clifton <nickc@redhat.com> + + * config/rl78/rl78.c (rl78_devirt_pass): Remove use of + TODO_dump_func flag. + +2012-04-13 Andrey Belevantsev <abel@ispras.ru> + + PR rtl-optimization/52203 + PR rtl-optimization/52715 + + Revert the 2012-03-07 fix for PR 52203. + * sel-sched.c (reset_sched_cycles_in_current_ebb): Check that + the insn does not modify DFA right before issuing, adjust + issue_rate accordingly. + +2012-04-13 Richard Guenther <rguenther@suse.de> + + PR c/52549 + * c-typeck.c (pointer_diff): Remove bogus assert. + +2012-04-13 Richard Guenther <rguenther@suse.de> + + PR c/52862 + * convert.c (convert_to_pointer): Remove special-casing of zero. + +2012-04-13 Joey Ye <joey.ye@arm.com> + + * config/arm/constraints.md (Pe): New constraint. + * config/arm/arm.md: New split for imm 256-510. + +2012-04-13 Terry Guo <terry.guo@arm.com> + + * config/arm/arm-cores.def: Added core cortex-m0plus. + * config/arm/arm-tune.md: Regenerated. + * config/arm/arm-tables.opt: Regenerated. + * doc/invoke.texi: Added entry for cpu ARM cortex-m0plus. + +2012-04-13 Alan Modra <amodra@gmail.com> + + PR target/52828 + * config/rs6000/rs6000.c (rs6000_emit_stack_tie): Rewrite with + tie regs on destination of sets. Delete forward declaration. + (rs6000_emit_stack_reset): Update rs6000_emit_stack_tie calls. + (rs6000_emit_prologue): Likewise. + (rs6000_emit_epilogue): Likewise. Use in place of gen_frame_tie + and gen_stack_tie. + (is_mem_ref): Use tie_operand to recognise stack ties. + * config/rs6000/predicates.md (tie_operand): New. + * config/rs6000/rs6000.md (restore_stack_block): Generate new + stack tie rtl. + (restore_stack_nonlocal): Likewise. + (stack_tie): Update. + (frame_tie): Delete. + +2012-04-12 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + * tree-ssa-reassoc.c (attempt_builtin_powi_stats): Change %ld to + HOST_WIDE_INT_PRINT_DEC in format strings. + +2012-04-12 Uros Bizjak <ubizjak@gmail.com> + + PR target/52932 + * config/i386/avx2intrin.h (_mm256_permutevar8x32_ps): Change second + argument type to __m256i. Update call to __builtin_ia32_permvarsf256. + * config/i386/sse.md (UNSPEC_VPERMVAR): New. + (UNSPEC_VPERMSI, UNSPEC_VPERMSF): Remove. + (avx2_permvarv8sf, avx2_permvarv8si): Switch operands 1 and 2. + (avx2_permvar<mode>): Macroize insn from avx2_permvarv8sf and + avx2_permvarv8si using VI4F_256 mode iterator. + * config/i386/i386.c (bdesc_args) <__builtin_ia32_permvarsf256>: + Update builtin type to V8SF_FTYPE_V8SF_V8SI. + (ix86_expand_vec_perm): Update calls to gen_avx2_permvarv8si and + gen_avx2_permvarv8sf. + (expand_vec_perm_pshufb): Ditto. + +2012-04-12 Michael Meissner <meissner@linux.vnet.ibm.com> + + PR target/52775 + * config/rs6000/rs6000.h (TARGET_FCFID): Add TARGET_PPC_GPOPT to + the list of options to enable the FCFID instruction. + (TARGET_EXTRA_BUILTINS): Adjust comment. + +2012-04-12 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR tree-optimization/18589 + * tree-ssa-reassoc.c (reassociate_stats): Add two fields. + (operand_entry): Add count field. + (add_repeat_to_ops_vec): New function. + (completely_remove_stmt): Likewise. + (remove_def_if_absorbed_call): Likewise. + (remove_visited_stmt_chain): Remove feeding builtin pow/powi calls. + (acceptable_pow_call): New function. + (linearize_expr_tree): Look for builtin pow/powi calls and add operand + entries with repeat counts when found. + (repeat_factor_d): New struct and associated typedefs. + (repeat_factor_vec): New static vector variable. + (compare_repeat_factors): New function. + (get_reassoc_pow_ssa_name): Likewise. + (attempt_builtin_powi): Likewise. + (reassociate_bb): Call attempt_builtin_powi. + (fini_reassoc): Two new calls to statistics_counter_event. + +2012-04-12 Richard Guenther <rguenther@suse.de> + + * Makefile.in (cgraphunit.o): Add $(EXCEPT_H) dependency. + * cgraph.h (tree_rest_of_compilation): Remove. + * cgraph.c (cgraph_add_new_function): Move ... + * cgraphunit.c (cgraph_add_new_function): ... here. + (tree_rest_of_compilation): Make static. + (cgraph_expand_function): Do not set cgraph_function_flags_ready. + * tree-optimize.c (gate_all_optimizations, pass_all_optimizations, + gate_all_early_local_passes, execute_all_early_local_passes, + pass_early_local_passes, gate_all_early_optimizations, + pass_all_early_optimizations): Move ... + * passes.c (gate_all_optimizations, pass_all_optimizations, + gate_all_early_local_passes, execute_all_early_local_passes, + pass_early_local_passes, gate_all_early_optimizations, + pass_all_early_optimizations): ... here. + * tree-optimize.c (execute_free_datastructures): Remove. + * tree-flow.h (execute_free_datastructures): Remove. + * tree-optimize.c (execute_init_datastructures, + pass_init_datastructures): Move ... + * tree-ssa.c (execute_init_datastructures, + pass_init_datastructures): ... here. + * cfgexpand.c (gimple_expand_cfg): Inline-expand call to + execute_free_datastructures. + +2012-04-12 Bernd Schmidt <bernds@codesourcery.com> + + * dbgcnt.def (ira_move): New counter. + * ira-int.h (ira_create_new_reg): Declare function. + (first_moveable_pseudo, last_moveable_pseudo): Declare variables. + * ira-emit.c (ira_create_new_reg): Renamed from craete_new_reg and + no longer static. All callers changed. + * ira.c: Include "dbgcnt.h". + (rtx_moveable_p, insn_dominated_by_p, find_moveable_pseudos, + move_unallocated_pseudos): New static functions. + (first_moveable_pseudo, last_moveable_pseudo): New global variables. + (pseudo_replaced_reg, pseudo_move_insn): New static variables. + (ira): Call find_moveable_pseudos and move_unallocated_pseudos. + * ira-costs.c (find_costs_and_classes): Assign a memory cost of zero + to the pseudos generated in find_moveable_pseudos. + * Makefile.in (ira.o): Add $(DBGCNT_H). + +2012-04-12 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/52943 + * tree-chrec.h (chrec_is_positive): Remove. + * tree-scalar-evolution.c (chrec_is_positive): Move ... + * tree-data-ref.c (chrec_is_positive): ... here. Make static. + Return false for a constant zero instead of negative. + (analyze_siv_subscript_cst_affine): Handle zero difference + in the initial condition explicitely. + +2012-04-12 Richard Guenther <rguenther@suse.de> + + * tree-parloops.c (parallelize_loops): Also consult the upper + bound for the number of iterations. + * tree-ssa-loop-prefetch.c (determine_loop_nest_reuse): Likewise. + (loop_prefetch_arrays): Likewise. + +2012-04-12 Richard Guenther <rguenther@suse.de> + + * cfgloop.h (estimated_loop_iterations_int): Ditch + 'conservative' parameter. + (max_stmt_executions_int): Likewise. + (estimated_loop_iterations): Likewise. + (max_stmt_executions): Likewise. + (max_loop_iterations): Declare. + (max_loop_iterations_int): Likewise. + (estimated_stmt_executions): Likewise. + (estimated_stmt_executions_int): Likewise. + * tree-ssa-loop-niter.c (estimated_loop_iterations): + Split parts to ... + (max_loop_iterations): ... this. + (estimated_loop_iterations_int): Split parts to ... + (max_loop_iterations_int): ... this. + (max_stmt_executions_int): Split parts to ... + (estimated_stmt_executions_int): ... this. + (max_stmt_executions): Split parts to ... + (estimated_stmt_executions): ... this. + * graphite-sese-to-poly.c (build_loop_iteration_domains): Adjust. + * predict.c (predict_loops): Likewise. + * tree-data-ref.c (max_stmt_executions_tree): Likewise. + (analyze_siv_subscript_cst_affine): Likewise. + (compute_overlap_steps_for_affine_1_2): Likewise. + (analyze_subscript_affine_affine): Likewise. + (init_omega_for_ddr_1): Likewise. + * tree-parloops.c (parallelize_loops): Likewise. + * tree-ssa-loop-ivopts.c (avg_loop_niter): Likewise. + (may_eliminate_iv): Likewise. + * tree-ssa-loop-prefetch.c (determine_loop_nest_reuse): Likewise. + (loop_prefetch_arrays): Likewise. + * tree-vrp.c (adjust_range_with_scev): Likewise. + +2012-04-12 Oleg Endo <olegendo@gcc.gnu.org> + + * config/sh/sh.h (RETURN_ADDR_RTX): Use NULL_RTX instead of 0. + * config/sh/sh.c (INSN_REGMODE_WEIGHT, CURR_REGMODE_PRESSURE): + Fix line width. + (dump_table): Use bool type for need_align and have_df variables. + (find_barrier, sfunc_uses_reg): Use NULL_RTX instead of 0. + (regs_used): Remove register modifier. + (barrier_align): Move variables slot, credit, jump_to_next + into if block above for loop. Use bool type for jump_to_next. + (sh_function_arg): Use NULL_RTX instead of 0. + +2012-04-11 Andreas Schwab <schwab@linux-m68k.org> + + * config/m68k/m68k.md (rotrhi3+1): Name it rotrhi_lowpart. + (bswapsi2): New expander. + +2012-04-11 H.J. Lu <hongjiu.lu@intel.com> + + * config/host-linux.c (TRY_EMPTY_VM_SPACE): Defined to + 0x60000000 if __x86_64 is defined and __LP64__ isn't defined. + +2012-04-11 H.J. Lu <hongjiu.lu@intel.com> + + PR rtl-optimization/52876 + * emit-rtl.c (set_reg_attrs_from_value): Handle arbitrary value. + Don't call mark_reg_pointer for incompatible pointer sign extension. + + * reginfo.c (reg_scan_mark_refs): Call set_reg_attrs_from_value + directly. + +2012-04-11 Bernd Schmidt <bernds@codesourcery.com> + + * fold-const.c (fold_unary_loc): Use GET_MODE_PRECISION for + comparisons against TYPE_PRECISION. + * tree-ssa-forwprop.c (combine_conversions): Likewise. + +2012-04-11 Xinliang David Li <davidxl@google.com> + + * tree-passes.h: Remove TODO_dump_func. + * tree-ssa-tail-merge.c (tail_merge_optimize): Remove TODO_dump_func. + * trans-mem.c: Remove TODO_dump_func. + * ira.c: Remove TODO_dump_func. + +2012-04-11 H.J. Lu <hongjiu.lu@intel.com> + + * config/i386/i386.c (ix86_option_override_internal): Check + SUBTARGET_OVERRIDE_OPTIONS and SUBSUBTARGET_OVERRIDE_OPTIONS + after TARGET_64BIT is updated. + +2012-04-11 Oleg Endo <olegendo@gcc.gnu.org> + + * config/sh/sh.h: Remove old secondary reload code. + +2012-04-11 Oleg Endo <olegendo@gcc.gnu.org> + + * config/sh/sh.c (SCHED_REORDER): Merge macro into ... + (ready_reorder): ... this function. + +2012-04-11 Bernd Schmidt <bernds@codesourcery.com> + + * sel-sched.c (sel_global_init): Swap order of sched_rgn_init and + sched_init calls. + + * haifa-sched.c (prune_ready_list): Rework handling of SCHED_GROUP_P + insns so that no other insn is queued for a time before them. + + * config/c6x/c6x.md (load_got_gotoff): Set op_pattern attribute to + unknown. + +2012-04-11 Richard Guenther <rguenther@suse.de> + + PR middle-end/52621 + * tree-chrec.c (evolution_function_is_invariant_rec_p): Properly + consider loop nesting. + (evolution_function_is_univariate_p): Properly check the remainder + for chrecs. + +2012-04-11 Richard Guenther <rguenther@suse.de> + + PR middle-end/52918 + * except.c (sjlj_emit_dispatch_table): Properly update loop structure. + +2012-04-11 Nick Clifton <nickc@redhat.com> + + * config/rl78/rl78.c (rl78_expand_prologue): Set stack use + information, if requested. + + * config/rx/rx.c (rx_expand_prologue): Likewise. + +2012-04-11 Peter Bergner <bergner@vnet.ibm.com> + Michael Matz <matz@suse.de> + + PR target/16458 + * rtlanal.c (unsigned_reg_p): New function. + Update copyright notice dates. + * rtl.h (unsigned_reg_p): Prototype it. + Update copyright notice dates. + * config/rs6000/rs6000.c (rs6000_generate_compare): Use it. + Update comment. + * expr.c (expand_expr_real_1): Set register attributes. + * stmt.c (expand_case): Likewise. + +2012-04-11 Oleg Endo <olegendo@gcc.gnu.org> + + PR target/50751 + * config/sh/sh-protos.h (sh_legitimate_index_p): Add new arguments + consider_sh2a and allow_zero. + * config/sh/sh.c (sh_legitimate_index_p): Likewise. + (disp_addr_displacement): New function. + (sh_address_cost): Use disp_addr_displacement function instead + of DISP_ADDR_OFFSET. + (sh_legitimate_address_p): Adapt to changed + sh_legitimate_index_p declaration. + (sh_find_mov_disp_adjust): Remove HImode check. + (sh_secondary_reload): Add HImode case. Use satisfies_constraint_Sdd, + disp_addr_displacement and max_mov_insn_displacement. + (max_mov_insn_displacement): Remove HImode check. + * config/sh/sh.h (CONST_OK_FOR_K04, CONST_OK_FOR_K12, + DISP_ADDR_P, DISP_ADDR_OFFSET): Remove. + * config/sh/constraints.md (K05, K13): New constraints. + (K12): Correct comment. + (Sdd): Do not use DISP_ADDR_P macro. + (Snd, Sbw): Use satisfies_constraint_Sdd. + * config/sh/sh.md (extendhisi2): Remove constraints from expander. + (*extendhisi2_compact, movhi_i): Remove. + (*extendhisi2_compact_reg, *extendhisi2_compact_mem_disp, + *extendhisi2_compact_mem_disp, *extendhisi2_compact_snd, + *movhi_reg_reg, *movhi_store_mem_disp05, *movhi_store_mem_disp13, + *movhi_load_mem_disp, *movhi_load_mem_disp, *movhi): New insns. + (*extendqisi2_compact_mem_disp, *extendqisi2_compact_mem_disp, + *movqi_store_mem_disp04, *movqi_store_mem_disp12, *movqi_load_mem_disp, + *movqi_load_mem_disp): Use sh_legitimate_index_p instead of + CONST_OK_FOR_Kxx. + Add new peepholes for HImode displacement addressing. + +2012-04-11 Oleg Endo <olegendo@gcc.gnu.org> + + * config/sh/sh.h (SIDI_OFF): Remove. + * config/sh/sh.md: Use gen_highpart and gen_lowpart to access + DImode subregs instead of gen_rtx_REG or simplifly_gen_subreg + or operand_subword. + +2012-04-11 Eric Botcazou <ebotcazou@adacore.com> + + PR target/52624 + * doc/extend.texi (Other Builtins): Document __builtin_bswap16. + (PowerPC AltiVec/VSX Built-in Functions): Remove it. + * doc/md.texi (Standard Names): Add bswap. + * builtin-types.def (BT_UINT16): New primitive type. + (BT_FN_UINT16_UINT16): New function type. + * builtins.def (BUILT_IN_BSWAP16): New. + * builtins.c (expand_builtin_bswap): Add TARGET_MODE argument. + (expand_builtin) <BUILT_IN_BSWAP16>: New case. Pass TARGET_MODE to + expand_builtin_bswap. + (fold_builtin_bswap): Add BUILT_IN_BSWAP16 case. + (fold_builtin_1): Likewise. + (is_inexpensive_builtin): Likewise. + * optabs.c (expand_unop): Deal with bswap in HImode specially. Add + missing bits for bswap to libcall code. + * tree.c (build_common_tree_nodes): Build uint16_type_node. + * tree.h (enum tree_index): Add TI_UINT16_TYPE. + (uint16_type_node): New define. + * config/rs6000/rs6000-builtin.def (RS6000_BUILTIN_BSWAP_HI): Delete. + * config/rs6000/rs6000.c (rs6000_expand_builtin): Remove handling of + above builtin. + (rs6000_init_builtins): Likewise. + * config/rs6000/rs6000.md (bswaphi2): Add TARGET_POWERPC predicate. + +2012-04-11 Tristan Gingold <gingold@adacore.com> + + * doc/extend.texi (Type Attributes): Move paragraph. + +2012-04-11 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR 24985 + * diagnostic.h (show_caret): Declare. + (caret_max_width): Declare. + (diagnostic_show_locus): Declare. + * diagnostic.c (diagnostic_initialize): Initialize to false. + (diagnostic_show_locus): New. + (diagnostic_report_diagnostic): Call it. + (getenv_columns): New. + (adjust_line): New. + (diagnostic_set_caret_max_width): New. + * input.c (read_line): New. + (location_get_source_line): New. + * input.h (location_get_source_line): Declare. + * toplev.c (general_init): Initialize show_caret from options. + * dwarf2out.c (gen_producer_string): Handle fdiagnostics-show-caret. + * opts.c (common_handle_option): Likewise. + * pretty-print.h (pp_get_prefix): New. + (pp_base_get_prefix): New. + * common.opt (fdiagnostics-show-caret): New option. + * doc/invoke.texi (fdiagnostics-show-caret): Document it. + +2012-04-11 Richard Guenther <rguenther@suse.de> + + PR rtl-optimization/52881 + * ifcvt.c (find_if_case_2): Avoid speculating loop latches. + +2012-04-11 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/52912 + * tree-ssa-threadupdate.c (thread_block): Tell the cfg + manipulation code we are threading through a loop header + to an exit destination. + +2012-04-10 Manuel López-Ibáñez <manu@gcc.gnu.org> + + * tree.h (warn_if_unused_value): Move declaration from here. + * stmt.c (warn_if_unused_value): Move definition from here. + +2010-04-10 Michael Matz <matz@suse.de> + + * tree-vectorizer.h (_loop_vec_info.strided_stores): Rename to + grouped_stores. + (LOOP_VINFO_STRIDED_STORES): Rename to LOOP_VINFO_GROUPED_STORES. + (struce _bb_vec_info.strided_stores): Rename to grouped_stores. + (BB_VINFO_STRIDED_STORES): Rename to BB_VINFO_GROUPED_STORES. + (STMT_VINFO_STRIDED_ACCESS): Rename to STMT_VINFO_GROUPED_ACCESS. + (vect_strided_store_supported): Rename to vect_grouped_store_supported. + (vect_strided_load_supported): Rename to vect_grouped_load_supported. + (vect_transform_strided_load): Rename to vect_transform_grouped_load. + (vect_record_strided_load_vectors): Rename to + vect_record_grouped_load_vectors. + * tree-vect-data-refs.c (vect_update_misalignment_for_peel): + Rename use of above macros. + (vect_verify_datarefs_alignment): Ditto. + (vector_alignment_reachable_p): Ditto. + (vect_peeling_hash_get_lowest_cost): Ditto. + (vect_enhance_data_refs_alignment): Ditto. + (vect_analyze_group_access): Ditto and rename stride to groupsize. + (vect_analyze_data_ref_access): Rename "strided" to "grouped". + (vect_strided_store_supported): Rename to vect_grouped_store_supported. + (vect_strided_load_supported): Rename to vect_grouped_load_supported. + (vect_transform_strided_load): Rename to vect_transform_grouped_load. + (vect_record_strided_load_vectors): Rename to + vect_record_grouped_load_vectors. + * tree-vect-loop.c (new_loop_vec_info): Rename use of above macros. + (destroy_loop_vec_info): Ditto. + (vect_transform_loop): Ditto and rename strided_store to grouped_store. + * tree-vect-slp.c (vect_build_slp_tree): Rename use of above macros. + (vect_analyze_slp): Ditto. + (new_bb_vec_info): Ditto. + (destroy_bb_vec_info): Ditto. + (vect_schedule_slp_instance): Ditto and rename strided_store to + grouped_store. + * tree-vect-stmts.c (vect_cost_strided_group_size): Rename to + vect_cost_group_size. + (vect_model_store_cost): Rename use of above macros and call + to vect_cost_strided_group_size. + (vect_model_load_cost): Ditto. + (vectorizable_store): Ditto, rename strided_store to grouped_store + and calls to renamed tree-vectorizer.h functions. + (vectorizable_load): Ditto. + (vect_transform_stmt): Rename use of above macros and strided_store + to grouped_store. + +2012-04-10 Jan Hubicka <jh@suse.cz> + + * cgraph.h: Remove misledaing comment on ipa-ref.h. + (symtab_type): New enum. + (symtab_node): New structure. + (cgraph_node, varpool_node): Add symbol base type. + (cgraph, varpool): New accestor functions. + * cgraph.c (cgraph_create_node_1): Set symbol type. + * varpool.c (varpool_node): Set symbol type. + +2012-04-10 Ulrich Weigand <ulrich.weigand@linaro.org> + Richard Sandiford <rdsandiford@googlemail.com> + + * fwprop.c (propagate_rtx): Also set PR_CAN_APPEAR for subregs. + +2012-04-10 Richard Guenther <rguenther@suse.de> + + PR middle-end/52888 + * gimple-low.c (gimple_check_call_args): Properly account for + compatible aggregate types. + +2012-04-10 Richard Guenther <rguenther@suse.de> + + * toplev.h (tree_rest_of_compilation): Remove. + * tree-optimize.c (tree_rest_of_compilation): Likewise. + * cgraph.h (tree_rest_of_compilation): Declare. + * tree-optimize.c (tree_rest_of_compilation): Move ... + * cgraphunit.c (tree_rest_of_compilation): ... here. + * cgraph.c (cgraph_add_new_function): Adjust. + * Makefile.in (tree-optimize.o): Adjust. + (cgraphunit.o): Likewise. + +2012-04-10 Ulrich Weigand <ulrich.weigand@linaro.org> + + PR tree-optimization/52870 + * tree-vect-patterns.c (vect_recog_widen_mult_pattern): Verify that + presumed pattern statement is within the same loop or basic block. + +2012-04-10 Tristan Gingold <gingold@adacore.com> + + * gengtype.c (main): Make uintptr_t a known type. + +2012-04-10 Richard Guenther <rguenther@suse.de> + + * tree-pass.h (tree_lowering_passes): Remove. + * tree-optimize.c (tree_lowering_passes): Remove. + * cgraph.c (cgraph_add_new_function): Inline relevant parts + of tree_lowering_passes, avoid redundant call of early local passes. + * cgraphunit.c (cgraph_lower_function): Fold into ... + (cgraph_analyze_function): ... its single caller. Inline + relevant parts of tree_lowering_passes. + 2012-04-09 H.J. Lu <hongjiu.lu@intel.com> PR other/52777 @@ -7,9 +1597,9 @@ PR lto/52722 PR lto/51765 - PR lto/52634 - * lto-cgraph.c (compute_ltrans_boundary): When alias is in the boundary, - add its target too. + PR lto/52634 + * lto-cgraph.c (compute_ltrans_boundary): When alias is in the + boundary, add its target too. * lto.c (add_references_to_partition): Add also aliased nodes. (add_cgraph_node_to_partition, add_varpool_node_to_partition): Work on nodes, not functions/variables; @@ -130,8 +1720,7 @@ 2012-04-05 Teresa Johnson <tejohnson@google.com> H.J. Lu <hongjiu.lu@intel.com> - * config/i386/i386.h (ix86_tune_indices): Add - X86_TUNE_LCP_STALL. + * config/i386/i386.h (ix86_tune_indices): Add X86_TUNE_LCP_STALL. * config/i386/i386.md (move immediate to memory peephole2): Add cases for HImode move when LCP stall avoidance is needed. * config/i386/i386.c (initial_ix86_tune_features): Initialize @@ -208,8 +1797,7 @@ 2012-04-04 Mike Stump <mikestump@comcast.net> * doc/rtl.texi (const_double): Document as sign-extending. - * expmed.c (expand_mult): Ensure we don't use shift - incorrectly. + * expmed.c (expand_mult): Ensure we don't use shift incorrectly. * emit-rtl.c (immed_double_int_const): Refine to state the value is signed. * simplify-rtx.c (mode_signbit_p): Add a fixme for wider than @@ -217,8 +1805,7 @@ (simplify_const_unary_operation, UNSIGNED_FLOAT): Ensure no negative values are converted. Fix conversions bigger than HOST_BITS_PER_WIDE_INT. - (simplify_binary_operation_1): Ensure we don't use shift - incorrectly. + (simplify_binary_operation_1): Ensure we don't use shift incorrectly. (simplify_immed_subreg): Sign-extend CONST_DOUBLEs. * explow.c (plus_constant_mode): Add. (plus_constant): Implement with plus_constant_mode. @@ -227,8 +1814,7 @@ 2012-04-04 Richard Guenther <rguenther@suse.de> PR tree-optimization/52808 - * tracer.c (tail_duplicate): Do not tail-duplicate loop header - blocks. + * tracer.c (tail_duplicate): Do not tail-duplicate loop header blocks. * Makefile.in (tracer.o): Depend on $(CFGLOOP_H). 2012-04-04 Tristan Gingold <gingold@adacore.com> @@ -251,15 +1837,15 @@ 2012-04-03 Sandeep Kumar Singh <Sandeep.Singh2@kpitcummins.com> * h8300/h8300.c (h8300_current_function_monitor_function_p): - New function. Added to check monitor functions. - (h8300_option_override): Modified to generate error/warning - messages for invalid combinations of different command line + New function. Added to check monitor functions. + (h8300_option_override): Modified to generate error/warning + messages for invalid combinations of different command line options. * h8300/h8300.md: Generate 'rte' for monitor functions. Do not - save EXR on stack for monitor function in case of H8S target + save EXR on stack for monitor function in case of H8S target when "-mno-exr" is passed. - * h8300/h8300-protos.h - (h8300_current_function_monitor_function_p): Add prototype. + * h8300/h8300-protos.h (h8300_current_function_monitor_function_p): + Add prototype. * doc/invoke.texi: Document H8S options. 2012-04-03 Tristan Gingold <gingold@adacore.com> @@ -558,8 +2144,7 @@ PR middle-end/50708 * double-int.h (rshift_double): Remove. - * double-int.c (lshift_double): Use absu_hwi to make count - positive. + * double-int.c (lshift_double): Use absu_hwi to make count positive. (rshift_double): Make static, take unsigned count argument, remove handling of negative count argument. (double_int_rshift): Dispatch to lshift_double. @@ -3186,8 +4771,7 @@ 2012-02-20 Richard Guenther <rguenther@suse.de> PR tree-optimization/52298 * tree-vect-stmts.c (vectorizable_load): Properly use - STMT_VINFO_DR_STEP instead of DR_STEP when vectorizing - outer loops. + STMT_VINFO_DR_STEP instead of DR_STEP when vectorizing outer loops. 2012-02-28 Aldy Hernandez <aldyh@redhat.com> diff --git a/gcc/ChangeLog.MELT b/gcc/ChangeLog.MELT index 1a4fef6f14a..37aeda6a1d3 100644 --- a/gcc/ChangeLog.MELT +++ b/gcc/ChangeLog.MELT @@ -1,4 +1,35 @@ +2012-04-23 Basile Starynkevitch <basile@starynkevitch.net> + + {{improvements for merging with GCC 4.8 trunk svn rev 186692}} + * melt-run.proto.h (MELT_GCC_VERSION): Define, if unknown, in the + generated melt-run.h + + * melt-runtime.c (melt_val2passflag): TODO_dump_func & + TODO_dump_cgraph don't exist in GCC 4.8. + + * melt-build.tpl: Say flavor, not variant! Build first the + quicklybuilt application modules, to catch error in macro C + strings... + + * melt-build.mk: Regenerate. + + * melt/warmelt-base.melt (valdesc_strbuf): Check for MELT_GCC_VERSION also. + + * melt/warmelt-genobj.melt (compilobj_nrep_citeration): Use + meltcit prefix in generated citerator names.. + + * melt/warmelt-outobj.melt (syntestgen_citerator): Use + meltcitstate prefix. + + * melt/xtramelt-ana-base.melt (each_cgraph_fun_body) + (each_cgraph_fun_entryblock, each_cgraph_fun_call_flow_graph) + (each_bb_cfun, with_cfun_decl): Adapt to GCC 4.8, add + documentation. + (each_cgraph_decl): Only for GCC 4.6 & 4.7 + + + 2012-04-15 Basile Starynkevitch <basile@starynkevitch.net> * melt-runtime.c (melt_really_initialize): Don't print null strings for print-settings diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index eec6a8d8178..f1ee68ae25b 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20120410 +20120423 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2d5136ae896..69a018319b8 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1178,6 +1178,7 @@ OBJS = \ cfgloopanal.o \ cfgloopmanip.o \ cfgrtl.o \ + symtab.o \ cgraph.o \ cgraphbuild.o \ cgraphunit.o \ @@ -2569,7 +2570,7 @@ tree-optimize.o : tree-optimize.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TREE_DUMP_H) toplev.h $(DIAGNOSTIC_CORE_H) $(FUNCTION_H) langhooks.h \ $(FLAGS_H) $(CGRAPH_H) $(PLUGIN_H) \ $(TREE_INLINE_H) $(GGC_H) graph.h $(CGRAPH_H) \ - $(TREE_PASS_H) $(CFGLOOP_H) $(EXCEPT_H) $(REGSET_H) + $(TREE_PASS_H) $(CFGLOOP_H) $(EXCEPT_H) gimplify.o : gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(GIMPLE_H) \ $(DIAGNOSTIC_H) $(GIMPLE_H) $(TREE_INLINE_H) langhooks.h \ @@ -2805,7 +2806,9 @@ melt-run-md5.h melt-run.h: $(srcdir)/melt-run.proto.h \ tree-pass.h $(MELT_H) gt-melt-runtime.h $(PLUGIN_H) $(TOPLEV_H) $(VERSION_H) | Makefile melt_run_md5=`$(CC) -C -E $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(srcdir)/melt-run.proto.h | grep -v '^#' | md5sum | cut -c 1-32`; \ ( echo "const char melt_run_preprocessed_md5[]=\"$$melt_run_md5\";" > melt-run-md5.h-tmp ; \ - sed -e "s,#define *MELT_RUN_HASHMD5 *XX,#define MELT_RUN_HASHMD5 \"$$melt_run_md5\"," < $(srcdir)/melt-run.proto.h > melt-run.h-tmp ) + sed -e "s,#define *MELT_RUN_HASHMD5 *XX,#define MELT_RUN_HASHMD5 \"$$melt_run_md5\"," \ + -e "s,#define *MELT_GCC_VERSION *YY,#define MELT_GCC_VERSION $(shell cat $(BASEVER) | $(AWK) '{split($$0,vertab,"."); printf "%d", vertab[1]*1000+vertab[2]}')," \ + < $(srcdir)/melt-run.proto.h > melt-run.h-tmp ) $(SHELL) $(srcdir)/../move-if-change melt-run-md5.h-tmp melt-run-md5.h $(SHELL) $(srcdir)/../move-if-change melt-run.h-tmp melt-run.h @@ -2999,6 +3002,9 @@ simplify-rtx.o : simplify-rtx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ $(RECOG_H) $(EXPR_H) $(DIAGNOSTIC_CORE_H) output.h $(FUNCTION_H) $(GGC_H) $(TM_P_H) \ $(TREE_H) $(TARGET_H) +symtab.o : symtab.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + langhooks.h toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \ + $(HASHTAB_H) gt-symtab.h cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ langhooks.h toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \ gt-cgraph.h output.h intl.h $(BASIC_BLOCK_H) debug.h $(HASHTAB_H) \ @@ -3012,7 +3018,7 @@ cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(FIBHEAP_H) output.h $(PARAMS_H) $(RTL_H) $(TIMEVAR_H) $(IPA_PROP_H) \ gt-cgraphunit.h tree-iterator.h $(COVERAGE_H) $(TREE_DUMP_H) \ tree-pretty-print.h gimple-pretty-print.h ipa-inline.h $(IPA_UTILS_H) \ - $(LTO_STREAMER_H) + $(LTO_STREAMER_H) output.h $(REGSET_H) $(EXCEPT_H) cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) langhooks.h $(CGRAPH_H) intl.h pointer-set.h $(GIMPLE_H) \ $(TREE_FLOW_H) $(TREE_PASS_H) $(IPA_UTILS_H) $(EXCEPT_H) \ @@ -3020,7 +3026,7 @@ cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(CGRAPH_H) langhooks.h $(DIAGNOSTIC_CORE_H) $(HASHTAB_H) \ $(GGC_H) $(TIMEVAR_H) debug.h $(TARGET_H) output.h $(GIMPLE_H) \ - $(TREE_FLOW_H) gt-varpool.h + $(TREE_FLOW_H) ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) \ $(TREE_PASS_H) $(TIMEVAR_H) $(GIMPLE_H) $(GGC_H) pointer-set.h \ $(IPA_UTILS_H) @@ -3382,7 +3388,7 @@ ira-lives.o: ira-lives.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(DF_H) sparseset.h $(IRA_INT_H) ira.o: ira.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(REGS_H) $(RTL_H) $(TM_P_H) $(TARGET_H) $(FLAGS_H) $(OBSTACK_H) \ - $(BITMAP_H) hard-reg-set.h $(BASIC_BLOCK_H) \ + $(BITMAP_H) hard-reg-set.h $(BASIC_BLOCK_H) $(DBGCNT_H) \ $(EXPR_H) $(RECOG_H) $(PARAMS_H) $(TIMEVAR_H) $(TREE_PASS_H) output.h \ $(EXCEPT_H) reload.h toplev.h $(DIAGNOSTIC_CORE_H) $(INTEGRATE_H) $(DF_H) $(GGC_H) $(IRA_INT_H) regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ @@ -3776,7 +3782,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/fixed-value.h \ $(srcdir)/output.h $(srcdir)/cfgloop.h \ $(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \ - $(srcdir)/reload.h $(srcdir)/caller-save.c \ + $(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/matrix-reorg.c \ $(srcdir)/dbxout.c \ @@ -3806,7 +3812,6 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/tree-scalar-evolution.c \ $(srcdir)/tree-ssa-operands.h \ $(srcdir)/tree-profile.c $(srcdir)/tree-nested.c \ - $(srcdir)/varpool.c \ $(srcdir)/tree-parloops.c \ $(srcdir)/omp-low.c \ $(srcdir)/targhooks.c $(out_file) $(srcdir)/passes.c $(srcdir)/cgraphunit.c \ diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 1d002615888..34144913fd9 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,18 @@ +2012-04-22 Jan Hubicka <jh@suse.cz> + + * gcc-interface/utils.c (gnat_write_global_declarations): Do not mark + needed node. + +2012-04-20 Jan Hubicka <jh@suse.cz> + + * gcc-interface/utils.c (gnat_write_global_declarations): Update for new + force_output placement. + +2012-04-14 Jan Hubicka <jh@suse.cz> + + * gcc-interface/trans.c (finalize_nrv): Update field referenced for new + cgraph/varpool layout. + 2012-04-09 Mike Stump <mikestump@comcast.net> * a-assert.ads: Remove execute permission. diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 89f54386e7d..cdcc2172275 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -3024,7 +3024,7 @@ finalize_nrv (tree fndecl, bitmap nrv, VEC(tree,gc) *other, Node_Id gnat_ret) /* Prune also the candidates that are referenced by nested functions. */ node = cgraph_get_create_node (fndecl); for (node = node->nested; node; node = node->next_nested) - walk_tree_without_duplicates (&DECL_SAVED_TREE (node->decl), prune_nrv_r, + walk_tree_without_duplicates (&DECL_SAVED_TREE (node->symbol.decl), prune_nrv_r, &data); if (bitmap_empty_p (nrv)) return; diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 1460a43ea94..41f83bfbe8a 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -4859,8 +4859,7 @@ gnat_write_global_declarations (void) TREE_STATIC (dummy_global) = 1; TREE_ASM_WRITTEN (dummy_global) = 1; node = varpool_node (dummy_global); - node->force_output = 1; - varpool_mark_needed_node (node); + node->symbol.force_output = 1; while (!VEC_empty (tree, types_used_by_cur_var_decl)) { diff --git a/gcc/alias.c b/gcc/alias.c index e9d701f9636..8366f9c3a5e 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -1,6 +1,6 @@ /* Alias analysis for GNU C Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by John Carr (jfc@mit.edu). This file is part of GCC. @@ -187,26 +187,54 @@ static void memory_modified_1 (rtx, const_rtx, void *); of the first set. A base address can be an ADDRESS, SYMBOL_REF, or LABEL_REF. ADDRESS - expressions represent certain special values: function arguments and - the stack, frame, and argument pointers. + expressions represent three types of base: - The contents of an ADDRESS is not normally used, the mode of the - ADDRESS determines whether the ADDRESS is a function argument or some - other special value. Pointer equality, not rtx_equal_p, determines whether - two ADDRESS expressions refer to the same base address. + 1. incoming arguments. There is just one ADDRESS to represent all + arguments, since we do not know at this level whether accesses + based on different arguments can alias. The ADDRESS has id 0. - The only use of the contents of an ADDRESS is for determining if the - current function performs nonlocal memory memory references for the - purposes of marking the function as a constant function. */ + 2. stack_pointer_rtx, frame_pointer_rtx, hard_frame_pointer_rtx + (if distinct from frame_pointer_rtx) and arg_pointer_rtx. + Each of these rtxes has a separate ADDRESS associated with it, + each with a negative id. + + GCC is (and is required to be) precise in which register it + chooses to access a particular region of stack. We can therefore + assume that accesses based on one of these rtxes do not alias + accesses based on another of these rtxes. + + 3. bases that are derived from malloc()ed memory (REG_NOALIAS). + Each such piece of memory has a separate ADDRESS associated + with it, each with an id greater than 0. + + Accesses based on one ADDRESS do not alias accesses based on other + ADDRESSes. Accesses based on ADDRESSes in groups (2) and (3) do not + alias globals either; the ADDRESSes have Pmode to indicate this. + The ADDRESS in group (1) _may_ alias globals; it has VOIDmode to + indicate this. */ static GTY(()) VEC(rtx,gc) *reg_base_value; static rtx *new_reg_base_value; +/* The single VOIDmode ADDRESS that represents all argument bases. + It has id 0. */ +static GTY(()) rtx arg_base_value; + +/* Used to allocate unique ids to each REG_NOALIAS ADDRESS. */ +static int unique_id; + /* We preserve the copy of old array around to avoid amount of garbage produced. About 8% of garbage produced were attributed to this array. */ static GTY((deletable)) VEC(rtx,gc) *old_reg_base_value; +/* Values of XINT (address, 0) of Pmode ADDRESS rtxes for special + registers. */ +#define UNIQUE_BASE_VALUE_SP -1 +#define UNIQUE_BASE_VALUE_ARGP -2 +#define UNIQUE_BASE_VALUE_FP -3 +#define UNIQUE_BASE_VALUE_HFP -4 + #define static_reg_base_value \ (this_target_rtl->x_static_reg_base_value) @@ -993,6 +1021,43 @@ get_frame_alias_set (void) return frame_set; } +/* Create a new, unique base with id ID. */ + +static rtx +unique_base_value (HOST_WIDE_INT id) +{ + return gen_rtx_ADDRESS (Pmode, id); +} + +/* Return true if accesses based on any other base value cannot alias + those based on X. */ + +static bool +unique_base_value_p (rtx x) +{ + return GET_CODE (x) == ADDRESS && GET_MODE (x) == Pmode; +} + +/* Return true if X is known to be a base value. */ + +static bool +known_base_value_p (rtx x) +{ + switch (GET_CODE (x)) + { + case LABEL_REF: + case SYMBOL_REF: + return true; + + case ADDRESS: + /* Arguments may or may not be bases; we don't know for sure. */ + return GET_MODE (x) != VOIDmode; + + default: + return false; + } +} + /* Inside SRC, the source of a SET, find a base address. */ static rtx @@ -1049,7 +1114,7 @@ find_base_value (rtx src) && (XEXP (src, 0) == arg_pointer_rtx || (GET_CODE (XEXP (src, 0)) == PLUS && XEXP (XEXP (src, 0), 0) == arg_pointer_rtx))) - return gen_rtx_ADDRESS (VOIDmode, src); + return arg_base_value; return 0; case CONST: @@ -1090,18 +1155,10 @@ find_base_value (rtx src) /* If either base is named object or a special address (like an argument or stack reference), then use it for the base term. */ - if (src_0 != 0 - && (GET_CODE (src_0) == SYMBOL_REF - || GET_CODE (src_0) == LABEL_REF - || (GET_CODE (src_0) == ADDRESS - && GET_MODE (src_0) != VOIDmode))) + if (src_0 != 0 && known_base_value_p (src_0)) return src_0; - if (src_1 != 0 - && (GET_CODE (src_1) == SYMBOL_REF - || GET_CODE (src_1) == LABEL_REF - || (GET_CODE (src_1) == ADDRESS - && GET_MODE (src_1) != VOIDmode))) + if (src_1 != 0 && known_base_value_p (src_1)) return src_1; /* Guess which operand is the base address: @@ -1128,7 +1185,7 @@ find_base_value (rtx src) return 0; case TRUNCATE: - /* As we do not know which address space the pointer is refering to, we can + /* As we do not know which address space the pointer is referring to, we can handle this only if the target does not support different pointer or address modes depending on the address space. */ if (!target_default_pointer_address_modes_p ()) @@ -1147,7 +1204,7 @@ find_base_value (rtx src) case ZERO_EXTEND: case SIGN_EXTEND: /* used for NT/Alpha pointers */ - /* As we do not know which address space the pointer is refering to, we can + /* As we do not know which address space the pointer is referring to, we can handle this only if the target does not support different pointer or address modes depending on the address space. */ if (!target_default_pointer_address_modes_p ()) @@ -1169,16 +1226,14 @@ find_base_value (rtx src) return 0; } -/* Called from init_alias_analysis indirectly through note_stores. */ +/* Called from init_alias_analysis indirectly through note_stores, + or directly if DEST is a register with a REG_NOALIAS note attached. + SET is null in the latter case. */ /* While scanning insns to find base values, reg_seen[N] is nonzero if register N has been set in this function. */ static char *reg_seen; -/* Addresses which are known not to alias anything else are identified - by a unique integer. */ -static int unique_id; - static void record_set (rtx dest, const_rtx set, void *data ATTRIBUTE_UNUSED) { @@ -1223,14 +1278,14 @@ record_set (rtx dest, const_rtx set, void *data ATTRIBUTE_UNUSED) } else { + /* There's a REG_NOALIAS note against DEST. */ if (reg_seen[regno]) { new_reg_base_value[regno] = 0; return; } reg_seen[regno] = 1; - new_reg_base_value[regno] = gen_rtx_ADDRESS (Pmode, - GEN_INT (unique_id++)); + new_reg_base_value[regno] = unique_base_value (unique_id++); return; } @@ -1536,7 +1591,7 @@ rtx_equal_for_memref_p (const_rtx x, const_rtx y) return 1; } -rtx +static rtx find_base_term (rtx x) { cselib_val *val; @@ -1554,7 +1609,7 @@ find_base_term (rtx x) return REG_BASE_VALUE (x); case TRUNCATE: - /* As we do not know which address space the pointer is refering to, we can + /* As we do not know which address space the pointer is referring to, we can handle this only if the target does not support different pointer or address modes depending on the address space. */ if (!target_default_pointer_address_modes_p ()) @@ -1573,7 +1628,7 @@ find_base_term (rtx x) case ZERO_EXTEND: case SIGN_EXTEND: /* Used for Alpha/NT pointers */ - /* As we do not know which address space the pointer is refering to, we can + /* As we do not know which address space the pointer is referring to, we can handle this only if the target does not support different pointer or address modes depending on the address space. */ if (!target_default_pointer_address_modes_p ()) @@ -1666,18 +1721,10 @@ find_base_term (rtx x) /* If either base term is named object or a special address (like an argument or stack reference), then use it for the base term. */ - if (tmp1 != 0 - && (GET_CODE (tmp1) == SYMBOL_REF - || GET_CODE (tmp1) == LABEL_REF - || (GET_CODE (tmp1) == ADDRESS - && GET_MODE (tmp1) != VOIDmode))) + if (tmp1 != 0 && known_base_value_p (tmp1)) return tmp1; - if (tmp2 != 0 - && (GET_CODE (tmp2) == SYMBOL_REF - || GET_CODE (tmp2) == LABEL_REF - || (GET_CODE (tmp2) == ADDRESS - && GET_MODE (tmp2) != VOIDmode))) + if (tmp2 != 0 && known_base_value_p (tmp2)) return tmp2; /* We could not determine which of the two operands was the @@ -1700,6 +1747,16 @@ find_base_term (rtx x) } } +/* Return true if accesses to address X may alias accesses based + on the stack pointer. */ + +bool +may_be_sp_based_p (rtx x) +{ + rtx base = find_base_term (x); + return !base || base == static_reg_base_value[STACK_POINTER_REGNUM]; +} + /* Return 0 if the addresses X and Y are known to point to different objects, 1 if they might be pointers to the same object. */ @@ -1762,12 +1819,7 @@ base_alias_check (rtx x, rtx y, enum machine_mode x_mode, if (GET_CODE (x_base) != ADDRESS && GET_CODE (y_base) != ADDRESS) return 0; - /* If one address is a stack reference there can be no alias: - stack references using different base registers do not alias, - a stack reference can not alias a parameter, and a stack reference - can not alias a global. */ - if ((GET_CODE (x_base) == ADDRESS && GET_MODE (x_base) == Pmode) - || (GET_CODE (y_base) == ADDRESS && GET_MODE (y_base) == Pmode)) + if (unique_base_value_p (x_base) || unique_base_value_p (y_base)) return 0; return 1; @@ -2328,7 +2380,7 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y, bool loop_invariant) && ! rtx_equal_p (rtlx, rtly)) return 1; - /* If we have MEMs refering to different address spaces (which can + /* If we have MEMs referring to different address spaces (which can potentially overlap), we cannot easily tell from the addresses whether the references overlap. */ if (MEM_P (rtlx) && MEM_P (rtly) @@ -2436,7 +2488,7 @@ true_dependence_1 (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr, if (MEM_READONLY_P (x)) return 0; - /* If we have MEMs refering to different address spaces (which can + /* If we have MEMs referring to different address spaces (which can potentially overlap), we cannot easily tell from the addresses whether the references overlap. */ if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) @@ -2554,7 +2606,7 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep) if (!writep && MEM_READONLY_P (mem)) return 0; - /* If we have MEMs refering to different address spaces (which can + /* If we have MEMs referring to different address spaces (which can potentially overlap), we cannot easily tell from the addresses whether the references overlap. */ if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) @@ -2641,7 +2693,7 @@ may_alias_p (const_rtx mem, const_rtx x) if (MEM_READONLY_P (x)) return 0; - /* If we have MEMs refering to different address spaces (which can + /* If we have MEMs referring to different address spaces (which can potentially overlap), we cannot easily tell from the addresses whether the references overlap. */ if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) @@ -2686,6 +2738,9 @@ init_alias_target (void) { int i; + if (!arg_base_value) + arg_base_value = gen_rtx_ADDRESS (VOIDmode, 0); + memset (static_reg_base_value, 0, sizeof static_reg_base_value); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) @@ -2694,18 +2749,17 @@ init_alias_target (void) numbers, so translate if necessary due to register windows. */ if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (i)) && HARD_REGNO_MODE_OK (i, Pmode)) - static_reg_base_value[i] - = gen_rtx_ADDRESS (VOIDmode, gen_rtx_REG (Pmode, i)); + static_reg_base_value[i] = arg_base_value; static_reg_base_value[STACK_POINTER_REGNUM] - = gen_rtx_ADDRESS (Pmode, stack_pointer_rtx); + = unique_base_value (UNIQUE_BASE_VALUE_SP); static_reg_base_value[ARG_POINTER_REGNUM] - = gen_rtx_ADDRESS (Pmode, arg_pointer_rtx); + = unique_base_value (UNIQUE_BASE_VALUE_ARGP); static_reg_base_value[FRAME_POINTER_REGNUM] - = gen_rtx_ADDRESS (Pmode, frame_pointer_rtx); + = unique_base_value (UNIQUE_BASE_VALUE_FP); #if !HARD_FRAME_POINTER_IS_FRAME_POINTER static_reg_base_value[HARD_FRAME_POINTER_REGNUM] - = gen_rtx_ADDRESS (Pmode, hard_frame_pointer_rtx); + = unique_base_value (UNIQUE_BASE_VALUE_HFP); #endif } @@ -2791,8 +2845,8 @@ init_alias_analysis (void) changed = 0; /* We want to assign the same IDs each iteration of this loop, so - start counting from zero each iteration of the loop. */ - unique_id = 0; + start counting from one each iteration of the loop. */ + unique_id = 1; /* We're at the start of the function each iteration through the loop, so we're copying arguments. */ diff --git a/gcc/alias.h b/gcc/alias.h index 49905b13649..9e0d1872658 100644 --- a/gcc/alias.h +++ b/gcc/alias.h @@ -1,5 +1,6 @@ /* Exported functions from alias.c - Copyright (C) 2004, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2004, 2007, 2008, 2009, 2010, 2012 + Free Software Foundation, Inc. This file is part of GCC. diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index fd37c2ca83a..d8e9e566694 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -76,6 +76,7 @@ DEF_PRIMITIVE_TYPE (BT_INT128, int128_integer_type_node) DEF_PRIMITIVE_TYPE (BT_UINT128, int128_unsigned_type_node) DEF_PRIMITIVE_TYPE (BT_INTMAX, intmax_type_node) DEF_PRIMITIVE_TYPE (BT_UINTMAX, uintmax_type_node) +DEF_PRIMITIVE_TYPE (BT_UINT16, uint16_type_node) DEF_PRIMITIVE_TYPE (BT_UINT32, uint32_type_node) DEF_PRIMITIVE_TYPE (BT_UINT64, uint64_type_node) DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1)) @@ -226,6 +227,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_VOID_PTRPTR, BT_VOID, BT_PTR_PTR) DEF_FUNCTION_TYPE_1 (BT_FN_UINT_UINT, BT_UINT, BT_UINT) DEF_FUNCTION_TYPE_1 (BT_FN_ULONG_ULONG, BT_ULONG, BT_ULONG) DEF_FUNCTION_TYPE_1 (BT_FN_ULONGLONG_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG) +DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_UINT16, BT_UINT16, BT_UINT16) DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT32, BT_UINT32, BT_UINT32) DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_UINT64, BT_UINT64, BT_UINT64) diff --git a/gcc/builtins.c b/gcc/builtins.c index 7afe61df505..b47f2180527 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -4626,13 +4626,15 @@ expand_builtin_alloca (tree exp, bool cannot_accumulate) return result; } -/* Expand a call to a bswap builtin with argument ARG0. MODE - is the mode to expand with. */ +/* Expand a call to bswap builtin in EXP. + Return NULL_RTX if a normal call should be emitted rather than expanding the + function in-line. If convenient, the result should be placed in TARGET. + SUBTARGET may be used as the target for computing one of EXP's operands. */ static rtx -expand_builtin_bswap (tree exp, rtx target, rtx subtarget) +expand_builtin_bswap (enum machine_mode target_mode, tree exp, rtx target, + rtx subtarget) { - enum machine_mode mode; tree arg; rtx op0; @@ -4640,14 +4642,18 @@ expand_builtin_bswap (tree exp, rtx target, rtx subtarget) return NULL_RTX; arg = CALL_EXPR_ARG (exp, 0); - mode = TYPE_MODE (TREE_TYPE (arg)); - op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL); + op0 = expand_expr (arg, + subtarget && GET_MODE (subtarget) == target_mode + ? subtarget : NULL_RTX, + target_mode, EXPAND_NORMAL); + if (GET_MODE (op0) != target_mode) + op0 = convert_to_mode (target_mode, op0, 1); - target = expand_unop (mode, bswap_optab, op0, target, 1); + target = expand_unop (target_mode, bswap_optab, op0, target, 1); gcc_assert (target); - return convert_to_mode (mode, target, 0); + return convert_to_mode (target_mode, target, 1); } /* Expand a call to a unary builtin in EXP. @@ -6077,10 +6083,10 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, expand_stack_restore (CALL_EXPR_ARG (exp, 0)); return const0_rtx; + case BUILT_IN_BSWAP16: case BUILT_IN_BSWAP32: case BUILT_IN_BSWAP64: - target = expand_builtin_bswap (exp, target, subtarget); - + target = expand_builtin_bswap (target_mode, exp, target, subtarget); if (target) return target; break; @@ -8169,7 +8175,7 @@ fold_builtin_bitop (tree fndecl, tree arg) return NULL_TREE; } -/* Fold function call to builtin_bswap and the long and long long +/* Fold function call to builtin_bswap and the short, long and long long variants. Return NULL_TREE if no simplification can be made. */ static tree fold_builtin_bswap (tree fndecl, tree arg) @@ -8182,15 +8188,15 @@ fold_builtin_bswap (tree fndecl, tree arg) { HOST_WIDE_INT hi, width, r_hi = 0; unsigned HOST_WIDE_INT lo, r_lo = 0; - tree type; + tree type = TREE_TYPE (TREE_TYPE (fndecl)); - type = TREE_TYPE (arg); width = TYPE_PRECISION (type); lo = TREE_INT_CST_LOW (arg); hi = TREE_INT_CST_HIGH (arg); switch (DECL_FUNCTION_CODE (fndecl)) { + case BUILT_IN_BSWAP16: case BUILT_IN_BSWAP32: case BUILT_IN_BSWAP64: { @@ -8220,9 +8226,9 @@ fold_builtin_bswap (tree fndecl, tree arg) } if (width < HOST_BITS_PER_WIDE_INT) - return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), r_lo); + return build_int_cst (type, r_lo); else - return build_int_cst_wide (TREE_TYPE (TREE_TYPE (fndecl)), r_lo, r_hi); + return build_int_cst_wide (type, r_lo, r_hi); } return NULL_TREE; @@ -10575,6 +10581,7 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore) CASE_FLT_FN (BUILT_IN_LLRINT): return fold_fixed_mathfn (loc, fndecl, arg0); + case BUILT_IN_BSWAP16: case BUILT_IN_BSWAP32: case BUILT_IN_BSWAP64: return fold_builtin_bswap (fndecl, arg0); @@ -14339,6 +14346,7 @@ is_inexpensive_builtin (tree decl) case BUILT_IN_ABS: case BUILT_IN_ALLOCA: case BUILT_IN_ALLOCA_WITH_ALIGN: + case BUILT_IN_BSWAP16: case BUILT_IN_BSWAP32: case BUILT_IN_BSWAP64: case BUILT_IN_CLZ: diff --git a/gcc/builtins.def b/gcc/builtins.def index 0cba2feea63..d03e41092b8 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -628,6 +628,7 @@ DEF_GCC_BUILTIN (BUILT_IN_AGGREGATE_INCOMING_ADDRESS, "aggregate_incoming DEF_EXT_LIB_BUILTIN (BUILT_IN_ALLOCA, "alloca", BT_FN_PTR_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST) DEF_GCC_BUILTIN (BUILT_IN_APPLY, "apply", BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE, ATTR_NULL) DEF_GCC_BUILTIN (BUILT_IN_APPLY_ARGS, "apply_args", BT_FN_PTR_VAR, ATTR_LEAF_LIST) +DEF_GCC_BUILTIN (BUILT_IN_BSWAP16, "bswap16", BT_FN_UINT16_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GCC_BUILTIN (BUILT_IN_BSWAP32, "bswap32", BT_FN_UINT32_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GCC_BUILTIN (BUILT_IN_BSWAP64, "bswap64", BT_FN_UINT64_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN_CLEAR_CACHE, "__clear_cache", BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST) diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 160d393e7ba..10fd4c5a3a9 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -1837,7 +1837,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, } else if (pedantic && !flag_isoc11) { - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "redefinition of typedef %q+D", newdecl); locate_old_decl (olddecl); } @@ -3897,11 +3897,11 @@ build_array_declarator (location_t loc, if (!flag_isoc99) { if (static_p || quals != NULL) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support %<static%> or type " "qualifiers in parameter array declarators"); if (vla_unspec_p) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support %<[*]%> array declarators"); } if (vla_unspec_p) @@ -4594,7 +4594,7 @@ mark_forward_parm_decls (void) if (pedantic && !current_scope->warned_forward_parm_decls) { - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C forbids forward parameter declarations"); current_scope->warned_forward_parm_decls = true; } @@ -4746,7 +4746,7 @@ check_bitfield_type_and_width (tree *type, tree *width, tree orig_name) { *width = c_fully_fold (*width, false, NULL); if (TREE_CODE (*width) == INTEGER_CST) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "bit-field %qs width not an integer constant expression", name); } @@ -4782,7 +4782,7 @@ check_bitfield_type_and_width (tree *type, tree *width, tree orig_name) && type_mv != integer_type_node && type_mv != unsigned_type_node && type_mv != boolean_type_node) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "type of bit-field %qs is a GCC extension", name); max_width = TYPE_PRECISION (*type); @@ -5076,11 +5076,11 @@ grokdeclarator (const struct c_declarator *declarator, if (pedantic && !flag_isoc99) { if (constp > 1) - pedwarn (loc, OPT_pedantic, "duplicate %<const%>"); + pedwarn (loc, OPT_Wpedantic, "duplicate %<const%>"); if (restrictp > 1) - pedwarn (loc, OPT_pedantic, "duplicate %<restrict%>"); + pedwarn (loc, OPT_Wpedantic, "duplicate %<restrict%>"); if (volatilep > 1) - pedwarn (loc, OPT_pedantic, "duplicate %<volatile%>"); + pedwarn (loc, OPT_Wpedantic, "duplicate %<volatile%>"); } if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2) @@ -5107,7 +5107,7 @@ grokdeclarator (const struct c_declarator *declarator, { if (storage_class == csc_auto) pedwarn (loc, - (current_scope == file_scope) ? 0 : OPT_pedantic, + (current_scope == file_scope) ? 0 : OPT_Wpedantic, "function definition declared %<auto%>"); if (storage_class == csc_register) error_at (loc, "function definition declared %<register%>"); @@ -5173,7 +5173,7 @@ grokdeclarator (const struct c_declarator *declarator, error_at (loc, "file-scope declaration of %qE specifies %<auto%>", name); if (pedantic && storage_class == csc_register) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "file-scope declaration of %qE specifies %<register%>", name); } else @@ -5295,7 +5295,7 @@ grokdeclarator (const struct c_declarator *declarator, } if (pedantic && !in_system_header && flexible_array_type_p (type)) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "invalid use of structure with flexible array member"); if (size == error_mark_node) @@ -5335,10 +5335,10 @@ grokdeclarator (const struct c_declarator *declarator, if (pedantic && size_maybe_const && integer_zerop (size)) { if (name) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids zero-size array %qE", name); else - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids zero-size array"); } @@ -5463,7 +5463,7 @@ grokdeclarator (const struct c_declarator *declarator, } if (flexible_array_member && pedantic && !flag_isoc99 && !in_system_header) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support flexible array members"); /* ISO C99 Flexible array members are effectively @@ -5664,7 +5664,7 @@ grokdeclarator (const struct c_declarator *declarator, if (pedantic && TREE_CODE (type) == FUNCTION_TYPE && type_quals) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids qualified function types"); if (type_quals) type = c_build_qualified_type (type, type_quals); @@ -5842,7 +5842,7 @@ grokdeclarator (const struct c_declarator *declarator, tree decl; if (pedantic && TREE_CODE (type) == FUNCTION_TYPE && type_quals) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids qualified function types"); if (type_quals) type = c_build_qualified_type (type, type_quals); @@ -5888,7 +5888,7 @@ grokdeclarator (const struct c_declarator *declarator, && !declspecs->inline_p && !declspecs->noreturn_p); if (pedantic && TREE_CODE (type) == FUNCTION_TYPE && type_quals) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids const or volatile function types"); if (type_quals) type = c_build_qualified_type (type, type_quals); @@ -5899,7 +5899,7 @@ grokdeclarator (const struct c_declarator *declarator, && variably_modified_type_p (type, NULL_TREE)) { /* C99 6.7.2.1p8 */ - pedwarn (loc, OPT_pedantic, "a member of a structure or union cannot " + pedwarn (loc, OPT_Wpedantic, "a member of a structure or union cannot " "have a variably modified type"); } @@ -5954,7 +5954,7 @@ grokdeclarator (const struct c_declarator *declarator, else if (TREE_CODE (type) == FUNCTION_TYPE) { if (type_quals) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids qualified function types"); if (type_quals) type = c_build_qualified_type (type, type_quals); @@ -6032,7 +6032,7 @@ grokdeclarator (const struct c_declarator *declarator, GCC allows 'auto', perhaps with 'inline', to support nested functions. */ if (storage_class == csc_auto) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "invalid storage class for function %qE", name); else if (storage_class == csc_static) { @@ -6049,7 +6049,7 @@ grokdeclarator (const struct c_declarator *declarator, decl = build_decl_attribute_variant (decl, decl_attr); if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl)) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids qualified function types"); /* Every function declaration is an external reference @@ -6101,10 +6101,10 @@ grokdeclarator (const struct c_declarator *declarator, if (!flag_isoc11) { if (flag_isoc99) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C99 does not support %<_Noreturn%>"); else - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support %<_Noreturn%>"); } TREE_THIS_VOLATILE (decl) = 1; @@ -6816,10 +6816,10 @@ grokfield (location_t loc, if (!flag_isoc11) { if (flag_isoc99) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C99 doesn%'t support unnamed structs/unions"); else - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C90 doesn%'t support unnamed structs/unions"); } } @@ -7104,16 +7104,16 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, if (TREE_CODE (t) == UNION_TYPE) { if (fieldlist) - pedwarn (loc, OPT_pedantic, "union has no named members"); + pedwarn (loc, OPT_Wpedantic, "union has no named members"); else - pedwarn (loc, OPT_pedantic, "union has no members"); + pedwarn (loc, OPT_Wpedantic, "union has no members"); } else { if (fieldlist) - pedwarn (loc, OPT_pedantic, "struct has no named members"); + pedwarn (loc, OPT_Wpedantic, "struct has no named members"); else - pedwarn (loc, OPT_pedantic, "struct has no members"); + pedwarn (loc, OPT_Wpedantic, "struct has no members"); } } } @@ -7195,7 +7195,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, if (pedantic && TREE_CODE (t) == RECORD_TYPE && flexible_array_type_p (TREE_TYPE (x))) - pedwarn (DECL_SOURCE_LOCATION (x), OPT_pedantic, + pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, "invalid use of structure with flexible array member"); if (DECL_NAME (x) @@ -7617,7 +7617,7 @@ build_enumerator (location_t decl_loc, location_t loc, { value = c_fully_fold (value, false, NULL); if (TREE_CODE (value) == INTEGER_CST) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "enumerator value for %qE is not an integer " "constant expression", name); } @@ -7649,7 +7649,7 @@ build_enumerator (location_t decl_loc, location_t loc, (6.4.4.3/2 in the C99 Standard). GCC allows any integer type as an extension. */ else if (!int_fits_type_p (value, integer_type_node)) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C restricts enumerator values to range of %<int%>"); /* The ISO C Standard mandates enumerators to have type int, even @@ -8195,14 +8195,14 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info) old-style definition and discarded? */ if (current_function_prototype_built_in) warning_at (DECL_SOURCE_LOCATION (parm), - OPT_pedantic, "promoted argument %qD " + OPT_Wpedantic, "promoted argument %qD " "doesn%'t match built-in prototype", parm); else { pedwarn (DECL_SOURCE_LOCATION (parm), - OPT_pedantic, "promoted argument %qD " + OPT_Wpedantic, "promoted argument %qD " "doesn%'t match prototype", parm); - pedwarn (current_function_prototype_locus, OPT_pedantic, + pedwarn (current_function_prototype_locus, OPT_Wpedantic, "prototype declaration"); } } @@ -8878,7 +8878,7 @@ declspecs_add_qual (struct c_declspecs *specs, tree qual) gcc_unreachable (); } if (dupe && !flag_isoc99) - pedwarn (input_location, OPT_pedantic, "duplicate %qE", qual); + pedwarn (input_location, OPT_Wpedantic, "duplicate %qE", qual); return specs; } @@ -9094,7 +9094,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, case RID_COMPLEX: dupe = specs->complex_p; if (!flag_isoc99 && !in_system_header) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support complex types"); if (specs->typespec_word == cts_void) error_at (loc, @@ -9133,7 +9133,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, break; case RID_SAT: dupe = specs->saturating_p; - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C does not support saturating types"); if (specs->typespec_word == cts_int128) { @@ -9212,7 +9212,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, return specs; } if (!in_system_header) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C does not support %<__int128%> type"); if (specs->long_p) @@ -9415,7 +9415,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, error_at (loc, ("decimal floating point not supported " "for this target")); - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C does not support decimal floating point"); return specs; case RID_FRACT: @@ -9439,7 +9439,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, if (!targetm.fixed_point_supported_p ()) error_at (loc, "fixed-point types not supported for this target"); - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C does not support fixed-point types"); return specs; default: @@ -9675,7 +9675,7 @@ finish_declspecs (struct c_declspecs *specs) else if (specs->complex_p) { specs->typespec_word = cts_double; - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C does not support plain %<complex%> meaning " "%<double complex%>"); } @@ -9720,7 +9720,7 @@ finish_declspecs (struct c_declspecs *specs) specs->type = char_type_node; if (specs->complex_p) { - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C does not support complex integer types"); specs->type = build_complex_type (specs->type); } @@ -9733,7 +9733,7 @@ finish_declspecs (struct c_declspecs *specs) : int128_integer_type_node); if (specs->complex_p) { - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C does not support complex integer types"); specs->type = build_complex_type (specs->type); } @@ -9759,7 +9759,7 @@ finish_declspecs (struct c_declspecs *specs) : integer_type_node); if (specs->complex_p) { - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C does not support complex integer types"); specs->type = build_complex_type (specs->type); } diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 6c4ac8b1edb..fb895315d43 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,38 @@ +2012-04-22 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR c/44774 + * c.opt (Wpedantic): New. + (pedantic): Alias Wpedantic. + * c-opts.c (c_common_handle_option): Replace -pedantic with -Wpedantic. + (c_common_post_options): Likewise. + (sanitize_cpp_opts): Likewise. + * c-lex.c (interpret_float): Likewise. + * c-format.c (check_format_types): Likewise. + * c-common.c (pointer_int_sum): Likewise. + (c_sizeof_or_alignof_type): Likewise. + (c_add_case_label): Likewise. + (c_do_switch_warnings): Likewise. + * c-pragma.c (handle_pragma_float_const_decimal64): Likewise. + +2012-04-15 Jason Merrill <jason@redhat.com> + + PR c++/52818 + * c-format.c (CPLUSPLUS_STD_VER): C++11 inherits from C99. + (C_STD_NAME): Distinguish between C++98 and C++11. + +2012-04-11 Eric Botcazou <ebotcazou@adacore.com> + + PR target/52624 + * c-common.h (uint16_type_node): Rename into... + (c_uint16_type_node): ...this. + * c-common.c (c_common_nodes_and_builtins): Adjust for above renaming. + * c-cppbuiltin.c (builtin_define_stdint_macros): Likewise. + +2012-04-10 Manuel López-Ibáñez <manu@gcc.gnu.org> + + * c-common.c (warn_if_unused_value): Move definition to here. + * c-common.h (warn_if_unused_value): Move declaration to here. + 2012-03-23 William Bader <williambader@hotmail.com> * c-lex.c (c_lex_with_flags): Avoid declarations after stmts. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index fc83b04c8a1..4eacd198d77 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -1649,6 +1649,103 @@ warn_logical_operator (location_t location, enum tree_code code, tree type, } +/* Warn if EXP contains any computations whose results are not used. + Return true if a warning is printed; false otherwise. LOCUS is the + (potential) location of the expression. */ + +bool +warn_if_unused_value (const_tree exp, location_t locus) +{ + restart: + if (TREE_USED (exp) || TREE_NO_WARNING (exp)) + return false; + + /* Don't warn about void constructs. This includes casting to void, + void function calls, and statement expressions with a final cast + to void. */ + if (VOID_TYPE_P (TREE_TYPE (exp))) + return false; + + if (EXPR_HAS_LOCATION (exp)) + locus = EXPR_LOCATION (exp); + + switch (TREE_CODE (exp)) + { + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + case MODIFY_EXPR: + case INIT_EXPR: + case TARGET_EXPR: + case CALL_EXPR: + case TRY_CATCH_EXPR: + case WITH_CLEANUP_EXPR: + case EXIT_EXPR: + case VA_ARG_EXPR: + return false; + + case BIND_EXPR: + /* For a binding, warn if no side effect within it. */ + exp = BIND_EXPR_BODY (exp); + goto restart; + + case SAVE_EXPR: + case NON_LVALUE_EXPR: + case NOP_EXPR: + exp = TREE_OPERAND (exp, 0); + goto restart; + + case TRUTH_ORIF_EXPR: + case TRUTH_ANDIF_EXPR: + /* In && or ||, warn if 2nd operand has no side effect. */ + exp = TREE_OPERAND (exp, 1); + goto restart; + + case COMPOUND_EXPR: + if (warn_if_unused_value (TREE_OPERAND (exp, 0), locus)) + return true; + /* Let people do `(foo (), 0)' without a warning. */ + if (TREE_CONSTANT (TREE_OPERAND (exp, 1))) + return false; + exp = TREE_OPERAND (exp, 1); + goto restart; + + case COND_EXPR: + /* If this is an expression with side effects, don't warn; this + case commonly appears in macro expansions. */ + if (TREE_SIDE_EFFECTS (exp)) + return false; + goto warn; + + case INDIRECT_REF: + /* Don't warn about automatic dereferencing of references, since + the user cannot control it. */ + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE) + { + exp = TREE_OPERAND (exp, 0); + goto restart; + } + /* Fall through. */ + + default: + /* Referencing a volatile value is a side effect, so don't warn. */ + if ((DECL_P (exp) || REFERENCE_CLASS_P (exp)) + && TREE_THIS_VOLATILE (exp)) + return false; + + /* If this is an expression which has no operands, there is no value + to be unused. There are no such language-independent codes, + but front ends may define such. */ + if (EXPRESSION_CLASS_P (exp) && TREE_OPERAND_LENGTH (exp) == 0) + return false; + + warn: + return warning_at (locus, OPT_Wunused_value, "value computed is not used"); + } +} + + /* Print a warning about casts that might indicate violation of strict aliasing rules if -Wstrict-aliasing is used and strict aliasing mode is in effect. OTYPE is the original @@ -3761,19 +3858,19 @@ pointer_int_sum (location_t loc, enum tree_code resultcode, if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) { - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "pointer of type %<void *%> used in arithmetic"); size_exp = integer_one_node; } else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) { - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "pointer to a function used in arithmetic"); size_exp = integer_one_node; } else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE) { - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "pointer to member function used in arithmetic"); size_exp = integer_one_node; } @@ -4352,7 +4449,7 @@ c_sizeof_or_alignof_type (location_t loc, if (is_sizeof) { if (complain && (pedantic || warn_pointer_arith)) - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "invalid application of %<sizeof%> to a function type"); else if (!complain) return error_mark_node; @@ -4363,10 +4460,10 @@ c_sizeof_or_alignof_type (location_t loc, if (complain) { if (c_dialect_cxx ()) - pedwarn (loc, OPT_pedantic, "ISO C++ does not permit " + pedwarn (loc, OPT_Wpedantic, "ISO C++ does not permit " "%<alignof%> applied to a function type"); else - pedwarn (loc, OPT_pedantic, "ISO C does not permit " + pedwarn (loc, OPT_Wpedantic, "ISO C does not permit " "%<_Alignof%> applied to a function type"); } value = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT); @@ -4376,7 +4473,7 @@ c_sizeof_or_alignof_type (location_t loc, { if (type_code == VOID_TYPE && complain && (pedantic || warn_pointer_arith)) - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "invalid application of %qs to a void type", op_name); else if (!complain) return error_mark_node; @@ -4991,7 +5088,7 @@ c_common_nodes_and_builtins (void) uint8_type_node = TREE_TYPE (identifier_global_value (c_get_ident (UINT8_TYPE))); if (UINT16_TYPE) - uint16_type_node = + c_uint16_type_node = TREE_TYPE (identifier_global_value (c_get_ident (UINT16_TYPE))); if (UINT32_TYPE) c_uint32_type_node = @@ -5344,7 +5441,7 @@ c_add_case_label (location_t loc, splay_tree cases, tree cond, tree orig_type, /* Case ranges are a GNU extension. */ if (high_value) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "range expressions in switch statements are non-standard"); type = TREE_TYPE (cond); @@ -5658,7 +5755,7 @@ finish_label_address_expr (tree label, location_t loc) { tree result; - pedwarn (input_location, OPT_pedantic, "taking the address of a label is non-standard"); + pedwarn (input_location, OPT_Wpedantic, "taking the address of a label is non-standard"); if (label == error_mark_node) return error_mark_node; diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 8552f0c92e9..dd411032272 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -390,7 +390,7 @@ extern const unsigned int num_c_common_reswords; #define int32_type_node c_global_trees[CTI_INT32_TYPE] #define int64_type_node c_global_trees[CTI_INT64_TYPE] #define uint8_type_node c_global_trees[CTI_UINT8_TYPE] -#define uint16_type_node c_global_trees[CTI_UINT16_TYPE] +#define c_uint16_type_node c_global_trees[CTI_UINT16_TYPE] #define c_uint32_type_node c_global_trees[CTI_UINT32_TYPE] #define c_uint64_type_node c_global_trees[CTI_UINT64_TYPE] #define int_least8_type_node c_global_trees[CTI_INT_LEAST8_TYPE] @@ -772,6 +772,7 @@ extern bool strict_aliasing_warning (tree, tree, tree); extern void warnings_for_convert_and_check (tree, tree, tree); extern tree convert_and_check (tree, tree); extern void overflow_warning (location_t, tree); +extern bool warn_if_unused_value (const_tree, location_t); extern void warn_logical_operator (location_t, enum tree_code, tree, enum tree_code, tree, enum tree_code, tree); extern void check_main_parameter_types (tree decl); diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index 49804f98146..920154a73c8 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -448,8 +448,8 @@ builtin_define_stdint_macros (void) builtin_define_type_max ("__INT64_MAX__", int64_type_node); if (uint8_type_node) builtin_define_type_max ("__UINT8_MAX__", uint8_type_node); - if (uint16_type_node) - builtin_define_type_max ("__UINT16_MAX__", uint16_type_node); + if (c_uint16_type_node) + builtin_define_type_max ("__UINT16_MAX__", c_uint16_type_node); if (c_uint32_type_node) builtin_define_type_max ("__UINT32_MAX__", c_uint32_type_node); if (c_uint64_type_node) diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c index 9fabc399565..158e8dc12e7 100644 --- a/gcc/c-family/c-format.c +++ b/gcc/c-family/c-format.c @@ -334,7 +334,7 @@ decode_format_attr (tree args, function_format_info *info, int validated_p) /* The C standard version C++ is treated as equivalent to or inheriting from, for the purpose of format features supported. */ -#define CPLUSPLUS_STD_VER STD_C94 +#define CPLUSPLUS_STD_VER (cxx_dialect < cxx11 ? STD_C94 : STD_C99) /* The C standard version we are checking formats against when pedantic. */ #define C_STD_VER ((int) (c_dialect_cxx () \ ? CPLUSPLUS_STD_VER \ @@ -345,7 +345,8 @@ decode_format_attr (tree args, function_format_info *info, int validated_p) pedantic. FEATURE_VER is the version in which the feature warned out appeared, which is higher than C_STD_VER. */ #define C_STD_NAME(FEATURE_VER) (c_dialect_cxx () \ - ? "ISO C++" \ + ? (cxx_dialect < cxx11 ? "ISO C++98" \ + : "ISO C++11") \ : ((FEATURE_VER) == STD_EXT \ ? "ISO C" \ : "ISO C90")) @@ -2423,13 +2424,13 @@ check_format_types (format_wanted_type *types) continue; /* If we want 'void *', allow any pointer type. (Anything else would already have got a warning.) - With -pedantic, only allow pointers to void and to character + With -Wpedantic, only allow pointers to void and to character types. */ if (wanted_type == void_type_node && (!pedantic || (i == 1 && char_type_flag))) continue; /* Don't warn about differences merely in signedness, unless - -pedantic. With -pedantic, warn if the type is a pointer + -Wpedantic. With -Wpedantic, warn if the type is a pointer target and not a character type, and for character types at a second level of indirection. */ if (TREE_CODE (wanted_type) == INTEGER_TYPE diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c index f45650bb1d8..b39201c215d 100644 --- a/gcc/c-family/c-gimplify.c +++ b/gcc/c-family/c-gimplify.c @@ -100,7 +100,7 @@ c_genericize (tree fndecl) /* Dump all nested functions now. */ cgn = cgraph_get_create_node (fndecl); for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) - c_genericize (cgn->decl); + c_genericize (cgn->symbol.decl); } static void diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c index 7e2029ce056..2a605f65e82 100644 --- a/gcc/c-family/c-lex.c +++ b/gcc/c-family/c-lex.c @@ -734,7 +734,7 @@ interpret_float (const cpp_token *token, unsigned int flags, return error_mark_node; } else - pedwarn (input_location, OPT_pedantic, "non-standard suffix on floating constant"); + pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant"); type = c_common_type_for_mode (mode, 0); gcc_assert (type); diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 0ee4390d589..17e1958ad58 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -740,11 +740,11 @@ c_common_handle_option (size_t scode, const char *arg, int value, error ("output filename specified twice"); break; - /* We need to handle the -pedantic switches here, rather than in + /* We need to handle the -Wpedantic switches here, rather than in c_common_post_options, so that a subsequent -Wno-endif-labels is not overridden. */ case OPT_pedantic_errors: - case OPT_pedantic: + case OPT_Wpedantic: cpp_opts->cpp_pedantic = 1; cpp_opts->warn_endif_labels = 1; if (warn_pointer_sign == -1) @@ -925,7 +925,7 @@ c_common_post_options (const char **pfilename) warn_ignored_qualifiers = extra_warnings; /* -Wpointer-sign is disabled by default, but it is enabled if any - of -Wall or -pedantic are given. */ + of -Wall or -Wpedantic are given. */ if (warn_pointer_sign == -1) warn_pointer_sign = 0; @@ -936,7 +936,7 @@ c_common_post_options (const char **pfilename) if (warn_jump_misses_init == -1) warn_jump_misses_init = 0; - /* -Woverlength-strings is off by default, but is enabled by -pedantic. + /* -Woverlength-strings is off by default, but is enabled by -Wpedantic. It is never enabled in C++, as the minimum limit is not normative in that standard. */ if (warn_overlength_strings == -1 || c_dialect_cxx ()) @@ -1278,8 +1278,8 @@ sanitize_cpp_opts (void) cpp_opts->stdc_0_in_system_headers = STDC_0_IN_SYSTEM_HEADERS; /* Wlong-long is disabled by default. It is enabled by: - [-pedantic | -Wtraditional] -std=[gnu|c]++98 ; or - [-pedantic | -Wtraditional] -std=non-c99 . + [-Wpedantic | -Wtraditional] -std=[gnu|c]++98 ; or + [-Wpedantic | -Wtraditional] -std=non-c99 . Either -Wlong-long or -Wno-long-long override any other settings. */ if (warn_long_long == -1) diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 5a8debc75d3..ed847c07ae7 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1127,7 +1127,7 @@ handle_pragma_float_const_decimal64 (cpp_reader *ARG_UNUSED (dummy)) return; } - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C does not support %<#pragma STDC FLOAT_CONST_DECIMAL64%>"); switch (handle_stdc_pragma ("STDC FLOAT_CONST_DECIMAL64")) diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index f785b606155..d8c944d7e13 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -557,6 +557,10 @@ Wparentheses C ObjC C++ ObjC++ Var(warn_parentheses) Warning Warn about possibly missing parentheses +Wpedantic +C ObjC C++ ObjC++ Warning +; Documented in common.opt + Wpmf-conversions C++ ObjC++ Var(warn_pmf2ptr) Init(1) Warning Warn when converting the type of pointers to member functions @@ -1184,7 +1188,7 @@ C ObjC C++ ObjC++ Joined Separate ; Documented in common.opt pedantic -C ObjC C++ ObjC++ +C ObjC C++ ObjC++ Alias(Wpedantic) ; Documented in common.opt pedantic-errors diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 0d6f7a43056..87e43dc0ab7 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -1238,7 +1238,7 @@ c_parser_translation_unit (c_parser *parser) { if (c_parser_next_token_is (parser, CPP_EOF)) { - pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "ISO C forbids an empty translation unit"); } else @@ -1336,7 +1336,7 @@ c_parser_external_declaration (c_parser *parser) } break; case CPP_SEMICOLON: - pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "ISO C does not allow extra %<;%> outside of a function"); c_parser_consume_token (parser); break; @@ -1715,7 +1715,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, /* Function definition (nested or otherwise). */ if (nested) { - pedwarn (here, OPT_pedantic, "ISO C forbids nested functions"); + pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions"); c_push_function_context (); } if (!start_function (specs, declarator, all_prefix_attrs)) @@ -1830,10 +1830,10 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) if (!flag_isoc11) { if (flag_isoc99) - pedwarn (assert_loc, OPT_pedantic, + pedwarn (assert_loc, OPT_Wpedantic, "ISO C99 does not support %<_Static_assert%>"); else - pedwarn (assert_loc, OPT_pedantic, + pedwarn (assert_loc, OPT_Wpedantic, "ISO C90 does not support %<_Static_assert%>"); } c_parser_consume_token (parser); @@ -1874,7 +1874,7 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser) { value = c_fully_fold (value, false, NULL); if (TREE_CODE (value) == INTEGER_CST) - pedwarn (value_loc, OPT_pedantic, "expression in static assertion " + pedwarn (value_loc, OPT_Wpedantic, "expression in static assertion " "is not an integer constant expression"); } if (TREE_CODE (value) != INTEGER_CST) @@ -2292,7 +2292,7 @@ c_parser_enum_specifier (c_parser *parser) if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { if (seen_comma && !flag_isoc99) - pedwarn (comma_loc, OPT_pedantic, "comma at end of enumerator list"); + pedwarn (comma_loc, OPT_Wpedantic, "comma at end of enumerator list"); c_parser_consume_token (parser); break; } @@ -2328,7 +2328,7 @@ c_parser_enum_specifier (c_parser *parser) if (pedantic && !COMPLETE_TYPE_P (ret.spec)) { gcc_assert (ident); - pedwarn (enum_loc, OPT_pedantic, + pedwarn (enum_loc, OPT_Wpedantic, "ISO C forbids forward references to %<enum%> types"); } return ret; @@ -2463,7 +2463,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) /* Parse any stray semicolon. */ if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "extra semicolon in struct or union specified"); c_parser_consume_token (parser); continue; @@ -2601,7 +2601,7 @@ c_parser_struct_declaration (c_parser *parser) tree ret; if (specs->typespec_kind == ctsk_none) { - pedwarn (decl_loc, OPT_pedantic, + pedwarn (decl_loc, OPT_Wpedantic, "ISO C forbids member declarations with no members"); shadow_tag_warned (specs, pedantic); ret = NULL_TREE; @@ -2785,10 +2785,10 @@ c_parser_alignas_specifier (c_parser * parser) if (!flag_isoc11) { if (flag_isoc99) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C99 does not support %<_Alignas%>"); else - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support %<_Alignas%>"); } if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) @@ -3745,7 +3745,7 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p) really_start_incremental_init (type); if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { - pedwarn (brace_loc, OPT_pedantic, "ISO C forbids empty initializer braces"); + pedwarn (brace_loc, OPT_Wpedantic, "ISO C forbids empty initializer braces"); } else { @@ -3795,7 +3795,7 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) set_init_label (c_parser_peek_token (parser)->value, braced_init_obstack); /* Use the colon as the error location. */ - pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_pedantic, + pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_Wpedantic, "obsolete use of designated initializer with %<:%>"); c_parser_consume_token (parser); c_parser_consume_token (parser); @@ -3935,7 +3935,7 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) c_parser_consume_token (parser); set_init_index (first, second, braced_init_obstack); if (second) - pedwarn (ellipsis_loc, OPT_pedantic, + pedwarn (ellipsis_loc, OPT_Wpedantic, "ISO C forbids specifying range of elements to initialize"); } else @@ -3948,14 +3948,14 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) if (c_parser_next_token_is (parser, CPP_EQ)) { if (!flag_isoc99) - pedwarn (des_loc, OPT_pedantic, + pedwarn (des_loc, OPT_Wpedantic, "ISO C90 forbids specifying subobject to initialize"); c_parser_consume_token (parser); } else { if (des_seen == 1) - pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "obsolete use of designated initializer without %<=%>"); else { @@ -4120,7 +4120,7 @@ c_parser_compound_statement_nostart (c_parser *parser) } c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>"); } - pedwarn (label_loc, OPT_pedantic, "ISO C forbids label declarations"); + pedwarn (label_loc, OPT_Wpedantic, "ISO C forbids label declarations"); } /* We must now have at least one statement, label or declaration. */ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) @@ -4156,7 +4156,7 @@ c_parser_compound_statement_nostart (c_parser *parser) if (last_stmt) pedwarn_c90 (loc, (pedantic && !flag_isoc99) - ? OPT_pedantic + ? OPT_Wpedantic : OPT_Wdeclaration_after_statement, "ISO C90 forbids mixed declarations and code"); last_stmt = false; @@ -4186,7 +4186,7 @@ c_parser_compound_statement_nostart (c_parser *parser) restore_extension_diagnostics (ext); if (last_stmt) pedwarn_c90 (loc, (pedantic && !flag_isoc99) - ? OPT_pedantic + ? OPT_Wpedantic : OPT_Wdeclaration_after_statement, "ISO C90 forbids mixed declarations and code"); last_stmt = false; @@ -5441,7 +5441,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) tree eptype = NULL_TREE; middle_loc = c_parser_peek_token (parser)->location; - pedwarn (middle_loc, OPT_pedantic, + pedwarn (middle_loc, OPT_Wpedantic, "ISO C forbids omitting the middle term of a ?: expression"); warn_for_omitted_condop (middle_loc, cond.value); if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR) @@ -6049,10 +6049,10 @@ c_parser_alignof_expression (c_parser *parser) && strcmp (IDENTIFIER_POINTER (alignof_spelling), "_Alignof") == 0) { if (flag_isoc99) - pedwarn (loc, OPT_pedantic, "ISO C99 does not support %qE", + pedwarn (loc, OPT_Wpedantic, "ISO C99 does not support %qE", alignof_spelling); else - pedwarn (loc, OPT_pedantic, "ISO C90 does not support %qE", + pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support %qE", alignof_spelling); } c_parser_consume_token (parser); @@ -6103,7 +6103,7 @@ c_parser_alignof_expression (c_parser *parser) mark_exp_read (expr.value); c_inhibit_evaluation_warnings--; in_alignof--; - pedwarn (loc, OPT_pedantic, "ISO C does not allow %<%E (expression)%>", + pedwarn (loc, OPT_Wpedantic, "ISO C does not allow %<%E (expression)%>", alignof_spelling); ret.value = c_alignof_expr (loc, expr.value); ret.original_code = ERROR_MARK; @@ -6329,7 +6329,7 @@ c_parser_postfix_expression (c_parser *parser) c_parser_compound_statement_nostart (parser); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids braced-groups within expressions"); expr.value = c_finish_stmt_expr (brace_loc, stmt); mark_exp_read (expr.value); @@ -6640,7 +6640,7 @@ c_parser_postfix_expression (c_parser *parser) break; } if (!flag_isoc99) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support complex types"); expr.value = build2 (COMPLEX_EXPR, build_complex_type @@ -6819,7 +6819,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, } if (!flag_isoc99) - pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals"); + pedwarn (start_loc, OPT_Wpedantic, "ISO C90 forbids compound literals"); non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) ? CONSTRUCTOR_NON_CONST (init.value) : init.original_code == C_MAYBE_CONST_EXPR); @@ -7238,7 +7238,7 @@ c_parser_objc_class_instance_variables (c_parser *parser) /* Parse any stray semicolon. */ if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "extra semicolon"); c_parser_consume_token (parser); continue; @@ -7486,7 +7486,7 @@ c_parser_objc_method_definition (c_parser *parser) if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { c_parser_consume_token (parser); - pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "extra semicolon in method definition specified"); } @@ -7538,7 +7538,7 @@ c_parser_objc_methodprotolist (c_parser *parser) switch (c_parser_peek_token (parser)->type) { case CPP_SEMICOLON: - pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, + pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, "ISO C does not allow extra %<;%> outside of a function"); c_parser_consume_token (parser); break; diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 9891348029c..7fd2c95b837 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -562,7 +562,7 @@ composite_type (tree t1, tree t2) { TREE_VALUE (n) = composite_type (TREE_TYPE (memb), TREE_VALUE (p2)); - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; } @@ -587,7 +587,7 @@ composite_type (tree t1, tree t2) { TREE_VALUE (n) = composite_type (TREE_TYPE (memb), TREE_VALUE (p1)); - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; } @@ -1217,7 +1217,7 @@ comp_target_types (location_t location, tree ttl, tree ttr) val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p); if (val == 2) - pedwarn (location, OPT_pedantic, "types are not quite compatible"); + pedwarn (location, OPT_Wpedantic, "types are not quite compatible"); if (val == 1 && enum_and_int_p && warn_cxx_compat) warning_at (location, OPT_Wc___compat, @@ -2394,10 +2394,10 @@ build_array_ref (location_t loc, tree array, tree index) while (TREE_CODE (foo) == COMPONENT_REF) foo = TREE_OPERAND (foo, 0); if (TREE_CODE (foo) == VAR_DECL && C_DECL_REGISTER (foo)) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids subscripting %<register%> array"); else if (!flag_isoc99 && !lvalue_p (foo)) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C90 forbids subscripting non-lvalue array"); } @@ -2682,6 +2682,14 @@ build_function_call (location_t loc, tree function, tree params) return ret; } +/* Give a note about the location of the declaration of DECL. */ + +static void inform_declaration (tree decl) +{ + if (decl && (TREE_CODE (decl) != FUNCTION_DECL || !DECL_BUILT_IN (decl))) + inform (DECL_SOURCE_LOCATION (decl), "declared here"); +} + /* Build a function call to function FUNCTION with parameters PARAMS. ORIGTYPES, if not NULL, is a vector of types; each element is either NULL or the original type of the corresponding element in @@ -2744,7 +2752,20 @@ build_function_call_vec (location_t loc, tree function, VEC(tree,gc) *params, if (!(TREE_CODE (fntype) == POINTER_TYPE && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)) { - error_at (loc, "called object %qE is not a function", function); + if (!flag_diagnostics_show_caret) + error_at (loc, + "called object %qE is not a function or function pointer", + function); + else if (DECL_P (function)) + { + error_at (loc, + "called object %qD is not a function or function pointer", + function); + inform_declaration (function); + } + else + error_at (loc, + "called object is not a function or function pointer"); return error_mark_node; } @@ -3034,9 +3055,7 @@ convert_arguments (tree typelist, VEC(tree,gc) *values, else error_at (input_location, "too many arguments to function %qE", function); - - if (fundecl && !DECL_BUILT_IN (fundecl)) - inform (DECL_SOURCE_LOCATION (fundecl), "declared here"); + inform_declaration (fundecl); return parmnum; } @@ -3269,8 +3288,7 @@ convert_arguments (tree typelist, VEC(tree,gc) *values, { error_at (input_location, "too few arguments to function %qE", function); - if (fundecl && !DECL_BUILT_IN (fundecl)) - inform (DECL_SOURCE_LOCATION (fundecl), "declared here"); + inform_declaration (fundecl); return -1; } @@ -3419,10 +3437,10 @@ pointer_diff (location_t loc, tree op0, tree op1) if (TREE_CODE (target_type) == VOID_TYPE) - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "pointer of type %<void *%> used in subtraction"); if (TREE_CODE (target_type) == FUNCTION_TYPE) - pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (loc, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "pointer to a function used in subtraction"); /* If the conversion to ptrdiff_type does anything like widening or @@ -3446,8 +3464,6 @@ pointer_diff (location_t loc, tree op0, tree op1) else con1 = op1; - gcc_assert (TREE_CODE (con0) != PLUS_EXPR - && TREE_CODE (con1) != PLUS_EXPR); if (TREE_CODE (con0) == POINTER_PLUS_EXPR) { lit0 = TREE_OPERAND (con0, 1); @@ -3588,7 +3604,7 @@ build_unary_op (location_t location, else if (typecode == COMPLEX_TYPE) { code = CONJ_EXPR; - pedwarn (location, OPT_pedantic, + pedwarn (location, OPT_Wpedantic, "ISO C does not support %<~%> for complex conjugation"); if (!noconvert) arg = default_conversion (arg); @@ -3694,7 +3710,7 @@ build_unary_op (location_t location, { tree real, imag; - pedwarn (location, OPT_pedantic, + pedwarn (location, OPT_Wpedantic, "ISO C does not support %<++%> and %<--%> on complex types"); arg = stabilize_reference (arg); @@ -3745,10 +3761,10 @@ build_unary_op (location_t location, || TREE_CODE (TREE_TYPE (argtype)) == VOID_TYPE) { if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) - pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (location, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "wrong type argument to increment"); else - pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (location, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "wrong type argument to decrement"); } @@ -4289,7 +4305,7 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, else if (code1 == VOID_TYPE || code2 == VOID_TYPE) { if (code1 != VOID_TYPE || code2 != VOID_TYPE) - pedwarn (colon_loc, OPT_pedantic, + pedwarn (colon_loc, OPT_Wpedantic, "ISO C forbids conditional expr with only one void side"); result_type = void_type_node; } @@ -4314,7 +4330,7 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, else if (VOID_TYPE_P (TREE_TYPE (type1))) { if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE) - pedwarn (colon_loc, OPT_pedantic, + pedwarn (colon_loc, OPT_Wpedantic, "ISO C forbids conditional expr between " "%<void *%> and function pointer"); result_type = build_pointer_type (qualify_type (TREE_TYPE (type1), @@ -4323,7 +4339,7 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, else if (VOID_TYPE_P (TREE_TYPE (type2))) { if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE) - pedwarn (colon_loc, OPT_pedantic, + pedwarn (colon_loc, OPT_Wpedantic, "ISO C forbids conditional expr between " "%<void *%> and function pointer"); result_type = build_pointer_type (qualify_type (TREE_TYPE (type2), @@ -4634,7 +4650,7 @@ build_c_cast (location_t loc, tree type, tree expr) { if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C forbids casting nonscalar to the same type"); } else if (TREE_CODE (type) == UNION_TYPE) @@ -4652,7 +4668,7 @@ build_c_cast (location_t loc, tree type, tree expr) tree t; bool maybe_const = true; - pedwarn (loc, OPT_pedantic, "ISO C forbids casts to union type"); + pedwarn (loc, OPT_Wpedantic, "ISO C forbids casts to union type"); t = c_fully_fold (value, false, &maybe_const); t = build_constructor_single (type, field, t); if (!maybe_const) @@ -4766,7 +4782,7 @@ build_c_cast (location_t loc, tree type, tree expr) && TREE_CODE (otype) == POINTER_TYPE && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE) - pedwarn (loc, OPT_pedantic, "ISO C forbids " + pedwarn (loc, OPT_Wpedantic, "ISO C forbids " "conversion of function pointer to object pointer type"); if (pedantic @@ -4775,7 +4791,7 @@ build_c_cast (location_t loc, tree type, tree expr) && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE && !null_pointer_constant_p (value)) - pedwarn (loc, OPT_pedantic, "ISO C forbids " + pedwarn (loc, OPT_Wpedantic, "ISO C forbids " "conversion of object pointer to function pointer type"); ovalue = value; @@ -5487,7 +5503,7 @@ convert_for_assignment (location_t location, tree type, tree rhs, } if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl)) - pedwarn (location, OPT_pedantic, + pedwarn (location, OPT_Wpedantic, "ISO C prohibits argument conversion to union type"); rhs = fold_convert_loc (location, TREE_TYPE (memb), rhs); @@ -5624,7 +5640,7 @@ convert_for_assignment (location_t location, tree type, tree rhs, (VOID_TYPE_P (ttr) && !null_pointer_constant && TREE_CODE (ttl) == FUNCTION_TYPE))) - WARN_FOR_ASSIGNMENT (location, OPT_pedantic, + WARN_FOR_ASSIGNMENT (location, OPT_Wpedantic, G_("ISO C forbids passing argument %d of " "%qE between function pointer " "and %<void *%>"), @@ -6061,7 +6077,7 @@ maybe_warn_string_init (tree type, struct c_expr expr) && TREE_CODE (type) == ARRAY_TYPE && TREE_CODE (expr.value) == STRING_CST && expr.original_code != STRING_CST) - pedwarn_init (input_location, OPT_pedantic, + pedwarn_init (input_location, OPT_Wpedantic, "array initialized from parenthesized string constant"); } @@ -6134,7 +6150,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, maybe_warn_string_init (type, expr); if (TYPE_DOMAIN (type) && !TYPE_MAX_VALUE (TYPE_DOMAIN (type))) - pedwarn_init (init_loc, OPT_pedantic, + pedwarn_init (init_loc, OPT_Wpedantic, "initialization of a flexible array member"); if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), @@ -6291,7 +6307,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, return error_mark_node; } - /* Compound expressions can only occur here if -pedantic or + /* Compound expressions can only occur here if -Wpedantic or -pedantic-errors is specified. In the later case, we always want an error. In the former case, we simply want a warning. */ if (require_constant && pedantic @@ -6303,7 +6319,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, if (inside_init == error_mark_node) error_init ("initializer element is not constant"); else - pedwarn_init (init_loc, OPT_pedantic, + pedwarn_init (init_loc, OPT_Wpedantic, "initializer element is not constant"); if (flag_pedantic_errors) inside_init = error_mark_node; @@ -7009,7 +7025,7 @@ pop_init_level (int implicit, struct obstack * braced_init_obstack) if (constructor_depth > 2) error_init ("initialization of flexible array member in a nested context"); else - pedwarn_init (input_location, OPT_pedantic, + pedwarn_init (input_location, OPT_Wpedantic, "initialization of a flexible array member"); /* We have already issued an error message for the existence @@ -7246,7 +7262,7 @@ set_init_index (tree first, tree last, { first = c_fully_fold (first, false, NULL); if (TREE_CODE (first) == INTEGER_CST) - pedwarn_init (input_location, OPT_pedantic, + pedwarn_init (input_location, OPT_Wpedantic, "array index in initializer is not " "an integer constant expression"); } @@ -7255,7 +7271,7 @@ set_init_index (tree first, tree last, { last = c_fully_fold (last, false, NULL); if (TREE_CODE (last) == INTEGER_CST) - pedwarn_init (input_location, OPT_pedantic, + pedwarn_init (input_location, OPT_Wpedantic, "array index in initializer is not " "an integer constant expression"); } @@ -8688,7 +8704,7 @@ tree c_finish_goto_ptr (location_t loc, tree expr) { tree t; - pedwarn (loc, OPT_pedantic, "ISO C forbids %<goto *expr;%>"); + pedwarn (loc, OPT_Wpedantic, "ISO C forbids %<goto *expr;%>"); expr = c_fully_fold (expr, false, NULL); expr = convert (ptr_type_node, expr); t = build1 (GOTO_EXPR, void_type_node, expr); @@ -8745,7 +8761,7 @@ c_finish_return (location_t loc, tree retval, tree origtype) pedwarn (loc, 0, "%<return%> with a value, in function returning void"); else - pedwarn (loc, OPT_pedantic, "ISO C forbids " + pedwarn (loc, OPT_Wpedantic, "ISO C forbids " "%<return%> with expression, in function returning void"); } else @@ -8927,7 +8943,7 @@ do_case (location_t loc, tree low_value, tree high_value) { low_value = c_fully_fold (low_value, false, NULL); if (TREE_CODE (low_value) == INTEGER_CST) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "case label is not an integer constant expression"); } @@ -8935,7 +8951,7 @@ do_case (location_t loc, tree low_value, tree high_value) { high_value = c_fully_fold (high_value, false, NULL); if (TREE_CODE (high_value) == INTEGER_CST) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "case label is not an integer constant expression"); } @@ -10107,13 +10123,13 @@ build_binary_op (location_t location, enum tree_code code, else if (VOID_TYPE_P (tt0)) { if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE) - pedwarn (location, OPT_pedantic, "ISO C forbids " + pedwarn (location, OPT_Wpedantic, "ISO C forbids " "comparison of %<void *%> with function pointer"); } else if (VOID_TYPE_P (tt1)) { if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE) - pedwarn (location, OPT_pedantic, "ISO C forbids " + pedwarn (location, OPT_Wpedantic, "ISO C forbids " "comparison of %<void *%> with function pointer"); } else @@ -10190,7 +10206,7 @@ build_binary_op (location_t location, enum tree_code code, pedwarn (location, 0, "comparison of complete and incomplete pointers"); else if (TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE) - pedwarn (location, OPT_pedantic, "ISO C forbids " + pedwarn (location, OPT_Wpedantic, "ISO C forbids " "ordered comparisons of pointers to functions"); else if (null_pointer_constant_p (orig_op0) || null_pointer_constant_p (orig_op1)) @@ -10217,7 +10233,7 @@ build_binary_op (location_t location, enum tree_code code, { result_type = type0; if (pedantic) - pedwarn (location, OPT_pedantic, + pedwarn (location, OPT_Wpedantic, "ordered comparison of pointer with integer zero"); else if (extra_warnings) warning_at (location, OPT_Wextra, @@ -10227,7 +10243,7 @@ build_binary_op (location_t location, enum tree_code code, { result_type = type1; if (pedantic) - pedwarn (location, OPT_pedantic, + pedwarn (location, OPT_Wpedantic, "ordered comparison of pointer with integer zero"); else if (extra_warnings) warning_at (location, OPT_Wextra, diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 3824797485d..d06a9b1a903 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -2637,20 +2637,7 @@ try_optimize_cfg (int mode) || ! label_is_jump_target_p (BB_HEAD (b), BB_END (single_pred (b))))) { - rtx label = BB_HEAD (b); - - delete_insn_chain (label, label, false); - /* If the case label is undeletable, move it after the - BASIC_BLOCK note. */ - if (NOTE_KIND (BB_HEAD (b)) == NOTE_INSN_DELETED_LABEL) - { - rtx bb_note = NEXT_INSN (BB_HEAD (b)); - - reorder_insns_nobb (label, label, bb_note); - BB_HEAD (b) = bb_note; - if (BB_END (b) == bb_note) - BB_END (b) = label; - } + delete_insn (BB_HEAD (b)); if (dump_file) fprintf (dump_file, "Deleted label in block %i.\n", b->index); diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index d148853143b..9de3e51c673 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -1488,9 +1488,9 @@ estimated_stack_frame_size (struct cgraph_node *node) tree var; tree old_cur_fun_decl = current_function_decl; referenced_var_iterator rvi; - struct function *fn = DECL_STRUCT_FUNCTION (node->decl); + struct function *fn = DECL_STRUCT_FUNCTION (node->symbol.decl); - current_function_decl = node->decl; + current_function_decl = node->symbol.decl; push_cfun (fn); gcc_checking_assert (gimple_referenced_vars (fn)); @@ -4555,7 +4555,11 @@ gimple_expand_cfg (void) if (MAY_HAVE_DEBUG_INSNS) expand_debug_locations (); - execute_free_datastructures (); + /* Free stuff we no longer need after GIMPLE optimizations. */ + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + delete_tree_cfg_annotations (); + timevar_push (TV_OUT_OF_SSA); finish_out_of_ssa (&SA); timevar_pop (TV_OUT_OF_SSA); diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index 22d3d87e68b..c6e1f8324d8 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -857,6 +857,9 @@ fixup_reorder_chain (void) (e_taken->src, e_taken->dest)); e_taken->flags |= EDGE_FALLTHRU; update_br_prob_note (bb); + if (LABEL_NUSES (ret_label) == 0 + && single_pred_p (e_taken->dest)) + delete_insn (ret_label); continue; } } diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index 510bc10bd4a..b3c862cb12e 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -278,11 +278,16 @@ gcov_type expected_loop_iterations_unbounded (const struct loop *); extern unsigned expected_loop_iterations (const struct loop *); extern rtx doloop_condition_get (rtx); -void estimate_numbers_of_iterations_loop (struct loop *, bool); -HOST_WIDE_INT estimated_loop_iterations_int (struct loop *, bool); -HOST_WIDE_INT max_stmt_executions_int (struct loop *, bool); -bool estimated_loop_iterations (struct loop *, bool, double_int *); -bool max_stmt_executions (struct loop *, bool, double_int *); +void estimate_numbers_of_iterations_loop (struct loop *); +void record_niter_bound (struct loop *, double_int, bool, bool); +bool estimated_loop_iterations (struct loop *, double_int *); +bool max_loop_iterations (struct loop *, double_int *); +HOST_WIDE_INT estimated_loop_iterations_int (struct loop *); +HOST_WIDE_INT max_loop_iterations_int (struct loop *); +bool max_stmt_executions (struct loop *, double_int *); +bool estimated_stmt_executions (struct loop *, double_int *); +HOST_WIDE_INT max_stmt_executions_int (struct loop *); +HOST_WIDE_INT estimated_stmt_executions_int (struct loop *); /* Loop manipulation. */ extern bool can_duplicate_loop_p (const struct loop *loop); diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index ea293933704..e3ffc9c656e 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -111,12 +111,11 @@ can_delete_label_p (const_rtx label) && !in_expr_list_p (forced_labels, label)); } -/* Delete INSN by patching it out. Return the next insn. */ +/* Delete INSN by patching it out. */ -rtx +void delete_insn (rtx insn) { - rtx next = NEXT_INSN (insn); rtx note; bool really_delete = true; @@ -128,11 +127,22 @@ delete_insn (rtx insn) if (! can_delete_label_p (insn)) { const char *name = LABEL_NAME (insn); + basic_block bb = BLOCK_FOR_INSN (insn); + rtx bb_note = NEXT_INSN (insn); really_delete = false; PUT_CODE (insn, NOTE); NOTE_KIND (insn) = NOTE_INSN_DELETED_LABEL; NOTE_DELETED_LABEL_NAME (insn) = name; + + if (bb_note != NULL_RTX && NOTE_INSN_BASIC_BLOCK_P (bb_note) + && BLOCK_FOR_INSN (bb_note) == bb) + { + reorder_insns_nobb (insn, insn, bb_note); + BB_HEAD (bb) = bb_note; + if (BB_END (bb) == bb_note) + BB_END (bb) = insn; + } } remove_node_from_expr_list (insn, &nonlocal_goto_handler_labels); @@ -190,26 +200,22 @@ delete_insn (rtx insn) LABEL_NUSES (label)--; } } - - return next; } /* Like delete_insn but also purge dead edges from BB. */ -rtx +void delete_insn_and_edges (rtx insn) { - rtx x; bool purge = false; if (INSN_P (insn) && BLOCK_FOR_INSN (insn) && BB_END (BLOCK_FOR_INSN (insn)) == insn) purge = true; - x = delete_insn (insn); + delete_insn (insn); if (purge) purge_dead_edges (BLOCK_FOR_INSN (insn)); - return x; } /* Unlink a chain of insns between START and FINISH, leaving notes @@ -219,25 +225,26 @@ delete_insn_and_edges (rtx insn) void delete_insn_chain (rtx start, rtx finish, bool clear_bb) { - rtx next; + rtx prev, current; /* Unchain the insns one by one. It would be quicker to delete all of these with a single unchaining, rather than one at a time, but we need to keep the NOTE's. */ + current = finish; while (1) { - next = NEXT_INSN (start); - if (NOTE_P (start) && !can_delete_note_p (start)) + prev = PREV_INSN (current); + if (NOTE_P (current) && !can_delete_note_p (current)) ; else - next = delete_insn (start); + delete_insn (current); - if (clear_bb && !INSN_DELETED_P (start)) - set_block_for_insn (start, NULL); + if (clear_bb && !INSN_DELETED_P (current)) + set_block_for_insn (current, NULL); - if (start == finish) + if (current == start) break; - start = next; + current = prev; } } diff --git a/gcc/cgraph.c b/gcc/cgraph.c index e429a91d82e..ed4cdf64d08 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1,6 +1,6 @@ /* Callgraph handling code. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011, 2012 Free Software Foundation, Inc. Contributed by Jan Hubicka This file is part of GCC. @@ -119,21 +119,9 @@ static void cgraph_node_remove_callers (struct cgraph_node *node); static inline void cgraph_edge_remove_caller (struct cgraph_edge *e); static inline void cgraph_edge_remove_callee (struct cgraph_edge *e); -/* Hash table used to convert declarations into nodes. */ -static GTY((param_is (struct cgraph_node))) htab_t cgraph_hash; -/* Hash table used to convert assembler names into nodes. */ -static GTY((param_is (struct cgraph_node))) htab_t assembler_name_hash; - -/* The linked list of cgraph nodes. */ -struct cgraph_node *cgraph_nodes; - /* Queue of cgraph nodes scheduled to be lowered. */ -struct cgraph_node *cgraph_nodes_queue; - -/* Queue of cgraph nodes scheduled to be added into cgraph. This is a - secondary queue used during optimization to accommodate passes that - may generate new functions that need to be optimized and expanded. */ -struct cgraph_node *cgraph_new_nodes; +symtab_node x_cgraph_nodes_queue; +#define cgraph_nodes_queue ((struct cgraph_node *)x_cgraph_nodes_queue) /* Number of nodes in existence. */ int cgraph_n_nodes; @@ -148,7 +136,7 @@ int cgraph_edge_max_uid; bool cgraph_global_info_ready = false; /* What state callgraph is in right now. */ -enum cgraph_state cgraph_state = CGRAPH_STATE_CONSTRUCTION; +enum cgraph_state cgraph_state = CGRAPH_STATE_PARSING; /* Set when the cgraph is fully build and the basic flags are computed. */ bool cgraph_function_flags_ready = false; @@ -159,11 +147,6 @@ struct cgraph_asm_node *cgraph_asm_nodes; /* Last node in cgraph_asm_nodes. */ static GTY(()) struct cgraph_asm_node *cgraph_asm_last_node; -/* The order index of the next cgraph node to be created. This is - used so that we can sort the cgraph nodes in order by when we saw - them, to support -fno-toplevel-reorder. */ -int cgraph_order; - /* List of hooks triggered on cgraph_edge events. */ struct cgraph_edge_hook_list { cgraph_edge_hook hook; @@ -215,7 +198,8 @@ bool same_body_aliases_done; /* Macros to access the next item in the list of free cgraph nodes and edges. */ -#define NEXT_FREE_NODE(NODE) (NODE)->next +#define NEXT_FREE_NODE(NODE) cgraph ((NODE)->symbol.next) +#define SET_NEXT_FREE_NODE(NODE,NODE2) ((NODE))->symbol.next = (symtab_node)NODE2 #define NEXT_FREE_EDGE(EDGE) (EDGE)->prev_caller /* Register HOOK to be called with DATA on each removed edge. */ @@ -425,26 +409,6 @@ cgraph_call_node_duplication_hooks (struct cgraph_node *node1, } } -/* Returns a hash code for P. */ - -static hashval_t -hash_node (const void *p) -{ - const struct cgraph_node *n = (const struct cgraph_node *) p; - return (hashval_t) DECL_UID (n->decl); -} - - -/* Returns nonzero if P1 and P2 are equal. */ - -static int -eq_node (const void *p1, const void *p2) -{ - const struct cgraph_node *n1 = (const struct cgraph_node *) p1; - const struct cgraph_node *n2 = (const struct cgraph_node *) p2; - return DECL_UID (n1->decl) == DECL_UID (n2->decl); -} - /* Allocate new callgraph node. */ static inline struct cgraph_node * @@ -473,15 +437,9 @@ cgraph_create_node_1 (void) { struct cgraph_node *node = cgraph_allocate_node (); - node->next = cgraph_nodes; - node->order = cgraph_order++; - if (cgraph_nodes) - cgraph_nodes->previous = node; - node->previous = NULL; + node->symbol.type = SYMTAB_FUNCTION; node->frequency = NODE_FREQUENCY_NORMAL; node->count_materialization_scale = REG_BR_PROB_BASE; - ipa_empty_ref_list (&node->ref_list); - cgraph_nodes = node; cgraph_n_nodes++; return node; } @@ -491,41 +449,18 @@ cgraph_create_node_1 (void) struct cgraph_node * cgraph_create_node (tree decl) { - struct cgraph_node key, *node, **slot; - + struct cgraph_node *node = cgraph_create_node_1 (); gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); - if (!cgraph_hash) - cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL); - - key.decl = decl; - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT); - gcc_assert (!*slot); + node->symbol.decl = decl; + symtab_register_node ((symtab_node) node); - node = cgraph_create_node_1 (); - node->decl = decl; - *slot = node; if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) { node->origin = cgraph_get_create_node (DECL_CONTEXT (decl)); node->next_nested = node->origin->nested; node->origin->nested = node; } - if (assembler_name_hash) - { - void **aslot; - tree name = DECL_ASSEMBLER_NAME (decl); - - aslot = htab_find_slot_with_hash (assembler_name_hash, name, - decl_assembler_name_hash (name), - INSERT); - /* We can have multiple declarations with same assembler name. For C++ - it is __builtin_strlen and strlen, for instance. Do we need to - record them all? Original implementation marked just first one - so lets hope for the best. */ - if (*aslot == NULL) - *aslot = node; - } return node; } @@ -559,11 +494,6 @@ cgraph_create_function_alias (tree alias, tree decl) alias_node->thunk.alias = decl; alias_node->local.finalized = true; alias_node->alias = 1; - - if ((TREE_PUBLIC (alias) && !DECL_COMDAT (alias) && !DECL_EXTERNAL (alias)) - || (DECL_VIRTUAL_P (alias) - && (DECL_COMDAT (alias) || DECL_EXTERNAL (alias)))) - cgraph_mark_reachable_node (alias_node); return alias_node; } @@ -588,8 +518,8 @@ cgraph_same_body_alias (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, tree ali n = cgraph_create_function_alias (alias, decl); n->same_body_alias = true; if (same_body_aliases_done) - ipa_record_reference (n, NULL, cgraph_get_node (decl), NULL, IPA_REF_ALIAS, - NULL); + ipa_record_reference ((symtab_node)n, (symtab_node)cgraph_get_node (decl), + IPA_REF_ALIAS, NULL); return n; } @@ -599,7 +529,7 @@ cgraph_same_body_alias (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, tree ali struct cgraph_node * cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, - tree alias, tree decl, + tree alias, tree decl ATTRIBUTE_UNUSED, bool this_adjusting, HOST_WIDE_INT fixed_offset, HOST_WIDE_INT virtual_value, tree virtual_offset, @@ -629,111 +559,21 @@ cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, node->thunk.thunk_p = true; node->local.finalized = true; - if (cgraph_decide_is_function_needed (node, decl)) - cgraph_mark_needed_node (node); - - if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) - || (DECL_VIRTUAL_P (decl) - && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl)))) - cgraph_mark_reachable_node (node); - - return node; -} - -/* Returns the cgraph node assigned to DECL or NULL if no cgraph node - is assigned. */ - -struct cgraph_node * -cgraph_get_node (const_tree decl) -{ - struct cgraph_node key, *node = NULL, **slot; - - gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); - - if (!cgraph_hash) - return NULL; - - key.decl = CONST_CAST2 (tree, const_tree, decl); - - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, - NO_INSERT); - - if (slot && *slot) - node = *slot; return node; } -/* Insert already constructed node into hashtable. */ - -void -cgraph_insert_node_to_hashtable (struct cgraph_node *node) -{ - struct cgraph_node **slot; - - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, node, INSERT); - - gcc_assert (!*slot); - *slot = node; -} - -/* Returns a hash code for P. */ - -static hashval_t -hash_node_by_assembler_name (const void *p) -{ - const struct cgraph_node *n = (const struct cgraph_node *) p; - return (hashval_t) decl_assembler_name_hash (DECL_ASSEMBLER_NAME (n->decl)); -} - -/* Returns nonzero if P1 and P2 are equal. */ - -static int -eq_assembler_name (const void *p1, const void *p2) -{ - const struct cgraph_node *n1 = (const struct cgraph_node *) p1; - const_tree name = (const_tree)p2; - return (decl_assembler_name_equal (n1->decl, name)); -} - /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME. Return NULL if there's no such node. */ struct cgraph_node * cgraph_node_for_asm (tree asmname) { - struct cgraph_node *node; - void **slot; - - if (!assembler_name_hash) - { - assembler_name_hash = - htab_create_ggc (10, hash_node_by_assembler_name, eq_assembler_name, - NULL); - for (node = cgraph_nodes; node; node = node->next) - if (!node->global.inlined_to) - { - tree name = DECL_ASSEMBLER_NAME (node->decl); - slot = htab_find_slot_with_hash (assembler_name_hash, name, - decl_assembler_name_hash (name), - INSERT); - /* We can have multiple declarations with same assembler name. For C++ - it is __builtin_strlen and strlen, for instance. Do we need to - record them all? Original implementation marked just first one - so lets hope for the best. */ - if (!*slot) - *slot = node; - } - } - - slot = htab_find_slot_with_hash (assembler_name_hash, asmname, - decl_assembler_name_hash (asmname), - NO_INSERT); + symtab_node node = symtab_node_for_asm (asmname); - if (slot) - { - node = (struct cgraph_node *) *slot; - return node; - } + /* We do not want to look at inline clones. */ + for (node = symtab_node_for_asm (asmname); node; node = node->symbol.next_sharing_asm_name) + if (symtab_function_p (node) && !cgraph(node)->global.inlined_to) + return cgraph (node); return NULL; } @@ -840,7 +680,7 @@ cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt) cgraph_make_edge_direct (e, new_callee); } - push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl)); + push_cfun (DECL_STRUCT_FUNCTION (e->caller->symbol.decl)); e->can_throw_external = stmt_can_throw_external (new_stmt); pop_cfun (); if (e->caller->call_site_hash) @@ -985,13 +825,13 @@ cgraph_create_edge_1 (struct cgraph_node *caller, struct cgraph_node *callee, gcc_assert (freq <= CGRAPH_FREQ_MAX); edge->call_stmt = call_stmt; - push_cfun (DECL_STRUCT_FUNCTION (caller->decl)); + push_cfun (DECL_STRUCT_FUNCTION (caller->symbol.decl)); edge->can_throw_external = call_stmt ? stmt_can_throw_external (call_stmt) : false; pop_cfun (); if (call_stmt - && callee && callee->decl - && !gimple_check_call_matching_types (call_stmt, callee->decl)) + && callee && callee->symbol.decl + && !gimple_check_call_matching_types (call_stmt, callee->symbol.decl)) edge->call_stmt_cannot_inline_p = true; else edge->call_stmt_cannot_inline_p = false; @@ -1191,7 +1031,7 @@ cgraph_make_edge_direct (struct cgraph_edge *edge, struct cgraph_node *callee) if (edge->call_stmt) edge->call_stmt_cannot_inline_p - = !gimple_check_call_matching_types (edge->call_stmt, callee->decl); + = !gimple_check_call_matching_types (edge->call_stmt, callee->symbol.decl); /* We need to re-determine the inlining status of the edge. */ initialize_inline_failed (edge); @@ -1234,7 +1074,7 @@ cgraph_update_edges_for_call_stmt_node (struct cgraph_node *node, struct cgraph_node *callee = e->callee; while (callee) { - if (callee->decl == new_call + if (callee->symbol.decl == new_call || callee->former_clone_of == new_call) return; callee = callee->clone_of; @@ -1360,10 +1200,10 @@ cgraph_node_remove_callers (struct cgraph_node *node) void cgraph_release_function_body (struct cgraph_node *node) { - if (DECL_STRUCT_FUNCTION (node->decl)) + if (DECL_STRUCT_FUNCTION (node->symbol.decl)) { tree old_decl = current_function_decl; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); if (cfun->cfg && current_loops) { @@ -1372,7 +1212,7 @@ cgraph_release_function_body (struct cgraph_node *node) } if (cfun->gimple_df) { - current_function_decl = node->decl; + current_function_decl = node->symbol.decl; delete_tree_ssa (); delete_tree_cfg_annotations (); cfun->eh = NULL; @@ -1387,20 +1227,105 @@ cgraph_release_function_body (struct cgraph_node *node) if (cfun->value_histograms) free_histograms (); pop_cfun(); - gimple_set_body (node->decl, NULL); + gimple_set_body (node->symbol.decl, NULL); VEC_free (ipa_opt_pass, heap, node->ipa_transforms_to_apply); /* Struct function hangs a lot of data that would leak if we didn't removed all pointers to it. */ - ggc_free (DECL_STRUCT_FUNCTION (node->decl)); - DECL_STRUCT_FUNCTION (node->decl) = NULL; + ggc_free (DECL_STRUCT_FUNCTION (node->symbol.decl)); + DECL_STRUCT_FUNCTION (node->symbol.decl) = NULL; } - DECL_SAVED_TREE (node->decl) = NULL; + DECL_SAVED_TREE (node->symbol.decl) = NULL; /* If the node is abstract and needed, then do not clear DECL_INITIAL of its associated function function declaration because it's needed to emit debug info later. */ if (!node->abstract_and_needed) - DECL_INITIAL (node->decl) = error_mark_node; + DECL_INITIAL (node->symbol.decl) = error_mark_node; +} + +/* NODE is being removed from symbol table; see if its entry can be replaced by + other inline clone. */ +struct cgraph_node * +cgraph_find_replacement_node (struct cgraph_node *node) +{ + struct cgraph_node *next_inline_clone, *replacement; + + for (next_inline_clone = node->clones; + next_inline_clone + && next_inline_clone->symbol.decl != node->symbol.decl; + next_inline_clone = next_inline_clone->next_sibling_clone) + ; + + /* If there is inline clone of the node being removed, we need + to put it into the position of removed node and reorganize all + other clones to be based on it. */ + if (next_inline_clone) + { + struct cgraph_node *n; + struct cgraph_node *new_clones; + + replacement = next_inline_clone; + + /* Unlink inline clone from the list of clones of removed node. */ + if (next_inline_clone->next_sibling_clone) + next_inline_clone->next_sibling_clone->prev_sibling_clone + = next_inline_clone->prev_sibling_clone; + if (next_inline_clone->prev_sibling_clone) + { + gcc_assert (node->clones != next_inline_clone); + next_inline_clone->prev_sibling_clone->next_sibling_clone + = next_inline_clone->next_sibling_clone; + } + else + { + gcc_assert (node->clones == next_inline_clone); + node->clones = next_inline_clone->next_sibling_clone; + } + + new_clones = node->clones; + node->clones = NULL; + + /* Copy clone info. */ + next_inline_clone->clone = node->clone; + + /* Now place it into clone tree at same level at NODE. */ + next_inline_clone->clone_of = node->clone_of; + next_inline_clone->prev_sibling_clone = NULL; + next_inline_clone->next_sibling_clone = NULL; + if (node->clone_of) + { + if (node->clone_of->clones) + node->clone_of->clones->prev_sibling_clone = next_inline_clone; + next_inline_clone->next_sibling_clone = node->clone_of->clones; + node->clone_of->clones = next_inline_clone; + } + + /* Merge the clone list. */ + if (new_clones) + { + if (!next_inline_clone->clones) + next_inline_clone->clones = new_clones; + else + { + n = next_inline_clone->clones; + while (n->next_sibling_clone) + n = n->next_sibling_clone; + n->next_sibling_clone = new_clones; + new_clones->prev_sibling_clone = n; + } + } + + /* Update clone_of pointers. */ + n = new_clones; + while (n) + { + n->clone_of = next_inline_clone; + n = n->next_sibling_clone; + } + return replacement; + } + else + return NULL; } /* Remove the node from cgraph. */ @@ -1408,22 +1333,18 @@ cgraph_release_function_body (struct cgraph_node *node) void cgraph_remove_node (struct cgraph_node *node) { - void **slot; - bool kill_body = false; struct cgraph_node *n; int uid = node->uid; cgraph_call_node_removal_hooks (node); cgraph_node_remove_callers (node); cgraph_node_remove_callees (node); - ipa_remove_all_references (&node->ref_list); - ipa_remove_all_refering (&node->ref_list); VEC_free (ipa_opt_pass, heap, node->ipa_transforms_to_apply); /* Incremental inlining access removed nodes stored in the postorder list. */ - node->needed = node->reachable = false; + node->symbol.force_output = node->reachable = false; for (n = node->nested; n; n = n->next_nested) n->origin = NULL; node->nested = NULL; @@ -1435,98 +1356,7 @@ cgraph_remove_node (struct cgraph_node *node) node2 = &(*node2)->next_nested; *node2 = node->next_nested; } - if (node->previous) - node->previous->next = node->next; - else - cgraph_nodes = node->next; - if (node->next) - node->next->previous = node->previous; - node->next = NULL; - node->previous = NULL; - slot = htab_find_slot (cgraph_hash, node, NO_INSERT); - if (*slot == node) - { - struct cgraph_node *next_inline_clone; - - for (next_inline_clone = node->clones; - next_inline_clone && next_inline_clone->decl != node->decl; - next_inline_clone = next_inline_clone->next_sibling_clone) - ; - - /* If there is inline clone of the node being removed, we need - to put it into the position of removed node and reorganize all - other clones to be based on it. */ - if (next_inline_clone) - { - struct cgraph_node *n; - struct cgraph_node *new_clones; - - *slot = next_inline_clone; - - /* Unlink inline clone from the list of clones of removed node. */ - if (next_inline_clone->next_sibling_clone) - next_inline_clone->next_sibling_clone->prev_sibling_clone - = next_inline_clone->prev_sibling_clone; - if (next_inline_clone->prev_sibling_clone) - { - gcc_assert (node->clones != next_inline_clone); - next_inline_clone->prev_sibling_clone->next_sibling_clone - = next_inline_clone->next_sibling_clone; - } - else - { - gcc_assert (node->clones == next_inline_clone); - node->clones = next_inline_clone->next_sibling_clone; - } - - new_clones = node->clones; - node->clones = NULL; - - /* Copy clone info. */ - next_inline_clone->clone = node->clone; - - /* Now place it into clone tree at same level at NODE. */ - next_inline_clone->clone_of = node->clone_of; - next_inline_clone->prev_sibling_clone = NULL; - next_inline_clone->next_sibling_clone = NULL; - if (node->clone_of) - { - if (node->clone_of->clones) - node->clone_of->clones->prev_sibling_clone = next_inline_clone; - next_inline_clone->next_sibling_clone = node->clone_of->clones; - node->clone_of->clones = next_inline_clone; - } - - /* Merge the clone list. */ - if (new_clones) - { - if (!next_inline_clone->clones) - next_inline_clone->clones = new_clones; - else - { - n = next_inline_clone->clones; - while (n->next_sibling_clone) - n = n->next_sibling_clone; - n->next_sibling_clone = new_clones; - new_clones->prev_sibling_clone = n; - } - } - - /* Update clone_of pointers. */ - n = new_clones; - while (n) - { - n->clone_of = next_inline_clone; - n = n->next_sibling_clone; - } - } - else - { - htab_clear_slot (cgraph_hash, slot); - kill_body = true; - } - - } + symtab_unregister_node ((symtab_node)node); if (node->prev_sibling_clone) node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone; else if (node->clone_of) @@ -1564,47 +1394,20 @@ cgraph_remove_node (struct cgraph_node *node) } } - if (node->same_comdat_group) - { - struct cgraph_node *prev; - for (prev = node->same_comdat_group; - prev->same_comdat_group != node; - prev = prev->same_comdat_group) - ; - if (node->same_comdat_group == prev) - prev->same_comdat_group = NULL; - else - prev->same_comdat_group = node->same_comdat_group; - node->same_comdat_group = NULL; - } - /* While all the clones are removed after being proceeded, the function itself is kept in the cgraph even after it is compiled. Check whether we are done with this body and reclaim it proactively if this is the case. */ - if (!kill_body && *slot) - { - struct cgraph_node *n = (struct cgraph_node *) *slot; - if (!n->clones && !n->clone_of && !n->global.inlined_to + n = cgraph_get_node (node->symbol.decl); + if (!n + || (!n->clones && !n->clone_of && !n->global.inlined_to && (cgraph_global_info_ready - && (TREE_ASM_WRITTEN (n->decl) || DECL_EXTERNAL (n->decl) - || n->in_other_partition))) - kill_body = true; - } - if (assembler_name_hash) - { - tree name = DECL_ASSEMBLER_NAME (node->decl); - slot = htab_find_slot_with_hash (assembler_name_hash, name, - decl_assembler_name_hash (name), - NO_INSERT); - /* Inline clones are not hashed. */ - if (slot && *slot == node) - htab_clear_slot (assembler_name_hash, slot); - } - - if (kill_body) + && (TREE_ASM_WRITTEN (n->symbol.decl) + || DECL_EXTERNAL (n->symbol.decl) + || n->symbol.in_other_partition)))) cgraph_release_function_body (node); - node->decl = NULL; + + node->symbol.decl = NULL; if (node->call_site_hash) { htab_delete (node->call_site_hash); @@ -1615,33 +1418,34 @@ cgraph_remove_node (struct cgraph_node *node) /* Clear out the node to NULL all pointers and add the node to the free list. */ memset (node, 0, sizeof(*node)); + node->symbol.type = SYMTAB_FUNCTION; node->uid = uid; - NEXT_FREE_NODE (node) = free_nodes; + SET_NEXT_FREE_NODE (node, free_nodes); free_nodes = node; } /* Add NEW_ to the same comdat group that OLD is in. */ void -cgraph_add_to_same_comdat_group (struct cgraph_node *new_, - struct cgraph_node *old) +cgraph_add_to_same_comdat_group (struct cgraph_node *new_node, + struct cgraph_node *old_node) { - gcc_assert (DECL_ONE_ONLY (old->decl)); - gcc_assert (!new_->same_comdat_group); - gcc_assert (new_ != old); + gcc_assert (DECL_ONE_ONLY (old_node->symbol.decl)); + gcc_assert (!new_node->symbol.same_comdat_group); + gcc_assert (new_node != old_node); - DECL_COMDAT_GROUP (new_->decl) = DECL_COMDAT_GROUP (old->decl); - new_->same_comdat_group = old; - if (!old->same_comdat_group) - old->same_comdat_group = new_; + DECL_COMDAT_GROUP (new_node->symbol.decl) = DECL_COMDAT_GROUP (old_node->symbol.decl); + new_node->symbol.same_comdat_group = (symtab_node)old_node; + if (!old_node->symbol.same_comdat_group) + old_node->symbol.same_comdat_group = (symtab_node)new_node; else { - struct cgraph_node *n; - for (n = old->same_comdat_group; - n->same_comdat_group != old; - n = n->same_comdat_group) + symtab_node n; + for (n = old_node->symbol.same_comdat_group; + n->symbol.same_comdat_group != (symtab_node)old_node; + n = n->symbol.same_comdat_group) ; - n->same_comdat_group = new_; + n->symbol.same_comdat_group = (symtab_node)new_node; } } @@ -1680,15 +1484,12 @@ cgraph_mark_reachable_node (struct cgraph_node *node) /* Verify that function does not appear to be needed out of blue during the optimization process. This can happen for extern inlines when bodies was removed after inlining. */ - gcc_assert ((node->analyzed || node->in_other_partition - || DECL_EXTERNAL (node->decl))); + gcc_assert ((node->analyzed || node->symbol.in_other_partition + || DECL_EXTERNAL (node->symbol.decl))); } else - notice_global_symbol (node->decl); + notice_global_symbol (node->symbol.decl); node->reachable = 1; - - node->next_needed = cgraph_nodes_queue; - cgraph_nodes_queue = node; } } @@ -1696,9 +1497,9 @@ cgraph_mark_reachable_node (struct cgraph_node *node) external means. */ void -cgraph_mark_needed_node (struct cgraph_node *node) +cgraph_mark_force_output_node (struct cgraph_node *node) { - node->needed = 1; + node->symbol.force_output = 1; gcc_assert (!node->global.inlined_to); cgraph_mark_reachable_node (node); } @@ -1716,9 +1517,9 @@ cgraph_mark_address_taken_node (struct cgraph_node *node) of the object was taken (and thus it should be set on node alias is referring to). We should remove the first use and the remove the following set. */ - node->address_taken = 1; + node->symbol.address_taken = 1; node = cgraph_function_or_thunk_node (node, NULL); - node->address_taken = 1; + node->symbol.address_taken = 1; } /* Return local info for the compiled function. */ @@ -1760,7 +1561,7 @@ cgraph_rtl_info (tree decl) node = cgraph_get_node (decl); if (!node || (decl != current_function_decl - && !TREE_ASM_WRITTEN (node->decl))) + && !TREE_ASM_WRITTEN (node->symbol.decl))) return NULL; return &node->rtl; } @@ -1783,13 +1584,6 @@ cgraph_inline_failed_string (cgraph_inline_failed_t reason) return cif_string_table[reason]; } -/* Return name of the node used in debug output. */ -const char * -cgraph_node_name (struct cgraph_node *node) -{ - return lang_hooks.decl_printable_name (node->decl, 2); -} - /* Names used to print out the availability enum. */ const char * const cgraph_availability_names[] = {"unset", "not_available", "overwritable", "available", "local"}; @@ -1803,59 +1597,42 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) struct cgraph_edge *edge; int indirect_calls_count = 0; - fprintf (f, "%s/%i", cgraph_node_name (node), node->uid); - dump_addr (f, " @", (void *)node); - if (DECL_ASSEMBLER_NAME_SET_P (node->decl)) - fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))); + dump_symtab_base (f, (symtab_node) node); + if (node->global.inlined_to) - fprintf (f, " (inline copy in %s/%i)", + fprintf (f, " Function %s/%i is inline copy in %s/%i\n", + cgraph_node_name (node), + node->symbol.order, cgraph_node_name (node->global.inlined_to), - node->global.inlined_to->uid); - if (node->same_comdat_group) - fprintf (f, " (same comdat group as %s/%i)", - cgraph_node_name (node->same_comdat_group), - node->same_comdat_group->uid); + node->global.inlined_to->symbol.order); if (node->clone_of) - fprintf (f, " (clone of %s/%i)", - cgraph_node_name (node->clone_of), - node->clone_of->uid); + fprintf (f, " Clone of %s/%i\n", + cgraph_node_asm_name (node->clone_of), + node->clone_of->symbol.order); if (cgraph_function_flags_ready) - fprintf (f, " availability:%s", + fprintf (f, " Availability: %s\n", cgraph_availability_names [cgraph_function_body_availability (node)]); + + fprintf (f, " Function flags:"); if (node->analyzed) fprintf (f, " analyzed"); - if (node->in_other_partition) - fprintf (f, " in_other_partition"); if (node->count) fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x", (HOST_WIDEST_INT)node->count); if (node->origin) - fprintf (f, " nested in: %s", cgraph_node_name (node->origin)); - if (node->needed) - fprintf (f, " needed"); - if (node->address_taken) - fprintf (f, " address_taken"); + fprintf (f, " nested in: %s", cgraph_node_asm_name (node->origin)); else if (node->reachable) fprintf (f, " reachable"); - else if (node->reachable_from_other_partition) - fprintf (f, " reachable_from_other_partition"); - if (gimple_has_body_p (node->decl)) + if (gimple_has_body_p (node->symbol.decl)) fprintf (f, " body"); if (node->process) fprintf (f, " process"); if (node->local.local) fprintf (f, " local"); - if (node->local.externally_visible) - fprintf (f, " externally_visible"); - if (node->resolution != LDPR_UNKNOWN) - fprintf (f, " %s", - ld_plugin_symbol_resolution_names[(int)node->resolution]); if (node->local.finalized) fprintf (f, " finalized"); if (node->local.redefined_extern_inline) fprintf (f, " redefined_extern_inline"); - if (TREE_ASM_WRITTEN (node->decl)) - fprintf (f, " asm_written"); if (node->only_called_at_startup) fprintf (f, " only_called_at_startup"); if (node->only_called_at_exit) @@ -1869,7 +1646,7 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) if (node->thunk.thunk_p) { - fprintf (f, " thunk of %s (asm: %s) fixed offset %i virtual value %i has " + fprintf (f, " Thunk of %s (asm: %s) fixed offset %i virtual value %i has " "virtual offset %i)\n", lang_hooks.decl_printable_name (node->thunk.alias, 2), IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->thunk.alias)), @@ -1879,7 +1656,7 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) } if (node->alias && node->thunk.alias) { - fprintf (f, " alias of %s", + fprintf (f, " Alias of %s", lang_hooks.decl_printable_name (node->thunk.alias, 2)); if (DECL_ASSEMBLER_NAME_SET_P (node->thunk.alias)) fprintf (f, " (asm: %s)", @@ -1887,12 +1664,12 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) fprintf (f, "\n"); } - fprintf (f, " called by: "); + fprintf (f, " Called by: "); for (edge = node->callers; edge; edge = edge->next_caller) { - fprintf (f, "%s/%i ", cgraph_node_name (edge->caller), - edge->caller->uid); + fprintf (f, "%s/%i ", cgraph_node_asm_name (edge->caller), + edge->caller->symbol.order); if (edge->count) fprintf (f, "("HOST_WIDEST_INT_PRINT_DEC"x) ", (HOST_WIDEST_INT)edge->count); @@ -1907,11 +1684,11 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) fprintf(f, "(can throw external) "); } - fprintf (f, "\n calls: "); + fprintf (f, "\n Calls: "); for (edge = node->callees; edge; edge = edge->next_callee) { - fprintf (f, "%s/%i ", cgraph_node_name (edge->callee), - edge->callee->uid); + fprintf (f, "%s/%i ", cgraph_node_asm_name (edge->callee), + edge->callee->symbol.order); if (!edge->inline_failed) fprintf(f, "(inlined) "); if (edge->indirect_inlining_edge) @@ -1926,15 +1703,11 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) fprintf(f, "(can throw external) "); } fprintf (f, "\n"); - fprintf (f, " References: "); - ipa_dump_references (f, &node->ref_list); - fprintf (f, " Refering this function: "); - ipa_dump_refering (f, &node->ref_list); for (edge = node->indirect_calls; edge; edge = edge->next_callee) indirect_calls_count++; if (indirect_calls_count) - fprintf (f, " has %i outgoing edges for indirect calls.\n", + fprintf (f, " Has %i outgoing edges for indirect calls.\n", indirect_calls_count); } @@ -1956,7 +1729,7 @@ dump_cgraph (FILE *f) struct cgraph_node *node; fprintf (f, "callgraph:\n\n"); - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) dump_cgraph_node (f, node); } @@ -1969,51 +1742,6 @@ debug_cgraph (void) dump_cgraph (stderr); } - -/* Set the DECL_ASSEMBLER_NAME and update cgraph hashtables. */ - -void -change_decl_assembler_name (tree decl, tree name) -{ - struct cgraph_node *node; - void **slot; - if (!DECL_ASSEMBLER_NAME_SET_P (decl)) - SET_DECL_ASSEMBLER_NAME (decl, name); - else - { - if (name == DECL_ASSEMBLER_NAME (decl)) - return; - - if (assembler_name_hash - && TREE_CODE (decl) == FUNCTION_DECL - && (node = cgraph_get_node (decl)) != NULL) - { - tree old_name = DECL_ASSEMBLER_NAME (decl); - slot = htab_find_slot_with_hash (assembler_name_hash, old_name, - decl_assembler_name_hash (old_name), - NO_INSERT); - /* Inline clones are not hashed. */ - if (slot && *slot == node) - htab_clear_slot (assembler_name_hash, slot); - } - if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) - && DECL_RTL_SET_P (decl)) - warning (0, "%D renamed after being referenced in assembly", decl); - - SET_DECL_ASSEMBLER_NAME (decl, name); - } - if (assembler_name_hash - && TREE_CODE (decl) == FUNCTION_DECL - && (node = cgraph_get_node (decl)) != NULL) - { - slot = htab_find_slot_with_hash (assembler_name_hash, name, - decl_assembler_name_hash (name), - INSERT); - gcc_assert (!*slot); - *slot = node; - } -} - /* Add a top-level asm statement to the list. */ struct cgraph_asm_node * @@ -2023,7 +1751,7 @@ cgraph_add_asm_node (tree asm_str) node = ggc_alloc_cleared_cgraph_asm_node (); node->asm_str = asm_str; - node->order = cgraph_order++; + node->order = symtab_order++; node->next = NULL; if (cgraph_asm_nodes == NULL) cgraph_asm_nodes = node; @@ -2127,7 +1855,8 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, gcov_type count_scale; unsigned i; - new_node->decl = decl; + new_node->symbol.decl = decl; + symtab_register_node ((symtab_node)new_node); new_node->origin = n->origin; if (new_node->origin) { @@ -2136,7 +1865,7 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, } new_node->analyzed = n->analyzed; new_node->local = n->local; - new_node->local.externally_visible = false; + new_node->symbol.externally_visible = false; new_node->local.local = true; new_node->global = n->global; new_node->rtl = n->rtl; @@ -2175,7 +1904,7 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, for (e = n->indirect_calls; e; e = e->next_callee) cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid, count_scale, freq, update_original); - ipa_clone_references (new_node, NULL, &n->ref_list); + ipa_clone_references ((symtab_node)new_node, &n->symbol.ref_list); new_node->next_sibling_clone = n->clones; if (n->clones) @@ -2183,25 +1912,6 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, n->clones = new_node; new_node->clone_of = n; - if (n->decl != decl) - { - struct cgraph_node **slot; - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, new_node, INSERT); - gcc_assert (!*slot); - *slot = new_node; - if (assembler_name_hash) - { - void **aslot; - tree name = DECL_ASSEMBLER_NAME (decl); - - aslot = htab_find_slot_with_hash (assembler_name_hash, name, - decl_assembler_name_hash (name), - INSERT); - gcc_assert (!*aslot); - *aslot = new_node; - } - } - if (call_duplication_hook) cgraph_call_node_duplication_hooks (n, new_node); return new_node; @@ -2245,7 +1955,7 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, bitmap args_to_skip, const char * suffix) { - tree old_decl = old_node->decl; + tree old_decl = old_node->symbol.decl; struct cgraph_node *new_node = NULL; tree new_decl; size_t i; @@ -2276,20 +1986,21 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, that is not weak also. ??? We cannot use COMDAT linkage because there is no ABI support for this. */ - DECL_EXTERNAL (new_node->decl) = 0; + DECL_EXTERNAL (new_node->symbol.decl) = 0; if (DECL_ONE_ONLY (old_decl)) - DECL_SECTION_NAME (new_node->decl) = NULL; - DECL_COMDAT_GROUP (new_node->decl) = 0; - TREE_PUBLIC (new_node->decl) = 0; - DECL_COMDAT (new_node->decl) = 0; - DECL_WEAK (new_node->decl) = 0; - DECL_STATIC_CONSTRUCTOR (new_node->decl) = 0; - DECL_STATIC_DESTRUCTOR (new_node->decl) = 0; + DECL_SECTION_NAME (new_node->symbol.decl) = NULL; + DECL_COMDAT_GROUP (new_node->symbol.decl) = 0; + TREE_PUBLIC (new_node->symbol.decl) = 0; + DECL_COMDAT (new_node->symbol.decl) = 0; + DECL_WEAK (new_node->symbol.decl) = 0; + DECL_STATIC_CONSTRUCTOR (new_node->symbol.decl) = 0; + DECL_STATIC_DESTRUCTOR (new_node->symbol.decl) = 0; new_node->clone.tree_map = tree_map; new_node->clone.args_to_skip = args_to_skip; FOR_EACH_VEC_ELT (ipa_replace_map_p, tree_map, i, map) { tree var = map->new_tree; + symtab_node ref_node; STRIP_NOPS (var); if (TREE_CODE (var) != ADDR_EXPR) @@ -2297,19 +2008,16 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, var = get_base_var (var); if (!var) continue; + if (TREE_CODE (var) != FUNCTION_DECL + && TREE_CODE (var) != VAR_DECL) + continue; /* Record references of the future statement initializing the constant argument. */ - if (TREE_CODE (var) == FUNCTION_DECL) - { - struct cgraph_node *ref_node = cgraph_get_node (var); - gcc_checking_assert (ref_node); - ipa_record_reference (new_node, NULL, ref_node, NULL, IPA_REF_ADDR, - NULL); - } - else if (TREE_CODE (var) == VAR_DECL) - ipa_record_reference (new_node, NULL, NULL, varpool_node (var), - IPA_REF_ADDR, NULL); + ref_node = symtab_get_node (var); + gcc_checking_assert (ref_node); + ipa_record_reference ((symtab_node)new_node, (symtab_node)ref_node, + IPA_REF_ADDR, NULL); } if (!args_to_skip) new_node->clone.combined_args_to_skip = old_node->clone.combined_args_to_skip; @@ -2321,7 +2029,8 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, struct cgraph_node *orig_node; for (orig_node = old_node; orig_node->clone_of; orig_node = orig_node->clone_of) ; - for (arg = DECL_ARGUMENTS (orig_node->decl); arg; arg = DECL_CHAIN (arg), oldi++) + for (arg = DECL_ARGUMENTS (orig_node->symbol.decl); + arg; arg = DECL_CHAIN (arg), oldi++) { if (bitmap_bit_p (old_node->clone.combined_args_to_skip, oldi)) { @@ -2336,7 +2045,7 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node, } else new_node->clone.combined_args_to_skip = args_to_skip; - new_node->local.externally_visible = 0; + new_node->symbol.externally_visible = 0; new_node->local.local = 1; new_node->lowered = true; new_node->reachable = true; @@ -2371,12 +2080,12 @@ cgraph_function_body_availability (struct cgraph_node *node) avail = AVAIL_NOT_AVAILABLE; else if (node->local.local) avail = AVAIL_LOCAL; - else if (!node->local.externally_visible) + else if (!node->symbol.externally_visible) avail = AVAIL_AVAILABLE; /* Inline functions are safe to be analyzed even if their symbol can be overwritten at runtime. It is not meaningful to enforce any sane behaviour on replacing inline function by different body. */ - else if (DECL_DECLARED_INLINE_P (node->decl)) + else if (DECL_DECLARED_INLINE_P (node->symbol.decl)) avail = AVAIL_AVAILABLE; /* If the function can be overwritten, return OVERWRITABLE. Take @@ -2389,105 +2098,23 @@ cgraph_function_body_availability (struct cgraph_node *node) AVAIL_AVAILABLE here? That would be good reason to preserve this bit. */ - else if (decl_replaceable_p (node->decl) && !DECL_EXTERNAL (node->decl)) + else if (decl_replaceable_p (node->symbol.decl) + && !DECL_EXTERNAL (node->symbol.decl)) avail = AVAIL_OVERWRITABLE; else avail = AVAIL_AVAILABLE; return avail; } -/* Add the function FNDECL to the call graph. - Unlike cgraph_finalize_function, this function is intended to be used - by middle end and allows insertion of new function at arbitrary point - of compilation. The function can be either in high, low or SSA form - GIMPLE. - - The function is assumed to be reachable and have address taken (so no - API breaking optimizations are performed on it). - - Main work done by this function is to enqueue the function for later - processing to avoid need the passes to be re-entrant. */ - -void -cgraph_add_new_function (tree fndecl, bool lowered) -{ - struct cgraph_node *node; - switch (cgraph_state) - { - case CGRAPH_STATE_CONSTRUCTION: - /* Just enqueue function to be processed at nearest occurrence. */ - node = cgraph_create_node (fndecl); - node->next_needed = cgraph_new_nodes; - if (lowered) - node->lowered = true; - cgraph_new_nodes = node; - break; - - case CGRAPH_STATE_IPA: - case CGRAPH_STATE_IPA_SSA: - case CGRAPH_STATE_EXPANSION: - /* Bring the function into finalized state and enqueue for later - analyzing and compilation. */ - node = cgraph_get_create_node (fndecl); - node->local.local = false; - node->local.finalized = true; - node->reachable = node->needed = true; - if (!lowered && cgraph_state == CGRAPH_STATE_EXPANSION) - { - push_cfun (DECL_STRUCT_FUNCTION (fndecl)); - current_function_decl = fndecl; - gimple_register_cfg_hooks (); - tree_lowering_passes (fndecl); - bitmap_obstack_initialize (NULL); - if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl))) - execute_pass_list (pass_early_local_passes.pass.sub); - bitmap_obstack_release (NULL); - pop_cfun (); - current_function_decl = NULL; - - lowered = true; - } - if (lowered) - node->lowered = true; - node->next_needed = cgraph_new_nodes; - cgraph_new_nodes = node; - break; - - case CGRAPH_STATE_FINISHED: - /* At the very end of compilation we have to do all the work up - to expansion. */ - node = cgraph_create_node (fndecl); - if (lowered) - node->lowered = true; - cgraph_analyze_function (node); - push_cfun (DECL_STRUCT_FUNCTION (fndecl)); - current_function_decl = fndecl; - gimple_register_cfg_hooks (); - bitmap_obstack_initialize (NULL); - if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl))) - execute_pass_list (pass_early_local_passes.pass.sub); - bitmap_obstack_release (NULL); - tree_rest_of_compilation (fndecl); - pop_cfun (); - current_function_decl = NULL; - break; - } - - /* Set a personality if required and we already passed EH lowering. */ - if (lowered - && (function_needs_eh_personality (DECL_STRUCT_FUNCTION (fndecl)) - == eh_personality_lang)) - DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality (); -} - /* Worker for cgraph_node_can_be_local_p. */ static bool cgraph_node_cannot_be_local_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) { - return !(!node->needed - && ((DECL_COMDAT (node->decl) && !node->same_comdat_group) - || !node->local.externally_visible)); + return !(!node->symbol.force_output + && ((DECL_COMDAT (node->symbol.decl) + && !node->symbol.same_comdat_group) + || !node->symbol.externally_visible)); } /* Return true if NODE can be made local for API change. @@ -2497,7 +2124,7 @@ cgraph_node_cannot_be_local_p_1 (struct cgraph_node *node, bool cgraph_node_can_be_local_p (struct cgraph_node *node) { - return (!node->address_taken + return (!node->symbol.address_taken && !cgraph_for_node_and_aliases (node, cgraph_node_cannot_be_local_p_1, NULL, true)); @@ -2530,8 +2157,8 @@ cgraph_make_decl_local (tree decl) struct cgraph_node *node = cgraph_get_node (decl); change_decl_assembler_name (decl, clone_function_name (decl, "local")); - if (node->local.lto_file_data) - lto_record_renamed_decl (node->local.lto_file_data, + if (node->symbol.lto_file_data) + lto_record_renamed_decl (node->symbol.lto_file_data, old_name, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); @@ -2543,8 +2170,8 @@ cgraph_make_decl_local (tree decl) C++ frontend still sets TREE_SYMBOL_REFERENCED on them. */ SET_DECL_ASSEMBLER_NAME (decl, clone_function_name (decl, "local")); - if (vnode->lto_file_data) - lto_record_renamed_decl (vnode->lto_file_data, + if (vnode->symbol.lto_file_data) + lto_record_renamed_decl (vnode->symbol.lto_file_data, old_name, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); @@ -2597,10 +2224,10 @@ cgraph_for_node_thunks_and_aliases (struct cgraph_node *node, if (cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable)) return true; - for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); i++) if (ref->use == IPA_REF_ALIAS) { - struct cgraph_node *alias = ipa_ref_refering_node (ref); + struct cgraph_node *alias = ipa_ref_referring_node (ref); if (include_overwritable || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) if (cgraph_for_node_thunks_and_aliases (alias, callback, data, @@ -2625,10 +2252,10 @@ cgraph_for_node_and_aliases (struct cgraph_node *node, if (callback (node, data)) return true; - for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); i++) if (ref->use == IPA_REF_ALIAS) { - struct cgraph_node *alias = ipa_ref_refering_node (ref); + struct cgraph_node *alias = ipa_ref_referring_node (ref); if (include_overwritable || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) if (cgraph_for_node_and_aliases (alias, callback, data, @@ -2644,13 +2271,13 @@ static bool cgraph_make_node_local_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) { gcc_checking_assert (cgraph_node_can_be_local_p (node)); - if (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl)) + if (DECL_COMDAT (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl)) { - cgraph_make_decl_local (node->decl); + cgraph_make_decl_local (node->symbol.decl); - node->local.externally_visible = false; + node->symbol.externally_visible = false; node->local.local = true; - node->resolution = LDPR_PREVAILING_DEF_IRONLY; + node->symbol.resolution = LDPR_PREVAILING_DEF_IRONLY; gcc_assert (cgraph_function_body_availability (node) == AVAIL_LOCAL); } return false; @@ -2672,7 +2299,7 @@ cgraph_set_nothrow_flag_1 (struct cgraph_node *node, void *data) { struct cgraph_edge *e; - TREE_NOTHROW (node->decl) = data != NULL; + TREE_NOTHROW (node->symbol.decl) = data != NULL; if (data != NULL) for (e = node->callers; e; e = e->next_caller) @@ -2699,13 +2326,13 @@ cgraph_set_const_flag_1 (struct cgraph_node *node, void *data) optimized out. */ if (data && !((size_t)data & 2)) { - if (DECL_STATIC_CONSTRUCTOR (node->decl)) - DECL_STATIC_CONSTRUCTOR (node->decl) = 0; - if (DECL_STATIC_DESTRUCTOR (node->decl)) - DECL_STATIC_DESTRUCTOR (node->decl) = 0; + if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl)) + DECL_STATIC_CONSTRUCTOR (node->symbol.decl) = 0; + if (DECL_STATIC_DESTRUCTOR (node->symbol.decl)) + DECL_STATIC_DESTRUCTOR (node->symbol.decl) = 0; } - TREE_READONLY (node->decl) = data != NULL; - DECL_LOOPING_CONST_OR_PURE_P (node->decl) = ((size_t)data & 2) != 0; + TREE_READONLY (node->symbol.decl) = data != NULL; + DECL_LOOPING_CONST_OR_PURE_P (node->symbol.decl) = ((size_t)data & 2) != 0; return false; } @@ -2729,13 +2356,13 @@ cgraph_set_pure_flag_1 (struct cgraph_node *node, void *data) optimized out. */ if (data && !((size_t)data & 2)) { - if (DECL_STATIC_CONSTRUCTOR (node->decl)) - DECL_STATIC_CONSTRUCTOR (node->decl) = 0; - if (DECL_STATIC_DESTRUCTOR (node->decl)) - DECL_STATIC_DESTRUCTOR (node->decl) = 0; + if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl)) + DECL_STATIC_CONSTRUCTOR (node->symbol.decl) = 0; + if (DECL_STATIC_DESTRUCTOR (node->symbol.decl)) + DECL_STATIC_DESTRUCTOR (node->symbol.decl) = 0; } - DECL_PURE_P (node->decl) = data != NULL; - DECL_LOOPING_CONST_OR_PURE_P (node->decl) = ((size_t)data & 2) != 0; + DECL_PURE_P (node->symbol.decl) = data != NULL; + DECL_LOOPING_CONST_OR_PURE_P (node->symbol.decl) = ((size_t)data & 2) != 0; return false; } @@ -2780,7 +2407,7 @@ cgraph_propagate_frequency_1 (struct cgraph_node *node, void *data) /* It makes sense to put main() together with the static constructors. It will be executed for sure, but rest of functions called from main are definitely not at startup only. */ - if (MAIN_NAME_P (DECL_NAME (edge->caller->decl))) + if (MAIN_NAME_P (DECL_NAME (edge->caller->symbol.decl))) d->only_called_at_startup = 0; d->only_called_at_exit &= edge->caller->only_called_at_exit; } @@ -2878,7 +2505,7 @@ cgraph_propagate_frequency (struct cgraph_node *node) bool cgraph_node_cannot_return (struct cgraph_node *node) { - int flags = flags_from_decl_or_type (node->decl); + int flags = flags_from_decl_or_type (node->symbol.decl); if (!flag_exceptions) return (flags & ECF_NORETURN) != 0; else @@ -2917,17 +2544,17 @@ cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node) { gcc_assert (!node->global.inlined_to); /* Extern inlines can always go, we will use the external definition. */ - if (DECL_EXTERNAL (node->decl)) + if (DECL_EXTERNAL (node->symbol.decl)) return true; /* When function is needed, we can not remove it. */ - if (node->needed || node->reachable_from_other_partition) + if (node->symbol.force_output || node->symbol.used_from_other_partition) return false; - if (DECL_STATIC_CONSTRUCTOR (node->decl) - || DECL_STATIC_DESTRUCTOR (node->decl)) + if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl) + || DECL_STATIC_DESTRUCTOR (node->symbol.decl)) return false; /* Only COMDAT functions can be removed if externally visible. */ - if (node->local.externally_visible - && (!DECL_COMDAT (node->decl) + if (node->symbol.externally_visible + && (!DECL_COMDAT (node->symbol.decl) || cgraph_used_from_object_file_p (node))) return false; return true; @@ -2948,9 +2575,9 @@ bool cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node) { /* Extern inlines can always go, we will use the external definition. */ - if (DECL_EXTERNAL (node->decl)) + if (DECL_EXTERNAL (node->symbol.decl)) return true; - if (node->address_taken) + if (node->symbol.address_taken) return false; return !cgraph_for_node_and_aliases (node, nonremovable_p, NULL, true); } @@ -2987,7 +2614,7 @@ cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node return cgraph_only_called_directly_p (node); else { - if (DECL_EXTERNAL (node->decl)) + if (DECL_EXTERNAL (node->symbol.decl)) return true; return cgraph_can_remove_if_no_direct_calls_p (node); } @@ -3013,9 +2640,9 @@ bool cgraph_used_from_object_file_p (struct cgraph_node *node) { gcc_assert (!node->global.inlined_to); - if (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)) + if (!TREE_PUBLIC (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl)) return false; - if (resolution_used_from_other_file_p (node->resolution)) + if (resolution_used_from_other_file_p (node->symbol.resolution)) return true; return false; } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 726285989fc..8e06fc1fc1b 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1,6 +1,6 @@ /* Callgraph handling code. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Contributed by Jan Hubicka This file is part of GCC. @@ -27,7 +27,60 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "basic-block.h" #include "function.h" -#include "ipa-ref.h" /* FIXME: inappropriate dependency of cgraph on IPA. */ +#include "ipa-ref.h" + +/* Symbol table consists of functions and variables. + TODO: add labels, constant pool and aliases. */ +enum symtab_type +{ + SYMTAB_SYMBOL, + SYMTAB_FUNCTION, + SYMTAB_VARIABLE +}; + +/* Base of all entries in the symbol table. + The symtab_node is inherited by cgraph and varpol nodes. */ +struct GTY(()) symtab_node_base +{ + /* Type of the symbol. */ + enum symtab_type type; + tree decl; + struct ipa_ref_list ref_list; + /* Circular list of nodes in the same comdat group if non-NULL. */ + symtab_node same_comdat_group; + /* Ordering of all symtab entries. */ + int order; + enum ld_plugin_symbol_resolution resolution; + /* File stream where this node is being written to. */ + struct lto_file_decl_data * lto_file_data; + + /* Linked list of symbol table entries starting with symtab_nodes. */ + symtab_node next; + symtab_node previous; + /* Linked list of symbols with the same asm name. There may be multiple + entries for single symbol name in the case of LTO resolutions, + existence of inline clones, or duplicated declaration. The last case + is a long standing bug frontends and builtin handling. */ + symtab_node next_sharing_asm_name; + symtab_node previous_sharing_asm_name; + + PTR GTY ((skip)) aux; + + /* Set when function has address taken. + In current implementation it imply needed flag. */ + unsigned address_taken : 1; + /* Set when variable is used from other LTRANS partition. */ + unsigned used_from_other_partition : 1; + /* Set when function is available in the other LTRANS partition. + During WPA output it is used to mark nodes that are present in + multiple partitions. */ + unsigned in_other_partition : 1; + /* Set when function is visible by other units. */ + unsigned externally_visible : 1; + /* Needed variables might become dead by optimization. This flag + forces the variable to be output even if it appears dead otherwise. */ + unsigned force_output : 1; +}; enum availability { @@ -75,16 +128,10 @@ struct GTY(()) cgraph_thunk_info { Available after function is analyzed. */ struct GTY(()) cgraph_local_info { - /* File stream where this node is being written to. */ - struct lto_file_decl_data * lto_file_data; - /* Set when function function is visible in current compilation unit only and its address is never taken. */ unsigned local : 1; - /* Set when function is visible by other units. */ - unsigned externally_visible : 1; - /* Set once it has been finalized so we consider it to be output. */ unsigned finalized : 1; @@ -149,44 +196,41 @@ struct GTY(()) cgraph_clone_info /* The cgraph data structure. Each function decl has assigned cgraph_node listing callees and callers. */ -struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node { - tree decl; +struct GTY(()) cgraph_node { + struct symtab_node_base symbol; struct cgraph_edge *callees; struct cgraph_edge *callers; - struct cgraph_node *next; - struct cgraph_node *previous; /* List of edges representing indirect calls with a yet undetermined callee. */ struct cgraph_edge *indirect_calls; /* For nested functions points to function the node is nested in. */ - struct cgraph_node *origin; + struct cgraph_node * + GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", "(symtab_node)%h"))) + origin; /* Points to first nested function, if any. */ - struct cgraph_node *nested; + struct cgraph_node * + GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", "(symtab_node)%h"))) + nested; /* Pointer to the next function with same origin, if any. */ - struct cgraph_node *next_nested; - /* Pointer to the next function in cgraph_nodes_queue. */ - struct cgraph_node *next_needed; + struct cgraph_node * + GTY ((nested_ptr (union symtab_node_def, "(struct cgraph_node *)(%h)", "(symtab_node)%h"))) + next_nested; /* Pointer to the next clone. */ struct cgraph_node *next_sibling_clone; struct cgraph_node *prev_sibling_clone; struct cgraph_node *clones; struct cgraph_node *clone_of; - /* Circular list of nodes in the same comdat group if non-NULL. */ - struct cgraph_node *same_comdat_group; /* For functions with many calls sites it holds map from call expression to the edge to speed up cgraph_edge function. */ htab_t GTY((param_is (struct cgraph_edge))) call_site_hash; /* Declaration node used to be clone of. */ tree former_clone_of; - PTR GTY ((skip)) aux; - /* Interprocedural passes scheduled to have their transform functions applied next time we execute local pass on them. We maintain it per-function in order to allow IPA passes to introduce new functions. */ VEC(ipa_opt_pass,heap) * GTY((skip)) ipa_transforms_to_apply; - struct ipa_ref_list ref_list; struct cgraph_local_info local; struct cgraph_global_info global; struct cgraph_rtl_info rtl; @@ -200,20 +244,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node { int count_materialization_scale; /* Unique id of the node. */ int uid; - /* Ordering of all cgraph nodes. */ - int order; - enum ld_plugin_symbol_resolution resolution; - - /* Set when function must be output for some reason. The primary - use of this flag is to mark functions needed to be output for - non-standard reason. Functions that are externally visible - or reachable from functions needed to be output are marked - by specialized flags. */ - unsigned needed : 1; - /* Set when function has address taken. - In current implementation it imply needed flag. */ - unsigned address_taken : 1; /* Set when decl is an abstract function pointed to by the ABSTRACT_DECL_ORIGIN of a reachable function. */ unsigned abstract_and_needed : 1; @@ -224,17 +255,11 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node { cgraph_remove_unreachable_nodes cgraph still can contain unreachable nodes when they are needed for virtual clone instantiation. */ unsigned reachable : 1; - /* Set when function is reachable by call from other LTRANS partition. */ - unsigned reachable_from_other_partition : 1; /* Set once the function is lowered (i.e. its CFG is built). */ unsigned lowered : 1; /* Set once the function has been instantiated and its callee lists created. */ unsigned analyzed : 1; - /* Set when function is available in the other LTRANS partition. - During WPA output it is used to mark nodes that are present in - multiple partitions. */ - unsigned in_other_partition : 1; /* Set when function is scheduled to be processed by local passes. */ unsigned process : 1; /* Set for aliases once they got through assemble_alias. */ @@ -386,30 +411,14 @@ DEF_VEC_ALLOC_P(cgraph_edge_p,heap); /* The varpool data structure. Each static variable decl has assigned varpool_node. */ -struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node { - tree decl; +struct GTY(()) varpool_node { + struct symtab_node_base symbol; /* For aliases points to declaration DECL is alias of. */ tree alias_of; - /* Pointer to the next function in varpool_nodes. */ - struct varpool_node *next, *prev; - /* Pointer to the next function in varpool_nodes_queue. */ - struct varpool_node *next_needed, *prev_needed; - /* Circular list of nodes in the same comdat group if non-NULL. */ - struct varpool_node *same_comdat_group; - struct ipa_ref_list ref_list; - /* File stream where this node is being written to. */ - struct lto_file_decl_data * lto_file_data; - PTR GTY ((skip)) aux; - /* Ordering of all cgraph nodes. */ - int order; - enum ld_plugin_symbol_resolution resolution; /* Set when function must be output - it is externally visible or its address is taken. */ unsigned needed : 1; - /* Needed variables might become dead by optimization. This flag - forces the variable to be output even if it appears dead otherwise. */ - unsigned force_output : 1; /* Set once the variable has been instantiated and its callee lists created. */ unsigned analyzed : 1; @@ -417,18 +426,10 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node { unsigned finalized : 1; /* Set when variable is scheduled to be assembled. */ unsigned output : 1; - /* Set when function is visible by other units. */ - unsigned externally_visible : 1; /* Set for aliases once they got through assemble_alias. Also set for extra name aliases in varpool_extra_name_alias. */ unsigned alias : 1; unsigned extra_name_alias : 1; - /* Set when variable is used from other LTRANS partition. */ - unsigned used_from_other_partition : 1; - /* Set when variable is available in the other LTRANS partition. - During WPA output it is used to mark nodes that are present in - multiple partitions. */ - unsigned in_other_partition : 1; }; /* Every top level asm statement is put into a cgraph_asm_node. */ @@ -442,13 +443,25 @@ struct GTY(()) cgraph_asm_node { int order; }; -extern GTY(()) struct cgraph_node *cgraph_nodes; +/* Symbol table entry. */ +union GTY((desc ("%h.symbol.type"), chain_next ("%h.symbol.next"), + chain_prev ("%h.symbol.previous"))) symtab_node_def { + struct symtab_node_base GTY ((tag ("SYMTAB_SYMBOL"))) symbol; + /* Use cgraph (symbol) accessor to get cgraph_node. */ + struct cgraph_node GTY ((tag ("SYMTAB_FUNCTION"))) x_function; + /* Use varpool (symbol) accessor to get varpool_node. */ + struct varpool_node GTY ((tag ("SYMTAB_VARIABLE"))) x_variable; +}; + +extern GTY(()) symtab_node symtab_nodes; extern GTY(()) int cgraph_n_nodes; extern GTY(()) int cgraph_max_uid; extern GTY(()) int cgraph_edge_max_uid; extern bool cgraph_global_info_ready; enum cgraph_state { + /* Frontend is parsing and finalizing functions. */ + CGRAPH_STATE_PARSING, /* Callgraph is being constructed. It is safe to add new functions. */ CGRAPH_STATE_CONSTRUCTION, /* Callgraph is built and IPA passes are being run. */ @@ -462,21 +475,38 @@ enum cgraph_state }; extern enum cgraph_state cgraph_state; extern bool cgraph_function_flags_ready; -extern GTY(()) struct cgraph_node *cgraph_nodes_queue; -extern GTY(()) struct cgraph_node *cgraph_new_nodes; +extern cgraph_node_set cgraph_new_nodes; extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes; -extern GTY(()) int cgraph_order; +extern GTY(()) int symtab_order; extern bool same_body_aliases_done; +/* In symtab.c */ +void symtab_register_node (symtab_node); +void symtab_unregister_node (symtab_node); +void symtab_remove_node (symtab_node); +symtab_node symtab_get_node (const_tree); +symtab_node symtab_node_for_asm (const_tree asmname); +const char * symtab_node_asm_name (symtab_node); +const char * symtab_node_name (symtab_node); +void symtab_insert_node_to_hashtable (symtab_node); +void dump_symtab (FILE *); +void debug_symtab (void); +void dump_symtab_node (FILE *, symtab_node); +void debug_symtab_node (symtab_node); +void dump_symtab_base (FILE *, symtab_node); +void verify_symtab (void); +void verify_symtab_node (symtab_node); +bool verify_symtab_base (symtab_node); + /* In cgraph.c */ void dump_cgraph (FILE *); void debug_cgraph (void); void dump_cgraph_node (FILE *, struct cgraph_node *); void debug_cgraph_node (struct cgraph_node *); -void cgraph_insert_node_to_hashtable (struct cgraph_node *node); void cgraph_remove_edge (struct cgraph_edge *); void cgraph_remove_node (struct cgraph_node *); +struct cgraph_node *cgraph_find_replacement_node (struct cgraph_node *); void cgraph_add_to_same_comdat_group (struct cgraph_node *, struct cgraph_node *); bool cgraph_remove_node_and_inline_clones (struct cgraph_node *, struct cgraph_node *); void cgraph_release_function_body (struct cgraph_node *); @@ -487,7 +517,6 @@ struct cgraph_edge *cgraph_create_edge (struct cgraph_node *, struct cgraph_edge *cgraph_create_indirect_edge (struct cgraph_node *, gimple, int, gcov_type, int); struct cgraph_indirect_call_info *cgraph_allocate_init_indirect_info (void); -struct cgraph_node * cgraph_get_node (const_tree); struct cgraph_node * cgraph_create_node (tree); struct cgraph_node * cgraph_get_create_node (tree); struct cgraph_node * cgraph_same_body_alias (struct cgraph_node *, tree, tree); @@ -505,7 +534,6 @@ void cgraph_update_edges_for_call_stmt (gimple, tree, gimple); struct cgraph_local_info *cgraph_local_info (tree); struct cgraph_global_info *cgraph_global_info (tree); struct cgraph_rtl_info *cgraph_rtl_info (tree); -const char * cgraph_node_name (struct cgraph_node *); struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *, struct cgraph_node *, gimple, unsigned, gcov_type, int, bool); @@ -565,7 +593,7 @@ void cgraph_mark_if_needed (tree); void cgraph_analyze_function (struct cgraph_node *); void cgraph_finalize_compilation_unit (void); void cgraph_optimize (void); -void cgraph_mark_needed_node (struct cgraph_node *); +void cgraph_mark_force_output_node (struct cgraph_node *); void cgraph_mark_address_taken_node (struct cgraph_node *); void cgraph_mark_reachable_node (struct cgraph_node *); bool cgraph_inline_p (struct cgraph_edge *, cgraph_inline_failed_t *reason); @@ -648,9 +676,6 @@ bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e); bool cgraph_optimize_for_size_p (struct cgraph_node *); /* In varpool.c */ -extern GTY(()) struct varpool_node *varpool_nodes_queue; -extern GTY(()) struct varpool_node *varpool_nodes; - struct varpool_node *varpool_node (tree); struct varpool_node *varpool_node_for_asm (tree asmname); void varpool_mark_needed_node (struct varpool_node *); @@ -666,17 +691,14 @@ void cgraph_make_node_local (struct cgraph_node *); bool cgraph_node_can_be_local_p (struct cgraph_node *); -struct varpool_node * varpool_get_node (const_tree decl); void varpool_remove_node (struct varpool_node *node); void varpool_finalize_named_section_flags (struct varpool_node *node); bool varpool_assemble_pending_decls (void); bool varpool_assemble_decl (struct varpool_node *node); -bool varpool_analyze_pending_decls (void); +void varpool_analyze_node (struct varpool_node *); void varpool_remove_unreferenced_decls (void); -void varpool_empty_needed_queue (void); struct varpool_node * varpool_extra_name_alias (tree, tree); struct varpool_node * varpool_create_variable_alias (tree, tree); -const char * varpool_node_name (struct varpool_node *node); void varpool_reset_queue (void); bool const_value_known_p (tree); bool varpool_for_node_and_aliases (struct varpool_node *, @@ -684,20 +706,126 @@ bool varpool_for_node_and_aliases (struct varpool_node *, void *, bool); void varpool_add_new_variable (tree); -/* Walk all reachable static variables. */ -#define FOR_EACH_STATIC_VARIABLE(node) \ - for ((node) = varpool_nodes_queue; (node); (node) = (node)->next_needed) +/* Return true when NODE is function. */ +static inline bool +symtab_function_p (symtab_node node) +{ + return node->symbol.type == SYMTAB_FUNCTION; +} + +/* Return true when NODE is variable. */ +static inline bool +symtab_variable_p (symtab_node node) +{ + return node->symbol.type == SYMTAB_VARIABLE; +} + +/* Return callgraph node for given symbol and check it is a function. */ +static inline struct cgraph_node * +cgraph (symtab_node node) +{ + gcc_checking_assert (!node || node->symbol.type == SYMTAB_FUNCTION); + return (struct cgraph_node *)node; +} + +/* Return varpool node for given symbol and check it is a variable. */ +static inline struct varpool_node * +varpool (symtab_node node) +{ + gcc_checking_assert (!node || node->symbol.type == SYMTAB_VARIABLE); + return (struct varpool_node *)node; +} + +/* Return callgraph node for given symbol and check it is a function. */ +static inline struct cgraph_node * +cgraph_get_node (const_tree decl) +{ + gcc_checking_assert (TREE_CODE (decl) == FUNCTION_DECL); + return cgraph (symtab_get_node (decl)); +} + +/* Return varpool node for given symbol and check it is a function. */ +static inline struct varpool_node * +varpool_get_node (const_tree decl) +{ + gcc_checking_assert (TREE_CODE (decl) == VAR_DECL); + return varpool (symtab_get_node (decl)); +} + +/* Return asm name of cgraph node. */ +static inline const char * +cgraph_node_asm_name(struct cgraph_node *node) +{ + return symtab_node_asm_name ((symtab_node)node); +} + +/* Return asm name of varpool node. */ +static inline const char * +varpool_node_asm_name(struct varpool_node *node) +{ + return symtab_node_asm_name ((symtab_node)node); +} + +/* Return name of cgraph node. */ +static inline const char * +cgraph_node_name(struct cgraph_node *node) +{ + return symtab_node_name ((symtab_node)node); +} + +/* Return name of varpool node. */ +static inline const char * +varpool_node_name(struct varpool_node *node) +{ + return symtab_node_name ((symtab_node)node); +} + +/* Walk all symbols. */ +#define FOR_EACH_SYMBOL(node) \ + for ((node) = symtab_nodes; (node); (node) = (node)->symbol.next) + + +/* Return first variable. */ +static inline struct varpool_node * +varpool_first_variable (void) +{ + symtab_node node; + for (node = symtab_nodes; node; node = node->symbol.next) + { + if (symtab_variable_p (node)) + return varpool (node); + } + return NULL; +} + +/* Return next variable after NODE. */ +static inline struct varpool_node * +varpool_next_variable (struct varpool_node *node) +{ + symtab_node node1 = (symtab_node) node->symbol.next; + for (; node1; node1 = node1->symbol.next) + { + if (symtab_variable_p (node1)) + return varpool (node1); + } + return NULL; +} +/* Walk all variables. */ +#define FOR_EACH_VARIABLE(node) \ + for ((node) = varpool_first_variable (); \ + (node); \ + (node) = varpool_next_variable ((node))) /* Return first reachable static variable with initializer. */ static inline struct varpool_node * varpool_first_static_initializer (void) { - struct varpool_node *node; - for (node = varpool_nodes_queue; node; node = node->next_needed) + symtab_node node; + for (node = symtab_nodes; node; node = node->symbol.next) { - gcc_checking_assert (TREE_CODE (node->decl) == VAR_DECL); - if (DECL_INITIAL (node->decl)) - return node; + if (symtab_variable_p (node) + && DECL_INITIAL (node->symbol.decl)) + return varpool (node); } return NULL; } @@ -706,11 +834,12 @@ varpool_first_static_initializer (void) static inline struct varpool_node * varpool_next_static_initializer (struct varpool_node *node) { - for (node = node->next_needed; node; node = node->next_needed) + symtab_node node1 = (symtab_node) node->symbol.next; + for (; node1; node1 = node1->symbol.next) { - gcc_checking_assert (TREE_CODE (node->decl) == VAR_DECL); - if (DECL_INITIAL (node->decl)) - return node; + if (symtab_variable_p (node1) + && DECL_INITIAL (node1->symbol.decl)) + return varpool (node1); } return NULL; } @@ -720,15 +849,45 @@ varpool_next_static_initializer (struct varpool_node *node) for ((node) = varpool_first_static_initializer (); (node); \ (node) = varpool_next_static_initializer (node)) +/* Return first reachable static variable with initializer. */ +static inline struct varpool_node * +varpool_first_defined_variable (void) +{ + symtab_node node; + for (node = symtab_nodes; node; node = node->symbol.next) + { + if (symtab_variable_p (node) && varpool (node)->analyzed) + return varpool (node); + } + return NULL; +} + +/* Return next reachable static variable with initializer after NODE. */ +static inline struct varpool_node * +varpool_next_defined_variable (struct varpool_node *node) +{ + symtab_node node1 = (symtab_node) node->symbol.next; + for (; node1; node1 = node1->symbol.next) + { + if (symtab_variable_p (node1) && varpool (node1)->analyzed) + return varpool (node1); + } + return NULL; +} +/* Walk all variables with definitions in current unit. */ +#define FOR_EACH_DEFINED_VARIABLE(node) \ + for ((node) = varpool_first_defined_variable (); (node); \ + (node) = varpool_next_defined_variable (node)) + /* Return first function with body defined. */ static inline struct cgraph_node * cgraph_first_defined_function (void) { - struct cgraph_node *node; - for (node = cgraph_nodes; node; node = node->next) + symtab_node node; + for (node = symtab_nodes; node; node = node->symbol.next) { - if (node->analyzed) - return node; + if (symtab_function_p (node) && cgraph (node)->analyzed) + return cgraph (node); } return NULL; } @@ -737,10 +896,11 @@ cgraph_first_defined_function (void) static inline struct cgraph_node * cgraph_next_defined_function (struct cgraph_node *node) { - for (node = node->next; node; node = node->next) + symtab_node node1 = (symtab_node) node->symbol.next; + for (; node1; node1 = node1->symbol.next) { - if (node->analyzed) - return node; + if (symtab_function_p (node1) && cgraph (node1)->analyzed) + return cgraph (node1); } return NULL; } @@ -748,8 +908,37 @@ cgraph_next_defined_function (struct cgraph_node *node) /* Walk all functions with body defined. */ #define FOR_EACH_DEFINED_FUNCTION(node) \ for ((node) = cgraph_first_defined_function (); (node); \ - (node) = cgraph_next_defined_function (node)) + (node) = cgraph_next_defined_function ((node))) + +/* Return first function. */ +static inline struct cgraph_node * +cgraph_first_function (void) +{ + symtab_node node; + for (node = symtab_nodes; node; node = node->symbol.next) + { + if (symtab_function_p (node)) + return cgraph (node); + } + return NULL; +} +/* Return next function. */ +static inline struct cgraph_node * +cgraph_next_function (struct cgraph_node *node) +{ + symtab_node node1 = (symtab_node) node->symbol.next; + for (; node1; node1 = node1->symbol.next) + { + if (symtab_function_p (node1)) + return cgraph (node1); + } + return NULL; +} +/* Walk all functions. */ +#define FOR_EACH_FUNCTION(node) \ + for ((node) = cgraph_first_function (); (node); \ + (node) = cgraph_next_function ((node))) /* Return true when NODE is a function with Gimple body defined in current unit. Functions can also be define externally or they @@ -767,11 +956,12 @@ cgraph_function_with_gimple_body_p (struct cgraph_node *node) static inline struct cgraph_node * cgraph_first_function_with_gimple_body (void) { - struct cgraph_node *node; - for (node = cgraph_nodes; node; node = node->next) + symtab_node node; + for (node = symtab_nodes; node; node = node->symbol.next) { - if (cgraph_function_with_gimple_body_p (node)) - return node; + if (symtab_function_p (node) + && cgraph_function_with_gimple_body_p (cgraph (node))) + return cgraph (node); } return NULL; } @@ -780,10 +970,12 @@ cgraph_first_function_with_gimple_body (void) static inline struct cgraph_node * cgraph_next_function_with_gimple_body (struct cgraph_node *node) { - for (node = node->next; node; node = node->next) + symtab_node node1 = node->symbol.next; + for (; node1; node1 = node1->symbol.next) { - if (cgraph_function_with_gimple_body_p (node)) - return node; + if (symtab_function_p (node1) + && cgraph_function_with_gimple_body_p (cgraph (node1))) + return cgraph (node1); } return NULL; } @@ -931,11 +1123,11 @@ static inline bool cgraph_only_called_directly_or_aliased_p (struct cgraph_node *node) { gcc_assert (!node->global.inlined_to); - return (!node->needed && !node->address_taken - && !node->reachable_from_other_partition - && !DECL_STATIC_CONSTRUCTOR (node->decl) - && !DECL_STATIC_DESTRUCTOR (node->decl) - && !node->local.externally_visible); + return (!node->symbol.force_output && !node->symbol.address_taken + && !node->symbol.used_from_other_partition + && !DECL_STATIC_CONSTRUCTOR (node->symbol.decl) + && !DECL_STATIC_DESTRUCTOR (node->symbol.decl) + && !node->symbol.externally_visible); } /* Return true when function NODE can be removed from callgraph @@ -944,8 +1136,10 @@ cgraph_only_called_directly_or_aliased_p (struct cgraph_node *node) static inline bool varpool_can_remove_if_no_refs (struct varpool_node *node) { - return (!node->force_output && !node->used_from_other_partition - && (DECL_COMDAT (node->decl) || !node->externally_visible)); + return (!node->symbol.force_output && !node->symbol.used_from_other_partition + && (DECL_COMDAT (node->symbol.decl) + || !node->symbol.externally_visible + || DECL_EXTERNAL (node->symbol.decl))); } /* Return true when all references to VNODE must be visible in ipa_ref_list. @@ -957,9 +1151,9 @@ static inline bool varpool_all_refs_explicit_p (struct varpool_node *vnode) { return (vnode->analyzed - && !vnode->externally_visible - && !vnode->used_from_other_partition - && !vnode->force_output); + && !vnode->symbol.externally_visible + && !vnode->symbol.used_from_other_partition + && !vnode->symbol.force_output); } /* Constant pool accessor function. */ @@ -975,9 +1169,9 @@ cgraph_alias_aliased_node (struct cgraph_node *n) { struct ipa_ref *ref; - ipa_ref_list_reference_iterate (&n->ref_list, 0, ref); + ipa_ref_list_reference_iterate (&n->symbol.ref_list, 0, ref); gcc_checking_assert (ref->use == IPA_REF_ALIAS); - if (ref->refered_type == IPA_REF_CGRAPH) + if (symtab_function_p (ref->referred)) return ipa_ref_node (ref); return NULL; } @@ -989,9 +1183,9 @@ varpool_alias_aliased_node (struct varpool_node *n) { struct ipa_ref *ref; - ipa_ref_list_reference_iterate (&n->ref_list, 0, ref); + ipa_ref_list_reference_iterate (&n->symbol.ref_list, 0, ref); gcc_checking_assert (ref->use == IPA_REF_ALIAS); - if (ref->refered_type == IPA_REF_VARPOOL) + if (symtab_variable_p (ref->referred)) return ipa_ref_varpool_node (ref); return NULL; } @@ -1088,9 +1282,9 @@ cgraph_edge_recursive_p (struct cgraph_edge *e) { struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL); if (e->caller->global.inlined_to) - return e->caller->global.inlined_to->decl == callee->decl; + return e->caller->global.inlined_to->symbol.decl == callee->symbol.decl; else - return e->caller->decl == callee->decl; + return e->caller->symbol.decl == callee->symbol.decl; } /* Return true if the TM_CLONE bit is set for a given FNDECL. */ diff --git a/gcc/cgraphbuild.c b/gcc/cgraphbuild.c index d7ef7f9d99d..445a392110d 100644 --- a/gcc/cgraphbuild.c +++ b/gcc/cgraphbuild.c @@ -77,7 +77,8 @@ record_reference (tree *tp, int *walk_subtrees, void *data) struct cgraph_node *node = cgraph_get_create_node (decl); if (!ctx->only_vars) cgraph_mark_address_taken_node (node); - ipa_record_reference (NULL, ctx->varpool_node, node, NULL, + ipa_record_reference ((symtab_node)ctx->varpool_node, + (symtab_node)node, IPA_REF_ADDR, NULL); } @@ -86,9 +87,8 @@ record_reference (tree *tp, int *walk_subtrees, void *data) struct varpool_node *vnode = varpool_node (decl); if (lang_hooks.callgraph.analyze_expr) lang_hooks.callgraph.analyze_expr (&decl, walk_subtrees); - varpool_mark_needed_node (vnode); - ipa_record_reference (NULL, ctx->varpool_node, - NULL, vnode, + ipa_record_reference ((symtab_node)ctx->varpool_node, + (symtab_node)vnode, IPA_REF_ADDR, NULL); } *walk_subtrees = 0; @@ -129,9 +129,8 @@ record_type_list (struct cgraph_node *node, tree list) if (TREE_CODE (type) == VAR_DECL) { struct varpool_node *vnode = varpool_node (type); - varpool_mark_needed_node (vnode); - ipa_record_reference (node, NULL, - NULL, vnode, + ipa_record_reference ((symtab_node)node, + (symtab_node)vnode, IPA_REF_ADDR, NULL); } } @@ -146,12 +145,12 @@ record_eh_tables (struct cgraph_node *node, struct function *fun) { eh_region i; - if (DECL_FUNCTION_PERSONALITY (node->decl)) + if (DECL_FUNCTION_PERSONALITY (node->symbol.decl)) { struct cgraph_node *per_node; - per_node = cgraph_get_create_node (DECL_FUNCTION_PERSONALITY (node->decl)); - ipa_record_reference (node, NULL, per_node, NULL, IPA_REF_ADDR, NULL); + per_node = cgraph_get_create_node (DECL_FUNCTION_PERSONALITY (node->symbol.decl)); + ipa_record_reference ((symtab_node)node, (symtab_node)per_node, IPA_REF_ADDR, NULL); cgraph_mark_address_taken_node (per_node); } @@ -232,8 +231,8 @@ mark_address (gimple stmt, tree addr, void *data) { struct cgraph_node *node = cgraph_get_create_node (addr); cgraph_mark_address_taken_node (node); - ipa_record_reference ((struct cgraph_node *)data, NULL, - node, NULL, + ipa_record_reference ((symtab_node)data, + (symtab_node)node, IPA_REF_ADDR, stmt); } else if (addr && TREE_CODE (addr) == VAR_DECL @@ -244,9 +243,8 @@ mark_address (gimple stmt, tree addr, void *data) if (lang_hooks.callgraph.analyze_expr) lang_hooks.callgraph.analyze_expr (&addr, &walk_subtrees); - varpool_mark_needed_node (vnode); - ipa_record_reference ((struct cgraph_node *)data, NULL, - NULL, vnode, + ipa_record_reference ((symtab_node)data, + (symtab_node)vnode, IPA_REF_ADDR, stmt); } @@ -265,8 +263,8 @@ mark_load (gimple stmt, tree t, void *data) directly manipulated in the code. Pretend that it's an address. */ struct cgraph_node *node = cgraph_get_create_node (t); cgraph_mark_address_taken_node (node); - ipa_record_reference ((struct cgraph_node *)data, NULL, - node, NULL, + ipa_record_reference ((symtab_node)data, + (symtab_node)node, IPA_REF_ADDR, stmt); } else if (t && TREE_CODE (t) == VAR_DECL @@ -277,9 +275,8 @@ mark_load (gimple stmt, tree t, void *data) if (lang_hooks.callgraph.analyze_expr) lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees); - varpool_mark_needed_node (vnode); - ipa_record_reference ((struct cgraph_node *)data, NULL, - NULL, vnode, + ipa_record_reference ((symtab_node)data, + (symtab_node)vnode, IPA_REF_LOAD, stmt); } return false; @@ -299,9 +296,8 @@ mark_store (gimple stmt, tree t, void *data) if (lang_hooks.callgraph.analyze_expr) lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees); - varpool_mark_needed_node (vnode); - ipa_record_reference ((struct cgraph_node *)data, NULL, - NULL, vnode, + ipa_record_reference ((symtab_node)data, + (symtab_node)vnode, IPA_REF_STORE, stmt); } return false; @@ -348,19 +344,22 @@ build_cgraph_edges (void) && gimple_omp_parallel_child_fn (stmt)) { tree fn = gimple_omp_parallel_child_fn (stmt); - ipa_record_reference (node, NULL, cgraph_get_create_node (fn), - NULL, IPA_REF_ADDR, stmt); + ipa_record_reference ((symtab_node)node, + (symtab_node)cgraph_get_create_node (fn), + IPA_REF_ADDR, stmt); } if (gimple_code (stmt) == GIMPLE_OMP_TASK) { tree fn = gimple_omp_task_child_fn (stmt); if (fn) - ipa_record_reference (node, NULL, cgraph_get_create_node (fn), - NULL, IPA_REF_ADDR, stmt); + ipa_record_reference ((symtab_node)node, + (symtab_node) cgraph_get_create_node (fn), + IPA_REF_ADDR, stmt); fn = gimple_omp_task_copy_fn (stmt); if (fn) - ipa_record_reference (node, NULL, cgraph_get_create_node (fn), - NULL, IPA_REF_ADDR, stmt); + ipa_record_reference ((symtab_node)node, + (symtab_node)cgraph_get_create_node (fn), + IPA_REF_ADDR, stmt); } } for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi)) @@ -427,7 +426,7 @@ rebuild_cgraph_edges (void) gimple_stmt_iterator gsi; cgraph_node_remove_callees (node); - ipa_remove_all_references (&node->ref_list); + ipa_remove_all_references (&node->symbol.ref_list); node->count = ENTRY_BLOCK_PTR->count; @@ -475,7 +474,7 @@ cgraph_rebuild_references (void) struct cgraph_node *node = cgraph_get_node (current_function_decl); gimple_stmt_iterator gsi; - ipa_remove_all_references (&node->ref_list); + ipa_remove_all_references (&node->symbol.ref_list); node->count = ENTRY_BLOCK_PTR->count; diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 9e5820fc901..409afa13da4 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -111,6 +111,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tm.h" #include "tree.h" +#include "output.h" #include "rtl.h" #include "tree-flow.h" #include "tree-inline.h" @@ -141,73 +142,78 @@ along with GCC; see the file COPYING3. If not see #include "ipa-inline.h" #include "ipa-utils.h" #include "lto-streamer.h" +#include "except.h" +#include "regset.h" /* FIXME: For reg_obstack. */ + +/* Queue of cgraph nodes scheduled to be added into cgraph. This is a + secondary queue used during optimization to accommodate passes that + may generate new functions that need to be optimized and expanded. */ +cgraph_node_set cgraph_new_nodes; static void cgraph_expand_all_functions (void); static void cgraph_mark_functions_to_output (void); static void cgraph_expand_function (struct cgraph_node *); static void cgraph_output_pending_asms (void); +static void tree_rest_of_compilation (struct cgraph_node *); FILE *cgraph_dump_file; /* Used for vtable lookup in thunk adjusting. */ static GTY (()) tree vtable_entry_type; -/* Determine if function DECL is needed. That is, visible to something - either outside this translation unit, something magic in the system - configury. */ +/* Determine if function DECL is trivially needed and should stay in the + compilation unit. This is used at the symbol table construction time + and differs from later logic removing unnecesary functions that can + take into account results of analysis, whole program info etc. */ bool cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl) { /* If the user told us it is used, then it must be so. */ - if (node->local.externally_visible) + if (node->symbol.force_output) return true; - /* ??? If the assembler name is set by hand, it is possible to assemble - the name later after finalizing the function and the fact is noticed - in assemble_name then. This is arguably a bug. */ - if (DECL_ASSEMBLER_NAME_SET_P (decl) - && (!node->thunk.thunk_p && !node->same_body_alias) - && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) - return true; + /* Double check that no one output the function into assembly file + early. */ + gcc_checking_assert (!DECL_ASSEMBLER_NAME_SET_P (decl) + || (node->thunk.thunk_p || node->same_body_alias) + || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))); - /* With -fkeep-inline-functions we are keeping all inline functions except - for extern inline ones. */ - if (flag_keep_inline_functions - && DECL_DECLARED_INLINE_P (decl) - && !DECL_EXTERNAL (decl) - && !DECL_DISREGARD_INLINE_LIMITS (decl)) - return true; - /* If we decided it was needed before, but at the time we didn't have - the body of the function available, then it's still needed. We have - to go back and re-check its dependencies now. */ - if (node->needed) - return true; + /* Keep constructors, destructors and virtual functions. */ + if (DECL_STATIC_CONSTRUCTOR (decl) + || DECL_STATIC_DESTRUCTOR (decl) + || (DECL_VIRTUAL_P (decl) + && optimize && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl)))) + return true; /* Externally visible functions must be output. The exception is - COMDAT functions that must be output only when they are needed. + COMDAT functions that must be output only when they are needed. */ - When not optimizing, also output the static functions. (see - PR24561), but don't do so for always_inline functions, functions - declared inline and nested functions. These were optimized out - in the original implementation and it is unclear whether we want - to change the behavior here. */ - if (((TREE_PUBLIC (decl) - || (!optimize - && !node->same_body_alias - && !DECL_DISREGARD_INLINE_LIMITS (decl) - && !DECL_DECLARED_INLINE_P (decl) - && !(DECL_CONTEXT (decl) - && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL))) - && !flag_whole_program - && !flag_lto) + if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) return true; return false; } +/* Head of the queue of nodes to be processed while building callgraph */ + +static symtab_node first = (symtab_node)(void *)1; + +/* Add NODE to queue starting at FIRST. + The queue is linked via AUX pointers and terminated by pointer to 1. */ + +static void +enqueue_node (symtab_node node) +{ + if (node->symbol.aux) + return; + gcc_checking_assert (first); + node->symbol.aux = first; + first = node; +} + /* Process CGRAPH_NEW_FUNCTIONS and perform actions necessary to add these functions into callgraph in a way so they look like ordinary reachable functions inserted into callgraph already at construction time. */ @@ -218,26 +224,26 @@ cgraph_process_new_functions (void) bool output = false; tree fndecl; struct cgraph_node *node; + cgraph_node_set_iterator csi; - varpool_analyze_pending_decls (); + if (!cgraph_new_nodes) + return false; /* Note that this queue may grow as its being processed, as the new functions may generate new ones. */ - while (cgraph_new_nodes) + for (csi = csi_start (cgraph_new_nodes); !csi_end_p (csi); csi_next (&csi)) { - node = cgraph_new_nodes; - fndecl = node->decl; - cgraph_new_nodes = cgraph_new_nodes->next_needed; + node = csi_node (csi); + fndecl = node->symbol.decl; switch (cgraph_state) { case CGRAPH_STATE_CONSTRUCTION: /* At construction time we just need to finalize function and move it into reachable functions list. */ - node->next_needed = NULL; cgraph_finalize_function (fndecl, false); - cgraph_mark_reachable_node (node); output = true; cgraph_call_function_insertion_hooks (node); + enqueue_node ((symtab_node) node); break; case CGRAPH_STATE_IPA: @@ -278,8 +284,9 @@ cgraph_process_new_functions (void) gcc_unreachable (); break; } - varpool_analyze_pending_decls (); } + free_cgraph_node_set (cgraph_new_nodes); + cgraph_new_nodes = NULL; return output; } @@ -313,20 +320,6 @@ cgraph_reset_node (struct cgraph_node *node) cgraph_node_remove_callees (node); } -static void -cgraph_lower_function (struct cgraph_node *node) -{ - if (node->lowered) - return; - - if (node->nested) - lower_nested_functions (node->decl); - gcc_assert (!node->nested); - - tree_lowering_passes (node->decl); - node->lowered = true; -} - /* DECL has been parsed. Take it, queue it, compile it at the whim of the logic in effect. If NESTED is true, then our caller cannot stand to have the garbage collector run at the moment. We would need to either create @@ -347,22 +340,29 @@ cgraph_finalize_function (tree decl, bool nested) node->local.finalized = true; node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL; - if (cgraph_decide_is_function_needed (node, decl)) - cgraph_mark_needed_node (node); + /* With -fkeep-inline-functions we are keeping all inline functions except + for extern inline ones. */ + if (flag_keep_inline_functions + && DECL_DECLARED_INLINE_P (decl) + && !DECL_EXTERNAL (decl) + && !DECL_DISREGARD_INLINE_LIMITS (decl)) + node->symbol.force_output = 1; - /* Since we reclaim unreachable nodes at the end of every language - level unit, we need to be conservative about possible entry points - there. */ - if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) - || DECL_STATIC_CONSTRUCTOR (decl) - || DECL_STATIC_DESTRUCTOR (decl) - /* COMDAT virtual functions may be referenced by vtable from - other compilation unit. Still we want to devirtualize calls - to those so we need to analyze them. - FIXME: We should introduce may edges for this purpose and update - their handling in unreachable function removal and inliner too. */ - || (DECL_VIRTUAL_P (decl) - && optimize && (DECL_COMDAT (decl) || DECL_EXTERNAL (decl)))) + /* When not optimizing, also output the static functions. (see + PR24561), but don't do so for always_inline functions, functions + declared inline and nested functions. These were optimized out + in the original implementation and it is unclear whether we want + to change the behavior here. */ + if ((!optimize + && !node->same_body_alias + && !DECL_DISREGARD_INLINE_LIMITS (decl) + && !DECL_DECLARED_INLINE_P (decl) + && !(DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)) + && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) + node->symbol.force_output = 1; + + if (cgraph_decide_is_function_needed (node, decl)) cgraph_mark_reachable_node (node); /* If we've not yet emitted decl, tell the debug info about it. */ @@ -377,6 +377,97 @@ cgraph_finalize_function (tree decl, bool nested) ggc_collect (); } +/* Add the function FNDECL to the call graph. + Unlike cgraph_finalize_function, this function is intended to be used + by middle end and allows insertion of new function at arbitrary point + of compilation. The function can be either in high, low or SSA form + GIMPLE. + + The function is assumed to be reachable and have address taken (so no + API breaking optimizations are performed on it). + + Main work done by this function is to enqueue the function for later + processing to avoid need the passes to be re-entrant. */ + +void +cgraph_add_new_function (tree fndecl, bool lowered) +{ + struct cgraph_node *node; + switch (cgraph_state) + { + case CGRAPH_STATE_PARSING: + cgraph_finalize_function (fndecl, false); + break; + case CGRAPH_STATE_CONSTRUCTION: + /* Just enqueue function to be processed at nearest occurrence. */ + node = cgraph_create_node (fndecl); + if (lowered) + node->lowered = true; + if (!cgraph_new_nodes) + cgraph_new_nodes = cgraph_node_set_new (); + cgraph_node_set_add (cgraph_new_nodes, node); + break; + + case CGRAPH_STATE_IPA: + case CGRAPH_STATE_IPA_SSA: + case CGRAPH_STATE_EXPANSION: + /* Bring the function into finalized state and enqueue for later + analyzing and compilation. */ + node = cgraph_get_create_node (fndecl); + node->local.local = false; + node->local.finalized = true; + node->reachable = node->symbol.force_output = true; + if (!lowered && cgraph_state == CGRAPH_STATE_EXPANSION) + { + push_cfun (DECL_STRUCT_FUNCTION (fndecl)); + current_function_decl = fndecl; + gimple_register_cfg_hooks (); + bitmap_obstack_initialize (NULL); + execute_pass_list (all_lowering_passes); + execute_pass_list (pass_early_local_passes.pass.sub); + bitmap_obstack_release (NULL); + pop_cfun (); + current_function_decl = NULL; + + lowered = true; + } + if (lowered) + node->lowered = true; + if (!cgraph_new_nodes) + cgraph_new_nodes = cgraph_node_set_new (); + cgraph_node_set_add (cgraph_new_nodes, node); + break; + + case CGRAPH_STATE_FINISHED: + /* At the very end of compilation we have to do all the work up + to expansion. */ + node = cgraph_create_node (fndecl); + if (lowered) + node->lowered = true; + cgraph_analyze_function (node); + push_cfun (DECL_STRUCT_FUNCTION (fndecl)); + current_function_decl = fndecl; + gimple_register_cfg_hooks (); + bitmap_obstack_initialize (NULL); + if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl))) + execute_pass_list (pass_early_local_passes.pass.sub); + bitmap_obstack_release (NULL); + tree_rest_of_compilation (node); + pop_cfun (); + current_function_decl = NULL; + break; + + default: + gcc_unreachable (); + } + + /* Set a personality if required and we already passed EH lowering. */ + if (lowered + && (function_needs_eh_personality (DECL_STRUCT_FUNCTION (fndecl)) + == eh_personality_lang)) + DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality (); +} + /* C99 extern inline keywords allow changing of declaration after function has been finalized. We need to re-decide if we want to mark the function as needed then. */ @@ -386,7 +477,7 @@ cgraph_mark_if_needed (tree decl) { struct cgraph_node *node = cgraph_get_node (decl); if (node->local.finalized && cgraph_decide_is_function_needed (node, decl)) - cgraph_mark_needed_node (node); + cgraph_mark_reachable_node (node); } /* Return TRUE if NODE2 is equivalent to NODE or its clone. */ @@ -421,7 +512,7 @@ verify_edge_count_and_frequency (struct cgraph_edge *e) error ("caller edge frequency is too large"); error_found = true; } - if (gimple_has_body_p (e->caller->decl) + if (gimple_has_body_p (e->caller->symbol.decl) && !e->caller->global.inlined_to /* FIXME: Inline-analysis sets frequency to 0 when edge is optimized out. Remove this once edges are actualy removed from the function at that time. */ @@ -431,12 +522,12 @@ verify_edge_count_and_frequency (struct cgraph_edge *e) <= (unsigned) e->uid) || !inline_edge_summary (e)->predicate))) && (e->frequency - != compute_call_stmt_bb_frequency (e->caller->decl, + != compute_call_stmt_bb_frequency (e->caller->symbol.decl, gimple_bb (e->call_stmt)))) { error ("caller edge frequency %i does not match BB frequency %i", e->frequency, - compute_call_stmt_bb_frequency (e->caller->decl, + compute_call_stmt_bb_frequency (e->caller->symbol.decl, gimple_bb (e->call_stmt))); error_found = true; } @@ -467,11 +558,11 @@ verify_edge_corresponds_to_fndecl (struct cgraph_edge *e, tree decl) /* We do not know if a node from a different partition is an alias or what it aliases and therefore cannot do the former_clone_of check reliably. */ - if (!node || node->in_other_partition) + if (!node || node->symbol.in_other_partition) return false; node = cgraph_function_or_thunk_node (node, NULL); - if ((e->callee->former_clone_of != node->decl + if ((e->callee->former_clone_of != node->symbol.decl && (!node->same_body_alias || e->callee->former_clone_of != node->thunk.alias)) /* IPA-CP sometimes redirect edge to clone and then back to the former @@ -492,7 +583,7 @@ DEBUG_FUNCTION void verify_cgraph_node (struct cgraph_node *node) { struct cgraph_edge *e; - struct function *this_cfun = DECL_STRUCT_FUNCTION (node->decl); + struct function *this_cfun = DECL_STRUCT_FUNCTION (node->symbol.decl); basic_block this_block; gimple_stmt_iterator gsi; bool error_found = false; @@ -501,6 +592,7 @@ verify_cgraph_node (struct cgraph_node *node) return; timevar_push (TV_CGRAPH_VERIFY); + error_found |= verify_symtab_base ((symtab_node) node); for (e = node->callees; e; e = e->next_callee) if (e->aux) { @@ -514,19 +606,19 @@ verify_cgraph_node (struct cgraph_node *node) error ("execution count is negative"); error_found = true; } - if (node->global.inlined_to && node->local.externally_visible) + if (node->global.inlined_to && node->symbol.externally_visible) { error ("externally visible inline clone"); error_found = true; } - if (node->global.inlined_to && node->address_taken) + if (node->global.inlined_to && node->symbol.address_taken) { error ("inline clone with address taken"); error_found = true; } - if (node->global.inlined_to && node->needed) + if (node->global.inlined_to && node->symbol.force_output) { - error ("inline clone is needed"); + error ("inline clone is forced to output"); error_found = true; } for (e = node->indirect_calls; e; e = e->next_callee) @@ -587,12 +679,6 @@ verify_cgraph_node (struct cgraph_node *node) error_found = true; } - if (!cgraph_get_node (node->decl)) - { - error ("node not found in cgraph_hash"); - error_found = true; - } - if (node->clone_of) { struct cgraph_node *n; @@ -632,32 +718,6 @@ verify_cgraph_node (struct cgraph_node *node) error ("double linked list of clones corrupted"); error_found = true; } - if (node->same_comdat_group) - { - struct cgraph_node *n = node->same_comdat_group; - - if (!DECL_ONE_ONLY (node->decl)) - { - error ("non-DECL_ONE_ONLY node in a same_comdat_group list"); - error_found = true; - } - if (n == node) - { - error ("node is alone in a comdat group"); - error_found = true; - } - do - { - if (!n->same_comdat_group) - { - error ("same_comdat_group is not a circular list"); - error_found = true; - break; - } - n = n->same_comdat_group; - } - while (n != node); - } if (node->analyzed && node->alias) { @@ -670,7 +730,8 @@ verify_cgraph_node (struct cgraph_node *node) error ("Alias has call edges"); error_found = true; } - for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, + i, ref); i++) if (ref->use != IPA_REF_ALIAS) { error ("Alias has non-alias reference"); @@ -701,15 +762,15 @@ verify_cgraph_node (struct cgraph_node *node) error ("More than one edge out of thunk node"); error_found = true; } - if (gimple_has_body_p (node->decl)) + if (gimple_has_body_p (node->symbol.decl)) { error ("Thunk is not supposed to have body"); error_found = true; } } - else if (node->analyzed && gimple_has_body_p (node->decl) - && !TREE_ASM_WRITTEN (node->decl) - && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to) + else if (node->analyzed && gimple_has_body_p (node->symbol.decl) + && !TREE_ASM_WRITTEN (node->symbol.decl) + && (!DECL_EXTERNAL (node->symbol.decl) || node->global.inlined_to) && !flag_wpa) { if (this_cfun->cfg) @@ -742,7 +803,7 @@ verify_cgraph_node (struct cgraph_node *node) if (verify_edge_corresponds_to_fndecl (e, decl)) { error ("edge points to wrong declaration:"); - debug_tree (e->callee->decl); + debug_tree (e->callee->symbol.decl); fprintf (stderr," Instead of:"); debug_tree (decl); error_found = true; @@ -813,7 +874,7 @@ verify_cgraph (void) if (seen_error ()) return; - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) verify_cgraph_node (node); } @@ -837,7 +898,7 @@ void cgraph_analyze_function (struct cgraph_node *node) { tree save = current_function_decl; - tree decl = node->decl; + tree decl = node->symbol.decl; if (node->alias && node->thunk.alias) { @@ -848,52 +909,54 @@ cgraph_analyze_function (struct cgraph_node *node) n = n->analyzed ? cgraph_alias_aliased_node (n) : NULL) if (n == node) { - error ("function %q+D part of alias cycle", node->decl); + error ("function %q+D part of alias cycle", node->symbol.decl); node->alias = false; return; } - if (!VEC_length (ipa_ref_t, node->ref_list.references)) - ipa_record_reference (node, NULL, tgt, NULL, IPA_REF_ALIAS, NULL); + if (!VEC_length (ipa_ref_t, node->symbol.ref_list.references)) + ipa_record_reference ((symtab_node)node, (symtab_node)tgt, + IPA_REF_ALIAS, NULL); + cgraph_mark_reachable_node (tgt); if (node->same_body_alias) { - DECL_VIRTUAL_P (node->decl) = DECL_VIRTUAL_P (node->thunk.alias); - DECL_DECLARED_INLINE_P (node->decl) + DECL_VIRTUAL_P (node->symbol.decl) = DECL_VIRTUAL_P (node->thunk.alias); + DECL_DECLARED_INLINE_P (node->symbol.decl) = DECL_DECLARED_INLINE_P (node->thunk.alias); - DECL_DISREGARD_INLINE_LIMITS (node->decl) + DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl) = DECL_DISREGARD_INLINE_LIMITS (node->thunk.alias); } /* Fixup visibility nonsences C++ frontend produce on same body aliases. */ - if (TREE_PUBLIC (node->decl) && node->same_body_alias) + if (TREE_PUBLIC (node->symbol.decl) && node->same_body_alias) { - DECL_EXTERNAL (node->decl) = DECL_EXTERNAL (node->thunk.alias); + DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (node->thunk.alias); if (DECL_ONE_ONLY (node->thunk.alias)) { - DECL_COMDAT (node->decl) = DECL_COMDAT (node->thunk.alias); - DECL_COMDAT_GROUP (node->decl) = DECL_COMDAT_GROUP (node->thunk.alias); - if (DECL_ONE_ONLY (node->thunk.alias) && !node->same_comdat_group) + DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (node->thunk.alias); + DECL_COMDAT_GROUP (node->symbol.decl) = DECL_COMDAT_GROUP (node->thunk.alias); + if (DECL_ONE_ONLY (node->thunk.alias) && !node->symbol.same_comdat_group) { struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias); - node->same_comdat_group = tgt; - if (!tgt->same_comdat_group) - tgt->same_comdat_group = node; + node->symbol.same_comdat_group = (symtab_node)tgt; + if (!tgt->symbol.same_comdat_group) + tgt->symbol.same_comdat_group = (symtab_node)node; else { - struct cgraph_node *n; - for (n = tgt->same_comdat_group; - n->same_comdat_group != tgt; - n = n->same_comdat_group) + symtab_node n; + for (n = tgt->symbol.same_comdat_group; + n->symbol.same_comdat_group != (symtab_node)tgt; + n = n->symbol.same_comdat_group) ; - n->same_comdat_group = node; + n->symbol.same_comdat_group = (symtab_node)node; } } } } cgraph_mark_reachable_node (cgraph_alias_aliased_node (node)); - if (node->address_taken) + if (node->symbol.address_taken) cgraph_mark_address_taken_node (cgraph_alias_aliased_node (node)); - if (cgraph_decide_is_function_needed (node, node->decl)) - cgraph_mark_needed_node (node); + if (cgraph_decide_is_function_needed (node, node->symbol.decl)) + cgraph_mark_reachable_node (node); } else if (node->thunk.thunk_p) { @@ -905,7 +968,7 @@ cgraph_analyze_function (struct cgraph_node *node) current_function_decl = decl; push_cfun (DECL_STRUCT_FUNCTION (decl)); - assign_assembler_name_if_neeeded (node->decl); + assign_assembler_name_if_neeeded (node->symbol.decl); /* Make sure to gimplify bodies only once. During analyzing a function we lower it, which will require gimplified nested @@ -915,7 +978,23 @@ cgraph_analyze_function (struct cgraph_node *node) gimplify_function_tree (decl); dump_function (TDI_generic, decl); - cgraph_lower_function (node); + /* Lower the function. */ + if (!node->lowered) + { + if (node->nested) + lower_nested_functions (node->symbol.decl); + gcc_assert (!node->nested); + + gimple_register_cfg_hooks (); + bitmap_obstack_initialize (NULL); + execute_pass_list (all_lowering_passes); + free_dominance_info (CDI_POST_DOMINATORS); + free_dominance_info (CDI_DOMINATORS); + compact_blocks (); + bitmap_obstack_release (NULL); + node->lowered = true; + } + pop_cfun (); } node->analyzed = true; @@ -933,12 +1012,13 @@ void cgraph_process_same_body_aliases (void) { struct cgraph_node *node; - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) if (node->same_body_alias - && !VEC_length (ipa_ref_t, node->ref_list.references)) + && !VEC_length (ipa_ref_t, node->symbol.ref_list.references)) { struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias); - ipa_record_reference (node, NULL, tgt, NULL, IPA_REF_ALIAS, NULL); + ipa_record_reference ((symtab_node)node, (symtab_node)tgt, + IPA_REF_ALIAS, NULL); } same_body_aliases_done = true; } @@ -992,31 +1072,32 @@ process_function_and_variable_attributes (struct cgraph_node *first, struct cgraph_node *node; struct varpool_node *vnode; - for (node = cgraph_nodes; node != first; node = node->next) + for (node = cgraph_first_function (); node != first; + node = cgraph_next_function (node)) { - tree decl = node->decl; + tree decl = node->symbol.decl; if (DECL_PRESERVE_P (decl)) - cgraph_mark_needed_node (node); + cgraph_mark_force_output_node (node); if (TARGET_DLLIMPORT_DECL_ATTRIBUTES && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)) - && TREE_PUBLIC (node->decl)) + && TREE_PUBLIC (node->symbol.decl)) { if (node->local.finalized) - cgraph_mark_needed_node (node); + cgraph_mark_reachable_node (node); } else if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl))) { - if (! TREE_PUBLIC (node->decl)) - warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes, + if (! TREE_PUBLIC (node->symbol.decl)) + warning_at (DECL_SOURCE_LOCATION (node->symbol.decl), OPT_Wattributes, "%<externally_visible%>" " attribute have effect only on public objects"); else if (node->local.finalized) - cgraph_mark_needed_node (node); + cgraph_mark_reachable_node (node); } if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)) && (node->local.finalized && !node->alias)) { - warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes, + warning_at (DECL_SOURCE_LOCATION (node->symbol.decl), OPT_Wattributes, "%<weakref%> attribute ignored" " because function is defined"); DECL_WEAK (decl) = 0; @@ -1033,36 +1114,24 @@ process_function_and_variable_attributes (struct cgraph_node *first, process_common_attributes (decl); } - for (vnode = varpool_nodes; vnode != first_var; vnode = vnode->next) + for (vnode = varpool_first_variable (); vnode != first_var; + vnode = varpool_next_variable (vnode)) { - tree decl = vnode->decl; + tree decl = vnode->symbol.decl; if (DECL_PRESERVE_P (decl)) - { - vnode->force_output = true; - if (vnode->finalized) - varpool_mark_needed_node (vnode); - } - if (TARGET_DLLIMPORT_DECL_ATTRIBUTES - && lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)) - && TREE_PUBLIC (vnode->decl)) - { - if (vnode->finalized) - varpool_mark_needed_node (vnode); - } + vnode->symbol.force_output = true; else if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl))) { - if (! TREE_PUBLIC (vnode->decl)) - warning_at (DECL_SOURCE_LOCATION (vnode->decl), OPT_Wattributes, + if (! TREE_PUBLIC (vnode->symbol.decl)) + warning_at (DECL_SOURCE_LOCATION (vnode->symbol.decl), OPT_Wattributes, "%<externally_visible%>" " attribute have effect only on public objects"); - else if (vnode->finalized) - varpool_mark_needed_node (vnode); } if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)) && vnode->finalized && DECL_INITIAL (decl)) { - warning_at (DECL_SOURCE_LOCATION (vnode->decl), OPT_Wattributes, + warning_at (DECL_SOURCE_LOCATION (vnode->symbol.decl), OPT_Wattributes, "%<weakref%> attribute ignored" " because variable is initialized"); DECL_WEAK (decl) = 0; @@ -1073,10 +1142,54 @@ process_function_and_variable_attributes (struct cgraph_node *first, } } -/* Process CGRAPH_NODES_NEEDED queue, analyze each function (and transitively - each reachable functions) and build cgraph. - The function can be called multiple times after inserting new nodes - into beginning of queue. Just the new part of queue is re-scanned then. */ +/* Return true when there are references to NODE. */ + +static bool +referred_to_p (symtab_node node) +{ + int i; + struct ipa_ref *ref; + + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); + i++) + return true; + if (symtab_function_p (node) && cgraph (node)->callers) + return true; + return false; +} + +/* Mark DECL as finalized. By finalizing the declaration, frontend instruct the + middle end to output the variable to asm file, if needed or externally + visible. */ + +void +varpool_finalize_decl (tree decl) +{ + struct varpool_node *node = varpool_node (decl); + + gcc_assert (TREE_STATIC (decl)); + + if (node->finalized) + return; + notice_global_symbol (decl); + node->finalized = true; + if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl) + /* Traditionally we do not eliminate static variables when not + optimizing and when not doing toplevel reoder. */ + || (!flag_toplevel_reorder && !DECL_COMDAT (node->symbol.decl) + && !DECL_ARTIFICIAL (node->symbol.decl))) + node->symbol.force_output = true; + + if (cgraph_state == CGRAPH_STATE_CONSTRUCTION + && (decide_is_variable_needed (node, decl) + || referred_to_p ((symtab_node)node))) + enqueue_node ((symtab_node)node); + if (cgraph_state >= CGRAPH_STATE_IPA_SSA) + varpool_analyze_node (node); +} + +/* Discover all functions and variables that are trivially needed, analyze + them as well as all functions and variables referred by them */ static void cgraph_analyze_functions (void) @@ -1084,139 +1197,176 @@ cgraph_analyze_functions (void) /* Keep track of already processed nodes when called multiple times for intermodule optimization. */ static struct cgraph_node *first_analyzed; - struct cgraph_node *first_processed = first_analyzed; + struct cgraph_node *first_handled = first_analyzed; static struct varpool_node *first_analyzed_var; - struct cgraph_node *node, *next; + struct varpool_node *first_handled_var = first_analyzed_var; + + symtab_node node, next; + int i; + struct ipa_ref *ref; + bool changed = true; bitmap_obstack_initialize (NULL); - process_function_and_variable_attributes (first_processed, - first_analyzed_var); - first_processed = cgraph_nodes; - first_analyzed_var = varpool_nodes; - varpool_analyze_pending_decls (); - if (cgraph_dump_file) + cgraph_state = CGRAPH_STATE_CONSTRUCTION; + + /* Analysis adds static variables that in turn adds references to new functions. + So we need to iterate the process until it stabilize. */ + while (changed) { - fprintf (cgraph_dump_file, "Initial entry points:"); - for (node = cgraph_nodes; node != first_analyzed; node = node->next) - if (node->needed) - fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); - fprintf (cgraph_dump_file, "\n"); - } - cgraph_process_new_functions (); + changed = false; + process_function_and_variable_attributes (first_analyzed, + first_analyzed_var); - /* Propagate reachability flag and lower representation of all reachable - functions. In the future, lowering will introduce new functions and - new entry points on the way (by template instantiation and virtual - method table generation for instance). */ - while (cgraph_nodes_queue) - { - struct cgraph_edge *edge; - tree decl = cgraph_nodes_queue->decl; - - node = cgraph_nodes_queue; - cgraph_nodes_queue = cgraph_nodes_queue->next_needed; - node->next_needed = NULL; - - /* ??? It is possible to create extern inline function and later using - weak alias attribute to kill its body. See - gcc.c-torture/compile/20011119-1.c */ - if (!DECL_STRUCT_FUNCTION (decl) - && (!node->alias || !node->thunk.alias) - && !node->thunk.thunk_p) + /* First identify the trivially needed symbols. */ + for (node = symtab_nodes; + node != (symtab_node)first_analyzed + && node != (symtab_node)first_analyzed_var; node = node->symbol.next) { - cgraph_reset_node (node); - node->local.redefined_extern_inline = true; - continue; + if ((symtab_function_p (node) + && cgraph (node)->local.finalized + && cgraph_decide_is_function_needed (cgraph (node), node->symbol.decl)) + || (symtab_variable_p (node) + && varpool (node)->finalized + && !DECL_EXTERNAL (node->symbol.decl) + && decide_is_variable_needed (varpool (node), node->symbol.decl))) + { + enqueue_node (node); + if (!changed && cgraph_dump_file) + fprintf (cgraph_dump_file, "Trivially needed symbols:"); + changed = true; + if (cgraph_dump_file) + fprintf (cgraph_dump_file, " %s", symtab_node_asm_name (node)); + } + if (node == (symtab_node)first_analyzed + || node == (symtab_node)first_analyzed_var) + break; } + cgraph_process_new_functions (); + first_analyzed_var = varpool_first_variable (); + first_analyzed = cgraph_first_function (); - if (!node->analyzed) - cgraph_analyze_function (node); - - for (edge = node->callees; edge; edge = edge->next_callee) - if (!edge->callee->reachable) - cgraph_mark_reachable_node (edge->callee); - for (edge = node->callers; edge; edge = edge->next_caller) - if (!edge->caller->reachable && edge->caller->thunk.thunk_p) - cgraph_mark_reachable_node (edge->caller); + if (changed && dump_file) + fprintf (cgraph_dump_file, "\n"); - if (node->same_comdat_group) + /* Lower representation, build callgraph edges and references for all trivially + needed symbols and all symbols referred by them. */ + while (first != (symtab_node)(void *)1) { - for (next = node->same_comdat_group; - next != node; - next = next->same_comdat_group) - cgraph_mark_reachable_node (next); - } + changed = true; + node = first; + first = (symtab_node)first->symbol.aux; + if (symtab_function_p (node) && cgraph (node)->local.finalized) + { + struct cgraph_edge *edge; + struct cgraph_node *cnode; + tree decl; + + cnode = cgraph (node); + decl = cnode->symbol.decl; + + /* ??? It is possible to create extern inline function and later using + weak alias attribute to kill its body. See + gcc.c-torture/compile/20011119-1.c */ + if (!DECL_STRUCT_FUNCTION (decl) + && (!cnode->alias || !cnode->thunk.alias) + && !cnode->thunk.thunk_p) + { + cgraph_reset_node (cnode); + cnode->local.redefined_extern_inline = true; + continue; + } - /* If decl is a clone of an abstract function, mark that abstract - function so that we don't release its body. The DECL_INITIAL() of that - abstract function declaration will be later needed to output debug - info. */ - if (DECL_ABSTRACT_ORIGIN (decl)) - { - struct cgraph_node *origin_node; - origin_node = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl)); - origin_node->abstract_and_needed = true; - } + if (!cnode->analyzed) + cgraph_analyze_function (cnode); - /* We finalize local static variables during constructing callgraph - edges. Process their attributes too. */ - process_function_and_variable_attributes (first_processed, - first_analyzed_var); - first_processed = cgraph_nodes; - first_analyzed_var = varpool_nodes; - varpool_analyze_pending_decls (); - cgraph_process_new_functions (); + for (edge = cnode->callees; edge; edge = edge->next_callee) + { + cgraph_mark_reachable_node (edge->callee); + if (edge->callee->local.finalized) + enqueue_node ((symtab_node)edge->callee); + } + + /* If decl is a clone of an abstract function, mark that abstract + function so that we don't release its body. The DECL_INITIAL() of that + abstract function declaration will be later needed to output debug + info. */ + if (DECL_ABSTRACT_ORIGIN (decl)) + { + struct cgraph_node *origin_node; + origin_node = cgraph_get_node (DECL_ABSTRACT_ORIGIN (decl)); + origin_node->abstract_and_needed = true; + } + + } + else if (symtab_variable_p (node) + && varpool (node)->finalized) + { + varpool_analyze_node (varpool (node)); + } + + if (node->symbol.same_comdat_group) + { + symtab_node next; + for (next = node->symbol.same_comdat_group; + next != node; + next = next->symbol.same_comdat_group) + enqueue_node (next); + } + for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++) + if ((symtab_function_p (ref->referred) && cgraph (ref->referred)->local.finalized) + || (symtab_variable_p (ref->referred) && varpool (ref->referred)->finalized)) + enqueue_node (ref->referred); + cgraph_process_new_functions (); + } } /* Collect entry points to the unit. */ if (cgraph_dump_file) { - fprintf (cgraph_dump_file, "Unit entry points:"); - for (node = cgraph_nodes; node != first_analyzed; node = node->next) - if (node->needed) - fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); fprintf (cgraph_dump_file, "\n\nInitial "); - dump_cgraph (cgraph_dump_file); - dump_varpool (cgraph_dump_file); + dump_symtab (cgraph_dump_file); } if (cgraph_dump_file) - fprintf (cgraph_dump_file, "\nReclaiming functions:"); + fprintf (cgraph_dump_file, "\nRemoving unused symbols:"); - for (node = cgraph_nodes; node != first_analyzed; node = next) + for (node = symtab_nodes; + node != (symtab_node)first_handled + && node != (symtab_node)first_handled_var; node = next) { - tree decl = node->decl; - next = node->next; - - if (node->local.finalized && !gimple_has_body_p (decl) - && (!node->alias || !node->thunk.alias) - && !node->thunk.thunk_p) - cgraph_reset_node (node); - - if (!node->reachable - && (gimple_has_body_p (decl) || node->thunk.thunk_p - || (node->alias && node->thunk.alias))) + next = node->symbol.next; + if (!node->symbol.aux && !referred_to_p (node)) { if (cgraph_dump_file) - fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); - cgraph_remove_node (node); + fprintf (cgraph_dump_file, " %s", symtab_node_name (node)); + symtab_remove_node (node); continue; } - else - node->next_needed = NULL; - gcc_assert (!node->local.finalized || node->thunk.thunk_p - || node->alias - || gimple_has_body_p (decl)); - gcc_assert (node->analyzed == node->local.finalized); + if (symtab_function_p (node)) + { + tree decl = node->symbol.decl; + struct cgraph_node *cnode = cgraph (node); + + if (cnode->local.finalized && !gimple_has_body_p (decl) + && (!cnode->alias || !cnode->thunk.alias) + && !cnode->thunk.thunk_p) + cgraph_reset_node (cnode); + + gcc_assert (!cnode->local.finalized || cnode->thunk.thunk_p + || cnode->alias + || gimple_has_body_p (decl)); + gcc_assert (cnode->analyzed == cnode->local.finalized); + } + node->symbol.aux = NULL; } + first_analyzed = cgraph_first_function (); + first_analyzed_var = varpool_first_variable (); if (cgraph_dump_file) { fprintf (cgraph_dump_file, "\n\nReclaimed "); - dump_cgraph (cgraph_dump_file); - dump_varpool (cgraph_dump_file); + dump_symtab (cgraph_dump_file); } bitmap_obstack_release (NULL); - first_analyzed = cgraph_nodes; ggc_collect (); } @@ -1247,9 +1397,10 @@ handle_alias_pairs (void) However for weakref we insist on EXTERNAL flag being set. See gcc.dg/attr-alias-5.c */ if (DECL_EXTERNAL (p->decl)) - DECL_EXTERNAL (p->decl) = lookup_attribute ("weakref", - DECL_ATTRIBUTES (p->decl)) != NULL; - cgraph_create_function_alias (p->decl, target_node->decl); + DECL_EXTERNAL (p->decl) + = lookup_attribute ("weakref", + DECL_ATTRIBUTES (p->decl)) != NULL; + cgraph_create_function_alias (p->decl, target_node->symbol.decl); VEC_unordered_remove (alias_pair, alias_pairs, i); } else if (TREE_CODE (p->decl) == VAR_DECL @@ -1261,9 +1412,10 @@ handle_alias_pairs (void) However for weakref we insist on EXTERNAL flag being set. See gcc.dg/attr-alias-5.c */ if (DECL_EXTERNAL (p->decl)) - DECL_EXTERNAL (p->decl) = lookup_attribute ("weakref", - DECL_ATTRIBUTES (p->decl)) != NULL; - varpool_create_variable_alias (p->decl, target_vnode->decl); + DECL_EXTERNAL (p->decl) + = lookup_attribute ("weakref", + DECL_ATTRIBUTES (p->decl)) != NULL; + varpool_create_variable_alias (p->decl, target_vnode->symbol.decl); VEC_unordered_remove (alias_pair, alias_pairs, i); } /* Weakrefs with target not defined in current unit are easy to handle; they @@ -1303,16 +1455,16 @@ cgraph_mark_functions_to_output (void) #ifdef ENABLE_CHECKING bool check_same_comdat_groups = false; - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) gcc_assert (!node->process); #endif - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) { - tree decl = node->decl; + tree decl = node->symbol.decl; struct cgraph_edge *e; - gcc_assert (!node->process || node->same_comdat_group); + gcc_assert (!node->process || node->symbol.same_comdat_group); if (node->process) continue; @@ -1328,23 +1480,23 @@ cgraph_mark_functions_to_output (void) && !node->alias && !node->global.inlined_to && (!cgraph_only_called_directly_p (node) - || ((e || ipa_ref_has_aliases_p (&node->ref_list)) + || ((e || ipa_ref_has_aliases_p (&node->symbol.ref_list)) && node->reachable)) && !TREE_ASM_WRITTEN (decl) && !DECL_EXTERNAL (decl)) { node->process = 1; - if (node->same_comdat_group) + if (node->symbol.same_comdat_group) { struct cgraph_node *next; - for (next = node->same_comdat_group; + for (next = cgraph (node->symbol.same_comdat_group); next != node; - next = next->same_comdat_group) + next = cgraph (next->symbol.same_comdat_group)) if (!next->thunk.thunk_p && !next->alias) next->process = 1; } } - else if (node->same_comdat_group) + else if (node->symbol.same_comdat_group) { #ifdef ENABLE_CHECKING check_same_comdat_groups = true; @@ -1359,7 +1511,7 @@ cgraph_mark_functions_to_output (void) /* FIXME: in ltrans unit when offline copy is outside partition but inline copies are inside partition, we can end up not removing the body since we no longer have analyzed node pointing to it. */ - && !node->in_other_partition + && !node->symbol.in_other_partition && !node->alias && !DECL_EXTERNAL (decl)) { @@ -1369,7 +1521,7 @@ cgraph_mark_functions_to_output (void) #endif gcc_assert (node->global.inlined_to || !gimple_has_body_p (decl) - || node->in_other_partition + || node->symbol.in_other_partition || DECL_EXTERNAL (decl)); } @@ -1377,17 +1529,17 @@ cgraph_mark_functions_to_output (void) } #ifdef ENABLE_CHECKING if (check_same_comdat_groups) - for (node = cgraph_nodes; node; node = node->next) - if (node->same_comdat_group && !node->process) + FOR_EACH_FUNCTION (node) + if (node->symbol.same_comdat_group && !node->process) { - tree decl = node->decl; + tree decl = node->symbol.decl; if (!node->global.inlined_to && gimple_has_body_p (decl) /* FIXME: in an ltrans unit when the offline copy is outside a partition but inline copies are inside a partition, we can end up not removing the body since we no longer have an analyzed node pointing to it. */ - && !node->in_other_partition + && !node->symbol.in_other_partition && !DECL_EXTERNAL (decl)) { dump_cgraph_node (stderr, node); @@ -1555,7 +1707,7 @@ assemble_thunk (struct cgraph_node *node) HOST_WIDE_INT virtual_value = node->thunk.virtual_value; tree virtual_offset = NULL; tree alias = node->thunk.alias; - tree thunk_fndecl = node->decl; + tree thunk_fndecl = node->symbol.decl; tree a = DECL_ARGUMENTS (thunk_fndecl); current_function_decl = thunk_fndecl; @@ -1750,28 +1902,117 @@ assemble_thunks_and_aliases (struct cgraph_node *node) } else e = e->next_caller; - for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, + i, ref); i++) if (ref->use == IPA_REF_ALIAS) { - struct cgraph_node *alias = ipa_ref_refering_node (ref); + struct cgraph_node *alias = ipa_ref_referring_node (ref); bool saved_written = TREE_ASM_WRITTEN (alias->thunk.alias); /* Force assemble_alias to really output the alias this time instead of buffering it in same alias pairs. */ TREE_ASM_WRITTEN (alias->thunk.alias) = 1; - assemble_alias (alias->decl, + assemble_alias (alias->symbol.decl, DECL_ASSEMBLER_NAME (alias->thunk.alias)); assemble_thunks_and_aliases (alias); TREE_ASM_WRITTEN (alias->thunk.alias) = saved_written; } } +/* Perform IPA transforms and all further optimizations and compilation + for FNDECL. */ + +static void +tree_rest_of_compilation (struct cgraph_node *node) +{ + tree fndecl = node->symbol.decl; + location_t saved_loc; + + timevar_push (TV_REST_OF_COMPILATION); + + gcc_assert (cgraph_global_info_ready); + + /* Initialize the default bitmap obstack. */ + bitmap_obstack_initialize (NULL); + + /* Initialize the RTL code for the function. */ + current_function_decl = fndecl; + saved_loc = input_location; + input_location = DECL_SOURCE_LOCATION (fndecl); + init_function_start (fndecl); + + gimple_register_cfg_hooks (); + + bitmap_obstack_initialize (®_obstack); /* FIXME, only at RTL generation*/ + + execute_all_ipa_transforms (); + + /* Perform all tree transforms and optimizations. */ + + /* Signal the start of passes. */ + invoke_plugin_callbacks (PLUGIN_ALL_PASSES_START, NULL); + + execute_pass_list (all_passes); + + /* Signal the end of passes. */ + invoke_plugin_callbacks (PLUGIN_ALL_PASSES_END, NULL); + + bitmap_obstack_release (®_obstack); + + /* Release the default bitmap obstack. */ + bitmap_obstack_release (NULL); + + set_cfun (NULL); + + /* If requested, warn about function definitions where the function will + return a value (usually of some struct or union type) which itself will + take up a lot of stack space. */ + if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl)) + { + tree ret_type = TREE_TYPE (TREE_TYPE (fndecl)); + + if (ret_type && TYPE_SIZE_UNIT (ret_type) + && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST + && 0 < compare_tree_int (TYPE_SIZE_UNIT (ret_type), + larger_than_size)) + { + unsigned int size_as_int + = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type)); + + if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0) + warning (OPT_Wlarger_than_, "size of return value of %q+D is %u bytes", + fndecl, size_as_int); + else + warning (OPT_Wlarger_than_, "size of return value of %q+D is larger than %wd bytes", + fndecl, larger_than_size); + } + } + + gimple_set_body (fndecl, NULL); + if (DECL_STRUCT_FUNCTION (fndecl) == 0 + && !cgraph_get_node (fndecl)->origin) + { + /* Stop pointing to the local nodes about to be freed. + But DECL_INITIAL must remain nonzero so we know this + was an actual function definition. + For a nested function, this is done in c_pop_function_context. + If rest_of_compilation set this to 0, leave it 0. */ + if (DECL_INITIAL (fndecl) != 0) + DECL_INITIAL (fndecl) = error_mark_node; + } + + input_location = saved_loc; + + ggc_collect (); + timevar_pop (TV_REST_OF_COMPILATION); +} + /* Expand function specified by NODE. */ static void cgraph_expand_function (struct cgraph_node *node) { - tree decl = node->decl; + tree decl = node->symbol.decl; /* We ought to not compile any inline clones. */ gcc_assert (!node->global.inlined_to); @@ -1781,7 +2022,7 @@ cgraph_expand_function (struct cgraph_node *node) gcc_assert (node->lowered); /* Generate RTL for the body of DECL. */ - tree_rest_of_compilation (decl); + tree_rest_of_compilation (node); /* Make sure that BE didn't give up on compiling. */ gcc_assert (TREE_ASM_WRITTEN (decl)); @@ -1799,8 +2040,6 @@ cgraph_expand_function (struct cgraph_node *node) /* Eliminate all call edges. This is important so the GIMPLE_CALL no longer points to the dead function body. */ cgraph_node_remove_callees (node); - - cgraph_function_flags_ready = true; } /* Return true when CALLER_DECL should be inlined into CALLEE_DECL. */ @@ -1894,25 +2133,23 @@ cgraph_output_in_order (void) struct varpool_node *pv; struct cgraph_asm_node *pa; - max = cgraph_order; + max = symtab_order; nodes = XCNEWVEC (struct cgraph_order_sort, max); - varpool_analyze_pending_decls (); - - for (pf = cgraph_nodes; pf; pf = pf->next) + FOR_EACH_DEFINED_FUNCTION (pf) { if (pf->process && !pf->thunk.thunk_p && !pf->alias) { - i = pf->order; + i = pf->symbol.order; gcc_assert (nodes[i].kind == ORDER_UNDEFINED); nodes[i].kind = ORDER_FUNCTION; nodes[i].u.f = pf; } } - for (pv = varpool_nodes_queue; pv; pv = pv->next_needed) + FOR_EACH_DEFINED_VARIABLE (pv) { - i = pv->order; + i = pv->symbol.order; gcc_assert (nodes[i].kind == ORDER_UNDEFINED); nodes[i].kind = ORDER_VAR; nodes[i].u.v = pv; @@ -1927,14 +2164,6 @@ cgraph_output_in_order (void) } /* In toplevel reorder mode we output all statics; mark them as needed. */ - for (i = 0; i < max; ++i) - { - if (nodes[i].kind == ORDER_VAR) - { - varpool_mark_needed_node (nodes[i].u.v); - } - } - varpool_empty_needed_queue (); for (i = 0; i < max; ++i) if (nodes[i].kind == ORDER_VAR) @@ -2064,20 +2293,20 @@ output_weakrefs (void) { struct cgraph_node *node; struct varpool_node *vnode; - for (node = cgraph_nodes; node; node = node->next) - if (node->alias && DECL_EXTERNAL (node->decl) - && !TREE_ASM_WRITTEN (node->decl) - && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->decl))) - assemble_alias (node->decl, + FOR_EACH_FUNCTION (node) + if (node->alias && DECL_EXTERNAL (node->symbol.decl) + && !TREE_ASM_WRITTEN (node->symbol.decl) + && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl))) + assemble_alias (node->symbol.decl, node->thunk.alias ? DECL_ASSEMBLER_NAME (node->thunk.alias) - : get_alias_symbol (node->decl)); - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - if (vnode->alias && DECL_EXTERNAL (vnode->decl) - && !TREE_ASM_WRITTEN (vnode->decl) - && lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->decl))) - assemble_alias (vnode->decl, + : get_alias_symbol (node->symbol.decl)); + FOR_EACH_VARIABLE (vnode) + if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl) + && !TREE_ASM_WRITTEN (vnode->symbol.decl) + && lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl))) + assemble_alias (vnode->symbol.decl, vnode->alias_of ? DECL_ASSEMBLER_NAME (vnode->alias_of) - : get_alias_symbol (vnode->decl)); + : get_alias_symbol (vnode->symbol.decl)); } @@ -2103,8 +2332,8 @@ update_call_expr (struct cgraph_node *new_version) /* Update the call expr on the edges to call the new version. */ for (e = new_version->callers; e; e = e->next_caller) { - struct function *inner_function = DECL_STRUCT_FUNCTION (e->caller->decl); - gimple_call_set_fndecl (e->call_stmt, new_version->decl); + struct function *inner_function = DECL_STRUCT_FUNCTION (e->caller->symbol.decl); + gimple_call_set_fndecl (e->call_stmt, new_version->symbol.decl); maybe_clean_eh_stmt_fn (inner_function, e->call_stmt); } } @@ -2137,8 +2366,8 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version, new_version->analyzed = old_version->analyzed; new_version->local = old_version->local; - new_version->local.externally_visible = false; - new_version->local.local = true; + new_version->symbol.externally_visible = false; + new_version->local.local = old_version->analyzed; new_version->global = old_version->global; new_version->rtl = old_version->rtl; new_version->reachable = true; @@ -2200,7 +2429,7 @@ cgraph_function_versioning (struct cgraph_node *old_version_node, basic_block new_entry_block, const char *clone_name) { - tree old_decl = old_version_node->decl; + tree old_decl = old_version_node->symbol.decl; struct cgraph_node *new_version_node = NULL; tree new_decl; @@ -2240,9 +2469,9 @@ cgraph_function_versioning (struct cgraph_node *old_version_node, that is not weak also. ??? We cannot use COMDAT linkage because there is no ABI support for this. */ - cgraph_make_decl_local (new_version_node->decl); - DECL_VIRTUAL_P (new_version_node->decl) = 0; - new_version_node->local.externally_visible = 0; + cgraph_make_decl_local (new_version_node->symbol.decl); + DECL_VIRTUAL_P (new_version_node->symbol.decl) = 0; + new_version_node->symbol.externally_visible = 0; new_version_node->local.local = 1; new_version_node->lowered = true; @@ -2258,18 +2487,18 @@ static void cgraph_materialize_clone (struct cgraph_node *node) { bitmap_obstack_initialize (NULL); - node->former_clone_of = node->clone_of->decl; + node->former_clone_of = node->clone_of->symbol.decl; if (node->clone_of->former_clone_of) node->former_clone_of = node->clone_of->former_clone_of; /* Copy the OLD_VERSION_NODE function tree to the new version. */ - tree_function_versioning (node->clone_of->decl, node->decl, + tree_function_versioning (node->clone_of->symbol.decl, node->symbol.decl, node->clone.tree_map, true, node->clone.args_to_skip, false, NULL, NULL); if (cgraph_dump_file) { - dump_function_to_file (node->clone_of->decl, cgraph_dump_file, dump_flags); - dump_function_to_file (node->decl, cgraph_dump_file, dump_flags); + dump_function_to_file (node->clone_of->symbol.decl, cgraph_dump_file, dump_flags); + dump_function_to_file (node->symbol.decl, cgraph_dump_file, dump_flags); } /* Function is no longer clone. */ @@ -2285,7 +2514,7 @@ cgraph_materialize_clone (struct cgraph_node *node) { cgraph_release_function_body (node->clone_of); cgraph_node_remove_callees (node->clone_of); - ipa_remove_all_references (&node->clone_of->ref_list); + ipa_remove_all_references (&node->clone_of->symbol.ref_list); } node->clone_of = NULL; bitmap_obstack_release (NULL); @@ -2305,7 +2534,7 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e) #endif if (e->indirect_unknown_callee - || decl == e->callee->decl) + || decl == e->callee->symbol.decl) return e->call_stmt; #ifdef ENABLE_CHECKING @@ -2337,7 +2566,7 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e) new_stmt = gimple_call_copy_skip_args (e->call_stmt, e->callee->clone.combined_args_to_skip); - gimple_call_set_fndecl (new_stmt, e->callee->decl); + gimple_call_set_fndecl (new_stmt, e->callee->symbol.decl); if (gimple_vdef (new_stmt) && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME) @@ -2359,7 +2588,7 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e) else { new_stmt = e->call_stmt; - gimple_call_set_fndecl (new_stmt, e->callee->decl); + gimple_call_set_fndecl (new_stmt, e->callee->symbol.decl); update_stmt (new_stmt); } @@ -2396,12 +2625,12 @@ cgraph_materialize_all_clones (void) while (!stabilized) { stabilized = true; - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) { - if (node->clone_of && node->decl != node->clone_of->decl - && !gimple_has_body_p (node->decl)) + if (node->clone_of && node->symbol.decl != node->clone_of->symbol.decl + && !gimple_has_body_p (node->symbol.decl)) { - if (gimple_has_body_p (node->clone_of->decl)) + if (gimple_has_body_p (node->clone_of->symbol.decl)) { if (cgraph_dump_file) { @@ -2446,7 +2675,7 @@ cgraph_materialize_all_clones (void) } } } - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) if (!node->analyzed && node->callees) cgraph_node_remove_callees (node); if (cgraph_dump_file) @@ -2467,13 +2696,9 @@ cgraph_optimize (void) return; #ifdef ENABLE_CHECKING - verify_cgraph (); + verify_symtab (); #endif - /* Frontend may output common variables after the unit has been finalized. - It is safe to deal with them here as they are always zero initialized. */ - varpool_analyze_pending_decls (); - timevar_push (TV_CGRAPHOPT); if (pre_ipa_mem_report) { @@ -2503,8 +2728,7 @@ cgraph_optimize (void) if (cgraph_dump_file) { fprintf (cgraph_dump_file, "Optimized "); - dump_cgraph (cgraph_dump_file); - dump_varpool (cgraph_dump_file); + dump_symtab (cgraph_dump_file); } if (post_ipa_mem_report) { @@ -2518,7 +2742,7 @@ cgraph_optimize (void) if (!quiet_flag) fprintf (stderr, "Assembling functions:\n"); #ifdef ENABLE_CHECKING - verify_cgraph (); + verify_symtab (); #endif cgraph_materialize_all_clones (); @@ -2526,7 +2750,7 @@ cgraph_optimize (void) execute_ipa_pass_list (all_late_ipa_passes); cgraph_remove_unreachable_nodes (true, dump_file); #ifdef ENABLE_CHECKING - verify_cgraph (); + verify_symtab (); #endif bitmap_obstack_release (NULL); cgraph_mark_functions_to_output (); @@ -2551,11 +2775,10 @@ cgraph_optimize (void) if (cgraph_dump_file) { fprintf (cgraph_dump_file, "\nFinal "); - dump_cgraph (cgraph_dump_file); - dump_varpool (cgraph_dump_file); + dump_symtab (cgraph_dump_file); } #ifdef ENABLE_CHECKING - verify_cgraph (); + verify_symtab (); /* Double check that all inline clones are gone and that all function bodies have been released from memory. */ if (!seen_error ()) @@ -2563,10 +2786,9 @@ cgraph_optimize (void) struct cgraph_node *node; bool error_found = false; - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed - && (node->global.inlined_to - || gimple_has_body_p (node->decl))) + FOR_EACH_DEFINED_FUNCTION (node) + if (node->global.inlined_to + || gimple_has_body_p (node->symbol.decl)) { error_found = true; dump_cgraph_node (stderr, node); diff --git a/gcc/common.opt b/gcc/common.opt index 97c888b2b19..d2a8a0f8f78 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -307,7 +307,7 @@ Common Driver Joined Alias(o) MissingArgError(missing filename after %qs) Driver Alias(pass-exit-codes) -pedantic -Common Alias(pedantic) +Common Alias(Wpedantic) -pedantic-errors Common Alias(pedantic-errors) @@ -582,6 +582,10 @@ Wpadded Common Var(warn_padded) Warning Warn when padding is required to align structure members +Wpedantic +Common Var(pedantic) Warning +Issue warnings needed for strict compliance to the standard + Wshadow Common Var(warn_shadow) Warning Warn when one local variable shadows another @@ -788,6 +792,8 @@ Driver Undocumented ; argument. ; First selectable in G++ 4.7. ; +; 7: The version of the ABI that treats nullptr_t as a builtin type. +; First selectable in G++ 4.8. ; Additional positive integers will be assigned as new versions of ; the ABI become the default version of the ABI. fabi-version= @@ -1130,6 +1136,10 @@ Enum(diagnostic_prefixing_rule) String(once) Value(DIAGNOSTICS_SHOW_PREFIX_ONCE) EnumValue Enum(diagnostic_prefixing_rule) String(every-line) Value(DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE) +fdiagnostics-show-caret +Common Var(flag_diagnostics_show_caret) Init(1) +Show the source line with a caret indicating the column + fdiagnostics-show-option Common Var(flag_diagnostics_show_option) Init(1) Amend appropriate diagnostic messages with the command line option that controls them @@ -2417,8 +2427,7 @@ pass-exit-codes Driver Var(pass_exit_codes) pedantic -Common Var(pedantic) -Issue warnings needed for strict compliance to the standard +Common Alias(Wpedantic) pedantic-errors Common Var(flag_pedantic_errors) diff --git a/gcc/config.gcc b/gcc/config.gcc index 3eb2c7002df..63d661285b2 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -1228,7 +1228,7 @@ i[34567]86-*-linux* | i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-knetbsd*-gnu | i # Assume modern glibc default_gnu_indirect_function=yes if test x$enable_targets = xall; then - tm_file="${tm_file} i386/x86-64.h i386/gnu-user64.h i386/linux64.h" + tm_file="${tm_file} i386/x86-64.h i386/gnu-user-common.h i386/gnu-user64.h i386/linux-common.h i386/linux64.h" tm_defines="${tm_defines} TARGET_BI_ARCH=1" tmake_file="${tmake_file} i386/t-linux64" x86_multilibs="${with_multilib_list}" @@ -1263,29 +1263,29 @@ i[34567]86-*-linux* | i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-knetbsd*-gnu | i ;; esac else - tm_file="${tm_file} i386/gnu-user.h i386/linux.h" + tm_file="${tm_file} i386/gnu-user-common.h i386/gnu-user.h i386/linux-common.h i386/linux.h" fi ;; i[34567]86-*-knetbsd*-gnu) - tm_file="${tm_file} i386/gnu-user.h knetbsd-gnu.h i386/knetbsd-gnu.h" + tm_file="${tm_file} i386/gnu-user-common.h i386/gnu-user.h knetbsd-gnu.h i386/knetbsd-gnu.h" ;; i[34567]86-*-kfreebsd*-gnu) - tm_file="${tm_file} i386/gnu-user.h kfreebsd-gnu.h i386/kfreebsd-gnu.h" + tm_file="${tm_file} i386/gnu-user-common.h i386/gnu-user.h kfreebsd-gnu.h i386/kfreebsd-gnu.h" ;; i[34567]86-*-kopensolaris*-gnu) - tm_file="${tm_file} i386/gnu-user.h kopensolaris-gnu.h i386/kopensolaris-gnu.h" + tm_file="${tm_file} i386/gnu-user-common.h i386/gnu-user.h kopensolaris-gnu.h i386/kopensolaris-gnu.h" ;; i[34567]86-*-gnu*) - tm_file="$tm_file i386/gnu-user.h gnu.h i386/gnu.h" + tm_file="$tm_file i386/gnu-user-common.h i386/gnu-user.h gnu.h i386/gnu.h" ;; esac ;; x86_64-*-linux* | x86_64-*-kfreebsd*-gnu | x86_64-*-knetbsd*-gnu) tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h gnu-user.h glibc-stdint.h \ - i386/x86-64.h i386/gnu-user64.h" + i386/x86-64.h i386/gnu-user-common.h i386/gnu-user64.h" case ${target} in x86_64-*-linux*) - tm_file="${tm_file} linux.h i386/linux64.h" + tm_file="${tm_file} linux.h i386/linux-common.h i386/linux64.h" # Assume modern glibc default_gnu_indirect_function=yes ;; diff --git a/gcc/config/alpha/sync.md b/gcc/config/alpha/sync.md index 90f6c5cd8d4..bde99c456cf 100644 --- a/gcc/config/alpha/sync.md +++ b/gcc/config/alpha/sync.md @@ -19,7 +19,7 @@ (define_code_iterator FETCHOP [plus minus ior xor and]) (define_code_attr fetchop_name - [(plus "add") (minus "sub") (ior "ior") (xor "xor") (and "and")]) + [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")]) (define_code_attr fetchop_pred [(plus "add_operand") (minus "reg_or_8bit_operand") (ior "or_operand") (xor "or_operand") (and "and_operand")]) diff --git a/gcc/config/arm/arm-cores.def b/gcc/config/arm/arm-cores.def index 80609e0850d..d82b10baeff 100644 --- a/gcc/config/arm/arm-cores.def +++ b/gcc/config/arm/arm-cores.def @@ -137,4 +137,4 @@ ARM_CORE("cortex-m4", cortexm4, 7EM, FL_LDSCHED, cortex) ARM_CORE("cortex-m3", cortexm3, 7M, FL_LDSCHED, cortex) ARM_CORE("cortex-m1", cortexm1, 6M, FL_LDSCHED, cortex) ARM_CORE("cortex-m0", cortexm0, 6M, FL_LDSCHED, cortex) - +ARM_CORE("cortex-m0plus", cortexm0plus, 6M, FL_LDSCHED, cortex) diff --git a/gcc/config/arm/arm-tables.opt b/gcc/config/arm/arm-tables.opt index c0b2437d10e..aa64f9c9a77 100644 --- a/gcc/config/arm/arm-tables.opt +++ b/gcc/config/arm/arm-tables.opt @@ -270,6 +270,9 @@ Enum(processor_type) String(cortex-m1) Value(cortexm1) EnumValue Enum(processor_type) String(cortex-m0) Value(cortexm0) +EnumValue +Enum(processor_type) String(cortex-m0plus) Value(cortexm0plus) + Enum Name(arm_arch) Type(int) Known ARM architectures (for use with the -march= option): diff --git a/gcc/config/arm/arm-tune.md b/gcc/config/arm/arm-tune.md index 54ef0f18ce5..040587af6e4 100644 --- a/gcc/config/arm/arm-tune.md +++ b/gcc/config/arm/arm-tune.md @@ -1,5 +1,5 @@ ;; -*- buffer-read-only: t -*- ;; Generated automatically by gentune.sh from arm-cores.def (define_attr "tune" - "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,fa526,fa626,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,genericv7a,cortexa5,cortexa7,cortexa8,cortexa9,cortexa15,cortexr4,cortexr4f,cortexr5,cortexm4,cortexm3,cortexm1,cortexm0" + "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,fa526,fa626,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,genericv7a,cortexa5,cortexa7,cortexa8,cortexa9,cortexa15,cortexr4,cortexr4f,cortexr5,cortexm4,cortexm3,cortexm1,cortexm0,cortexm0plus" (const (symbol_ref "((enum attr_tune) arm_tune)"))) diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 5522fc12172..2cecf4546cd 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -17877,9 +17877,9 @@ arm_print_operand (FILE *stream, rtx x, int code) memsize = MEM_SIZE (x); /* Only certain alignment specifiers are supported by the hardware. */ - if (memsize == 16 && (align % 32) == 0) + if (memsize == 32 && (align % 32) == 0) align_bits = 256; - else if (memsize == 16 && (align % 16) == 0) + else if ((memsize == 16 || memsize == 32) && (align % 16) == 0) align_bits = 128; else if (memsize >= 8 && (align % 8) == 0) align_bits = 64; diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 3cdc1535f3a..79eff0e4fe4 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -5652,6 +5652,21 @@ }" ) +;; For thumb1 split imm move [256-510] into mov [1-255] and add #255 +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "TARGET_THUMB1 && satisfies_constraint_Pe (operands[1])" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (plus:SI (match_dup 2) (match_dup 3)))] + " + { + operands[1] = GEN_INT (INTVAL (operands[1]) - 255); + operands[2] = can_create_pseudo_p () ? gen_reg_rtx (SImode) : operands[0]; + operands[3] = GEN_INT (255); + }" +) + ;; When generating pic, we need to load the symbol offset into a register. ;; So that the optimizer does not confuse this with a normal symbol load ;; we use an unspec. The offset will be loaded from a constant pool entry, diff --git a/gcc/config/arm/constraints.md b/gcc/config/arm/constraints.md index 3ff968b98ea..6b59e8772e5 100644 --- a/gcc/config/arm/constraints.md +++ b/gcc/config/arm/constraints.md @@ -30,7 +30,7 @@ ;; The following multi-letter normal constraints have been used: ;; in ARM/Thumb-2 state: Da, Db, Dc, Dn, Dl, DL, Dv, Dy, Di, Dt, Dz -;; in Thumb-1 state: Pa, Pb, Pc, Pd +;; in Thumb-1 state: Pa, Pb, Pc, Pd, Pe ;; in Thumb-2 state: Pj, PJ, Ps, Pt, Pu, Pv, Pw, Px, Py ;; The following memory constraints have been used: @@ -172,6 +172,11 @@ (and (match_code "const_int") (match_test "TARGET_THUMB1 && ival >= 0 && ival <= 7"))) +(define_constraint "Pe" + "@internal In Thumb-1 state a constant in the range 256 to +510" + (and (match_code "const_int") + (match_test "TARGET_THUMB1 && ival >= 256 && ival <= 510"))) + (define_constraint "Ps" "@internal In Thumb-2 state a constant in the range -255 to +255" (and (match_code "const_int") diff --git a/gcc/config/arm/sync.md b/gcc/config/arm/sync.md index 96de0f37d8d..03838f5d247 100644 --- a/gcc/config/arm/sync.md +++ b/gcc/config/arm/sync.md @@ -29,7 +29,7 @@ (define_code_iterator syncop [plus minus ior xor and]) (define_code_attr sync_optab - [(ior "ior") (xor "xor") (and "and") (plus "add") (minus "sub")]) + [(ior "or") (xor "xor") (and "and") (plus "add") (minus "sub")]) (define_mode_attr sync_sfx [(QI "b") (HI "h") (SI "") (DI "d")]) diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index c25f8983a79..af00aeea07a 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -3476,15 +3476,16 @@ avr_out_load_psi (rtx insn, rtx *op, int *plen) "mov r27,__tmp_reg__", op, plen, -6); } - avr_asm_len ("adiw r26,%o1" CR_TAB - "ld r24,X+" CR_TAB - "ld r25,X+" CR_TAB - "ld r26,X", op, plen, -4); + avr_asm_len ("adiw r26,%o1" CR_TAB + "ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld %C0,X", op, plen, -4); - if (reg_dest != REG_X - 2) - avr_asm_len ("sbiw r26,%o1+2", op, plen, 1); + if (reg_dest != REG_W + && !reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len ("sbiw r26,%o1+2", op, plen, 1); - return ""; + return ""; } if (reg_dest == reg_base) diff --git a/gcc/config/c6x/c6x.md b/gcc/config/c6x/c6x.md index 8e6ef4a59e2..99f02d5dc98 100644 --- a/gcc/config/c6x/c6x.md +++ b/gcc/config/c6x/c6x.md @@ -433,6 +433,7 @@ "%|%.\\tldw\\t%$\\t*+%1[%2], %0" [(set_attr "type" "load") (set_attr "units" "d_addr") + (set_attr "op_pattern" "unknown") (set_attr "dest_regfile" "a,b") (set_attr "addr_regfile" "b")]) diff --git a/gcc/config/host-linux.c b/gcc/config/host-linux.c index 94b7a0b89a7..b5357587605 100644 --- a/gcc/config/host-linux.c +++ b/gcc/config/host-linux.c @@ -68,8 +68,10 @@ # define TRY_EMPTY_VM_SPACE 0x10000000000 #elif defined(__ia64) # define TRY_EMPTY_VM_SPACE 0x2000000100000000 -#elif defined(__x86_64) +#elif defined(__x86_64) && defined(__LP64__) # define TRY_EMPTY_VM_SPACE 0x1000000000 +#elif defined(__x86_64) +# define TRY_EMPTY_VM_SPACE 0x60000000 #elif defined(__i386) # define TRY_EMPTY_VM_SPACE 0x60000000 #elif defined(__powerpc__) diff --git a/gcc/config/i386/avx2intrin.h b/gcc/config/i386/avx2intrin.h index 12ed05fe029..cebd9a2fced 100644 --- a/gcc/config/i386/avx2intrin.h +++ b/gcc/config/i386/avx2intrin.h @@ -1034,9 +1034,9 @@ _mm256_permute4x64_pd (__m256d __X, const int __M) extern __inline __m256 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) -_mm256_permutevar8x32_ps (__m256 __X, __m256 __Y) +_mm256_permutevar8x32_ps (__m256 __X, __m256i __Y) { - return (__m256) __builtin_ia32_permvarsf256 ((__v8sf)__X,(__v8sf)__Y); + return (__m256) __builtin_ia32_permvarsf256 ((__v8sf)__X, (__v8si)__Y); } #ifdef __OPTIMIZE__ diff --git a/gcc/config/i386/gnu-user-common.h b/gcc/config/i386/gnu-user-common.h new file mode 100644 index 00000000000..55549368563 --- /dev/null +++ b/gcc/config/i386/gnu-user-common.h @@ -0,0 +1,72 @@ +/* Common definitions for Intel 386 and AMD x86-64 systems using + GNU userspace. Copyright (C) 2012 Free Software Foundation, Inc. + Contributed by Ilya Enkovich. + +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/>. */ + +/* The svr4 ABI for the i386 says that records and unions are returned + in memory. In the 64bit compilation we will turn this flag off in + ix86_option_override_internal, as we never do pcc_struct_return + scheme on this target. */ +#undef DEFAULT_PCC_STRUCT_RETURN +#define DEFAULT_PCC_STRUCT_RETURN 1 + +/* We arrange for the whole %fs segment to map the tls area. */ +#undef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT +#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT MASK_TLS_DIRECT_SEG_REFS + +#define TARGET_OS_CPP_BUILTINS() \ + do \ + { \ + GNU_USER_TARGET_OS_CPP_BUILTINS(); \ + } \ + while (0) + +#undef CPP_SPEC +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" + +#undef GNU_USER_TARGET_CC1_SPEC +#define GNU_USER_TARGET_CC1_SPEC "%(cc1_cpu) %{profile:-p}" + +#undef CC1_SPEC +#define CC1_SPEC GNU_USER_TARGET_CC1_SPEC + +/* Similar to standard GNU userspace, but adding -ffast-math support. */ +#define GNU_USER_TARGET_MATHFILE_SPEC \ + "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \ + %{mpc32:crtprec32.o%s} \ + %{mpc64:crtprec64.o%s} \ + %{mpc80:crtprec80.o%s}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + GNU_USER_TARGET_MATHFILE_SPEC " " \ + GNU_USER_TARGET_ENDFILE_SPEC + +/* Put all *tf routines in libgcc. */ +#undef LIBGCC2_HAS_TF_MODE +#define LIBGCC2_HAS_TF_MODE 1 +#define LIBGCC2_TF_CEXT q +#define TF_SIZE 113 + +#define TARGET_ASM_FILE_END file_end_indicate_exec_stack + +/* The stack pointer needs to be moved while checking the stack. */ +#define STACK_CHECK_MOVING_SP 1 + +/* Static stack checking is supported by means of probes. */ +#define STACK_CHECK_STATIC_BUILTIN 1 diff --git a/gcc/config/i386/gnu-user.h b/gcc/config/i386/gnu-user.h index 98d0a25cbe3..9020be9a3a9 100644 --- a/gcc/config/i386/gnu-user.h +++ b/gcc/config/i386/gnu-user.h @@ -24,15 +24,6 @@ along with GCC; see the file COPYING3. If not see /* The .file command should always begin the output. */ #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true -/* The svr4 ABI for the i386 says that records and unions are returned - in memory. */ -#undef DEFAULT_PCC_STRUCT_RETURN -#define DEFAULT_PCC_STRUCT_RETURN 1 - -/* We arrange for the whole %gs segment to map the tls area. */ -#undef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT -#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT MASK_TLS_DIRECT_SEG_REFS - #undef ASM_COMMENT_START #define ASM_COMMENT_START "#" @@ -67,19 +58,6 @@ along with GCC; see the file COPYING3. If not see #undef WCHAR_TYPE_SIZE #define WCHAR_TYPE_SIZE BITS_PER_WORD -#define TARGET_OS_CPP_BUILTINS() \ - do \ - { \ - GNU_USER_TARGET_OS_CPP_BUILTINS(); \ - } \ - while (0) - -#undef CPP_SPEC -#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" - -#undef CC1_SPEC -#define CC1_SPEC "%(cc1_cpu) %{profile:-p}" - /* Provide a LINK_SPEC appropriate for GNU userspace. Here we provide support for the special GCC options -static and -shared, which allow us to link things in one of these three modes by applying the appropriate @@ -97,22 +75,15 @@ along with GCC; see the file COPYING3. If not see { "link_emulation", GNU_USER_LINK_EMULATION },\ { "dynamic_linker", GNU_USER_DYNAMIC_LINKER } -#undef LINK_SPEC -#define LINK_SPEC "-m %(link_emulation) %{shared:-shared} \ +#define GNU_USER_TARGET_LINK_SPEC "-m %(link_emulation) %{shared:-shared} \ %{!shared: \ %{!static: \ %{rdynamic:-export-dynamic} \ -dynamic-linker %(dynamic_linker)} \ %{static:-static}}" -/* Similar to standard GNU userspace, but adding -ffast-math support. */ -#undef ENDFILE_SPEC -#define ENDFILE_SPEC \ - "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \ - %{mpc32:crtprec32.o%s} \ - %{mpc64:crtprec64.o%s} \ - %{mpc80:crtprec80.o%s} \ - %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s" +#undef LINK_SPEC +#define LINK_SPEC GNU_USER_TARGET_LINK_SPEC /* A C statement (sans semicolon) to output to the stdio stream FILE the assembler definition of uninitialized global DECL named @@ -180,20 +151,6 @@ along with GCC; see the file COPYING3. If not see : "=d"(BASE)) #endif -/* Put all *tf routines in libgcc. */ -#undef LIBGCC2_HAS_TF_MODE -#define LIBGCC2_HAS_TF_MODE 1 -#define LIBGCC2_TF_CEXT q -#define TF_SIZE 113 - -#define TARGET_ASM_FILE_END file_end_indicate_exec_stack - -/* The stack pointer needs to be moved while checking the stack. */ -#define STACK_CHECK_MOVING_SP 1 - -/* Static stack checking is supported by means of probes. */ -#define STACK_CHECK_STATIC_BUILTIN 1 - #ifdef TARGET_LIBC_PROVIDES_SSP /* i386 glibc provides __stack_chk_guard in %gs:0x14. */ #define TARGET_THREAD_SSP_OFFSET 0x14 diff --git a/gcc/config/i386/gnu-user64.h b/gcc/config/i386/gnu-user64.h index 6f7b5de2ab8..0e66d26169b 100644 --- a/gcc/config/i386/gnu-user64.h +++ b/gcc/config/i386/gnu-user64.h @@ -24,30 +24,6 @@ a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see <http://www.gnu.org/licenses/>. */ -#define TARGET_OS_CPP_BUILTINS() \ - do \ - { \ - GNU_USER_TARGET_OS_CPP_BUILTINS(); \ - } \ - while (0) - -#undef CPP_SPEC -#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" - -#undef CC1_SPEC -#define CC1_SPEC "%(cc1_cpu) %{profile:-p}" - -/* The svr4 ABI for the i386 says that records and unions are returned - in memory. In the 64bit compilation we will turn this flag off in - ix86_option_override_internal, as we never do pcc_struct_return - scheme on this target. */ -#undef DEFAULT_PCC_STRUCT_RETURN -#define DEFAULT_PCC_STRUCT_RETURN 1 - -/* We arrange for the whole %fs segment to map the tls area. */ -#undef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT -#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT MASK_TLS_DIRECT_SEG_REFS - /* Provide a LINK_SPEC. Here we provide support for the special GCC options -static and -shared, which allow us to link things in one of these three modes by applying the appropriate combinations of @@ -77,8 +53,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see %{" SPEC_X32 ":--x32} \ %{!mno-sse2avx:%{mavx:-msse2avx}} %{msse2avx:%{!mavx:-msse2avx}}" -#undef LINK_SPEC -#define LINK_SPEC "%{" SPEC_64 ":-m " GNU_USER_LINK_EMULATION64 "} \ +#define GNU_USER_TARGET_LINK_SPEC \ + "%{" SPEC_64 ":-m " GNU_USER_LINK_EMULATION64 "} \ %{" SPEC_32 ":-m " GNU_USER_LINK_EMULATION32 "} \ %{" SPEC_X32 ":-m " GNU_USER_LINK_EMULATIONX32 "} \ %{shared:-shared} \ @@ -90,14 +66,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see %{" SPEC_X32 ":-dynamic-linker " GNU_USER_DYNAMIC_LINKERX32 "}} \ %{static:-static}}" -/* Similar to standard GNU userspace, but adding -ffast-math support. */ -#undef ENDFILE_SPEC -#define ENDFILE_SPEC \ - "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \ - %{mpc32:crtprec32.o%s} \ - %{mpc64:crtprec64.o%s} \ - %{mpc80:crtprec80.o%s} \ - %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s" +#undef LINK_SPEC +#define LINK_SPEC GNU_USER_TARGET_LINK_SPEC #if TARGET_64BIT_DEFAULT #if TARGET_BI_ARCH == 2 @@ -109,23 +79,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define MULTILIB_DEFAULTS { "m32" } #endif -/* Put all *tf routines in libgcc. */ -#undef LIBGCC2_HAS_TF_MODE -#define LIBGCC2_HAS_TF_MODE 1 -#define LIBGCC2_TF_CEXT q -#define TF_SIZE 113 - -#define TARGET_ASM_FILE_END file_end_indicate_exec_stack - -/* The stack pointer needs to be moved while checking the stack. */ -#define STACK_CHECK_MOVING_SP 1 - -/* Static stack checking is supported by means of probes. */ -#define STACK_CHECK_STATIC_BUILTIN 1 - #ifdef TARGET_LIBC_PROVIDES_SSP /* i386 glibc provides __stack_chk_guard in %gs:0x14, - x32 glibc provides it in %fs:0x18. + x32 glibc provides it in %fs:0x18. x86_64 glibc provides it in %fs:0x28. */ #define TARGET_THREAD_SSP_OFFSET \ (TARGET_64BIT ? (TARGET_X32 ? 0x18 : 0x28) : 0x14) diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c index 8adb3b46dfa..49fd4d92ca8 100644 --- a/gcc/config/i386/i386-c.c +++ b/gcc/config/i386/i386-c.c @@ -383,6 +383,11 @@ ix86_target_macros (void) cpp_define (parse_in, "__amd64__"); cpp_define (parse_in, "__x86_64"); cpp_define (parse_in, "__x86_64__"); + if (TARGET_X32) + { + cpp_define (parse_in, "_ILP32"); + cpp_define (parse_in, "__ILP32__"); + } } else { diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 8974ddc9a02..abe3f1b96ca 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -3113,14 +3113,6 @@ ix86_option_override_internal (bool main_args_p) sw = "attribute"; } -#ifdef SUBTARGET_OVERRIDE_OPTIONS - SUBTARGET_OVERRIDE_OPTIONS; -#endif - -#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS - SUBSUBTARGET_OVERRIDE_OPTIONS; -#endif - /* Turn off both OPTION_MASK_ABI_64 and OPTION_MASK_ABI_X32 if TARGET_64BIT_DEFAULT is true and TARGET_64BIT is false. */ if (TARGET_64BIT_DEFAULT && !TARGET_64BIT) @@ -3161,6 +3153,14 @@ ix86_option_override_internal (bool main_args_p) ix86_isa_flags &= ~OPTION_MASK_ABI_X32; } +#ifdef SUBTARGET_OVERRIDE_OPTIONS + SUBTARGET_OVERRIDE_OPTIONS; +#endif + +#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS + SUBSUBTARGET_OVERRIDE_OPTIONS; +#endif + /* -fPIC is the default for x86_64. */ if (TARGET_MACHO && TARGET_64BIT) flag_pic = 2; @@ -19937,7 +19937,7 @@ ix86_expand_vec_perm (rtx operands[]) vt = force_reg (maskmode, vt); mask = gen_lowpart (maskmode, mask); if (maskmode == V8SImode) - emit_insn (gen_avx2_permvarv8si (t1, vt, mask)); + emit_insn (gen_avx2_permvarv8si (t1, mask, vt)); else emit_insn (gen_avx2_pshufbv32qi3 (t1, mask, vt)); @@ -19971,13 +19971,13 @@ ix86_expand_vec_perm (rtx operands[]) the high bits of the shuffle elements. No need for us to perform an AND ourselves. */ if (one_operand_shuffle) - emit_insn (gen_avx2_permvarv8si (target, mask, op0)); + emit_insn (gen_avx2_permvarv8si (target, op0, mask)); else { t1 = gen_reg_rtx (V8SImode); t2 = gen_reg_rtx (V8SImode); - emit_insn (gen_avx2_permvarv8si (t1, mask, op0)); - emit_insn (gen_avx2_permvarv8si (t2, mask, op1)); + emit_insn (gen_avx2_permvarv8si (t1, op0, mask)); + emit_insn (gen_avx2_permvarv8si (t2, op0, mask)); goto merge_two; } return; @@ -19985,13 +19985,13 @@ ix86_expand_vec_perm (rtx operands[]) case V8SFmode: mask = gen_lowpart (V8SFmode, mask); if (one_operand_shuffle) - emit_insn (gen_avx2_permvarv8sf (target, mask, op0)); + emit_insn (gen_avx2_permvarv8sf (target, op0, mask)); else { t1 = gen_reg_rtx (V8SFmode); t2 = gen_reg_rtx (V8SFmode); - emit_insn (gen_avx2_permvarv8sf (t1, mask, op0)); - emit_insn (gen_avx2_permvarv8sf (t2, mask, op1)); + emit_insn (gen_avx2_permvarv8sf (t1, op0, mask)); + emit_insn (gen_avx2_permvarv8sf (t2, op1, mask)); goto merge_two; } return; @@ -20004,7 +20004,7 @@ ix86_expand_vec_perm (rtx operands[]) t2 = gen_reg_rtx (V8SImode); emit_insn (gen_avx_vec_concatv8si (t1, op0, op1)); emit_insn (gen_avx_vec_concatv8si (t2, mask, mask)); - emit_insn (gen_avx2_permvarv8si (t1, t2, t1)); + emit_insn (gen_avx2_permvarv8si (t1, t1, t2)); emit_insn (gen_avx_vextractf128v8si (target, t1, const0_rtx)); return; @@ -20014,7 +20014,7 @@ ix86_expand_vec_perm (rtx operands[]) mask = gen_lowpart (V4SFmode, mask); emit_insn (gen_avx_vec_concatv8sf (t1, op0, op1)); emit_insn (gen_avx_vec_concatv8sf (t2, mask, mask)); - emit_insn (gen_avx2_permvarv8sf (t1, t2, t1)); + emit_insn (gen_avx2_permvarv8sf (t1, t1, t2)); emit_insn (gen_avx_vextractf128v8sf (target, t1, const0_rtx)); return; @@ -26948,8 +26948,8 @@ static const struct builtin_description bdesc_args[] = { OPTION_MASK_ISA_AVX2, CODE_FOR_avx2_pbroadcastv4si, "__builtin_ia32_pbroadcastd128", IX86_BUILTIN_PBROADCASTD128, UNKNOWN, (int) V4SI_FTYPE_V4SI }, { OPTION_MASK_ISA_AVX2, CODE_FOR_avx2_pbroadcastv2di, "__builtin_ia32_pbroadcastq128", IX86_BUILTIN_PBROADCASTQ128, UNKNOWN, (int) V2DI_FTYPE_V2DI }, { OPTION_MASK_ISA_AVX2, CODE_FOR_avx2_permvarv8si, "__builtin_ia32_permvarsi256", IX86_BUILTIN_VPERMVARSI256, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI }, + { OPTION_MASK_ISA_AVX2, CODE_FOR_avx2_permvarv8sf, "__builtin_ia32_permvarsf256", IX86_BUILTIN_VPERMVARSF256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SI }, { OPTION_MASK_ISA_AVX2, CODE_FOR_avx2_permv4df, "__builtin_ia32_permdf256", IX86_BUILTIN_VPERMDF256, UNKNOWN, (int) V4DF_FTYPE_V4DF_INT }, - { OPTION_MASK_ISA_AVX2, CODE_FOR_avx2_permvarv8sf, "__builtin_ia32_permvarsf256", IX86_BUILTIN_VPERMVARSF256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF }, { OPTION_MASK_ISA_AVX2, CODE_FOR_avx2_permv4di, "__builtin_ia32_permdi256", IX86_BUILTIN_VPERMDI256, UNKNOWN, (int) V4DI_FTYPE_V4DI_INT }, { OPTION_MASK_ISA_AVX2, CODE_FOR_avx2_permv2ti, "__builtin_ia32_permti256", IX86_BUILTIN_VPERMTI256, UNKNOWN, (int) V4DI_FTYPE_V4DI_V4DI_INT }, { OPTION_MASK_ISA_AVX2, CODE_FOR_avx2_extracti128, "__builtin_ia32_extract128i256", IX86_BUILTIN_VEXTRACT128I256, UNKNOWN, (int) V2DI_FTYPE_V4DI_INT }, @@ -36126,9 +36126,9 @@ expand_vec_perm_pshufb (struct expand_vec_perm_d *d) else if (vmode == V32QImode) emit_insn (gen_avx2_pshufbv32qi3 (target, op0, vperm)); else if (vmode == V8SFmode) - emit_insn (gen_avx2_permvarv8sf (target, vperm, op0)); + emit_insn (gen_avx2_permvarv8sf (target, op0, vperm)); else - emit_insn (gen_avx2_permvarv8si (target, vperm, op0)); + emit_insn (gen_avx2_permvarv8si (target, op0, vperm)); } else { diff --git a/gcc/config/i386/linux-common.h b/gcc/config/i386/linux-common.h new file mode 100644 index 00000000000..fd53b32ef38 --- /dev/null +++ b/gcc/config/i386/linux-common.h @@ -0,0 +1,55 @@ +/* Definitions for Intel 386 running Linux-based GNU systems with ELF format. + Copyright (C) 2012 Free Software Foundation, Inc. + Contributed by Ilya Enkovich. + +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/>. */ + +#undef TARGET_OS_CPP_BUILTINS +#define TARGET_OS_CPP_BUILTINS() \ + do \ + { \ + GNU_USER_TARGET_OS_CPP_BUILTINS(); \ + ANDROID_TARGET_OS_CPP_BUILTINS(); \ + } \ + while (0) + +#undef CC1_SPEC +#define CC1_SPEC \ + LINUX_OR_ANDROID_CC (GNU_USER_TARGET_CC1_SPEC, \ + GNU_USER_TARGET_CC1_SPEC " " ANDROID_CC1_SPEC) + +#undef LINK_SPEC +#define LINK_SPEC \ + LINUX_OR_ANDROID_LD (GNU_USER_TARGET_LINK_SPEC, \ + GNU_USER_TARGET_LINK_SPEC " " ANDROID_LINK_SPEC) + +#undef LIB_SPEC +#define LIB_SPEC \ + LINUX_OR_ANDROID_LD (GNU_USER_TARGET_LIB_SPEC, \ + GNU_USER_TARGET_LIB_SPEC " " ANDROID_LIB_SPEC) + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + LINUX_OR_ANDROID_LD (GNU_USER_TARGET_STARTFILE_SPEC, \ + ANDROID_STARTFILE_SPEC) + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + LINUX_OR_ANDROID_LD (GNU_USER_TARGET_MATHFILE_SPEC " " \ + GNU_USER_TARGET_ENDFILE_SPEC, \ + GNU_USER_TARGET_MATHFILE_SPEC " " \ + ANDROID_ENDFILE_SPEC) diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index b63d774e43f..d270c634ae0 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -79,8 +79,7 @@ UNSPEC_VCVTPS2PH ;; For AVX2 support - UNSPEC_VPERMSI - UNSPEC_VPERMSF + UNSPEC_VPERMVAR UNSPEC_VPERMTI UNSPEC_GATHER UNSPEC_VSIBADDR @@ -5305,83 +5304,33 @@ (sign_extend:V8SI (vec_select:V8HI (match_operand:V16HI 1 "nonimmediate_operand") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14)]))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14)]))) (sign_extend:V8SI (vec_select:V8HI (match_operand:V16HI 2 "nonimmediate_operand") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14)])))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14)])))) (mult:V8SI (sign_extend:V8SI (vec_select:V8HI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15)]))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15)]))) (sign_extend:V8SI (vec_select:V8HI (match_dup 2) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15)]))))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15)]))))))] "TARGET_AVX2" "ix86_fixup_binary_operands_no_copy (MULT, V16HImode, operands);") -(define_expand "sse2_pmaddwd" - [(set (match_operand:V4SI 0 "register_operand") - (plus:V4SI - (mult:V4SI - (sign_extend:V4SI - (vec_select:V4HI - (match_operand:V8HI 1 "nonimmediate_operand") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)]))) - (sign_extend:V4SI - (vec_select:V4HI - (match_operand:V8HI 2 "nonimmediate_operand") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)])))) - (mult:V4SI - (sign_extend:V4SI - (vec_select:V4HI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))) - (sign_extend:V4SI - (vec_select:V4HI (match_dup 2) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))))))] - "TARGET_SSE2" - "ix86_fixup_binary_operands_no_copy (MULT, V8HImode, operands);") - (define_insn "*avx2_pmaddwd" [(set (match_operand:V8SI 0 "register_operand" "=x") (plus:V8SI @@ -5389,52 +5338,62 @@ (sign_extend:V8SI (vec_select:V8HI (match_operand:V16HI 1 "nonimmediate_operand" "%x") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14)]))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14)]))) (sign_extend:V8SI (vec_select:V8HI (match_operand:V16HI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14)])))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14)])))) (mult:V8SI (sign_extend:V8SI (vec_select:V8HI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15)]))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15)]))) (sign_extend:V8SI (vec_select:V8HI (match_dup 2) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15)]))))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15)]))))))] "TARGET_AVX2 && ix86_binary_operator_ok (MULT, V16HImode, operands)" "vpmaddwd\t{%2, %1, %0|%0, %1, %2}" [(set_attr "type" "sseiadd") (set_attr "prefix" "vex") (set_attr "mode" "OI")]) +(define_expand "sse2_pmaddwd" + [(set (match_operand:V4SI 0 "register_operand") + (plus:V4SI + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "nonimmediate_operand") + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "nonimmediate_operand") + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)])))) + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI (match_dup 1) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)]))) + (sign_extend:V4SI + (vec_select:V4HI (match_dup 2) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)]))))))] + "TARGET_SSE2" + "ix86_fixup_binary_operands_no_copy (MULT, V8HImode, operands);") + (define_insn "*sse2_pmaddwd" [(set (match_operand:V4SI 0 "register_operand" "=x,x") (plus:V4SI @@ -5442,30 +5401,22 @@ (sign_extend:V4SI (vec_select:V4HI (match_operand:V8HI 1 "nonimmediate_operand" "%0,x") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)]))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)]))) (sign_extend:V4SI (vec_select:V4HI (match_operand:V8HI 2 "nonimmediate_operand" "xm,xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)])))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)])))) (mult:V4SI (sign_extend:V4SI (vec_select:V4HI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)]))) (sign_extend:V4SI (vec_select:V4HI (match_dup 2) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)]))))))] "TARGET_SSE2 && ix86_binary_operator_ok (MULT, V8HImode, operands)" "@ pmaddwd\t{%2, %0|%0, %2} @@ -5489,8 +5440,9 @@ (define_insn "*<sse4_1_avx2>_mul<mode>3" [(set (match_operand:VI4_AVX2 0 "register_operand" "=x,x") - (mult:VI4_AVX2 (match_operand:VI4_AVX2 1 "nonimmediate_operand" "%0,x") - (match_operand:VI4_AVX2 2 "nonimmediate_operand" "xm,xm")))] + (mult:VI4_AVX2 + (match_operand:VI4_AVX2 1 "nonimmediate_operand" "%0,x") + (match_operand:VI4_AVX2 2 "nonimmediate_operand" "xm,xm")))] "TARGET_SSE4_1 && ix86_binary_operator_ok (MULT, <MODE>mode, operands)" "@ pmulld\t{%2, %0|%0, %2} @@ -7021,9 +6973,10 @@ rtx t2 = gen_reg_rtx (<MODE>mode); emit_insn (gen_avx2_interleave_low<mode> (t1, operands[1], operands[2])); emit_insn (gen_avx2_interleave_high<mode> (t2, operands[1], operands[2])); - emit_insn (gen_avx2_permv2ti (gen_lowpart (V4DImode, operands[0]), - gen_lowpart (V4DImode, t1), - gen_lowpart (V4DImode, t2), GEN_INT (1 + (3 << 4)))); + emit_insn (gen_avx2_permv2ti + (gen_lowpart (V4DImode, operands[0]), + gen_lowpart (V4DImode, t1), + gen_lowpart (V4DImode, t2), GEN_INT (1 + (3 << 4)))); DONE; }) @@ -7037,9 +6990,10 @@ rtx t2 = gen_reg_rtx (<MODE>mode); emit_insn (gen_avx2_interleave_low<mode> (t1, operands[1], operands[2])); emit_insn (gen_avx2_interleave_high<mode> (t2, operands[1], operands[2])); - emit_insn (gen_avx2_permv2ti (gen_lowpart (V4DImode, operands[0]), - gen_lowpart (V4DImode, t1), - gen_lowpart (V4DImode, t2), GEN_INT (0 + (2 << 4)))); + emit_insn (gen_avx2_permv2ti + (gen_lowpart (V4DImode, operands[0]), + gen_lowpart (V4DImode, t1), + gen_lowpart (V4DImode, t2), GEN_INT (0 + (2 << 4)))); DONE; }) @@ -8038,9 +7992,10 @@ ;; surely not generally useful. (define_insn "<sse2_avx2>_psadbw" [(set (match_operand:VI8_AVX2 0 "register_operand" "=x,x") - (unspec:VI8_AVX2 [(match_operand:<ssebytemode> 1 "register_operand" "0,x") - (match_operand:<ssebytemode> 2 "nonimmediate_operand" "xm,xm")] - UNSPEC_PSADBW))] + (unspec:VI8_AVX2 + [(match_operand:<ssebytemode> 1 "register_operand" "0,x") + (match_operand:<ssebytemode> 2 "nonimmediate_operand" "xm,xm")] + UNSPEC_PSADBW))] "TARGET_SSE2" "@ psadbw\t{%2, %0|%0, %2} @@ -8176,375 +8131,125 @@ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(define_insn "avx2_phaddwv16hi3" - [(set (match_operand:V16HI 0 "register_operand" "=x") - (vec_concat:V16HI - (vec_concat:V8HI - (vec_concat:V4HI - (vec_concat:V2HI - (plus:HI - (vec_select:HI - (match_operand:V16HI 1 "register_operand" "x") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 5)]))) - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 7)]))))) - (vec_concat:V4HI - (vec_concat:V2HI - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 8)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 9)]))) - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 10)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 11)])))) - (vec_concat:V2HI - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 12)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 13)]))) - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 14)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 15)])))))) - (vec_concat:V8HI - (vec_concat:V4HI - (vec_concat:V2HI - (plus:HI - (vec_select:HI - (match_operand:V16HI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 5)]))) - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 7)]))))) - (vec_concat:V4HI - (vec_concat:V2HI - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 8)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 9)]))) - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 10)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 11)])))) - (vec_concat:V2HI - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 12)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 13)]))) - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 14)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 15)]))))))))] - "TARGET_AVX2" - "vphaddw\t{%2, %1, %0|%0, %1, %2}" - [(set_attr "type" "sseiadd") - (set_attr "prefix_extra" "1") - (set_attr "prefix" "vex") - (set_attr "mode" "OI")]) - -(define_insn "ssse3_phaddwv8hi3" - [(set (match_operand:V8HI 0 "register_operand" "=x,x") - (vec_concat:V8HI - (vec_concat:V4HI - (vec_concat:V2HI - (plus:HI - (vec_select:HI - (match_operand:V8HI 1 "register_operand" "0,x") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 5)]))) - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 7)]))))) - (vec_concat:V4HI - (vec_concat:V2HI - (plus:HI - (vec_select:HI - (match_operand:V8HI 2 "nonimmediate_operand" "xm,xm") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 5)]))) - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 7)])))))))] - "TARGET_SSSE3" - "@ - phaddw\t{%2, %0|%0, %2} - vphaddw\t{%2, %1, %0|%0, %1, %2}" - [(set_attr "isa" "noavx,avx") - (set_attr "type" "sseiadd") - (set_attr "atom_unit" "complex") - (set_attr "prefix_data16" "1,*") - (set_attr "prefix_extra" "1") - (set_attr "prefix" "orig,vex") - (set_attr "mode" "TI")]) +(define_code_iterator ssse3_plusminus [plus ss_plus minus ss_minus]) -(define_insn "ssse3_phaddwv4hi3" - [(set (match_operand:V4HI 0 "register_operand" "=y") - (vec_concat:V4HI - (vec_concat:V2HI - (plus:HI - (vec_select:HI - (match_operand:V4HI 1 "register_operand" "0") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (plus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (plus:HI - (vec_select:HI - (match_operand:V4HI 2 "nonimmediate_operand" "ym") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (plus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 3)]))))))] - "TARGET_SSSE3" - "phaddw\t{%2, %0|%0, %2}" - [(set_attr "type" "sseiadd") - (set_attr "atom_unit" "complex") - (set_attr "prefix_extra" "1") - (set (attr "prefix_rex") (symbol_ref "x86_extended_reg_mentioned_p (insn)")) - (set_attr "mode" "DI")]) - -(define_insn "avx2_phadddv8si3" - [(set (match_operand:V8SI 0 "register_operand" "=x") - (vec_concat:V8SI - (vec_concat:V4SI - (vec_concat:V2SI - (plus:SI - (vec_select:SI - (match_operand:V8SI 1 "register_operand" "x") - (parallel [(const_int 0)])) - (vec_select:SI (match_dup 1) (parallel [(const_int 1)]))) - (plus:SI - (vec_select:SI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:SI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2SI - (plus:SI - (vec_select:SI (match_dup 1) (parallel [(const_int 4)])) - (vec_select:SI (match_dup 1) (parallel [(const_int 5)]))) - (plus:SI - (vec_select:SI (match_dup 1) (parallel [(const_int 6)])) - (vec_select:SI (match_dup 1) (parallel [(const_int 7)]))))) - (vec_concat:V4SI - (vec_concat:V2SI - (plus:SI - (vec_select:SI - (match_operand:V8SI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0)])) - (vec_select:SI (match_dup 2) (parallel [(const_int 1)]))) - (plus:SI - (vec_select:SI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:SI (match_dup 2) (parallel [(const_int 3)])))) - (vec_concat:V2SI - (plus:SI - (vec_select:SI (match_dup 2) (parallel [(const_int 4)])) - (vec_select:SI (match_dup 2) (parallel [(const_int 5)]))) - (plus:SI - (vec_select:SI (match_dup 2) (parallel [(const_int 6)])) - (vec_select:SI (match_dup 2) (parallel [(const_int 7)])))))))] - "TARGET_AVX2" - "vphaddd\t{%2, %1, %0|%0, %1, %2}" - [(set_attr "type" "sseiadd") - (set_attr "prefix_extra" "1") - (set_attr "prefix" "vex") - (set_attr "mode" "OI")]) - -(define_insn "ssse3_phadddv4si3" - [(set (match_operand:V4SI 0 "register_operand" "=x,x") - (vec_concat:V4SI - (vec_concat:V2SI - (plus:SI - (vec_select:SI - (match_operand:V4SI 1 "register_operand" "0,x") - (parallel [(const_int 0)])) - (vec_select:SI (match_dup 1) (parallel [(const_int 1)]))) - (plus:SI - (vec_select:SI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:SI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2SI - (plus:SI - (vec_select:SI - (match_operand:V4SI 2 "nonimmediate_operand" "xm,xm") - (parallel [(const_int 0)])) - (vec_select:SI (match_dup 2) (parallel [(const_int 1)]))) - (plus:SI - (vec_select:SI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:SI (match_dup 2) (parallel [(const_int 3)]))))))] - "TARGET_SSSE3" - "@ - phaddd\t{%2, %0|%0, %2} - vphaddd\t{%2, %1, %0|%0, %1, %2}" - [(set_attr "isa" "noavx,avx") - (set_attr "type" "sseiadd") - (set_attr "atom_unit" "complex") - (set_attr "prefix_data16" "1,*") - (set_attr "prefix_extra" "1") - (set_attr "prefix" "orig,vex") - (set_attr "mode" "TI")]) - -(define_insn "ssse3_phadddv2si3" - [(set (match_operand:V2SI 0 "register_operand" "=y") - (vec_concat:V2SI - (plus:SI - (vec_select:SI - (match_operand:V2SI 1 "register_operand" "0") - (parallel [(const_int 0)])) - (vec_select:SI (match_dup 1) (parallel [(const_int 1)]))) - (plus:SI - (vec_select:SI - (match_operand:V2SI 2 "nonimmediate_operand" "ym") - (parallel [(const_int 0)])) - (vec_select:SI (match_dup 2) (parallel [(const_int 1)])))))] - "TARGET_SSSE3" - "phaddd\t{%2, %0|%0, %2}" - [(set_attr "type" "sseiadd") - (set_attr "atom_unit" "complex") - (set_attr "prefix_extra" "1") - (set (attr "prefix_rex") (symbol_ref "x86_extended_reg_mentioned_p (insn)")) - (set_attr "mode" "DI")]) - -(define_insn "avx2_phaddswv16hi3" +(define_insn "avx2_ph<plusminus_mnemonic>wv16hi3" [(set (match_operand:V16HI 0 "register_operand" "=x") (vec_concat:V16HI (vec_concat:V8HI (vec_concat:V4HI (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_operand:V16HI 1 "register_operand" "x") (parallel [(const_int 0)])) (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 4)])) (vec_select:HI (match_dup 1) (parallel [(const_int 5)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 6)])) (vec_select:HI (match_dup 1) (parallel [(const_int 7)]))))) (vec_concat:V4HI (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 8)])) (vec_select:HI (match_dup 1) (parallel [(const_int 9)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 10)])) (vec_select:HI (match_dup 1) (parallel [(const_int 11)])))) (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 12)])) (vec_select:HI (match_dup 1) (parallel [(const_int 13)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 14)])) (vec_select:HI (match_dup 1) (parallel [(const_int 15)])))))) (vec_concat:V8HI (vec_concat:V4HI (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_operand:V16HI 2 "nonimmediate_operand" "xm") (parallel [(const_int 0)])) (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) (vec_select:HI (match_dup 2) (parallel [(const_int 3)])))) (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 4)])) (vec_select:HI (match_dup 2) (parallel [(const_int 5)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 6)])) (vec_select:HI (match_dup 2) (parallel [(const_int 7)]))))) (vec_concat:V4HI (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 8)])) (vec_select:HI (match_dup 2) (parallel [(const_int 9)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 10)])) (vec_select:HI (match_dup 2) (parallel [(const_int 11)])))) (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 12)])) (vec_select:HI (match_dup 2) (parallel [(const_int 13)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 14)])) (vec_select:HI (match_dup 2) (parallel [(const_int 15)]))))))))] "TARGET_AVX2" - "vphaddsw\t{%2, %1, %0|%0, %1, %2}" + "vph<plusminus_mnemonic>w\t{%2, %1, %0|%0, %1, %2}" [(set_attr "type" "sseiadd") (set_attr "prefix_extra" "1") (set_attr "prefix" "vex") (set_attr "mode" "OI")]) -(define_insn "ssse3_phaddswv8hi3" +(define_insn "ssse3_ph<plusminus_mnemonic>wv8hi3" [(set (match_operand:V8HI 0 "register_operand" "=x,x") (vec_concat:V8HI (vec_concat:V4HI (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_operand:V8HI 1 "register_operand" "0,x") (parallel [(const_int 0)])) (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 4)])) (vec_select:HI (match_dup 1) (parallel [(const_int 5)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 6)])) (vec_select:HI (match_dup 1) (parallel [(const_int 7)]))))) (vec_concat:V4HI (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_operand:V8HI 2 "nonimmediate_operand" "xm,xm") (parallel [(const_int 0)])) (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) (vec_select:HI (match_dup 2) (parallel [(const_int 3)])))) (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 4)])) (vec_select:HI (match_dup 2) (parallel [(const_int 5)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 6)])) (vec_select:HI (match_dup 2) (parallel [(const_int 7)])))))))] "TARGET_SSSE3" "@ - phaddsw\t{%2, %0|%0, %2} - vphaddsw\t{%2, %1, %0|%0, %1, %2}" + ph<plusminus_mnemonic>w\t{%2, %0|%0, %2} + vph<plusminus_mnemonic>w\t{%2, %1, %0|%0, %1, %2}" [(set_attr "isa" "noavx,avx") (set_attr "type" "sseiadd") (set_attr "atom_unit" "complex") @@ -8553,259 +8258,104 @@ (set_attr "prefix" "orig,vex") (set_attr "mode" "TI")]) -(define_insn "ssse3_phaddswv4hi3" +(define_insn "ssse3_ph<plusminus_mnemonic>wv4hi3" [(set (match_operand:V4HI 0 "register_operand" "=y") (vec_concat:V4HI (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_operand:V4HI 1 "register_operand" "0") (parallel [(const_int 0)])) (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) (vec_concat:V2HI - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_operand:V4HI 2 "nonimmediate_operand" "ym") (parallel [(const_int 0)])) (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (ss_plus:HI + (ssse3_plusminus:HI (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) (vec_select:HI (match_dup 2) (parallel [(const_int 3)]))))))] "TARGET_SSSE3" - "phaddsw\t{%2, %0|%0, %2}" + "ph<plusminus_mnemonic>w\t{%2, %0|%0, %2}" [(set_attr "type" "sseiadd") (set_attr "atom_unit" "complex") (set_attr "prefix_extra" "1") (set (attr "prefix_rex") (symbol_ref "x86_extended_reg_mentioned_p (insn)")) (set_attr "mode" "DI")]) -(define_insn "avx2_phsubwv16hi3" - [(set (match_operand:V16HI 0 "register_operand" "=x") - (vec_concat:V16HI - (vec_concat:V8HI - (vec_concat:V4HI - (vec_concat:V2HI - (minus:HI - (vec_select:HI - (match_operand:V16HI 1 "register_operand" "x") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 5)]))) - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 7)]))))) - (vec_concat:V4HI - (vec_concat:V2HI - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 8)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 9)]))) - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 10)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 11)])))) - (vec_concat:V2HI - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 12)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 13)]))) - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 14)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 15)])))))) - (vec_concat:V8HI - (vec_concat:V4HI - (vec_concat:V2HI - (minus:HI - (vec_select:HI - (match_operand:V16HI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 5)]))) - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 7)]))))) - (vec_concat:V4HI - (vec_concat:V2HI - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 8)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 9)]))) - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 10)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 11)])))) - (vec_concat:V2HI - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 12)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 13)]))) - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 14)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 15)]))))))))] - "TARGET_AVX2" - "vphsubw\t{%2, %1, %0|%0, %1, %2}" - [(set_attr "type" "sseiadd") - (set_attr "prefix_extra" "1") - (set_attr "prefix" "vex") - (set_attr "mode" "OI")]) - -(define_insn "ssse3_phsubwv8hi3" - [(set (match_operand:V8HI 0 "register_operand" "=x,x") - (vec_concat:V8HI - (vec_concat:V4HI - (vec_concat:V2HI - (minus:HI - (vec_select:HI - (match_operand:V8HI 1 "register_operand" "0,x") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 5)]))) - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 7)]))))) - (vec_concat:V4HI - (vec_concat:V2HI - (minus:HI - (vec_select:HI - (match_operand:V8HI 2 "nonimmediate_operand" "xm,xm") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 5)]))) - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 7)])))))))] - "TARGET_SSSE3" - "@ - phsubw\t{%2, %0|%0, %2} - vphsubw\t{%2, %1, %0|%0, %1, %2}" - [(set_attr "isa" "noavx,avx") - (set_attr "type" "sseiadd") - (set_attr "atom_unit" "complex") - (set_attr "prefix_data16" "1,*") - (set_attr "prefix_extra" "1") - (set_attr "prefix" "orig,vex") - (set_attr "mode" "TI")]) - -(define_insn "ssse3_phsubwv4hi3" - [(set (match_operand:V4HI 0 "register_operand" "=y") - (vec_concat:V4HI - (vec_concat:V2HI - (minus:HI - (vec_select:HI - (match_operand:V4HI 1 "register_operand" "0") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (minus:HI - (vec_select:HI - (match_operand:V4HI 2 "nonimmediate_operand" "ym") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 3)]))))))] - "TARGET_SSSE3" - "phsubw\t{%2, %0|%0, %2}" - [(set_attr "type" "sseiadd") - (set_attr "atom_unit" "complex") - (set_attr "prefix_extra" "1") - (set (attr "prefix_rex") (symbol_ref "x86_extended_reg_mentioned_p (insn)")) - (set_attr "mode" "DI")]) - -(define_insn "avx2_phsubdv8si3" +(define_insn "avx2_ph<plusminus_mnemonic>dv8si3" [(set (match_operand:V8SI 0 "register_operand" "=x") (vec_concat:V8SI (vec_concat:V4SI (vec_concat:V2SI - (minus:SI + (plusminus:SI (vec_select:SI (match_operand:V8SI 1 "register_operand" "x") (parallel [(const_int 0)])) (vec_select:SI (match_dup 1) (parallel [(const_int 1)]))) - (minus:SI + (plusminus:SI (vec_select:SI (match_dup 1) (parallel [(const_int 2)])) (vec_select:SI (match_dup 1) (parallel [(const_int 3)])))) (vec_concat:V2SI - (minus:SI + (plusminus:SI (vec_select:SI (match_dup 1) (parallel [(const_int 4)])) (vec_select:SI (match_dup 1) (parallel [(const_int 5)]))) - (minus:SI + (plusminus:SI (vec_select:SI (match_dup 1) (parallel [(const_int 6)])) (vec_select:SI (match_dup 1) (parallel [(const_int 7)]))))) (vec_concat:V4SI (vec_concat:V2SI - (minus:SI + (plusminus:SI (vec_select:SI (match_operand:V8SI 2 "nonimmediate_operand" "xm") (parallel [(const_int 0)])) (vec_select:SI (match_dup 2) (parallel [(const_int 1)]))) - (minus:SI + (plusminus:SI (vec_select:SI (match_dup 2) (parallel [(const_int 2)])) (vec_select:SI (match_dup 2) (parallel [(const_int 3)])))) (vec_concat:V2SI - (minus:SI + (plusminus:SI (vec_select:SI (match_dup 2) (parallel [(const_int 4)])) (vec_select:SI (match_dup 2) (parallel [(const_int 5)]))) - (minus:SI + (plusminus:SI (vec_select:SI (match_dup 2) (parallel [(const_int 6)])) (vec_select:SI (match_dup 2) (parallel [(const_int 7)])))))))] "TARGET_AVX2" - "vphsubd\t{%2, %1, %0|%0, %1, %2}" + "vph<plusminus_mnemonic>d\t{%2, %1, %0|%0, %1, %2}" [(set_attr "type" "sseiadd") (set_attr "prefix_extra" "1") (set_attr "prefix" "vex") (set_attr "mode" "OI")]) -(define_insn "ssse3_phsubdv4si3" +(define_insn "ssse3_ph<plusminus_mnemonic>dv4si3" [(set (match_operand:V4SI 0 "register_operand" "=x,x") (vec_concat:V4SI (vec_concat:V2SI - (minus:SI + (plusminus:SI (vec_select:SI (match_operand:V4SI 1 "register_operand" "0,x") (parallel [(const_int 0)])) (vec_select:SI (match_dup 1) (parallel [(const_int 1)]))) - (minus:SI + (plusminus:SI (vec_select:SI (match_dup 1) (parallel [(const_int 2)])) (vec_select:SI (match_dup 1) (parallel [(const_int 3)])))) (vec_concat:V2SI - (minus:SI + (plusminus:SI (vec_select:SI (match_operand:V4SI 2 "nonimmediate_operand" "xm,xm") (parallel [(const_int 0)])) (vec_select:SI (match_dup 2) (parallel [(const_int 1)]))) - (minus:SI + (plusminus:SI (vec_select:SI (match_dup 2) (parallel [(const_int 2)])) (vec_select:SI (match_dup 2) (parallel [(const_int 3)]))))))] "TARGET_SSSE3" "@ - phsubd\t{%2, %0|%0, %2} - vphsubd\t{%2, %1, %0|%0, %1, %2}" - + ph<plusminus_mnemonic>d\t{%2, %0|%0, %2} + vph<plusminus_mnemonic>d\t{%2, %1, %0|%0, %1, %2}" [(set_attr "isa" "noavx,avx") (set_attr "type" "sseiadd") (set_attr "atom_unit" "complex") @@ -8814,175 +8364,21 @@ (set_attr "prefix" "orig,vex") (set_attr "mode" "TI")]) -(define_insn "ssse3_phsubdv2si3" +(define_insn "ssse3_ph<plusminus_mnemonic>dv2si3" [(set (match_operand:V2SI 0 "register_operand" "=y") (vec_concat:V2SI - (minus:SI + (plusminus:SI (vec_select:SI (match_operand:V2SI 1 "register_operand" "0") (parallel [(const_int 0)])) (vec_select:SI (match_dup 1) (parallel [(const_int 1)]))) - (minus:SI + (plusminus:SI (vec_select:SI (match_operand:V2SI 2 "nonimmediate_operand" "ym") (parallel [(const_int 0)])) (vec_select:SI (match_dup 2) (parallel [(const_int 1)])))))] "TARGET_SSSE3" - "phsubd\t{%2, %0|%0, %2}" - [(set_attr "type" "sseiadd") - (set_attr "atom_unit" "complex") - (set_attr "prefix_extra" "1") - (set (attr "prefix_rex") (symbol_ref "x86_extended_reg_mentioned_p (insn)")) - (set_attr "mode" "DI")]) - -(define_insn "avx2_phsubswv16hi3" - [(set (match_operand:V16HI 0 "register_operand" "=x") - (vec_concat:V16HI - (vec_concat:V8HI - (vec_concat:V4HI - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI - (match_operand:V16HI 1 "register_operand" "x") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 5)]))) - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 7)]))))) - (vec_concat:V4HI - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 8)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 9)]))) - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 10)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 11)])))) - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 12)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 13)]))) - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 14)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 15)])))))) - (vec_concat:V8HI - (vec_concat:V4HI - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI - (match_operand:V16HI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 5)]))) - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 7)]))))) - (vec_concat:V4HI - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 8)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 9)]))) - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 10)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 11)])))) - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 12)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 13)]))) - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 14)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 15)]))))))))] - "TARGET_AVX2" - "vphsubsw\t{%2, %1, %0|%0, %1, %2}" - [(set_attr "type" "sseiadd") - (set_attr "prefix_extra" "1") - (set_attr "prefix" "vex") - (set_attr "mode" "OI")]) - -(define_insn "ssse3_phsubswv8hi3" - [(set (match_operand:V8HI 0 "register_operand" "=x,x") - (vec_concat:V8HI - (vec_concat:V4HI - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI - (match_operand:V8HI 1 "register_operand" "0,x") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 5)]))) - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 7)]))))) - (vec_concat:V4HI - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI - (match_operand:V8HI 2 "nonimmediate_operand" "xm,xm") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 4)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 5)]))) - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 6)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 7)])))))))] - "TARGET_SSSE3" - "@ - phsubsw\t{%2, %0|%0, %2} - vphsubsw\t{%2, %1, %0|%0, %1, %2}" - [(set_attr "isa" "noavx,avx") - (set_attr "type" "sseiadd") - (set_attr "atom_unit" "complex") - (set_attr "prefix_data16" "1,*") - (set_attr "prefix_extra" "1") - (set_attr "prefix" "orig,vex") - (set_attr "mode" "TI")]) - -(define_insn "ssse3_phsubswv4hi3" - [(set (match_operand:V4HI 0 "register_operand" "=y") - (vec_concat:V4HI - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI - (match_operand:V4HI 1 "register_operand" "0") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 1)]))) - (ss_minus:HI - (vec_select:HI (match_dup 1) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 1) (parallel [(const_int 3)])))) - (vec_concat:V2HI - (ss_minus:HI - (vec_select:HI - (match_operand:V4HI 2 "nonimmediate_operand" "ym") - (parallel [(const_int 0)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 1)]))) - (ss_minus:HI - (vec_select:HI (match_dup 2) (parallel [(const_int 2)])) - (vec_select:HI (match_dup 2) (parallel [(const_int 3)]))))))] - "TARGET_SSSE3" - "phsubsw\t{%2, %0|%0, %2}" + "ph<plusminus_mnemonic>d\t{%2, %0|%0, %2}" [(set_attr "type" "sseiadd") (set_attr "atom_unit" "complex") (set_attr "prefix_extra" "1") @@ -8996,78 +8392,46 @@ (zero_extend:V16HI (vec_select:V16QI (match_operand:V32QI 1 "register_operand" "x") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14) - (const_int 16) - (const_int 18) - (const_int 20) - (const_int 22) - (const_int 24) - (const_int 26) - (const_int 28) - (const_int 30)]))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14) + (const_int 16) (const_int 18) + (const_int 20) (const_int 22) + (const_int 24) (const_int 26) + (const_int 28) (const_int 30)]))) (sign_extend:V16HI (vec_select:V16QI (match_operand:V32QI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14) - (const_int 16) - (const_int 18) - (const_int 20) - (const_int 22) - (const_int 24) - (const_int 26) - (const_int 28) - (const_int 30)])))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14) + (const_int 16) (const_int 18) + (const_int 20) (const_int 22) + (const_int 24) (const_int 26) + (const_int 28) (const_int 30)])))) (mult:V16HI (zero_extend:V16HI (vec_select:V16QI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15) - (const_int 17) - (const_int 19) - (const_int 21) - (const_int 23) - (const_int 25) - (const_int 27) - (const_int 29) - (const_int 31)]))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15) + (const_int 17) (const_int 19) + (const_int 21) (const_int 23) + (const_int 25) (const_int 27) + (const_int 29) (const_int 31)]))) (sign_extend:V16HI (vec_select:V16QI (match_dup 2) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15) - (const_int 17) - (const_int 19) - (const_int 21) - (const_int 23) - (const_int 25) - (const_int 27) - (const_int 29) - (const_int 31)]))))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15) + (const_int 17) (const_int 19) + (const_int 21) (const_int 23) + (const_int 25) (const_int 27) + (const_int 29) (const_int 31)]))))))] "TARGET_AVX2" "vpmaddubsw\t{%2, %1, %0|%0, %1, %2}" [(set_attr "type" "sseiadd") @@ -9082,46 +8446,30 @@ (zero_extend:V8HI (vec_select:V8QI (match_operand:V16QI 1 "register_operand" "0,x") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14)]))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14)]))) (sign_extend:V8HI (vec_select:V8QI (match_operand:V16QI 2 "nonimmediate_operand" "xm,xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14)])))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14)])))) (mult:V8HI (zero_extend:V8HI (vec_select:V8QI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15)]))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15)]))) (sign_extend:V8HI (vec_select:V8QI (match_dup 2) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15)]))))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15)]))))))] "TARGET_SSSE3" "@ pmaddubsw\t{%2, %0|%0, %2} @@ -9141,30 +8489,22 @@ (zero_extend:V4HI (vec_select:V4QI (match_operand:V8QI 1 "register_operand" "0") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)]))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)]))) (sign_extend:V4HI (vec_select:V4QI (match_operand:V8QI 2 "nonimmediate_operand" "ym") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)])))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)])))) (mult:V4HI (zero_extend:V4HI (vec_select:V4QI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)]))) (sign_extend:V4HI (vec_select:V4QI (match_dup 2) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)]))))))] "TARGET_SSSE3" "pmaddubsw\t{%2, %0|%0, %2}" [(set_attr "type" "sseiadd") @@ -9315,9 +8655,10 @@ (define_insn "<ssse3_avx2>_pshufb<mode>3" [(set (match_operand:VI1_AVX2 0 "register_operand" "=x,x") - (unspec:VI1_AVX2 [(match_operand:VI1_AVX2 1 "register_operand" "0,x") - (match_operand:VI1_AVX2 2 "nonimmediate_operand" "xm,xm")] - UNSPEC_PSHUFB))] + (unspec:VI1_AVX2 + [(match_operand:VI1_AVX2 1 "register_operand" "0,x") + (match_operand:VI1_AVX2 2 "nonimmediate_operand" "xm,xm")] + UNSPEC_PSHUFB))] "TARGET_SSSE3" "@ pshufb\t{%2, %0|%0, %2} @@ -9373,10 +8714,11 @@ (define_insn "<ssse3_avx2>_palignr<mode>" [(set (match_operand:SSESCALARMODE 0 "register_operand" "=x,x") - (unspec:SSESCALARMODE [(match_operand:SSESCALARMODE 1 "register_operand" "0,x") - (match_operand:SSESCALARMODE 2 "nonimmediate_operand" "xm,xm") - (match_operand:SI 3 "const_0_to_255_mul_8_operand" "n,n")] - UNSPEC_PALIGNR))] + (unspec:SSESCALARMODE + [(match_operand:SSESCALARMODE 1 "register_operand" "0,x") + (match_operand:SSESCALARMODE 2 "nonimmediate_operand" "xm,xm") + (match_operand:SI 3 "const_0_to_255_mul_8_operand" "n,n")] + UNSPEC_PALIGNR))] "TARGET_SSSE3" { operands[3] = GEN_INT (INTVAL (operands[3]) / 8); @@ -9596,10 +8938,11 @@ (define_insn "<sse4_1_avx2>_mpsadbw" [(set (match_operand:VI1_AVX2 0 "register_operand" "=x,x") - (unspec:VI1_AVX2 [(match_operand:VI1_AVX2 1 "register_operand" "0,x") - (match_operand:VI1_AVX2 2 "nonimmediate_operand" "xm,xm") - (match_operand:SI 3 "const_0_to_255_operand" "n,n")] - UNSPEC_MPSADBW))] + (unspec:VI1_AVX2 + [(match_operand:VI1_AVX2 1 "register_operand" "0,x") + (match_operand:VI1_AVX2 2 "nonimmediate_operand" "xm,xm") + (match_operand:SI 3 "const_0_to_255_operand" "n,n")] + UNSPEC_MPSADBW))] "TARGET_SSE4_1" "@ mpsadbw\t{%3, %2, %0|%0, %2, %3} @@ -9748,14 +9091,10 @@ (any_extend:V8HI (vec_select:V8QI (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 1) - (const_int 2) - (const_int 3) - (const_int 4) - (const_int 5) - (const_int 6) - (const_int 7)]))))] + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7)]))))] "TARGET_SSE4_1" "%vpmov<extsuffix>bw\t{%1, %0|%0, %q1}" [(set_attr "type" "ssemov") @@ -9768,14 +9107,10 @@ (any_extend:V8SI (vec_select:V8QI (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 1) - (const_int 2) - (const_int 3) - (const_int 4) - (const_int 5) - (const_int 6) - (const_int 7)]))))] + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7)]))))] "TARGET_AVX2" "vpmov<extsuffix>bd\t{%1, %0|%0, %q1}" [(set_attr "type" "ssemov") @@ -9788,10 +9123,8 @@ (any_extend:V4SI (vec_select:V4QI (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 1) - (const_int 2) - (const_int 3)]))))] + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3)]))))] "TARGET_SSE4_1" "%vpmov<extsuffix>bd\t{%1, %0|%0, %k1}" [(set_attr "type" "ssemov") @@ -9815,10 +9148,8 @@ (any_extend:V4SI (vec_select:V4HI (match_operand:V8HI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 1) - (const_int 2) - (const_int 3)]))))] + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3)]))))] "TARGET_SSE4_1" "%vpmov<extsuffix>wd\t{%1, %0|%0, %q1}" [(set_attr "type" "ssemov") @@ -9831,10 +9162,8 @@ (any_extend:V4DI (vec_select:V4QI (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 1) - (const_int 2) - (const_int 3)]))))] + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3)]))))] "TARGET_AVX2" "vpmov<extsuffix>bq\t{%1, %0|%0, %k1}" [(set_attr "type" "ssemov") @@ -9847,8 +9176,7 @@ (any_extend:V2DI (vec_select:V2QI (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 1)]))))] + (parallel [(const_int 0) (const_int 1)]))))] "TARGET_SSE4_1" "%vpmov<extsuffix>bq\t{%1, %0|%0, %w1}" [(set_attr "type" "ssemov") @@ -9861,10 +9189,8 @@ (any_extend:V4DI (vec_select:V4HI (match_operand:V8HI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 1) - (const_int 2) - (const_int 3)]))))] + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3)]))))] "TARGET_AVX2" "vpmov<extsuffix>wq\t{%1, %0|%0, %q1}" [(set_attr "type" "ssemov") @@ -9877,8 +9203,7 @@ (any_extend:V2DI (vec_select:V2HI (match_operand:V8HI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 1)]))))] + (parallel [(const_int 0) (const_int 1)]))))] "TARGET_SSE4_1" "%vpmov<extsuffix>wq\t{%1, %0|%0, %k1}" [(set_attr "type" "ssemov") @@ -9901,8 +9226,7 @@ (any_extend:V2DI (vec_select:V2SI (match_operand:V4SI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 1)]))))] + (parallel [(const_int 0) (const_int 1)]))))] "TARGET_SSE4_1" "%vpmov<extsuffix>dq\t{%1, %0|%0, %q1}" [(set_attr "type" "ssemov") @@ -10397,112 +9721,61 @@ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(define_code_iterator xop_plus [plus ss_plus]) + +(define_code_attr macs [(plus "macs") (ss_plus "macss")]) +(define_code_attr madcs [(plus "madcs") (ss_plus "madcss")]) + ;; XOP parallel integer multiply/add instructions. ;; Note the XOP multiply/add instructions ;; a[i] = b[i] * c[i] + d[i]; ;; do not allow the value being added to be a memory operation. -(define_insn "xop_pmacsww" - [(set (match_operand:V8HI 0 "register_operand" "=x") - (plus:V8HI - (mult:V8HI - (match_operand:V8HI 1 "nonimmediate_operand" "%x") - (match_operand:V8HI 2 "nonimmediate_operand" "xm")) - (match_operand:V8HI 3 "nonimmediate_operand" "x")))] - "TARGET_XOP" - "vpmacsww\t{%3, %2, %1, %0|%0, %1, %2, %3}" - [(set_attr "type" "ssemuladd") - (set_attr "mode" "TI")]) - -(define_insn "xop_pmacssww" - [(set (match_operand:V8HI 0 "register_operand" "=x") - (ss_plus:V8HI - (mult:V8HI (match_operand:V8HI 1 "nonimmediate_operand" "%x") - (match_operand:V8HI 2 "nonimmediate_operand" "xm")) - (match_operand:V8HI 3 "nonimmediate_operand" "x")))] - "TARGET_XOP" - "vpmacssww\t{%3, %2, %1, %0|%0, %1, %2, %3}" - [(set_attr "type" "ssemuladd") - (set_attr "mode" "TI")]) - -(define_insn "xop_pmacsdd" - [(set (match_operand:V4SI 0 "register_operand" "=x") - (plus:V4SI - (mult:V4SI - (match_operand:V4SI 1 "nonimmediate_operand" "%x") - (match_operand:V4SI 2 "nonimmediate_operand" "xm")) - (match_operand:V4SI 3 "nonimmediate_operand" "x")))] - "TARGET_XOP" - "vpmacsdd\t{%3, %2, %1, %0|%0, %1, %2, %3}" - [(set_attr "type" "ssemuladd") - (set_attr "mode" "TI")]) - -(define_insn "xop_pmacssdd" - [(set (match_operand:V4SI 0 "register_operand" "=x") - (ss_plus:V4SI - (mult:V4SI (match_operand:V4SI 1 "nonimmediate_operand" "%x") - (match_operand:V4SI 2 "nonimmediate_operand" "xm")) - (match_operand:V4SI 3 "nonimmediate_operand" "x")))] - "TARGET_XOP" - "vpmacssdd\t{%3, %2, %1, %0|%0, %1, %2, %3}" - [(set_attr "type" "ssemuladd") - (set_attr "mode" "TI")]) -(define_insn "xop_pmacssdql" - [(set (match_operand:V2DI 0 "register_operand" "=x") - (ss_plus:V2DI - (mult:V2DI - (sign_extend:V2DI - (vec_select:V2SI - (match_operand:V4SI 1 "nonimmediate_operand" "%x") - (parallel [(const_int 1) - (const_int 3)]))) - (vec_select:V2SI - (match_operand:V4SI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 1) - (const_int 3)]))) - (match_operand:V2DI 3 "nonimmediate_operand" "x")))] +(define_insn "xop_p<macs><ssemodesuffix><ssemodesuffix>" + [(set (match_operand:VI24_128 0 "register_operand" "=x") + (xop_plus:VI24_128 + (mult:VI24_128 + (match_operand:VI24_128 1 "nonimmediate_operand" "%x") + (match_operand:VI24_128 2 "nonimmediate_operand" "xm")) + (match_operand:VI24_128 3 "nonimmediate_operand" "x")))] "TARGET_XOP" - "vpmacssdql\t{%3, %2, %1, %0|%0, %1, %2, %3}" + "vp<macs><ssemodesuffix><ssemodesuffix>\t{%3, %2, %1, %0|%0, %1, %2, %3}" [(set_attr "type" "ssemuladd") (set_attr "mode" "TI")]) -(define_insn "xop_pmacssdqh" +(define_insn "xop_p<macs>dql" [(set (match_operand:V2DI 0 "register_operand" "=x") - (ss_plus:V2DI + (xop_plus:V2DI (mult:V2DI (sign_extend:V2DI (vec_select:V2SI (match_operand:V4SI 1 "nonimmediate_operand" "%x") - (parallel [(const_int 0) - (const_int 2)]))) + (parallel [(const_int 1) (const_int 3)]))) (sign_extend:V2DI (vec_select:V2SI (match_operand:V4SI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2)])))) + (parallel [(const_int 1) (const_int 3)])))) (match_operand:V2DI 3 "nonimmediate_operand" "x")))] "TARGET_XOP" - "vpmacssdqh\t{%3, %2, %1, %0|%0, %1, %2, %3}" + "vp<macs>dql\t{%3, %2, %1, %0|%0, %1, %2, %3}" [(set_attr "type" "ssemuladd") (set_attr "mode" "TI")]) -(define_insn "xop_pmacsdql" +(define_insn "xop_p<macs>dqh" [(set (match_operand:V2DI 0 "register_operand" "=x") - (plus:V2DI + (xop_plus:V2DI (mult:V2DI (sign_extend:V2DI (vec_select:V2SI (match_operand:V4SI 1 "nonimmediate_operand" "%x") - (parallel [(const_int 1) - (const_int 3)]))) + (parallel [(const_int 0) (const_int 2)]))) (sign_extend:V2DI (vec_select:V2SI (match_operand:V4SI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 1) - (const_int 3)])))) + (parallel [(const_int 0) (const_int 2)])))) (match_operand:V2DI 3 "nonimmediate_operand" "x")))] "TARGET_XOP" - "vpmacsdql\t{%3, %2, %1, %0|%0, %1, %2, %3}" + "vp<macs>dqh\t{%3, %2, %1, %0|%0, %1, %2, %3}" [(set_attr "type" "ssemuladd") (set_attr "mode" "TI")]) @@ -10516,13 +9789,11 @@ (sign_extend:V2DI (vec_select:V2SI (match_operand:V4SI 1 "register_operand" "%x") - (parallel [(const_int 1) - (const_int 3)]))) + (parallel [(const_int 1) (const_int 3)]))) (sign_extend:V2DI (vec_select:V2SI (match_operand:V4SI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 1) - (const_int 3)])))))] + (parallel [(const_int 1) (const_int 3)])))))] "TARGET_XOP" "#" "&& reload_completed" @@ -10534,13 +9805,11 @@ (sign_extend:V2DI (vec_select:V2SI (match_dup 1) - (parallel [(const_int 1) - (const_int 3)]))) + (parallel [(const_int 1) (const_int 3)]))) (sign_extend:V2DI (vec_select:V2SI (match_dup 2) - (parallel [(const_int 1) - (const_int 3)])))) + (parallel [(const_int 1) (const_int 3)])))) (match_dup 0)))] { operands[3] = CONST0_RTX (V2DImode); @@ -10548,26 +9817,6 @@ [(set_attr "type" "ssemul") (set_attr "mode" "TI")]) -(define_insn "xop_pmacsdqh" - [(set (match_operand:V2DI 0 "register_operand" "=x") - (plus:V2DI - (mult:V2DI - (sign_extend:V2DI - (vec_select:V2SI - (match_operand:V4SI 1 "nonimmediate_operand" "%x") - (parallel [(const_int 0) - (const_int 2)]))) - (sign_extend:V2DI - (vec_select:V2SI - (match_operand:V4SI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2)])))) - (match_operand:V2DI 3 "nonimmediate_operand" "x")))] - "TARGET_XOP" - "vpmacsdqh\t{%3, %2, %1, %0|%0, %1, %2, %3}" - [(set_attr "type" "ssemuladd") - (set_attr "mode" "TI")]) - ;; We don't have a straight 32-bit parallel multiply and extend on XOP, so ;; fake it with a multiply/add. In general, we expect the define_split to ;; occur before register allocation, so we have to handle the corner case where @@ -10578,13 +9827,11 @@ (sign_extend:V2DI (vec_select:V2SI (match_operand:V4SI 1 "register_operand" "%x") - (parallel [(const_int 0) - (const_int 2)]))) + (parallel [(const_int 0) (const_int 2)]))) (sign_extend:V2DI (vec_select:V2SI (match_operand:V4SI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2)])))))] + (parallel [(const_int 0) (const_int 2)])))))] "TARGET_XOP" "#" "&& reload_completed" @@ -10596,13 +9843,11 @@ (sign_extend:V2DI (vec_select:V2SI (match_dup 1) - (parallel [(const_int 0) - (const_int 2)]))) + (parallel [(const_int 0) (const_int 2)]))) (sign_extend:V2DI (vec_select:V2SI (match_dup 2) - (parallel [(const_int 0) - (const_int 2)])))) + (parallel [(const_int 0) (const_int 2)])))) (match_dup 0)))] { operands[3] = CONST0_RTX (V2DImode); @@ -10611,131 +9856,55 @@ (set_attr "mode" "TI")]) ;; XOP parallel integer multiply/add instructions for the intrinisics -(define_insn "xop_pmacsswd" +(define_insn "xop_p<macs>wd" [(set (match_operand:V4SI 0 "register_operand" "=x") - (ss_plus:V4SI + (xop_plus:V4SI (mult:V4SI (sign_extend:V4SI (vec_select:V4HI (match_operand:V8HI 1 "nonimmediate_operand" "%x") - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)]))) (sign_extend:V4SI (vec_select:V4HI (match_operand:V8HI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)])))) - (match_operand:V4SI 3 "nonimmediate_operand" "x")))] - "TARGET_XOP" - "vpmacsswd\t{%3, %2, %1, %0|%0, %1, %2, %3}" - [(set_attr "type" "ssemuladd") - (set_attr "mode" "TI")]) - -(define_insn "xop_pmacswd" - [(set (match_operand:V4SI 0 "register_operand" "=x") - (plus:V4SI - (mult:V4SI - (sign_extend:V4SI - (vec_select:V4HI - (match_operand:V8HI 1 "nonimmediate_operand" "%x") - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))) - (sign_extend:V4SI - (vec_select:V4HI - (match_operand:V8HI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)])))) - (match_operand:V4SI 3 "nonimmediate_operand" "x")))] - "TARGET_XOP" - "vpmacswd\t{%3, %2, %1, %0|%0, %1, %2, %3}" - [(set_attr "type" "ssemuladd") - (set_attr "mode" "TI")]) - -(define_insn "xop_pmadcsswd" - [(set (match_operand:V4SI 0 "register_operand" "=x") - (ss_plus:V4SI - (plus:V4SI - (mult:V4SI - (sign_extend:V4SI - (vec_select:V4HI - (match_operand:V8HI 1 "nonimmediate_operand" "%x") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)]))) - (sign_extend:V4SI - (vec_select:V4HI - (match_operand:V8HI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)])))) - (mult:V4SI - (sign_extend:V4SI - (vec_select:V4HI - (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))) - (sign_extend:V4SI - (vec_select:V4HI - (match_dup 2) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)])))) (match_operand:V4SI 3 "nonimmediate_operand" "x")))] "TARGET_XOP" - "vpmadcsswd\t{%3, %2, %1, %0|%0, %1, %2, %3}" + "vp<macs>wd\t{%3, %2, %1, %0|%0, %1, %2, %3}" [(set_attr "type" "ssemuladd") (set_attr "mode" "TI")]) -(define_insn "xop_pmadcswd" +(define_insn "xop_p<madcs>wd" [(set (match_operand:V4SI 0 "register_operand" "=x") - (plus:V4SI + (xop_plus:V4SI (plus:V4SI (mult:V4SI (sign_extend:V4SI (vec_select:V4HI (match_operand:V8HI 1 "nonimmediate_operand" "%x") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)]))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)]))) (sign_extend:V4SI (vec_select:V4HI (match_operand:V8HI 2 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)])))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)])))) (mult:V4SI (sign_extend:V4SI (vec_select:V4HI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)]))) (sign_extend:V4SI (vec_select:V4HI (match_dup 2) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)]))))) + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)]))))) (match_operand:V4SI 3 "nonimmediate_operand" "x")))] "TARGET_XOP" - "vpmadcswd\t{%3, %2, %1, %0|%0, %1, %2, %3}" + "vp<madcs>wd\t{%3, %2, %1, %0|%0, %1, %2, %3}" [(set_attr "type" "ssemuladd") (set_attr "mode" "TI")]) @@ -10751,376 +9920,156 @@ [(set_attr "type" "sse4arg")]) ;; XOP horizontal add/subtract instructions -(define_insn "xop_phaddbw" - [(set (match_operand:V8HI 0 "register_operand" "=x") - (plus:V8HI - (sign_extend:V8HI - (vec_select:V8QI - (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14)]))) - (sign_extend:V8HI - (vec_select:V8QI - (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15)])))))] - "TARGET_XOP" - "vphaddbw\t{%1, %0|%0, %1}" - [(set_attr "type" "sseiadd1")]) - -(define_insn "xop_phaddbd" - [(set (match_operand:V4SI 0 "register_operand" "=x") - (plus:V4SI - (plus:V4SI - (sign_extend:V4SI - (vec_select:V4QI - (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 4) - (const_int 8) - (const_int 12)]))) - (sign_extend:V4SI - (vec_select:V4QI - (match_dup 1) - (parallel [(const_int 1) - (const_int 5) - (const_int 9) - (const_int 13)])))) - (plus:V4SI - (sign_extend:V4SI - (vec_select:V4QI - (match_dup 1) - (parallel [(const_int 2) - (const_int 6) - (const_int 10) - (const_int 14)]))) - (sign_extend:V4SI - (vec_select:V4QI - (match_dup 1) - (parallel [(const_int 3) - (const_int 7) - (const_int 11) - (const_int 15)]))))))] - "TARGET_XOP" - "vphaddbd\t{%1, %0|%0, %1}" - [(set_attr "type" "sseiadd1")]) - -(define_insn "xop_phaddbq" - [(set (match_operand:V2DI 0 "register_operand" "=x") - (plus:V2DI - (plus:V2DI - (plus:V2DI - (sign_extend:V2DI - (vec_select:V2QI - (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 4)]))) - (sign_extend:V2DI - (vec_select:V2QI - (match_dup 1) - (parallel [(const_int 1) - (const_int 5)])))) - (plus:V2DI - (sign_extend:V2DI - (vec_select:V2QI - (match_dup 1) - (parallel [(const_int 2) - (const_int 6)]))) - (sign_extend:V2DI - (vec_select:V2QI - (match_dup 1) - (parallel [(const_int 3) - (const_int 7)]))))) - (plus:V2DI - (plus:V2DI - (sign_extend:V2DI - (vec_select:V2QI - (match_dup 1) - (parallel [(const_int 8) - (const_int 12)]))) - (sign_extend:V2DI - (vec_select:V2QI - (match_dup 1) - (parallel [(const_int 9) - (const_int 13)])))) - (plus:V2DI - (sign_extend:V2DI - (vec_select:V2QI - (match_dup 1) - (parallel [(const_int 10) - (const_int 14)]))) - (sign_extend:V2DI - (vec_select:V2QI - (match_dup 1) - (parallel [(const_int 11) - (const_int 15)])))))))] - "TARGET_XOP" - "vphaddbq\t{%1, %0|%0, %1}" - [(set_attr "type" "sseiadd1")]) - -(define_insn "xop_phaddwd" - [(set (match_operand:V4SI 0 "register_operand" "=x") - (plus:V4SI - (sign_extend:V4SI - (vec_select:V4HI - (match_operand:V8HI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)]))) - (sign_extend:V4SI - (vec_select:V4HI - (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)])))))] - "TARGET_XOP" - "vphaddwd\t{%1, %0|%0, %1}" - [(set_attr "type" "sseiadd1")]) - -(define_insn "xop_phaddwq" - [(set (match_operand:V2DI 0 "register_operand" "=x") - (plus:V2DI - (plus:V2DI - (sign_extend:V2DI - (vec_select:V2HI - (match_operand:V8HI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 4)]))) - (sign_extend:V2DI - (vec_select:V2HI - (match_dup 1) - (parallel [(const_int 1) - (const_int 5)])))) - (plus:V2DI - (sign_extend:V2DI - (vec_select:V2HI - (match_dup 1) - (parallel [(const_int 2) - (const_int 6)]))) - (sign_extend:V2DI - (vec_select:V2HI - (match_dup 1) - (parallel [(const_int 3) - (const_int 7)]))))))] - "TARGET_XOP" - "vphaddwq\t{%1, %0|%0, %1}" - [(set_attr "type" "sseiadd1")]) - -(define_insn "xop_phadddq" - [(set (match_operand:V2DI 0 "register_operand" "=x") - (plus:V2DI - (sign_extend:V2DI - (vec_select:V2SI - (match_operand:V4SI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2)]))) - (sign_extend:V2DI - (vec_select:V2SI - (match_dup 1) - (parallel [(const_int 1) - (const_int 3)])))))] - "TARGET_XOP" - "vphadddq\t{%1, %0|%0, %1}" - [(set_attr "type" "sseiadd1")]) - -(define_insn "xop_phaddubw" +(define_insn "xop_phadd<u>bw" [(set (match_operand:V8HI 0 "register_operand" "=x") (plus:V8HI - (zero_extend:V8HI + (any_extend:V8HI (vec_select:V8QI (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14)]))) - (zero_extend:V8HI + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14)]))) + (any_extend:V8HI (vec_select:V8QI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15)])))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15)])))))] "TARGET_XOP" - "vphaddubw\t{%1, %0|%0, %1}" + "vphadd<u>bw\t{%1, %0|%0, %1}" [(set_attr "type" "sseiadd1")]) -(define_insn "xop_phaddubd" +(define_insn "xop_phadd<u>bd" [(set (match_operand:V4SI 0 "register_operand" "=x") (plus:V4SI (plus:V4SI - (zero_extend:V4SI + (any_extend:V4SI (vec_select:V4QI (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 4) - (const_int 8) - (const_int 12)]))) - (zero_extend:V4SI + (parallel [(const_int 0) (const_int 4) + (const_int 8) (const_int 12)]))) + (any_extend:V4SI (vec_select:V4QI (match_dup 1) - (parallel [(const_int 1) - (const_int 5) - (const_int 9) - (const_int 13)])))) + (parallel [(const_int 1) (const_int 5) + (const_int 9) (const_int 13)])))) (plus:V4SI - (zero_extend:V4SI + (any_extend:V4SI (vec_select:V4QI (match_dup 1) - (parallel [(const_int 2) - (const_int 6) - (const_int 10) - (const_int 14)]))) - (zero_extend:V4SI + (parallel [(const_int 2) (const_int 6) + (const_int 10) (const_int 14)]))) + (any_extend:V4SI (vec_select:V4QI (match_dup 1) - (parallel [(const_int 3) - (const_int 7) - (const_int 11) - (const_int 15)]))))))] + (parallel [(const_int 3) (const_int 7) + (const_int 11) (const_int 15)]))))))] "TARGET_XOP" - "vphaddubd\t{%1, %0|%0, %1}" + "vphadd<u>bd\t{%1, %0|%0, %1}" [(set_attr "type" "sseiadd1")]) -(define_insn "xop_phaddubq" +(define_insn "xop_phadd<u>bq" [(set (match_operand:V2DI 0 "register_operand" "=x") (plus:V2DI (plus:V2DI (plus:V2DI - (zero_extend:V2DI + (any_extend:V2DI (vec_select:V2QI (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 4)]))) - (sign_extend:V2DI + (parallel [(const_int 0) (const_int 4)]))) + (any_extend:V2DI (vec_select:V2QI (match_dup 1) - (parallel [(const_int 1) - (const_int 5)])))) + (parallel [(const_int 1) (const_int 5)])))) (plus:V2DI - (zero_extend:V2DI + (any_extend:V2DI (vec_select:V2QI (match_dup 1) - (parallel [(const_int 2) - (const_int 6)]))) - (zero_extend:V2DI + (parallel [(const_int 2) (const_int 6)]))) + (any_extend:V2DI (vec_select:V2QI (match_dup 1) - (parallel [(const_int 3) - (const_int 7)]))))) + (parallel [(const_int 3) (const_int 7)]))))) (plus:V2DI (plus:V2DI - (zero_extend:V2DI + (any_extend:V2DI (vec_select:V2QI (match_dup 1) - (parallel [(const_int 8) - (const_int 12)]))) - (sign_extend:V2DI + (parallel [(const_int 8) (const_int 12)]))) + (any_extend:V2DI (vec_select:V2QI (match_dup 1) - (parallel [(const_int 9) - (const_int 13)])))) + (parallel [(const_int 9) (const_int 13)])))) (plus:V2DI - (zero_extend:V2DI + (any_extend:V2DI (vec_select:V2QI (match_dup 1) - (parallel [(const_int 10) - (const_int 14)]))) - (zero_extend:V2DI + (parallel [(const_int 10) (const_int 14)]))) + (any_extend:V2DI (vec_select:V2QI (match_dup 1) - (parallel [(const_int 11) - (const_int 15)])))))))] + (parallel [(const_int 11) (const_int 15)])))))))] "TARGET_XOP" - "vphaddubq\t{%1, %0|%0, %1}" + "vphadd<u>bq\t{%1, %0|%0, %1}" [(set_attr "type" "sseiadd1")]) -(define_insn "xop_phadduwd" +(define_insn "xop_phadd<u>wd" [(set (match_operand:V4SI 0 "register_operand" "=x") (plus:V4SI - (zero_extend:V4SI + (any_extend:V4SI (vec_select:V4HI (match_operand:V8HI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)]))) - (zero_extend:V4SI + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)]))) + (any_extend:V4SI (vec_select:V4HI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)])))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)])))))] "TARGET_XOP" - "vphadduwd\t{%1, %0|%0, %1}" + "vphadd<u>wd\t{%1, %0|%0, %1}" [(set_attr "type" "sseiadd1")]) -(define_insn "xop_phadduwq" +(define_insn "xop_phadd<u>wq" [(set (match_operand:V2DI 0 "register_operand" "=x") (plus:V2DI (plus:V2DI - (zero_extend:V2DI + (any_extend:V2DI (vec_select:V2HI (match_operand:V8HI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 4)]))) - (zero_extend:V2DI + (parallel [(const_int 0) (const_int 4)]))) + (any_extend:V2DI (vec_select:V2HI (match_dup 1) - (parallel [(const_int 1) - (const_int 5)])))) + (parallel [(const_int 1) (const_int 5)])))) (plus:V2DI - (zero_extend:V2DI + (any_extend:V2DI (vec_select:V2HI (match_dup 1) - (parallel [(const_int 2) - (const_int 6)]))) - (zero_extend:V2DI + (parallel [(const_int 2) (const_int 6)]))) + (any_extend:V2DI (vec_select:V2HI (match_dup 1) - (parallel [(const_int 3) - (const_int 7)]))))))] + (parallel [(const_int 3) (const_int 7)]))))))] "TARGET_XOP" - "vphadduwq\t{%1, %0|%0, %1}" + "vphadd<u>wq\t{%1, %0|%0, %1}" [(set_attr "type" "sseiadd1")]) -(define_insn "xop_phaddudq" +(define_insn "xop_phadd<u>dq" [(set (match_operand:V2DI 0 "register_operand" "=x") (plus:V2DI - (zero_extend:V2DI + (any_extend:V2DI (vec_select:V2SI (match_operand:V4SI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2)]))) - (zero_extend:V2DI + (parallel [(const_int 0) (const_int 2)]))) + (any_extend:V2DI (vec_select:V2SI (match_dup 1) - (parallel [(const_int 1) - (const_int 3)])))))] + (parallel [(const_int 1) (const_int 3)])))))] "TARGET_XOP" - "vphaddudq\t{%1, %0|%0, %1}" + "vphadd<u>dq\t{%1, %0|%0, %1}" [(set_attr "type" "sseiadd1")]) (define_insn "xop_phsubbw" @@ -11129,25 +10078,17 @@ (sign_extend:V8HI (vec_select:V8QI (match_operand:V16QI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6) - (const_int 8) - (const_int 10) - (const_int 12) - (const_int 14)]))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6) + (const_int 8) (const_int 10) + (const_int 12) (const_int 14)]))) (sign_extend:V8HI (vec_select:V8QI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7) - (const_int 9) - (const_int 11) - (const_int 13) - (const_int 15)])))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7) + (const_int 9) (const_int 11) + (const_int 13) (const_int 15)])))))] "TARGET_XOP" "vphsubbw\t{%1, %0|%0, %1}" [(set_attr "type" "sseiadd1")]) @@ -11158,17 +10099,13 @@ (sign_extend:V4SI (vec_select:V4HI (match_operand:V8HI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2) - (const_int 4) - (const_int 6)]))) + (parallel [(const_int 0) (const_int 2) + (const_int 4) (const_int 6)]))) (sign_extend:V4SI (vec_select:V4HI (match_dup 1) - (parallel [(const_int 1) - (const_int 3) - (const_int 5) - (const_int 7)])))))] + (parallel [(const_int 1) (const_int 3) + (const_int 5) (const_int 7)])))))] "TARGET_XOP" "vphsubwd\t{%1, %0|%0, %1}" [(set_attr "type" "sseiadd1")]) @@ -11179,13 +10116,11 @@ (sign_extend:V2DI (vec_select:V2SI (match_operand:V4SI 1 "nonimmediate_operand" "xm") - (parallel [(const_int 0) - (const_int 2)]))) + (parallel [(const_int 0) (const_int 2)]))) (sign_extend:V2DI (vec_select:V2SI (match_dup 1) - (parallel [(const_int 1) - (const_int 3)])))))] + (parallel [(const_int 1) (const_int 3)])))))] "TARGET_XOP" "vphsubdq\t{%1, %0|%0, %1}" [(set_attr "type" "sseiadd1")]) @@ -11901,26 +10836,14 @@ (set_attr "prefix" "vex") (set_attr "mode" "<sseinsnmode>")]) -(define_insn "avx2_permvarv8si" - [(set (match_operand:V8SI 0 "register_operand" "=x") - (unspec:V8SI - [(match_operand:V8SI 1 "register_operand" "x") - (match_operand:V8SI 2 "nonimmediate_operand" "xm")] - UNSPEC_VPERMSI))] - "TARGET_AVX2" - "vpermd\t{%2, %1, %0|%0, %1, %2}" - [(set_attr "type" "sselog") - (set_attr "prefix" "vex") - (set_attr "mode" "OI")]) - -(define_insn "avx2_permvarv8sf" - [(set (match_operand:V8SF 0 "register_operand" "=x") - (unspec:V8SF - [(match_operand:V8SF 1 "register_operand" "x") - (match_operand:V8SF 2 "nonimmediate_operand" "xm")] - UNSPEC_VPERMSF))] +(define_insn "avx2_permvar<mode>" + [(set (match_operand:VI4F_256 0 "register_operand" "=x") + (unspec:VI4F_256 + [(match_operand:VI4F_256 1 "nonimmediate_operand" "xm") + (match_operand:V8SI 2 "register_operand" "x")] + UNSPEC_VPERMVAR))] "TARGET_AVX2" - "vpermps\t{%2, %1, %0|%0, %1, %2}" + "vperm<ssemodesuffix>\t{%1, %2, %0|%0, %2, %1}" [(set_attr "type" "sselog") (set_attr "prefix" "vex") (set_attr "mode" "OI")]) diff --git a/gcc/config/i386/sync.md b/gcc/config/i386/sync.md index 18ccabfc112..faf65ba8a23 100644 --- a/gcc/config/i386/sync.md +++ b/gcc/config/i386/sync.md @@ -576,7 +576,7 @@ return "lock{%;} sub{<imodesuffix>}\t{%1, %0|%0, %1}"; }) -(define_insn "atomic_<code><mode>" +(define_insn "atomic_<logic><mode>" [(set (match_operand:SWI 0 "memory_operand" "+m") (unspec_volatile:SWI [(any_logic:SWI (match_dup 0) diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md index e4b4b59afc2..8104e75492b 100644 --- a/gcc/config/m68k/m68k.md +++ b/gcc/config/m68k/m68k.md @@ -1,6 +1,6 @@ ;;- Machine description for GNU compiler, Motorola 68000 Version ;; Copyright (C) 1987, 1988, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2001, -;; 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +;; 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 ;; Free Software Foundation, Inc. ;; This file is part of GCC. @@ -5475,7 +5475,7 @@ "!TARGET_COLDFIRE" "ror%.w %2,%0") -(define_insn "" +(define_insn "rotrhi_lowpart" [(set (strict_low_part (match_operand:HI 0 "register_operand" "+d")) (rotatert:HI (match_dup 0) (match_operand:HI 1 "general_operand" "dI")))] @@ -5495,6 +5495,19 @@ (match_operand:QI 1 "general_operand" "dI")))] "!TARGET_COLDFIRE" "ror%.b %1,%0") + +(define_expand "bswapsi2" + [(set (match_operand:SI 0 "register_operand") + (bswap:SI (match_operand:SI 1 "register_operand")))] + "!TARGET_COLDFIRE" +{ + rtx x = operands[0]; + emit_move_insn (x, operands[1]); + emit_insn (gen_rotrhi_lowpart (gen_lowpart (HImode, x), GEN_INT (8))); + emit_insn (gen_rotlsi3 (x, x, GEN_INT (16))); + emit_insn (gen_rotrhi_lowpart (gen_lowpart (HImode, x), GEN_INT (8))); + DONE; +}) ;; Bit set/clear in memory byte. diff --git a/gcc/config/rl78/rl78.c b/gcc/config/rl78/rl78.c index cae3fa6a446..17fa2b1855d 100644 --- a/gcc/config/rl78/rl78.c +++ b/gcc/config/rl78/rl78.c @@ -140,7 +140,7 @@ static struct opt_pass rl78_devirt_pass = TV_MACH_DEP, 0, 0, 0, 0, - TODO_dump_func + 0 }; static struct register_pass_info rl78_devirt_info = @@ -827,6 +827,9 @@ rl78_expand_prologue (void) if (!cfun->machine->computed) rl78_compute_frame_info (); + if (flag_stack_usage_info) + current_function_static_stack_size = cfun->machine->framesize; + for (i = 0; i < 16; i++) if (cfun->machine->need_to_push [i]) { diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 29dd18d75bd..232773d5d14 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1451,3 +1451,13 @@ return 1; }) + +;; Return 1 if OP is a stack tie operand. +(define_predicate "tie_operand" + (match_code "parallel") +{ + return (GET_CODE (XVECEXP (op, 0, 0)) == SET + && GET_CODE (XEXP (XVECEXP (op, 0, 0), 0)) == MEM + && GET_MODE (XEXP (XVECEXP (op, 0, 0), 0)) == BLKmode + && XEXP (XVECEXP (op, 0, 0), 1) == const0_rtx); +}) diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def index 776350bb5c0..2fd51af458f 100644 --- a/gcc/config/rs6000/rs6000-builtin.def +++ b/gcc/config/rs6000/rs6000-builtin.def @@ -1430,9 +1430,6 @@ BU_SPECIAL_X (RS6000_BUILTIN_RSQRT, "__builtin_rsqrt", RS6000_BTM_FRSQRTE, BU_SPECIAL_X (RS6000_BUILTIN_RSQRTF, "__builtin_rsqrtf", RS6000_BTM_FRSQRTES, RS6000_BTC_FP) -BU_SPECIAL_X (RS6000_BUILTIN_BSWAP_HI, "__builtin_bswap16", RS6000_BTM_POWERPC, - RS6000_BTC_MEM) - /* Darwin CfString builtin. */ BU_SPECIAL_X (RS6000_BUILTIN_CFSTRING, "__builtin_cfstring", RS6000_BTM_POWERPC, RS6000_BTC_MISC) diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index b6054b302c8..29749d20041 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -925,7 +925,6 @@ static const char *rs6000_invalid_within_doloop (const_rtx); static bool rs6000_legitimate_address_p (enum machine_mode, rtx, bool); static bool rs6000_debug_legitimate_address_p (enum machine_mode, rtx, bool); static rtx rs6000_generate_compare (rtx, enum machine_mode); -static void rs6000_emit_stack_tie (void); static bool spe_func_has_64bit_regs_p (void); static rtx gen_frame_mem_offset (enum machine_mode, rtx, int); static unsigned rs6000_hash_constant (rtx); @@ -11381,9 +11380,6 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, case RS6000_BUILTIN_RSQRT: return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target); - case RS6000_BUILTIN_BSWAP_HI: - return rs6000_expand_unop_builtin (CODE_FOR_bswaphi2, exp, target); - case POWER7_BUILTIN_BPERMD: return rs6000_expand_binop_builtin (((TARGET_64BIT) ? CODE_FOR_bpermd_di @@ -11673,12 +11669,6 @@ rs6000_init_builtins (void) POWER7_BUILTIN_BPERMD, "__builtin_bpermd"); def_builtin ("__builtin_bpermd", ftype, POWER7_BUILTIN_BPERMD); - /* Don't use builtin_function_type here, as it maps HI/QI to SI. */ - ftype = build_function_type_list (unsigned_intHI_type_node, - unsigned_intHI_type_node, - NULL_TREE); - def_builtin ("__builtin_bswap16", ftype, RS6000_BUILTIN_BSWAP_HI); - #if TARGET_XCOFF /* AIX libm provides clog as __clog. */ if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE) @@ -15570,14 +15560,11 @@ rs6000_generate_compare (rtx cmp, enum machine_mode mode) || code == GEU || code == LEU) comp_mode = CCUNSmode; else if ((code == EQ || code == NE) - && GET_CODE (op0) == SUBREG - && GET_CODE (op1) == SUBREG - && SUBREG_PROMOTED_UNSIGNED_P (op0) - && SUBREG_PROMOTED_UNSIGNED_P (op1)) + && unsigned_reg_p (op0) + && (unsigned_reg_p (op1) + || (CONST_INT_P (op1) && INTVAL (op1) != 0))) /* These are unsigned values, perhaps there will be a later - ordering compare that can be shared with this one. - Unfortunately we cannot detect the signedness of the operands - for non-subregs. */ + ordering compare that can be shared with this one. */ comp_mode = CCUNSmode; else comp_mode = CCmode; @@ -17470,8 +17457,9 @@ rs6000_savres_strategy (rs6000_stack_t *info, static chain is rarely used anyway. FPRs are saved w.r.t the stack pointer on Darwin. */ if (using_static_chain_p) - strategy |= (DEFAULT_ABI == ABI_DARWIN ? 0 : SAVE_INLINE_FPRS) - | SAVE_INLINE_GPRS; + strategy |= ((DEFAULT_ABI == ABI_DARWIN + ? 0 : SAVE_INLINE_FPRS | REST_INLINE_FPRS) + | SAVE_INLINE_GPRS); /* If we are going to use store multiple, then don't even bother with the out-of-line routines, since the store-multiple @@ -18517,12 +18505,29 @@ rs6000_aix_asm_output_dwarf_table_ref (char * frame_table_label) and the change to the stack pointer. */ static void -rs6000_emit_stack_tie (void) +rs6000_emit_stack_tie (rtx fp, bool hard_frame_needed) { - rtx mem = gen_frame_mem (BLKmode, - gen_rtx_REG (Pmode, STACK_POINTER_REGNUM)); + rtvec p; + int i; + rtx regs[3]; - emit_insn (gen_stack_tie (mem)); + i = 0; + regs[i++] = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); + if (hard_frame_needed) + regs[i++] = gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM); + if (!(REGNO (fp) == STACK_POINTER_REGNUM + || (hard_frame_needed + && REGNO (fp) == HARD_FRAME_POINTER_REGNUM))) + regs[i++] = fp; + + p = rtvec_alloc (i); + while (--i >= 0) + { + rtx mem = gen_frame_mem (BLKmode, regs[i]); + RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, mem, const0_rtx); + } + + emit_insn (gen_stack_tie (gen_rtx_PARALLEL (VOIDmode, p))); } /* Emit the correct code for allocating stack space, as insns. @@ -19142,7 +19147,7 @@ rs6000_emit_stack_reset (rs6000_stack_t *info, || (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0 && info->first_gp_reg_save != 32)) - rs6000_emit_stack_tie (); + rs6000_emit_stack_tie (frame_reg_rtx, frame_pointer_needed); if (frame_reg_rtx != sp_reg_rtx) { @@ -19208,9 +19213,9 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info, sym = rs6000_savres_routine_sym (info, savep, gpr, lr); RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym); - use_reg = DEFAULT_ABI == ABI_AIX ? (gpr && !lr ? 12 : 1) - : DEFAULT_ABI == ABI_DARWIN && !gpr ? 1 - : 11; + use_reg = (DEFAULT_ABI == ABI_AIX ? (gpr && !lr ? 12 : 1) + : DEFAULT_ABI == ABI_DARWIN && !gpr ? 1 + : 11); RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, use_reg)); @@ -19220,7 +19225,7 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info, rtx addr, reg, mem; reg = gen_rtx_REG (reg_mode, start_reg + i); addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (save_area_offset + reg_size*i)); + GEN_INT (save_area_offset + reg_size * i)); mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode, @@ -19289,9 +19294,9 @@ rs6000_emit_prologue (void) int saving_GPRs_inline; int using_store_multiple; int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE - && df_regs_ever_live_p (STATIC_CHAIN_REGNUM) + && df_regs_ever_live_p (STATIC_CHAIN_REGNUM) && call_used_regs[STATIC_CHAIN_REGNUM]); - HOST_WIDE_INT sp_offset = 0; + HOST_WIDE_INT frame_off = 0; if (flag_stack_usage_info) current_function_static_stack_size = info->total_size; @@ -19319,52 +19324,6 @@ rs6000_emit_prologue (void) reg_size = 8; } - strategy = info->savres_strategy; - using_store_multiple = strategy & SAVRES_MULTIPLE; - saving_FPRs_inline = strategy & SAVE_INLINE_FPRS; - saving_GPRs_inline = strategy & SAVE_INLINE_GPRS; - - /* For V.4, update stack before we do any saving and set back pointer. */ - if (! WORLD_SAVE_P (info) - && info->push_p - && (DEFAULT_ABI == ABI_V4 - || crtl->calls_eh_return)) - { - bool need_r11 = (TARGET_SPE - ? (!saving_GPRs_inline - && info->spe_64bit_regs_used == 0) - : (!saving_FPRs_inline || !saving_GPRs_inline)); - rtx copy_reg = need_r11 ? gen_rtx_REG (Pmode, 11) : NULL; - - if (info->total_size < 32767) - sp_offset = info->total_size; - else if (need_r11) - frame_reg_rtx = copy_reg; - else if (info->cr_save_p - || info->lr_save_p - || info->first_fp_reg_save < 64 - || info->first_gp_reg_save < 32 - || info->altivec_size != 0 - || info->vrsave_mask != 0 - || crtl->calls_eh_return) - { - copy_reg = frame_ptr_rtx; - frame_reg_rtx = copy_reg; - } - else - { - /* The prologue won't be saving any regs so there is no need - to set up a frame register to access any frame save area. - We also won't be using sp_offset anywhere below, but set - the correct value anyway to protect against future - changes to this function. */ - sp_offset = info->total_size; - } - rs6000_emit_allocate_stack (info->total_size, copy_reg); - if (frame_reg_rtx != sp_reg_rtx) - rs6000_emit_stack_tie (); - } - /* Handle world saves specially here. */ if (WORLD_SAVE_P (info)) { @@ -19392,7 +19351,7 @@ rs6000_emit_prologue (void) && info->push_p && info->lr_save_p && (!crtl->calls_eh_return - || info->ehrd_offset == -432) + || info->ehrd_offset == -432) && info->vrsave_save_offset == -224 && info->altivec_save_offset == -416); @@ -19419,14 +19378,14 @@ rs6000_emit_prologue (void) properly. */ for (i = 0; i < 64 - info->first_fp_reg_save; i++) { - rtx reg = gen_rtx_REG (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) - ? DFmode : SFmode), - info->first_fp_reg_save + i); + rtx reg = gen_rtx_REG ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT + ? DFmode : SFmode), + info->first_fp_reg_save + i); rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->fp_save_offset - + sp_offset + 8 * i)); - rtx mem = gen_frame_mem (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) - ? DFmode : SFmode), addr); + + frame_off + 8 * i)); + rtx mem = gen_frame_mem ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT + ? DFmode : SFmode), addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); } @@ -19435,7 +19394,7 @@ rs6000_emit_prologue (void) rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i); rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->altivec_save_offset - + sp_offset + 16 * i)); + + frame_off + 16 * i)); rtx mem = gen_frame_mem (V4SImode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); @@ -19445,7 +19404,7 @@ rs6000_emit_prologue (void) rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->gp_save_offset - + sp_offset + reg_size * i)); + + frame_off + reg_size * i)); rtx mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); @@ -19456,7 +19415,7 @@ rs6000_emit_prologue (void) rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO); rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->cr_save_offset - + sp_offset)); + + frame_off)); rtx mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); @@ -19466,7 +19425,7 @@ rs6000_emit_prologue (void) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->lr_save_offset - + sp_offset)); + + frame_off)); rtx mem = gen_frame_mem (reg_mode, addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg0); @@ -19480,7 +19439,53 @@ rs6000_emit_prologue (void) insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, treg, GEN_INT (-info->total_size)); - sp_offset = info->total_size; + frame_off = info->total_size; + } + + strategy = info->savres_strategy; + using_store_multiple = strategy & SAVRES_MULTIPLE; + saving_FPRs_inline = strategy & SAVE_INLINE_FPRS; + saving_GPRs_inline = strategy & SAVE_INLINE_GPRS; + + /* For V.4, update stack before we do any saving and set back pointer. */ + if (! WORLD_SAVE_P (info) + && info->push_p + && (DEFAULT_ABI == ABI_V4 + || crtl->calls_eh_return)) + { + bool need_r11 = (TARGET_SPE + ? (!saving_GPRs_inline + && info->spe_64bit_regs_used == 0) + : (!saving_FPRs_inline || !saving_GPRs_inline)); + rtx copy_reg = need_r11 ? gen_rtx_REG (Pmode, 11) : NULL; + + if (info->total_size < 32767) + frame_off = info->total_size; + else if (need_r11) + frame_reg_rtx = copy_reg; + else if (info->cr_save_p + || info->lr_save_p + || info->first_fp_reg_save < 64 + || info->first_gp_reg_save < 32 + || info->altivec_size != 0 + || info->vrsave_mask != 0 + || crtl->calls_eh_return) + { + copy_reg = frame_ptr_rtx; + frame_reg_rtx = copy_reg; + } + else + { + /* The prologue won't be saving any regs so there is no need + to set up a frame register to access any frame save area. + We also won't be using frame_off anywhere below, but set + the correct value anyway to protect against future + changes to this function. */ + frame_off = info->total_size; + } + rs6000_emit_allocate_stack (info->total_size, copy_reg); + if (frame_reg_rtx != sp_reg_rtx) + rs6000_emit_stack_tie (frame_reg_rtx, false); } /* If we use the link register, get it into r0. */ @@ -19496,7 +19501,7 @@ rs6000_emit_prologue (void) | SAVE_NOINLINE_FPRS_SAVES_LR))) { addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->lr_save_offset + sp_offset)); + GEN_INT (info->lr_save_offset + frame_off)); reg = gen_rtx_REG (Pmode, 0); mem = gen_rtx_MEM (Pmode, addr); /* This should not be of rs6000_sr_alias_set, because of @@ -19509,7 +19514,9 @@ rs6000_emit_prologue (void) } /* If we need to save CR, put it into r12 or r11. */ - if (!WORLD_SAVE_P (info) && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx) + if (!WORLD_SAVE_P (info) + && info->cr_save_p + && frame_reg_rtx != frame_ptr_rtx) { rtx set; @@ -19535,19 +19542,19 @@ rs6000_emit_prologue (void) { int i; for (i = 0; i < 64 - info->first_fp_reg_save; i++) - if ((df_regs_ever_live_p (info->first_fp_reg_save+i) - && ! call_used_regs[info->first_fp_reg_save+i])) - emit_frame_save (frame_reg_rtx, frame_ptr_rtx, - (TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) - ? DFmode : SFmode, + if (df_regs_ever_live_p (info->first_fp_reg_save + i) + && ! call_used_regs[info->first_fp_reg_save + i]) + emit_frame_save (frame_reg_rtx, frame_ptr_rtx, + (TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT + ? DFmode : SFmode), info->first_fp_reg_save + i, - info->fp_save_offset + sp_offset + 8 * i, + info->fp_save_offset + frame_off + 8 * i, info->total_size); } else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64) { insn = rs6000_emit_savres_rtx (info, frame_reg_rtx, - info->fp_save_offset + sp_offset, + info->fp_save_offset + frame_off, DFmode, /*savep=*/true, /*gpr=*/false, /*lr=*/((strategy @@ -19573,7 +19580,7 @@ rs6000_emit_prologue (void) to be saved with an offset from frame_reg_rtx that fits in the small const field for SPE memory instructions. */ int spe_regs_addressable - = (SPE_CONST_OFFSET_OK (info->spe_gp_save_offset + sp_offset + = (SPE_CONST_OFFSET_OK (info->spe_gp_save_offset + frame_off + reg_size * (32 - info->first_gp_reg_save - 1)) && saving_GPRs_inline); int spe_offset; @@ -19581,8 +19588,8 @@ rs6000_emit_prologue (void) if (spe_regs_addressable) { spe_save_area_ptr = frame_reg_rtx; - save_ptr_to_sp = info->total_size - sp_offset; - spe_offset = info->spe_gp_save_offset + sp_offset; + save_ptr_to_sp = info->total_size - frame_off; + spe_offset = info->spe_gp_save_offset + frame_off; } else { @@ -19594,9 +19601,9 @@ rs6000_emit_prologue (void) if (!saving_GPRs_inline) ool_adjust = 8 * (info->first_gp_reg_save - (FIRST_SAVRES_REGISTER + 1)); - offset = info->spe_gp_save_offset + sp_offset - ool_adjust; + offset = info->spe_gp_save_offset + frame_off - ool_adjust; spe_save_area_ptr = gen_rtx_REG (Pmode, 11); - save_ptr_to_sp = info->total_size - sp_offset + offset; + save_ptr_to_sp = info->total_size - frame_off + offset; spe_offset = 0; if (using_static_chain_p) @@ -19609,7 +19616,7 @@ rs6000_emit_prologue (void) emit_insn (gen_addsi3 (spe_save_area_ptr, frame_reg_rtx, GEN_INT (offset))); if (REGNO (frame_reg_rtx) == 11) - sp_offset = -info->spe_gp_save_offset + ool_adjust; + frame_off = -info->spe_gp_save_offset + ool_adjust; } if (saving_GPRs_inline) @@ -19630,8 +19637,7 @@ rs6000_emit_prologue (void) insn = emit_move_insn (mem, reg); - rs6000_frame_related (insn, - spe_save_area_ptr, save_ptr_to_sp, + rs6000_frame_related (insn, spe_save_area_ptr, save_ptr_to_sp, NULL_RTX, NULL_RTX); } } @@ -19664,10 +19670,10 @@ rs6000_emit_prologue (void) else { int save_off = 8 * (64 - info->first_fp_reg_save); - rtx offset = GEN_INT (sp_offset - save_off); + rtx offset = GEN_INT (frame_off - save_off); if (REGNO (dest_reg) == REGNO (frame_reg_rtx)) - sp_offset = save_off; + frame_off = save_off; emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset)); } } @@ -19676,15 +19682,15 @@ rs6000_emit_prologue (void) { rtx dest_reg = gen_rtx_REG (Pmode, DEFAULT_ABI == ABI_AIX ? 12 : 11); int save_off = 8 * (64 - info->first_fp_reg_save); - rtx offset = GEN_INT (sp_offset - save_off); + rtx offset = GEN_INT (frame_off - save_off); if (REGNO (dest_reg) == REGNO (frame_reg_rtx)) - sp_offset = save_off; + frame_off = save_off; emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset)); } insn = rs6000_emit_savres_rtx (info, frame_reg_rtx, - info->gp_save_offset + sp_offset, + info->gp_save_offset + frame_off, reg_mode, /*savep=*/true, /*gpr=*/true, /*lr=*/((strategy @@ -19704,7 +19710,7 @@ rs6000_emit_prologue (void) reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->gp_save_offset - + sp_offset + + frame_off + reg_size * i)); mem = gen_frame_mem (reg_mode, addr); @@ -19719,20 +19725,20 @@ rs6000_emit_prologue (void) int i; for (i = 0; i < 32 - info->first_gp_reg_save; i++) if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i)) - { - rtx addr, reg, mem; - reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); - - addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->gp_save_offset - + sp_offset - + reg_size * i)); - mem = gen_frame_mem (reg_mode, addr); - - insn = emit_move_insn (mem, reg); - rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, - NULL_RTX, NULL_RTX); - } + { + rtx addr, reg, mem; + reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); + + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->gp_save_offset + + frame_off + + reg_size * i)); + mem = gen_frame_mem (reg_mode, addr); + + insn = emit_move_insn (mem, reg); + rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, + NULL_RTX, NULL_RTX); + } } /* ??? There's no need to emit actual instructions here, but it's the @@ -19748,8 +19754,7 @@ rs6000_emit_prologue (void) break; emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno, - info->ehrd_offset + sp_offset - + reg_size * (int) i, + info->ehrd_offset + frame_off + reg_size * (int) i, info->total_size); } } @@ -19794,7 +19799,7 @@ rs6000_emit_prologue (void) LABEL_NUSES (toc_save_done) += 1; save_insn = emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, - TOC_REGNUM, sp_offset + 5 * reg_size, + TOC_REGNUM, frame_off + 5 * reg_size, info->total_size); emit_label (toc_save_done); @@ -19824,7 +19829,7 @@ rs6000_emit_prologue (void) if (!WORLD_SAVE_P (info) && info->cr_save_p) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->cr_save_offset + sp_offset)); + GEN_INT (info->cr_save_offset + frame_off)); rtx mem = gen_frame_mem (SImode, addr); /* See the large comment above about why CR2_REGNO is used. */ rtx magic_eh_cr_reg = gen_rtx_REG (SImode, CR2_REGNO); @@ -19855,7 +19860,7 @@ rs6000_emit_prologue (void) rtx copy_reg = NULL; if (info->total_size < 32767) - sp_offset = info->total_size; + frame_off = info->total_size; else if (info->altivec_size != 0 || info->vrsave_mask != 0) { @@ -19863,10 +19868,10 @@ rs6000_emit_prologue (void) frame_reg_rtx = copy_reg; } else - sp_offset = info->total_size; + frame_off = info->total_size; rs6000_emit_allocate_stack (info->total_size, copy_reg); if (frame_reg_rtx != sp_reg_rtx) - rs6000_emit_stack_tie (); + rs6000_emit_stack_tie (frame_reg_rtx, false); } /* Set frame pointer, if needed. */ @@ -19884,30 +19889,30 @@ rs6000_emit_prologue (void) int i; /* There should be a non inline version of this, for when we - are saving lots of vector registers. */ + are saving lots of vector registers. */ for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i) - if (info->vrsave_mask & ALTIVEC_REG_BIT (i)) - { - rtx areg, savereg, mem; - int offset; + if (info->vrsave_mask & ALTIVEC_REG_BIT (i)) + { + rtx areg, savereg, mem; + int offset; - offset = info->altivec_save_offset + sp_offset - + 16 * (i - info->first_altivec_reg_save); + offset = (info->altivec_save_offset + frame_off + + 16 * (i - info->first_altivec_reg_save)); - savereg = gen_rtx_REG (V4SImode, i); + savereg = gen_rtx_REG (V4SImode, i); - areg = gen_rtx_REG (Pmode, 0); - emit_move_insn (areg, GEN_INT (offset)); + areg = gen_rtx_REG (Pmode, 0); + emit_move_insn (areg, GEN_INT (offset)); - /* AltiVec addressing mode is [reg+reg]. */ - mem = gen_frame_mem (V4SImode, - gen_rtx_PLUS (Pmode, frame_reg_rtx, areg)); + /* AltiVec addressing mode is [reg+reg]. */ + mem = gen_frame_mem (V4SImode, + gen_rtx_PLUS (Pmode, frame_reg_rtx, areg)); - insn = emit_move_insn (mem, savereg); + insn = emit_move_insn (mem, savereg); - rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, - areg, GEN_INT (offset)); - } + rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, + areg, GEN_INT (offset)); + } } /* VRSAVE is a bit vector representing which AltiVec registers @@ -19926,19 +19931,19 @@ rs6000_emit_prologue (void) int offset; /* Get VRSAVE onto a GPR. Note that ABI_V4 might be using r12 - as frame_reg_rtx and r11 as the static chain pointer for - nested functions. */ + as frame_reg_rtx and r11 as the static chain pointer for + nested functions. */ reg = gen_rtx_REG (SImode, 0); vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO); if (TARGET_MACHO) - emit_insn (gen_get_vrsave_internal (reg)); + emit_insn (gen_get_vrsave_internal (reg)); else - emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave)); + emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave)); /* Save VRSAVE. */ - offset = info->vrsave_save_offset + sp_offset; + offset = info->vrsave_save_offset + frame_off; mem = gen_frame_mem (SImode, - gen_rtx_PLUS (Pmode, frame_reg_rtx, + gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (offset))); insn = emit_move_insn (mem, reg); @@ -20017,7 +20022,7 @@ rs6000_emit_prologue (void) both in terms of the size of DWARF info and the time taken in the unwinder to interpret it. R2 changes, apart from the calls_eh_return case earlier in this function, are handled by - linux-unwind.h frob_update_context. */ + linux-unwind.h frob_update_context. */ if (rs6000_save_toc_in_prologue_p ()) { rtx addr = gen_rtx_PLUS (Pmode, sp_reg_rtx, GEN_INT (5 * reg_size)); @@ -20165,7 +20170,7 @@ rs6000_emit_epilogue (int sibcall) int use_backchain_to_restore_sp; int restore_lr; int strategy; - int sp_offset = 0; + int frame_off = 0; rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1); rtx frame_reg_rtx = sp_reg_rtx; rtx cfa_restores = NULL_RTX; @@ -20285,14 +20290,14 @@ rs6000_emit_epilogue (int sibcall) } for (i = 0; info->first_fp_reg_save + i <= 63; i++) { - rtx reg = gen_rtx_REG (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) - ? DFmode : SFmode), - info->first_fp_reg_save + i); + rtx reg = gen_rtx_REG ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT + ? DFmode : SFmode), + info->first_fp_reg_save + i); rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->fp_save_offset + 8 * i)); - rtx mem = gen_frame_mem (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) - ? DFmode : SFmode), addr); + rtx mem = gen_frame_mem ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT + ? DFmode : SFmode), addr); RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem); if (flag_shrink_wrap) @@ -20319,9 +20324,9 @@ rs6000_emit_epilogue (int sibcall) return; } - /* frame_reg_rtx + sp_offset points to the top of this stack frame. */ + /* frame_reg_rtx + frame_off points to the top of this stack frame. */ if (info->push_p) - sp_offset = info->total_size; + frame_off = info->total_size; /* Restore AltiVec registers if we must do so before adjusting the stack. */ @@ -20338,7 +20343,7 @@ rs6000_emit_epilogue (int sibcall) frame_reg_rtx = gen_rtx_REG (Pmode, 11); emit_move_insn (frame_reg_rtx, gen_rtx_MEM (Pmode, sp_reg_rtx)); - sp_offset = 0; + frame_off = 0; } else if (frame_pointer_needed) frame_reg_rtx = hard_frame_pointer_rtx; @@ -20351,7 +20356,7 @@ rs6000_emit_epilogue (int sibcall) areg = gen_rtx_REG (Pmode, 0); emit_move_insn (areg, GEN_INT (info->altivec_save_offset - + sp_offset + + frame_off + 16 * (i - info->first_altivec_reg_save))); /* AltiVec addressing mode is [reg+reg]. */ @@ -20386,14 +20391,14 @@ rs6000_emit_epilogue (int sibcall) frame_reg_rtx = gen_rtx_REG (Pmode, 11); emit_move_insn (frame_reg_rtx, gen_rtx_MEM (Pmode, sp_reg_rtx)); - sp_offset = 0; + frame_off = 0; } else if (frame_pointer_needed) frame_reg_rtx = hard_frame_pointer_rtx; } addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->vrsave_save_offset + sp_offset)); + GEN_INT (info->vrsave_save_offset + frame_off)); mem = gen_frame_mem (SImode, addr); reg = gen_rtx_REG (SImode, 12); emit_move_insn (reg, mem); @@ -20415,7 +20420,7 @@ rs6000_emit_epilogue (int sibcall) insn = emit_move_insn (frame_reg_rtx, gen_rtx_MEM (Pmode, sp_reg_rtx)); - sp_offset = 0; + frame_off = 0; } else if (ALWAYS_RESTORE_ALTIVEC_BEFORE_POP && DEFAULT_ABI == ABI_V4) @@ -20437,17 +20442,11 @@ rs6000_emit_epilogue (int sibcall) /* Prevent reordering memory accesses against stack pointer restore. */ else if (cfun->calls_alloca || offset_below_red_zone_p (-info->total_size)) - { - rtx mem1 = gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx); - rtx mem2 = gen_rtx_MEM (BLKmode, sp_reg_rtx); - MEM_NOTRAP_P (mem1) = 1; - MEM_NOTRAP_P (mem2) = 1; - emit_insn (gen_frame_tie (mem1, mem2)); - } + rs6000_emit_stack_tie (frame_reg_rtx, true); insn = emit_insn (gen_add3_insn (frame_reg_rtx, hard_frame_pointer_rtx, GEN_INT (info->total_size))); - sp_offset = 0; + frame_off = 0; } else if (info->push_p && DEFAULT_ABI != ABI_V4 @@ -20456,14 +20455,10 @@ rs6000_emit_epilogue (int sibcall) /* Prevent reordering memory accesses against stack pointer restore. */ if (cfun->calls_alloca || offset_below_red_zone_p (-info->total_size)) - { - rtx mem = gen_rtx_MEM (BLKmode, sp_reg_rtx); - MEM_NOTRAP_P (mem) = 1; - emit_insn (gen_stack_tie (mem)); - } + rs6000_emit_stack_tie (frame_reg_rtx, false); insn = emit_insn (gen_add3_insn (sp_reg_rtx, sp_reg_rtx, GEN_INT (info->total_size))); - sp_offset = 0; + frame_off = 0; } if (insn && frame_reg_rtx == sp_reg_rtx) { @@ -20493,7 +20488,7 @@ rs6000_emit_epilogue (int sibcall) areg = gen_rtx_REG (Pmode, 0); emit_move_insn (areg, GEN_INT (info->altivec_save_offset - + sp_offset + + frame_off + 16 * (i - info->first_altivec_reg_save))); /* AltiVec addressing mode is [reg+reg]. */ @@ -20519,7 +20514,7 @@ rs6000_emit_epilogue (int sibcall) rtx addr, mem, reg; addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->vrsave_save_offset + sp_offset)); + GEN_INT (info->vrsave_save_offset + frame_off)); mem = gen_frame_mem (SImode, addr); reg = gen_rtx_REG (SImode, 12); emit_move_insn (reg, mem); @@ -20532,7 +20527,7 @@ rs6000_emit_epilogue (int sibcall) if (restore_lr && restoring_GPRs_inline) { rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, - info->lr_save_offset + sp_offset); + info->lr_save_offset + frame_off); emit_move_insn (gen_rtx_REG (Pmode, 0), mem); } @@ -20541,7 +20536,7 @@ rs6000_emit_epilogue (int sibcall) if (info->cr_save_p) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->cr_save_offset + sp_offset)); + GEN_INT (info->cr_save_offset + frame_off)); rtx mem = gen_frame_mem (SImode, addr); cr_save_reg = gen_rtx_REG (SImode, @@ -20565,7 +20560,7 @@ rs6000_emit_epilogue (int sibcall) if (TARGET_AIX) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (sp_offset + 5 * reg_size)); + GEN_INT (frame_off + 5 * reg_size)); rtx mem = gen_frame_mem (reg_mode, addr); emit_move_insn (gen_rtx_REG (reg_mode, 2), mem); @@ -20580,7 +20575,7 @@ rs6000_emit_epilogue (int sibcall) break; mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx, - info->ehrd_offset + sp_offset + info->ehrd_offset + frame_off + reg_size * (int) i); emit_move_insn (gen_rtx_REG (reg_mode, regno), mem); @@ -20597,14 +20592,14 @@ rs6000_emit_epilogue (int sibcall) to be saved with an offset from frame_reg_rtx that fits in the small const field for SPE memory instructions. */ int spe_regs_addressable - = (SPE_CONST_OFFSET_OK (info->spe_gp_save_offset + sp_offset + = (SPE_CONST_OFFSET_OK (info->spe_gp_save_offset + frame_off + reg_size * (32 - info->first_gp_reg_save - 1)) && restoring_GPRs_inline); int spe_offset; int ool_adjust = 0; if (spe_regs_addressable) - spe_offset = info->spe_gp_save_offset + sp_offset; + spe_offset = info->spe_gp_save_offset + frame_off; else { rtx old_frame_reg_rtx = frame_reg_rtx; @@ -20619,11 +20614,11 @@ rs6000_emit_epilogue (int sibcall) frame_reg_rtx = gen_rtx_REG (Pmode, 11); emit_insn (gen_addsi3 (frame_reg_rtx, old_frame_reg_rtx, GEN_INT (info->spe_gp_save_offset - + sp_offset + + frame_off - ool_adjust))); - /* Keep the invariant that frame_reg_rtx + sp_offset points + /* Keep the invariant that frame_reg_rtx + frame_off points at the top of the stack frame. */ - sp_offset = -info->spe_gp_save_offset + ool_adjust; + frame_off = -info->spe_gp_save_offset + ool_adjust; spe_offset = 0; } @@ -20662,7 +20657,7 @@ rs6000_emit_epilogue (int sibcall) if (can_use_exit) { rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx, - sp_offset, can_use_exit); + frame_off, can_use_exit); if (DEFAULT_ABI == ABI_DARWIN) /* we only need a copy, no fprs were saved. */ emit_move_insn (gen_rtx_REG (Pmode, 11), frame_reg_rtx); @@ -20675,9 +20670,9 @@ rs6000_emit_epilogue (int sibcall) rtx src_reg = gen_rtx_REG (Pmode, DEFAULT_ABI == ABI_AIX ? 12 : 11); emit_insn (gen_add3_insn (src_reg, frame_reg_rtx, - GEN_INT (sp_offset - info->fp_size))); + GEN_INT (frame_off - info->fp_size))); if (REGNO (frame_reg_rtx) == REGNO (src_reg)) - sp_offset = info->fp_size; + frame_off = info->fp_size; } rs6000_emit_savres_rtx (info, frame_reg_rtx, @@ -20693,7 +20688,7 @@ rs6000_emit_epilogue (int sibcall) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->gp_save_offset - + sp_offset + + frame_off + reg_size * i)); rtx mem = gen_frame_mem (reg_mode, addr); rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); @@ -20705,17 +20700,17 @@ rs6000_emit_epilogue (int sibcall) else { for (i = 0; i < 32 - info->first_gp_reg_save; i++) - if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i)) + if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i)) { - rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->gp_save_offset - + sp_offset - + reg_size * i)); - rtx mem = gen_frame_mem (reg_mode, addr); + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->gp_save_offset + + frame_off + + reg_size * i)); + rtx mem = gen_frame_mem (reg_mode, addr); rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); emit_move_insn (reg, mem); - } + } } if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap) @@ -20730,7 +20725,7 @@ rs6000_emit_epilogue (int sibcall) { insn = get_last_insn (); add_reg_note (insn, REG_CFA_DEF_CFA, - plus_constant (frame_reg_rtx, sp_offset)); + plus_constant (frame_reg_rtx, frame_off)); RTX_FRAME_RELATED_P (insn) = 1; } @@ -20781,7 +20776,7 @@ rs6000_emit_epilogue (int sibcall) if (restore_lr && !restoring_GPRs_inline) { rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, - info->lr_save_offset + sp_offset); + info->lr_save_offset + frame_off); emit_move_insn (gen_rtx_REG (Pmode, 0), mem); emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO), @@ -20797,15 +20792,15 @@ rs6000_emit_epilogue (int sibcall) rtx addr, mem, reg; addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->fp_save_offset - + sp_offset + + frame_off + 8 * i)); - mem = gen_frame_mem (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) - ? DFmode : SFmode), addr); - reg = gen_rtx_REG (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT) - ? DFmode : SFmode), + mem = gen_frame_mem ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT + ? DFmode : SFmode), addr); + reg = gen_rtx_REG ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT + ? DFmode : SFmode), info->first_fp_reg_save + i); - emit_move_insn (reg, mem); + emit_move_insn (reg, mem); if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap) cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores); } @@ -20817,7 +20812,7 @@ rs6000_emit_epilogue (int sibcall) /* If this is V.4, unwind the stack pointer after all of the loads have been done. */ insn = rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx, - sp_offset, !restoring_FPRs_inline); + frame_off, !restoring_FPRs_inline); if (insn) { if (cfa_restores) @@ -22847,8 +22842,7 @@ is_mem_ref (rtx pat) bool ret = false; /* stack_tie does not produce any real memory traffic. */ - if (GET_CODE (pat) == UNSPEC - && XINT (pat, 1) == UNSPEC_TIE) + if (tie_operand (pat, VOIDmode)) return false; if (GET_CODE (pat) == MEM) diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 6bd2b8d3108..0676915cdd2 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -467,10 +467,11 @@ extern int rs6000_vector_align[]; /* ISA 2.01 allowed FCFID to be done in 32-bit, previously it was 64-bit only. Enable 32-bit fcfid's on any of the switches for newer ISA machines or XILINX. */ -#define TARGET_FCFID (TARGET_POWERPC64 \ - || TARGET_POPCNTB /* ISA 2.02 */ \ - || TARGET_CMPB /* ISA 2.05 */ \ - || TARGET_POPCNTD /* ISA 2.06 */ \ +#define TARGET_FCFID (TARGET_POWERPC64 \ + || TARGET_PPC_GPOPT /* 970/power4 */ \ + || TARGET_POPCNTB /* ISA 2.02 */ \ + || TARGET_CMPB /* ISA 2.05 */ \ + || TARGET_POPCNTD /* ISA 2.06 */ \ || TARGET_XILINX_FPU) #define TARGET_FCTIDZ TARGET_FCFID @@ -492,7 +493,7 @@ extern int rs6000_vector_align[]; #define TARGET_EXTRA_BUILTINS (!TARGET_SPE && !TARGET_PAIRED_FLOAT \ && ((TARGET_POWERPC64 \ - || TARGET_PPC_GPOPT /* 970 */ \ + || TARGET_PPC_GPOPT /* 970/power4 */ \ || TARGET_POPCNTB /* ISA 2.02 */ \ || TARGET_CMPB /* ISA 2.05 */ \ || TARGET_POPCNTD /* ISA 2.06 */ \ @@ -770,8 +771,7 @@ extern unsigned rs6000_pointer_size; #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) \ (STRICT_ALIGNMENT \ || (((MODE) == SFmode || (MODE) == DFmode || (MODE) == TFmode \ - || (MODE) == SDmode || (MODE) == DDmode || (MODE) == TDmode \ - || (MODE) == DImode) \ + || (MODE) == SDmode || (MODE) == DDmode || (MODE) == TDmode) \ && (ALIGN) < 32) \ || (VECTOR_MODE_P ((MODE)) && (((int)(ALIGN)) < VECTOR_ALIGN (MODE)))) diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 22207bbf2b2..3d271695b94 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -73,7 +73,6 @@ (define_c_enum "unspec" [UNSPEC_FRSP ; frsp for POWER machines UNSPEC_PROBE_STACK ; probe stack memory reference - UNSPEC_TIE ; tie stack contents and stack pointer UNSPEC_TOCPTR ; address of a word pointing to the TOC UNSPEC_TOC ; address of the TOC (more-or-less) UNSPEC_MOVSI_GOT @@ -2386,7 +2385,7 @@ (bswap:HI (match_operand:HI 1 "reg_or_mem_operand" ""))) (clobber (match_scratch:SI 2 ""))])] - "" + "TARGET_POWERPC" { if (!REG_P (operands[0]) && !REG_P (operands[1])) operands[1] = force_reg (HImode, operands[1]); @@ -11989,17 +11988,23 @@ (define_expand "restore_stack_block" [(set (match_dup 2) (match_dup 3)) (set (match_dup 4) (match_dup 2)) - (set (match_dup 5) (unspec:BLK [(match_dup 5)] UNSPEC_TIE)) + (match_dup 5) (set (match_operand 0 "register_operand" "") (match_operand 1 "register_operand" ""))] "" " { + rtvec p; + operands[1] = force_reg (Pmode, operands[1]); operands[2] = gen_reg_rtx (Pmode); operands[3] = gen_frame_mem (Pmode, operands[0]); operands[4] = gen_frame_mem (Pmode, operands[1]); - operands[5] = gen_frame_mem (BLKmode, operands[0]); + p = rtvec_alloc (1); + RTVEC_ELT (p, 0) = gen_rtx_SET (VOIDmode, + gen_frame_mem (BLKmode, operands[0]), + const0_rtx); + operands[5] = gen_rtx_PARALLEL (VOIDmode, p); }") (define_expand "save_stack_nonlocal" @@ -12022,12 +12027,13 @@ [(set (match_dup 2) (match_operand 1 "memory_operand" "")) (set (match_dup 3) (match_dup 4)) (set (match_dup 5) (match_dup 2)) - (set (match_dup 6) (unspec:BLK [(match_dup 6)] UNSPEC_TIE)) + (match_dup 6) (set (match_operand 0 "register_operand" "") (match_dup 3))] "" " { int units_per_word = (TARGET_32BIT) ? 4 : 8; + rtvec p; /* Restore the backchain from the first word, sp from the second. */ operands[2] = gen_reg_rtx (Pmode); @@ -12035,7 +12041,11 @@ operands[1] = adjust_address_nv (operands[1], Pmode, 0); operands[4] = adjust_address_nv (operands[1], Pmode, units_per_word); operands[5] = gen_frame_mem (Pmode, operands[3]); - operands[6] = gen_frame_mem (BLKmode, operands[0]); + p = rtvec_alloc (1); + RTVEC_ELT (p, 0) = gen_rtx_SET (VOIDmode, + gen_frame_mem (BLKmode, operands[0]), + const0_rtx); + operands[6] = gen_rtx_PARALLEL (VOIDmode, p); }") ;; TOC register handling. @@ -15899,25 +15909,15 @@ [(set_attr "type" "branch") (set_attr "length" "4")]) -; These are to explain that changes to the stack pointer should -; not be moved over stores to stack memory. +; This is to explain that changes to the stack pointer should +; not be moved over loads from or stores to stack memory. (define_insn "stack_tie" - [(set (match_operand:BLK 0 "memory_operand" "+m") - (unspec:BLK [(match_dup 0)] UNSPEC_TIE))] - "" - "" - [(set_attr "length" "0")]) - -; Like stack_tie, but depend on both fp and sp based memory. -(define_insn "frame_tie" - [(set (match_operand:BLK 0 "memory_operand" "+m") - (unspec:BLK [(match_dup 0) - (match_operand:BLK 1 "memory_operand" "m")] UNSPEC_TIE))] + [(match_parallel 0 "tie_operand" + [(set (mem:BLK (reg 1)) (const_int 0))])] "" "" [(set_attr "length" "0")]) - (define_expand "epilogue" [(use (const_int 0))] "" diff --git a/gcc/config/rs6000/sync.md b/gcc/config/rs6000/sync.md index 38bd8bac354..d4848a81cc8 100644 --- a/gcc/config/rs6000/sync.md +++ b/gcc/config/rs6000/sync.md @@ -24,7 +24,7 @@ (define_code_iterator FETCHOP [plus minus ior xor and]) (define_code_attr fetchop_name - [(plus "add") (minus "sub") (ior "ior") (xor "xor") (and "and")]) + [(plus "add") (minus "sub") (ior "or") (xor "xor") (and "and")]) (define_code_attr fetchop_pred [(plus "add_operand") (minus "gpc_reg_operand") (ior "logical_operand") (xor "logical_operand") (and "and_operand")]) diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c index 4e080c5d799..eb360726005 100644 --- a/gcc/config/rx/rx.c +++ b/gcc/config/rx/rx.c @@ -1606,6 +1606,9 @@ rx_expand_prologue (void) rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size); + if (flag_stack_usage_info) + current_function_static_stack_size = frame_size + stack_size; + /* If we use any of the callee-saved registers, save them now. */ if (mask) { diff --git a/gcc/config/sh/constraints.md b/gcc/config/sh/constraints.md index 3a5fc364f9c..6c9bc5ecc95 100644 --- a/gcc/config/sh/constraints.md +++ b/gcc/config/sh/constraints.md @@ -145,16 +145,28 @@ (and (match_code "const_int") (match_test "ival >= 0 && ival <= 15"))) +(define_constraint "K05" + "An unsigned 5-bit constant, as used in mov.w displacement addressing." + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 31"))) + (define_constraint "K08" "An unsigned 8-bit constant, as used in and, or, etc." (and (match_code "const_int") (match_test "ival >= 0 && ival <= 255"))) (define_constraint "K12" - "An unsigned 12-bit constant, as used in SH2A 12-bit displacement addressing." + "An unsigned 12-bit constant, as used in SH2A 12-bit mov.b displacement + addressing." (and (match_code "const_int") (match_test "ival >= 0 && ival <= 4095"))) +(define_constraint "K13" + "An unsigned 13-bit constant, as used in SH2A 12-bit mov.w displacement + addressing." + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 8191"))) + (define_constraint "K16" "An unsigned 16-bit constant, as used in SHmedia shori." (and (match_code "const_int") @@ -262,6 +274,16 @@ (and (match_test "memory_operand (op, GET_MODE (op))") (match_test "GET_CODE (XEXP (op, 0)) != PLUS"))) +(define_memory_constraint "Sdd" + "A memory reference that uses displacement addressing." + (and (match_test "MEM_P (op) && GET_CODE (XEXP (op, 0)) == PLUS") + (match_test "REG_P (XEXP (XEXP (op, 0), 0))") + (match_test "CONST_INT_P (XEXP (XEXP (op, 0), 1))"))) + +(define_memory_constraint "Snd" + "A memory reference that excludes displacement addressing." + (match_test "! satisfies_constraint_Sdd (op)")) + (define_memory_constraint "Sbv" "A memory reference, as used in SH2A bclr.b, bset.b, etc." (and (match_test "MEM_P (op) && GET_MODE (op) == QImode") @@ -269,15 +291,7 @@ (define_memory_constraint "Sbw" "A memory reference, as used in SH2A bclr.b, bset.b, etc." - (and (match_test "MEM_P (op) && GET_MODE (op) == QImode") - (match_test "GET_CODE (XEXP (op, 0)) == PLUS") - (match_test "REG_P (XEXP (XEXP (op, 0), 0))") + (and (match_test "satisfies_constraint_Sdd (op)") + (match_test "GET_MODE (op) == QImode") (match_test "satisfies_constraint_K12 (XEXP (XEXP (op, 0), 1))"))) -(define_memory_constraint "Snd" - "A memory reference that excludes displacement addressing." - (match_test "! DISP_ADDR_P (op)")) - -(define_memory_constraint "Sdd" - "A memory reference that uses displacement addressing." - (match_test "DISP_ADDR_P (op)")) diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md index b00ad14c0c0..c6d0d464f08 100644 --- a/gcc/config/sh/predicates.md +++ b/gcc/config/sh/predicates.md @@ -404,7 +404,7 @@ if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) - return sh_legitimate_index_p (mode, XEXP (x, 1)); + return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false); } if (TARGET_SHMEDIA @@ -466,7 +466,7 @@ if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) - return sh_legitimate_index_p (mode, XEXP (x, 1)); + return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false); } return general_operand (op, mode); diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index 814374950c1..cb9ad0f203f 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -56,7 +56,7 @@ extern int sh_loop_align (rtx); extern bool fp_zero_operand (rtx); extern bool fp_one_operand (rtx); extern rtx get_fpscr_rtx (void); -extern bool sh_legitimate_index_p (enum machine_mode, rtx); +extern bool sh_legitimate_index_p (enum machine_mode, rtx, bool, bool); extern bool sh_legitimize_reload_address (rtx *, enum machine_mode, int, int); extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx); extern bool nonpic_symbol_mentioned_p (rtx); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 443f8002626..7dbbe1c5728 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -304,6 +304,7 @@ static bool sh_legitimate_constant_p (enum machine_mode, rtx); static int mov_insn_size (enum machine_mode, bool); static int max_mov_insn_displacement (enum machine_mode, bool); static int mov_insn_alignment_mask (enum machine_mode, bool); +static HOST_WIDE_INT disp_addr_displacement (rtx); static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED; @@ -546,10 +547,12 @@ static const struct attribute_spec sh_attribute_table[] = #define TARGET_FRAME_POINTER_REQUIRED sh_frame_pointer_required /* Return regmode weight for insn. */ -#define INSN_REGMODE_WEIGHT(INSN, MODE) regmode_weight[((MODE) == SImode) ? 0 : 1][INSN_UID (INSN)] +#define INSN_REGMODE_WEIGHT(INSN, MODE)\ + regmode_weight[((MODE) == SImode) ? 0 : 1][INSN_UID (INSN)] /* Return current register pressure for regmode. */ -#define CURR_REGMODE_PRESSURE(MODE) curr_regmode_pressure[((MODE) == SImode) ? 0 : 1] +#define CURR_REGMODE_PRESSURE(MODE)\ + curr_regmode_pressure[((MODE) == SImode) ? 0 : 1] #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO sh_encode_section_info @@ -3160,11 +3163,6 @@ max_mov_insn_displacement (enum machine_mode mode, bool consider_sh2a) scale the max. displacement value accordingly. */ const int disp_scale = consider_sh2a ? (4095 / 15) : 1; - /* FIXME: HImode with displacement addressing is not supported yet. - Make it purposefully fail for now. */ - if (mode == HImode) - return 0; - /* SH2A supports FPU move insns with 12 bit displacements. Other variants to do not support any kind of displacements for FPU move insns. */ @@ -3194,15 +3192,24 @@ mov_insn_alignment_mask (enum machine_mode mode, bool consider_sh2a) return mov_insn_sz > 0 ? (mov_insn_sz - 1) : 0; } +/* Return the displacement value of a displacement address. */ + +static inline HOST_WIDE_INT +disp_addr_displacement (rtx x) +{ + gcc_assert (satisfies_constraint_Sdd (x)); + return INTVAL (XEXP (XEXP (x, 0), 1)); +} + /* Compute the cost of an address. */ static int sh_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED) { /* 'reg + disp' addressing. */ - if (DISP_ADDR_P (x)) + if (satisfies_constraint_Sdd (x)) { - const HOST_WIDE_INT offset = DISP_ADDR_OFFSET (x); + const HOST_WIDE_INT offset = disp_addr_displacement (x); const enum machine_mode mode = GET_MODE (x); /* The displacement would fit into a 2 byte move insn. */ @@ -4197,10 +4204,10 @@ dump_table (rtx start, rtx barrier) { rtx scan = barrier; int i; - int need_align = 1; + bool need_align = true; rtx lab; label_ref_list_t ref; - int have_df = 0; + bool have_df = false; /* Do two passes, first time dump out the HI sized constants. */ @@ -4213,7 +4220,7 @@ dump_table (rtx start, rtx barrier) if (need_align) { scan = emit_insn_after (gen_align_2 (), scan); - need_align = 0; + need_align = false; } for (lab = p->label; lab; lab = LABEL_REFS (lab)) scan = emit_label_after (lab, scan); @@ -4226,15 +4233,15 @@ dump_table (rtx start, rtx barrier) } } else if (p->mode == DFmode) - have_df = 1; + have_df = true; } - need_align = 1; + need_align = true; if (start) { scan = emit_insn_after (gen_align_4 (), scan); - need_align = 0; + need_align = false; for (; start != barrier; start = NEXT_INSN (start)) if (NONJUMP_INSN_P (start) && recog_memoized (start) == CODE_FOR_casesi_worker_2) @@ -4251,7 +4258,7 @@ dump_table (rtx start, rtx barrier) scan = emit_label_after (gen_label_rtx (), scan); scan = emit_insn_after (gen_align_log (GEN_INT (3)), scan); - need_align = 0; + need_align = false; for (i = 0; i < pool_size; i++) { @@ -4293,7 +4300,7 @@ dump_table (rtx start, rtx barrier) { scan = emit_insn_after (gen_align_log (GEN_INT (3)), scan); align_insn = scan; - need_align = 0; + need_align = false; } case DImode: for (lab = p->label; lab; lab = LABEL_REFS (lab)) @@ -4331,7 +4338,7 @@ dump_table (rtx start, rtx barrier) case SFmode: if (need_align) { - need_align = 0; + need_align = false; scan = emit_label_after (gen_label_rtx (), scan); scan = emit_insn_after (gen_align_4 (), scan); } @@ -4344,7 +4351,7 @@ dump_table (rtx start, rtx barrier) case DImode: if (need_align) { - need_align = 0; + need_align = false; scan = emit_label_after (gen_label_rtx (), scan); scan = emit_insn_after (gen_align_4 (), scan); } @@ -4543,7 +4550,9 @@ find_barrier (int num_mova, rtx mova, rtx from) int hi_align = 2; int si_align = 2; int leading_mova = num_mova; - rtx barrier_before_mova = 0, found_barrier = 0, good_barrier = 0; + rtx barrier_before_mova = NULL_RTX; + rtx found_barrier = NULL_RTX; + rtx good_barrier = NULL_RTX; int si_limit; int hi_limit; rtx orig = from; @@ -4877,19 +4886,19 @@ sfunc_uses_reg (rtx insn) rtx pattern, part, reg_part, reg; if (!NONJUMP_INSN_P (insn)) - return 0; + return NULL_RTX; pattern = PATTERN (insn); if (GET_CODE (pattern) != PARALLEL || get_attr_type (insn) != TYPE_SFUNC) - return 0; + return NULL_RTX; - for (reg_part = 0, i = XVECLEN (pattern, 0) - 1; i >= 1; i--) + for (reg_part = NULL_RTX, i = XVECLEN (pattern, 0) - 1; i >= 1; i--) { part = XVECEXP (pattern, 0, i); if (GET_CODE (part) == USE && GET_MODE (XEXP (part, 0)) == SImode) reg_part = part; } if (! reg_part) - return 0; + return NULL_RTX; reg = XEXP (reg_part, 0); for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--) { @@ -4899,7 +4908,7 @@ sfunc_uses_reg (rtx insn) if (reg_mentioned_p (reg, ((GET_CODE (part) == SET && REG_P (SET_DEST (part))) ? SET_SRC (part) : part))) - return 0; + return NULL_RTX; } return reg; } @@ -5049,7 +5058,7 @@ regs_used (rtx x, int is_dest) { if (fmt[i] == 'E') { - register int j; + int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) used |= regs_used (XVECEXP (x, i, j), is_dest); } @@ -5334,7 +5343,6 @@ int barrier_align (rtx barrier_or_label) { rtx next = next_real_insn (barrier_or_label), pat, prev; - int slot, credit, jump_to_next = 0; if (! next) return 0; @@ -5386,13 +5394,17 @@ barrier_align (rtx barrier_or_label) /* PREV is presumed to be the JUMP_INSN for the barrier under investigation. Skip to the insn before it. */ + + int slot, credit; + bool jump_to_next = false; + prev = prev_real_insn (prev); for (slot = 2, credit = (1 << (CACHE_LOG - 2)) + 2; credit >= 0 && prev && NONJUMP_INSN_P (prev); prev = prev_real_insn (prev)) { - jump_to_next = 0; + jump_to_next = false; if (GET_CODE (PATTERN (prev)) == USE || GET_CODE (PATTERN (prev)) == CLOBBER) continue; @@ -5402,7 +5414,7 @@ barrier_align (rtx barrier_or_label) if (INSN_UID (prev) == INSN_UID (next)) { /* Delay slot was filled with insn at jump target. */ - jump_to_next = 1; + jump_to_next = true; continue; } } @@ -8433,7 +8445,7 @@ sh_function_arg (cumulative_args_t ca_v, enum machine_mode mode, regno = (BASE_ARG_REG (mode) + ROUND_REG (*ca, mode)) ^ (mode == SFmode && TARGET_SH4 - && TARGET_LITTLE_ENDIAN != 0 + && TARGET_LITTLE_ENDIAN && ! TARGET_HITACHI && ! ca->renesas_abi); return gen_rtx_REG (mode, regno); @@ -8471,10 +8483,10 @@ sh_function_arg (cumulative_args_t ca_v, enum machine_mode mode, + ca->arg_count[(int) SH_ARG_INT])); } - return 0; + return NULL_RTX; } - return 0; + return NULL_RTX; } /* Update the data in CUM to advance over an argument @@ -8635,7 +8647,7 @@ static rtx sh_struct_value_rtx (tree fndecl, int incoming ATTRIBUTE_UNUSED) { if (TARGET_HITACHI || sh_attr_renesas_p (fndecl)) - return 0; + return NULL_RTX; return gen_rtx_REG (Pmode, 2); } @@ -9190,7 +9202,7 @@ sh_attr_renesas_p (const_tree td) { if (TARGET_HITACHI) return true; - if (td == 0) + if (td == NULL_TREE) return false; if (DECL_P (td)) td = TREE_TYPE (td); @@ -9418,7 +9430,7 @@ reg_unused_after (rtx reg, rtx insn) else return false; } - if (set == 0 + if (set == NULL_RTX && reg_overlap_mentioned_p (reg, PATTERN (this_insn))) return false; } @@ -9613,7 +9625,7 @@ sh_insn_length_adjustment (rtx insn) rtx body = PATTERN (insn); const char *templ; char c; - int maybe_label = 1; + bool maybe_label = true; if (GET_CODE (body) == ASM_INPUT) templ = XSTR (body, 0); @@ -9649,7 +9661,7 @@ sh_insn_length_adjustment (rtx insn) break; } else if (c == '\'' || c == '"') - maybe_label = 0; + maybe_label = false; c = *templ++; } sum += ppi_adjust; @@ -9665,7 +9677,8 @@ sh_insn_length_adjustment (rtx insn) with MODE. */ bool -sh_legitimate_index_p (enum machine_mode mode, rtx op) +sh_legitimate_index_p (enum machine_mode mode, rtx op, bool consider_sh2a, + bool allow_zero) { if (! CONST_INT_P (op)) return false; @@ -9686,15 +9699,15 @@ sh_legitimate_index_p (enum machine_mode mode, rtx op) else { const HOST_WIDE_INT offset = INTVAL (op); - const int max_disp = max_mov_insn_displacement (mode, TARGET_SH2A); - const int align_mask = mov_insn_alignment_mask (mode, TARGET_SH2A); + const int max_disp = max_mov_insn_displacement (mode, consider_sh2a); + const int align_mask = mov_insn_alignment_mask (mode, consider_sh2a); /* If the mode does not support any displacement always return false. Even though an index of '0' is actually always valid, it will cause troubles when e.g. a DFmode move is split into two SFmode moves, where one SFmode move will have index '0' and the other move will have index '4'. */ - if (max_disp < 1) + if (!allow_zero && max_disp < 1) return false; return offset >= 0 && offset <= max_disp && (offset & align_mask) == 0; @@ -9728,7 +9741,7 @@ sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) if (GET_MODE_SIZE (mode) <= 8 && MAYBE_BASE_REGISTER_RTX_P (xop0, strict) - && sh_legitimate_index_p (mode, xop1)) + && sh_legitimate_index_p (mode, xop1, TARGET_SH2A, false)) return true; if ((ALLOW_INDEXED_ADDRESS || GET_MODE (x) == DImode @@ -9814,7 +9827,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, if (GET_CODE (orig) == LABEL_REF || (GET_CODE (orig) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (orig))) { - if (reg == 0) + if (reg == NULL_RTX) reg = gen_reg_rtx (Pmode); emit_insn (gen_symGOTOFF2reg (reg, orig)); @@ -9822,7 +9835,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, } else if (GET_CODE (orig) == SYMBOL_REF) { - if (reg == 0) + if (reg == NULL_RTX) reg = gen_reg_rtx (Pmode); emit_insn (gen_symGOT2reg (reg, orig)); @@ -9875,11 +9888,6 @@ sh_find_mov_disp_adjust (enum machine_mode mode, HOST_WIDE_INT offset) if (mode_sz < 1 || mode_sz > 8 || max_disp < 1) return res; - /* FIXME: HImode with displacement addressing is not supported yet. - Make it purposefully fail for now. */ - if (mov_insn_sz == 2) - return res; - /* Keeps the previous behavior for QImode displacement addressing. This just decides how the offset is re-based. Removing this special case will result in slightly bigger code on average, but it's not that @@ -10068,7 +10076,7 @@ mark_constant_pool_use (rtx x) { rtx insn, lab, pattern; - if (x == NULL) + if (x == NULL_RTX) return x; switch (GET_CODE (x)) @@ -10558,22 +10566,14 @@ swap_reorder (rtx *a, int n) a[i + 1] = insn; } -#define SCHED_REORDER(READY, N_READY) \ - do \ - { \ - if ((N_READY) == 2) \ - swap_reorder (READY, N_READY); \ - else if ((N_READY) > 2) \ - qsort (READY, N_READY, sizeof (rtx), rank_for_reorder); \ - } \ - while (0) - -/* Sort the ready list READY by ascending priority, using the SCHED_REORDER - macro. */ +/* Sort the ready list by ascending priority. */ static void ready_reorder (rtx *ready, int nready) { - SCHED_REORDER (ready, nready); + if (nready == 2) + swap_reorder (ready, nready); + else if (nready > 2) + qsort (ready, nready, sizeof (rtx), rank_for_reorder); } /* Count life regions of r0 for a block. */ @@ -11354,12 +11354,12 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode tmode = VOIDmode; int nop = 0, i; rtx op[4]; - rtx pat = 0; + rtx pat = NULL_RTX; if (signature_args[signature][0]) { if (ignore) - return 0; + return NULL_RTX; tmode = insn_data[icode].operand[0].mode; if (! target @@ -11418,7 +11418,7 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, gcc_unreachable (); } if (! pat) - return 0; + return NULL_RTX; emit_insn (pat); return target; } @@ -12196,7 +12196,7 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify) /* The following prevents loops occurrence when we change MEM in CONST_DOUBLE onto the same CONST_DOUBLE. */ - if (x != 0 && GET_CODE (x) == CONST_DOUBLE) + if (x != NULL_RTX && GET_CODE (x) == CONST_DOUBLE) return x; for (i = n_replacements - 1; i >= 0 ; i--) @@ -12204,8 +12204,8 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify) return replacements[i*2+1]; /* Allow this function to make replacements in EXPR_LISTs. */ - if (x == 0) - return 0; + if (x == NULL_RTX) + return NULL_RTX; if (GET_CODE (x) == SUBREG) { @@ -12566,12 +12566,14 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, if (rclass == FPUL_REGS && true_regnum (x) == -1) return GENERAL_REGS; - /* Force mov.b displacement addressing insn to use R0 as the other operand. + /* Force mov.b / mov.w displacement addressing insn to use R0 as + the other operand. On SH2A could also just leave it alone here, which would result in a 4 byte move insn being generated instead. However, for this to work the insns must have the appropriate alternatives. */ - if (mode == QImode && rclass != R0_REGS - && DISP_ADDR_P (x) && DISP_ADDR_OFFSET (x) < 16) + if ((mode == QImode || mode == HImode) && rclass != R0_REGS + && satisfies_constraint_Sdd (x) + && disp_addr_displacement (x) <= max_mov_insn_displacement (mode, false)) return R0_REGS; /* When reload is trying to address a QImode or HImode subreg on the stack, diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index c8af3626a07..a6fac9484c2 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -1210,98 +1210,12 @@ extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER]; ((HOST_BITS_PER_WIDE_INT >= 64 && (VALUE) == (HOST_WIDE_INT) 0xffffffff) \ || (HOST_BITS_PER_WIDE_INT >= 64 && (VALUE) == (HOST_WIDE_INT) -1 << 32)) -#define CONST_OK_FOR_K04(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \ - && ((HOST_WIDE_INT)(VALUE)) <= 15) - #define CONST_OK_FOR_K08(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \ && ((HOST_WIDE_INT)(VALUE)) <= 255) -#define CONST_OK_FOR_K12(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \ - && ((HOST_WIDE_INT)(VALUE)) <= 4095) - #define ZERO_EXTRACT_ANDMASK(EXTRACT_SZ_RTX, EXTRACT_POS_RTX)\ (((1 << INTVAL (EXTRACT_SZ_RTX)) - 1) << INTVAL (EXTRACT_POS_RTX)) -#define DISP_ADDR_P(X) (MEM_P (X) && GET_CODE (XEXP (X, 0)) == PLUS \ - && REG_P (XEXP (XEXP (X, 0), 0)) \ - && CONST_INT_P (XEXP (XEXP (X, 0), 1))) - -#define DISP_ADDR_OFFSET(X) (INTVAL (XEXP (XEXP (X, 0), 1))) - -#if 0 -#define SECONDARY_INOUT_RELOAD_CLASS(CLASS,MODE,X,ELSE) \ - ((((REGCLASS_HAS_FP_REG (CLASS) \ - && (REG_P (X) \ - && (GENERAL_OR_AP_REGISTER_P (REGNO (X)) \ - || (FP_REGISTER_P (REGNO (X)) && (MODE) == SImode \ - && TARGET_FMOVD)))) \ - || (REGCLASS_HAS_GENERAL_REG (CLASS) \ - && REG_P (X) \ - && FP_REGISTER_P (REGNO (X)))) \ - && ! TARGET_SHMEDIA \ - && ((MODE) == SFmode || (MODE) == SImode)) \ - ? FPUL_REGS \ - : (((CLASS) == FPUL_REGS \ - || (REGCLASS_HAS_FP_REG (CLASS) \ - && ! TARGET_SHMEDIA && MODE == SImode)) \ - && (MEM_P (X) \ - || (REG_P (X) \ - && (REGNO (X) >= FIRST_PSEUDO_REGISTER \ - || REGNO (X) == T_REG \ - || system_reg_operand (X, VOIDmode))))) \ - ? GENERAL_REGS \ - : (((CLASS) == TARGET_REGS \ - || (TARGET_SHMEDIA && (CLASS) == SIBCALL_REGS)) \ - && !satisfies_constraint_Csy (X) \ - && (!REG_P (X) || ! GENERAL_REGISTER_P (REGNO (X)))) \ - ? GENERAL_REGS \ - : (((CLASS) == MAC_REGS || (CLASS) == PR_REGS) \ - && REG_P (X) && ! GENERAL_REGISTER_P (REGNO (X)) \ - && (CLASS) != REGNO_REG_CLASS (REGNO (X))) \ - ? GENERAL_REGS \ - : ((CLASS) != GENERAL_REGS && REG_P (X) \ - && TARGET_REGISTER_P (REGNO (X))) \ - ? GENERAL_REGS : (ELSE)) - -#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \ - SECONDARY_INOUT_RELOAD_CLASS(CLASS,MODE,X,NO_REGS) - -#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \ - ((REGCLASS_HAS_FP_REG (CLASS) \ - && ! TARGET_SHMEDIA \ - && immediate_operand ((X), (MODE)) \ - && ! ((fp_zero_operand (X) || fp_one_operand (X)) \ - && (MODE) == SFmode && fldi_ok ())) \ - ? R0_REGS \ - : ((CLASS) == FPUL_REGS \ - && ((REG_P (X) \ - && (REGNO (X) == MACL_REG || REGNO (X) == MACH_REG \ - || REGNO (X) == T_REG)) \ - || GET_CODE (X) == PLUS)) \ - ? GENERAL_REGS \ - : (CLASS) == FPUL_REGS && immediate_operand ((X), (MODE)) \ - ? (satisfies_constraint_I08 (X) \ - ? GENERAL_REGS \ - : R0_REGS) \ - : ((CLASS) == FPSCR_REGS \ - && ((REG_P (X) && REGNO (X) >= FIRST_PSEUDO_REGISTER) \ - || (MEM_P (X) && GET_CODE (XEXP ((X), 0)) == PLUS))) \ - ? GENERAL_REGS \ - : (REGCLASS_HAS_FP_REG (CLASS) \ - && TARGET_SHMEDIA \ - && immediate_operand ((X), (MODE)) \ - && (X) != CONST0_RTX (GET_MODE (X)) \ - && GET_MODE (X) != V4SFmode) \ - ? GENERAL_REGS \ - : (((MODE) == QImode || (MODE) == HImode) \ - && TARGET_SHMEDIA && inqhi_operand ((X), (MODE))) \ - ? GENERAL_REGS \ - : (TARGET_SHMEDIA && (CLASS) == GENERAL_REGS \ - && (GET_CODE (X) == LABEL_REF || PIC_ADDR_P (X))) \ - ? TARGET_REGS \ - : SECONDARY_INOUT_RELOAD_CLASS((CLASS),(MODE),(X), NO_REGS)) -#endif - /* Return the maximum number of consecutive registers needed to represent mode MODE in a register of class CLASS. @@ -1737,7 +1651,7 @@ struct sh_args { can ignore COUNT. */ #define RETURN_ADDR_RTX(COUNT, FRAME) \ - (((COUNT) == 0) ? sh_get_pr_initial_val () : (rtx) 0) + (((COUNT) == 0) ? sh_get_pr_initial_val () : NULL_RTX) /* A C expression whose value is RTL representing the location of the incoming return address at the beginning of any function, before the @@ -2387,8 +2301,6 @@ extern int current_function_interrupt; #define MAX_FIXED_MODE_SIZE (TARGET_SH5 ? 128 : 64) -#define SIDI_OFF (TARGET_LITTLE_ENDIAN ? 0 : 4) - /* Better to allocate once the maximum space for outgoing args in the prologue rather than duplicate around each call. */ #define ACCUMULATE_OUTGOING_ARGS TARGET_ACCUMULATE_OUTGOING_ARGS diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 0fe9fca2bed..45a5edf6ad7 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -942,15 +942,10 @@ (set (reg:SI T_REG) (eq:SI (match_dup 4) (match_dup 5))) (match_dup 6)] { - operands[2] - = gen_rtx_REG (SImode, - true_regnum (operands[0]) + (TARGET_LITTLE_ENDIAN ? 1 : 0)); - operands[3] - = (operands[1] == const0_rtx - ? const0_rtx - : gen_rtx_REG (SImode, - true_regnum (operands[1]) - + (TARGET_LITTLE_ENDIAN ? 1 : 0))); + operands[2] = gen_highpart (SImode, operands[0]); + operands[3] = operands[1] == const0_rtx + ? const0_rtx + : gen_highpart (SImode, operands[1]); operands[4] = gen_lowpart (SImode, operands[0]); operands[5] = gen_lowpart (SImode, operands[1]); operands[6] = gen_label_rtx (); @@ -1453,13 +1448,10 @@ "TARGET_SH1 && reload_completed" [(const_int 0)] { - rtx high0, high2, low0 = gen_lowpart (SImode, operands[0]); - high0 = gen_rtx_REG (SImode, - true_regnum (operands[0]) - + (TARGET_LITTLE_ENDIAN ? 1 : 0)); - high2 = gen_rtx_REG (SImode, - true_regnum (operands[2]) - + (TARGET_LITTLE_ENDIAN ? 1 : 0)); + rtx high0 = gen_highpart (SImode, operands[0]); + rtx high2 = gen_highpart (SImode, operands[2]); + rtx low0 = gen_lowpart (SImode, operands[0]); + emit_insn (gen_clrt ()); emit_insn (gen_addc (low0, low0, gen_lowpart (SImode, operands[2]))); emit_insn (gen_addc1 (high0, high0, high2)); @@ -1581,13 +1573,10 @@ "TARGET_SH1 && reload_completed" [(const_int 0)] { - rtx high0, high2, low0 = gen_lowpart (SImode, operands[0]); - high0 = gen_rtx_REG (SImode, - true_regnum (operands[0]) - + (TARGET_LITTLE_ENDIAN ? 1 : 0)); - high2 = gen_rtx_REG (SImode, - true_regnum (operands[2]) - + (TARGET_LITTLE_ENDIAN ? 1 : 0)); + rtx high0 = gen_highpart (SImode, operands[0]); + rtx high2 = gen_highpart (SImode, operands[2]); + rtx low0 = gen_lowpart (SImode, operands[0]); + emit_insn (gen_clrt ()); emit_insn (gen_subc (low0, low0, gen_lowpart (SImode, operands[2]))); emit_insn (gen_subc1 (high0, high0, high2)); @@ -2321,7 +2310,7 @@ norm32: r25 rtx tab_ix = operands[2]; rtx norm32 = operands[3]; rtx scratch0 = operands[4]; - rtx scratch0_si = simplify_gen_subreg (SImode, scratch0, DImode, SIDI_OFF); + rtx scratch0_si = gen_lowpart (SImode, scratch0); rtx scratch1 = operands[5]; emit_insn (gen_divsi_inv_qitable (scratch0, tab_base, tab_ix)); @@ -2368,7 +2357,7 @@ norm32: r25 rtx scratch0b = operands[6]; rtx scratch0 = operands[7]; rtx scratch1 = operands[8]; - rtx scratch1_si = simplify_gen_subreg (SImode, scratch1, DImode, SIDI_OFF); + rtx scratch1_si = gen_lowpart (SImode, scratch1); emit_insn (gen_divsi_inv_m0 (inv0, tab_base, tab_ix, norm32, scratch0a, scratch0b)); @@ -2405,7 +2394,7 @@ norm32: r25 rtx inv1 = operands[2]; rtx i92 = operands[3]; rtx scratch0 = operands[4]; - rtx scratch0_si = simplify_gen_subreg (SImode, scratch0, DImode, SIDI_OFF); + rtx scratch0_si = gen_lowpart (SImode, scratch0); emit_insn (gen_mulsidi3_media (scratch0, inv1, norm32)); emit_insn (gen_ashrdi3_media (scratch0, scratch0, GEN_INT (16))); @@ -2518,9 +2507,9 @@ norm32: r25 rtx i2p27 = operands[7]; rtx i43 = operands[8]; rtx scratch0 = operands[9]; - rtx scratch0_si = simplify_gen_subreg (SImode, scratch0, DImode, SIDI_OFF); + rtx scratch0_si = gen_lowpart (SImode, scratch0); rtx scratch1 = operands[10]; - rtx scratch1_si = simplify_gen_subreg (SImode, scratch1, DImode, SIDI_OFF); + rtx scratch1_si = gen_lowpart (SImode, scratch1); rtx scratch2 = operands[11]; rtx scratch3 = operands[12]; rtx scratch4 = operands[13]; @@ -3919,17 +3908,14 @@ label: (match_operand:DI 2 "const_int_operand" "n")))] "TARGET_SH1 && INTVAL (operands[2]) < 32" { - int low_word = (TARGET_LITTLE_ENDIAN ? 0 : 1); - int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0); - rtx low_src = operand_subword (operands[1], low_word, 0, DImode); - rtx high_src = operand_subword (operands[1], high_word, 0, DImode); + rtx low_src = gen_lowpart (SImode, operands[1]); + rtx high_src = gen_highpart (SImode, operands[1]); rtx dst = gen_reg_rtx (DImode); - rtx low_dst = operand_subword (dst, low_word, 1, DImode); - rtx high_dst = operand_subword (dst, high_word, 1, DImode); - rtx tmp0, tmp1; + rtx low_dst = gen_lowpart (SImode, dst); + rtx high_dst = gen_highpart (SImode, dst); + rtx tmp0 = gen_reg_rtx (SImode); + rtx tmp1 = gen_reg_rtx (SImode); - tmp0 = gen_reg_rtx (SImode); - tmp1 = gen_reg_rtx (SImode); emit_insn (gen_lshrsi3 (tmp0, low_src, GEN_INT (32 - INTVAL (operands[2])))); emit_insn (gen_ashlsi3 (low_dst, low_src, operands[2])); emit_insn (gen_ashlsi3 (tmp1, high_src, operands[2])); @@ -4373,14 +4359,10 @@ label: "TARGET_SH1" [(const_int 0)] { - int low_word = (TARGET_LITTLE_ENDIAN ? 0 : 1); - int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0); - - rtx low_src = operand_subword (operands[1], low_word, 0, DImode); - rtx high_src = operand_subword (operands[1], high_word, 0, DImode); - - rtx low_dst = operand_subword (operands[0], low_word, 1, DImode); - rtx high_dst = operand_subword (operands[0], high_word, 1, DImode); + rtx low_src = gen_lowpart (SImode, operands[1]); + rtx high_src = gen_highpart (SImode, operands[1]); + rtx low_dst = gen_lowpart (SImode, operands[0]); + rtx high_dst = gen_highpart (SImode, operands[0]); emit_insn (gen_clrt ()); emit_insn (gen_negc (low_dst, low_src)); @@ -4493,8 +4475,7 @@ label: "&& reload_completed" [(const_int 0)] { - int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0); - rtx high_src = operand_subword (operands[1], high_word, 0, DImode); + rtx high_src = gen_highpart (SImode, operands[1]); emit_insn (gen_cmpgesi_t (high_src, const0_rtx)); emit_insn (gen_negdi_cond (operands[0], operands[1], operands[1], const1_rtx)); @@ -4509,9 +4490,7 @@ label: "&& reload_completed" [(const_int 0)] { - int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0); - rtx high_src = operand_subword (operands[1], high_word, 0, DImode); - + rtx high_src = gen_highpart (SImode, operands[1]); emit_insn (gen_cmpgesi_t (high_src, const0_rtx)); emit_insn (gen_negdi_cond (operands[0], operands[1], operands[1], const0_rtx)); @@ -4529,14 +4508,10 @@ label: "TARGET_SH1" [(const_int 0)] { - int low_word = (TARGET_LITTLE_ENDIAN ? 0 : 1); - int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0); - - rtx low_src = operand_subword (operands[1], low_word, 0, DImode); - rtx high_src = operand_subword (operands[1], high_word, 0, DImode); - - rtx low_dst = operand_subword (operands[0], low_word, 1, DImode); - rtx high_dst = operand_subword (operands[0], high_word, 1, DImode); + rtx low_src = gen_lowpart (SImode, operands[1]); + rtx high_src = gen_highpart (SImode, operands[1]); + rtx low_dst = gen_lowpart (SImode, operands[0]); + rtx high_dst = gen_highpart (SImode, operands[0]); rtx skip_neg_label = gen_label_rtx (); @@ -4768,20 +4743,18 @@ label: operands[1] = XEXP (operands[1], 0); }) +;; FIXME: Maybe fold HImode and QImode stuff with mode iterator? (define_expand "extendhisi2" - [(set (match_operand:SI 0 "arith_reg_dest" "=r,r") - (sign_extend:SI (match_operand:HI 1 "general_extend_operand" "r,m")))] + [(set (match_operand:SI 0 "arith_reg_dest" "") + (sign_extend:SI (match_operand:HI 1 "general_extend_operand" "")))] "" "") -(define_insn "*extendhisi2_compact" - [(set (match_operand:SI 0 "arith_reg_dest" "=r,r") - (sign_extend:SI (match_operand:HI 1 "general_movsrc_operand" "r,m")))] - "TARGET_SH1" - "@ - exts.w %1,%0 - mov.w %1,%0" - [(set_attr "type" "arith,load")]) +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "arith_reg_dest" "") + (sign_extend:SI (match_operand:QI 1 "general_extend_operand" "")))] + "" + "") (define_insn "*extendhisi2_media" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -4811,12 +4784,6 @@ label: subreg_lowpart_offset (SImode, GET_MODE (op1))); }) -(define_expand "extendqisi2" - [(set (match_operand:SI 0 "arith_reg_dest" "") - (sign_extend:SI (match_operand:QI 1 "general_extend_operand" "")))] - "" - "") - (define_insn "*extendqisi2_compact_reg" [(set (match_operand:SI 0 "arith_reg_dest" "=r,r") (sign_extend:SI (match_operand:QI 1 "register_operand" "r,t")))] @@ -4826,6 +4793,15 @@ label: movt %0" [(set_attr "type" "arith,arith")]) +(define_insn "*extendhisi2_compact_reg" + [(set (match_operand:SI 0 "arith_reg_dest" "=r,r") + (sign_extend:SI (match_operand:HI 1 "register_operand" "r,t")))] + "TARGET_SH1" + "@ + exts.w %1,%0 + movt %0" + [(set_attr "type" "arith,arith")]) + ;; FIXME: Fold non-SH2A and SH2A alternatives with "enabled" attribute. ;; See movqi insns. (define_insn "*extendqisi2_compact_mem_disp" @@ -4833,20 +4809,31 @@ label: (sign_extend:SI (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r") (match_operand:SI 2 "const_int_operand" "K04,N")))))] - "TARGET_SH1 && ! TARGET_SH2A && CONST_OK_FOR_K04 (INTVAL (operands[2]))" + "TARGET_SH1 && ! TARGET_SH2A + && sh_legitimate_index_p (QImode, operands[2], false, true)" "@ mov.b @(%O2,%1),%0 mov.b @%1,%0" [(set_attr "type" "load")]) +(define_insn "*extendhisi2_compact_mem_disp" + [(set (match_operand:SI 0 "arith_reg_dest" "=z,r") + (sign_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r") + (match_operand:SI 2 "const_int_operand" "K05,N")))))] + "TARGET_SH1 && ! TARGET_SH2A + && sh_legitimate_index_p (HImode, operands[2], false, true)" + "@ + mov.w @(%O2,%1),%0 + mov.w @%1,%0" + [(set_attr "type" "load")]) + (define_insn "*extendqisi2_compact_mem_disp" [(set (match_operand:SI 0 "arith_reg_dest" "=z,r,r") (sign_extend:SI (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r") (match_operand:SI 2 "const_int_operand" "K04,N,K12")))))] - "TARGET_SH2A - && (CONST_OK_FOR_K04 (INTVAL (operands[2])) - || (CONST_OK_FOR_K12 (INTVAL (operands[2]))))" + "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[2], true, true)" "@ mov.b @(%O2,%1),%0 mov.b @%1,%0 @@ -4854,8 +4841,23 @@ label: [(set_attr "type" "load") (set_attr "length" "2,2,4")]) -;; This will take care of other QImode addressing modes than displacement -;; addressing. +(define_insn "*extendhisi2_compact_mem_disp" + [(set (match_operand:SI 0 "arith_reg_dest" "=z,r,r") + (sign_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r") + (match_operand:SI 2 "const_int_operand" "K05,N,K13")))))] + "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[2], true, true)" + "@ + mov.w @(%O2,%1),%0 + mov.w @%1,%0 + mov.w @(%O2,%1),%0" + [(set_attr "type" "load") + (set_attr "length" "2,2,4")]) + +;; The *_snd patterns will take care of other QImode/HImode addressing +;; modes than displacement addressing. They must be defined _after_ the +;; displacement addressing patterns. Otherwise the displacement addressing +;; patterns will not be picked. (define_insn "*extendqisi2_compact_snd" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (sign_extend:SI (match_operand:QI 1 "movsrc_no_disp_mem_operand" "Snd")))] @@ -4863,6 +4865,13 @@ label: "mov.b %1,%0" [(set_attr "type" "load")]) +(define_insn "*extendhisi2_compact_snd" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (sign_extend:SI (match_operand:HI 1 "movsrc_no_disp_mem_operand" "Snd")))] + "TARGET_SH1" + "mov.w %1,%0" + [(set_attr "type" "load")]) + (define_insn "*extendqisi2_media" [(set (match_operand:SI 0 "register_operand" "=r,r") (sign_extend:SI (match_operand:QI 1 "general_extend_operand" "r,m")))] @@ -5441,6 +5450,14 @@ label: [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) +(define_expand "movhi" + [(set (match_operand:HI 0 "general_movdst_operand" "") + (match_operand:HI 1 "general_movsrc_operand" ""))] + "" +{ + prepare_move_operands (operands, HImode); +}) + (define_expand "movqi" [(set (match_operand:QI 0 "general_operand" "") (match_operand:QI 1 "general_operand" ""))] @@ -5456,6 +5473,7 @@ label: ;; With the movqi_reg_reg being specified before movqi it will be intially ;; picked to load/store regs. If the regs regs are on the stack reload will ;; try other insns and not stick to movqi_reg_reg. +;; The same applies to the movhi variants. (define_insn "*movqi_reg_reg" [(set (match_operand:QI 0 "arith_reg_dest" "=r,r") (match_operand:QI 1 "register_operand" "r,t"))] @@ -5465,44 +5483,82 @@ label: movt %0" [(set_attr "type" "move,arith")]) +(define_insn "*movhi_reg_reg" + [(set (match_operand:HI 0 "arith_reg_dest" "=r,r") + (match_operand:HI 1 "register_operand" "r,t"))] + "TARGET_SH1" + "@ + mov %1,%0 + movt %0" + [(set_attr "type" "move,arith")]) + ;; FIXME: The non-SH2A and SH2A variants should be combined by adding ;; "enabled" attribute as it is done in other targets. (define_insn "*movqi_store_mem_disp04" [(set (mem:QI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r,r") (match_operand:SI 1 "const_int_operand" "K04,N"))) (match_operand:QI 2 "arith_reg_operand" "z,r"))] - "TARGET_SH1 && CONST_OK_FOR_K04 (INTVAL (operands[1]))" + "TARGET_SH1 && sh_legitimate_index_p (QImode, operands[1], false, true)" "@ mov.b %2,@(%O1,%0) mov.b %2,@%0" [(set_attr "type" "store")]) +(define_insn "*movhi_store_mem_disp05" + [(set (mem:HI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r,r") + (match_operand:SI 1 "const_int_operand" "K05,N"))) + (match_operand:HI 2 "arith_reg_operand" "z,r"))] + "TARGET_SH1 && sh_legitimate_index_p (HImode, operands[1], false, true)" + "@ + mov.w %2,@(%O1,%0) + mov.w %2,@%0" + [(set_attr "type" "store")]) + (define_insn "*movqi_store_mem_disp12" [(set (mem:QI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r") (match_operand:SI 1 "const_int_operand" "K12"))) (match_operand:QI 2 "arith_reg_operand" "r"))] - "TARGET_SH2A && CONST_OK_FOR_K12 (INTVAL (operands[1]))" + "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[1], true, true)" "mov.b %2,@(%O1,%0)" [(set_attr "type" "store") (set_attr "length" "4")]) +(define_insn "*movhi_store_mem_disp13" + [(set (mem:HI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r") + (match_operand:SI 1 "const_int_operand" "K13"))) + (match_operand:HI 2 "arith_reg_operand" "r"))] + "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[1], true, true)" + "mov.w %2,@(%O1,%0)" + [(set_attr "type" "store") + (set_attr "length" "4")]) + (define_insn "*movqi_load_mem_disp" [(set (match_operand:QI 0 "arith_reg_dest" "=z,r") (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r") (match_operand:SI 2 "const_int_operand" "K04,N"))))] - "TARGET_SH1 && ! TARGET_SH2A && CONST_OK_FOR_K04 (INTVAL (operands[2]))" + "TARGET_SH1 && ! TARGET_SH2A + && sh_legitimate_index_p (QImode, operands[2], false, true)" "@ mov.b @(%O2,%1),%0 mov.b @%1,%0" [(set_attr "type" "load")]) +(define_insn "*movhi_load_mem_disp" + [(set (match_operand:HI 0 "arith_reg_dest" "=z,r") + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r") + (match_operand:SI 2 "const_int_operand" "K05,N"))))] + "TARGET_SH1 && ! TARGET_SH2A + && sh_legitimate_index_p (HImode, operands[2], false, true)" + "@ + mov.w @(%O2,%1),%0 + mov.w @%1,%0" + [(set_attr "type" "load")]) + (define_insn "*movqi_load_mem_disp" [(set (match_operand:QI 0 "arith_reg_dest" "=z,r,r") (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r") (match_operand:SI 2 "const_int_operand" "K04,N,K12"))))] - "TARGET_SH2A - && (CONST_OK_FOR_K04 (INTVAL (operands[2])) - || CONST_OK_FOR_K12 (INTVAL (operands[2])))" + "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[2], true, true)" "@ mov.b @(%O2,%1),%0 mov.b @%1,%0 @@ -5510,6 +5566,18 @@ label: [(set_attr "type" "load") (set_attr "length" "2,2,4")]) +(define_insn "*movhi_load_mem_disp" + [(set (match_operand:HI 0 "arith_reg_dest" "=z,r,r") + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r") + (match_operand:SI 2 "const_int_operand" "K05,N,K13"))))] + "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[2], true, true)" + "@ + mov.w @(%O2,%1),%0 + mov.w @%1,%0 + mov.w @(%O2,%1),%0" + [(set_attr "type" "load") + (set_attr "length" "2,2,4")]) + ;; The m constraints basically allow any kind of addresses to be used with any ;; source/target register as the other operand. This is not true for ;; displacement addressing modes on anything but SH2A. That's why the @@ -5528,6 +5596,21 @@ label: lds %1,%0" [(set_attr "type" "movi8,load,store,prget,prset")]) +(define_insn "*movhi" + [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,m,r,l") + (match_operand:HI 1 "general_movsrc_operand" "Q,i,m,r,l,r"))] + "TARGET_SH1 + && (arith_reg_operand (operands[0], HImode) + || arith_reg_operand (operands[1], HImode))" + "@ + mov.w %1,%0 + mov %1,%0 + mov.w %1,%0 + mov.w %1,%0 + sts %1,%0 + lds %1,%0" + [(set_attr "type" "pcload,movi8,load,store,prget,prset")]) + (define_insn "*movqi_media" [(set (match_operand:QI 0 "general_movdst_operand" "=r,r,r,m") (match_operand:QI 1 "general_movsrc_operand" "r,I16Css,m,rZ"))] @@ -5560,28 +5643,6 @@ label: operands[3] = gen_rtx_REG (DImode, REGNO (operands[2])); }) -;; When storing r0, we have to avoid reg+reg addressing. -(define_insn "movhi_i" - [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,r,m,r,l,r") - (match_operand:HI 1 "general_movsrc_operand" "Q,rI08,m,t,r,l,r,i"))] - "TARGET_SH1 - && (arith_reg_operand (operands[0], HImode) - || arith_reg_operand (operands[1], HImode)) - && (!MEM_P (operands[0]) - || GET_CODE (XEXP (operands[0], 0)) != PLUS - || !REG_P (XEXP (XEXP (operands[0], 0), 1)) - || ! refers_to_regno_p (R0_REG, R0_REG + 1, operands[1], (rtx *)0))" - "@ - mov.w %1,%0 - mov %1,%0 - mov.w %1,%0 - movt %0 - mov.w %1,%0 - sts %1,%0 - lds %1,%0 - fake %1,%0" - [(set_attr "type" "pcload,move,load,move,store,move,move,pcload")]) - (define_insn "*movhi_media" [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,r,m") (match_operand:HI 1 "general_movsrc_operand" "r,I16Css,n,m,rZ"))] @@ -5607,14 +5668,6 @@ label: && ! satisfies_constraint_I16 (operands[1])" [(set (subreg:DI (match_dup 0) 0) (match_dup 1))]) -(define_expand "movhi" - [(set (match_operand:HI 0 "general_movdst_operand" "") - (match_operand:HI 1 "general_movsrc_operand" ""))] - "" -{ - prepare_move_operands (operands, HImode); -}) - (define_expand "reload_inhi" [(set (match_operand:SI 2 "" "=&r") (match_operand:HI 1 "inqhi_operand" "")) @@ -11563,10 +11616,10 @@ label: ;; Fold sequence: ;; mov #54,r0 -;; mov.b @(r0,r15),r0 +;; mov.{b,w} @(r0,r15),r0 ;; mov r0,r3 ;; into: -;; mov.b @(54,r15),r3 +;; mov.{b,w} @(54,r15),r3 ;; (define_peephole2 [(set (match_operand:SI 0 "arith_reg_dest" "") @@ -11578,17 +11631,33 @@ label: (set (match_operand:QI 4 "arith_reg_dest" "") (match_operand:QI 5 "arith_reg_operand" ""))] "TARGET_SH2A - && CONST_OK_FOR_K12 (INTVAL (operands[1])) + && sh_legitimate_index_p (QImode, operands[1], true, true) && REGNO (operands[2]) == REGNO (operands[5]) && peep2_reg_dead_p (3, operands[5])" [(set (match_dup 4) (mem:QI (plus:SI (match_dup 3) (match_dup 1))))] "") +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (match_operand:SI 2 "arith_reg_dest" "") + (sign_extend:SI + (mem:HI (plus:SI (match_dup 0) + (match_operand:SI 3 "arith_reg_operand" ""))))) + (set (match_operand:HI 4 "arith_reg_dest" "") + (match_operand:HI 5 "arith_reg_operand" ""))] + "TARGET_SH2A + && sh_legitimate_index_p (HImode, operands[1], true, true) + && REGNO (operands[2]) == REGNO (operands[5]) + && peep2_reg_dead_p (3, operands[5])" + [(set (match_dup 4) (mem:HI (plus:SI (match_dup 3) (match_dup 1))))] + "") + ;; Fold sequence: ;; mov #54,r0 -;; mov.b @(r0,r15),r1 +;; mov.{b,w} @(r0,r15),r1 ;; into: -;; mov.b @(54,r15),r1 +;; mov.{b,w} @(54,r15),r1 ;; (define_peephole2 [(set (match_operand:SI 0 "arith_reg_dest" "") @@ -11598,19 +11667,37 @@ label: (mem:QI (plus:SI (match_dup 0) (match_operand:SI 3 "arith_reg_operand" "")))))] "TARGET_SH2A - && CONST_OK_FOR_K12 (INTVAL (operands[1])) + && sh_legitimate_index_p (QImode, operands[1], true, true) && (peep2_reg_dead_p (2, operands[0]) || REGNO (operands[0]) == REGNO (operands[2]))" [(set (match_dup 2) (sign_extend:SI (mem:QI (plus:SI (match_dup 3) (match_dup 1)))))] "") +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (match_operand:SI 2 "arith_reg_dest" "") + (sign_extend:SI + (mem:HI (plus:SI (match_dup 0) + (match_operand:SI 3 "arith_reg_operand" "")))))] + "TARGET_SH2A + && sh_legitimate_index_p (HImode, operands[1], true, true) + && (peep2_reg_dead_p (2, operands[0]) + || REGNO (operands[0]) == REGNO (operands[2]))" + [(set (match_dup 2) + (sign_extend:SI (mem:HI (plus:SI (match_dup 3) (match_dup 1)))))] + "") + ;; Fold sequence: -;; mov.b @(r0,r15),r0 +;; mov.{b,w} @(r0,r15),r0 ;; mov r0,r3 ;; into: -;; mov.b @(r0,r15),r3 +;; mov.{b,w} @(r0,r15),r3 ;; +;; This can happen when initially a displacement address is picked, where +;; the destination reg is fixed to r0, and then the address is transformed +;; into 'r0 + reg'. (define_peephole2 [(set (match_operand:SI 0 "arith_reg_dest" "") (sign_extend:SI @@ -11625,6 +11712,20 @@ label: (mem:QI (plus:SI (match_dup 1) (match_dup 2))))] "") +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest" "") + (sign_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "") + (match_operand:SI 2 "arith_reg_operand" ""))))) + (set (match_operand:HI 3 "arith_reg_dest" "") + (match_operand:HI 4 "arith_reg_operand" ""))] + "TARGET_SH1 + && REGNO (operands[0]) == REGNO (operands[4]) + && peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 3) + (mem:HI (plus:SI (match_dup 1) (match_dup 2))))] + "") + ;; These convert sequences such as `mov #k,r0; add r15,r0; mov.l @r0,rn' ;; to `mov #k,r0; mov.l @(r0,r15),rn'. These sequences are generated by ;; reload when the constant is too large for a reg+offset address. diff --git a/gcc/convert.c b/gcc/convert.c index dc9b7f29ea4..5e6b09e0654 100644 --- a/gcc/convert.c +++ b/gcc/convert.c @@ -44,11 +44,6 @@ convert_to_pointer (tree type, tree expr) if (TREE_TYPE (expr) == type) return expr; - /* Propagate overflow to the NULL pointer. */ - if (integer_zerop (expr)) - return force_fit_type_double (type, double_int_zero, 0, - TREE_OVERFLOW (expr)); - switch (TREE_CODE (TREE_TYPE (expr))) { case POINTER_TYPE: @@ -542,7 +537,6 @@ convert_to_integer (tree type, tree expr) else if (outprec >= inprec) { enum tree_code code; - tree tem; /* If the precision of the EXPR's type is K bits and the destination mode has more bits, and the sign is changing, @@ -560,13 +554,7 @@ convert_to_integer (tree type, tree expr) else code = NOP_EXPR; - tem = fold_unary (code, type, expr); - if (tem) - return tem; - - tem = build1 (code, type, expr); - TREE_NO_WARNING (tem) = 1; - return tem; + return fold_build1 (code, type, expr); } /* If TYPE is an enumeral type or a type with a precision less diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 78c43691d45..69c5916cfaf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,229 @@ +2012-04-22 Jan Hubicka <jh@suse.cz> + + * decl2.c (maybe_make_one_only): Mark keyed COMDATs as USED so they + gets finalized. + +2012-04-22 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR c/44774 + * typeck.c (composite_pointer_type): Likewise. + (cxx_sizeof_or_alignof_type): Likewise. + (cp_build_array_ref): Likewise. + (cp_build_function_call_vec): Likewise. + (cp_build_addr_expr_1): Likewise. + (convert_member_func_to_ptr): Likewise. + * decl.c (check_tag_decl): Likewise. + (check_static_variable_definition): Likewise. + (compute_array_index_type): Likewise. + (create_array_type_for_decl): Likewise. + (grokdeclarator): Likewise. + (grok_op_properties): Likewise. + * error.c (maybe_warn_cpp0x): Likewise. + * pt.c (maybe_process_partial_specialization): Likewise. + (convert_template_argument): Likewise. + (do_decl_instantiation): Likewise. + (do_type_instantiation): Likewise. + * parser.c (cp_parser_primary_expression): Likewise. + (cp_parser_postfix_expression): Likewise. + (cp_parser_unary_expression): Likewise. + (cp_parser_question_colon_clause): Likewise. + (cp_parser_lambda_introducer): Likewise. + (cp_parser_lambda_declarator_opt): Likewise. + (cp_parser_compound_statement): Likewise. + (cp_parser_jump_statement): Likewise. + (cp_parser_declaration_seq_opt): Likewise. + (cp_parser_enum_specifier): Likewise. + (cp_parser_enumerator_list): Likewise. + (cp_parser_initializer_list): Likewise. + (cp_parser_member_declaration): Likewise. + * call.c (build_conditional_expr_1): Likewise. + * friend.c (make_friend_class): Likewise. + * name-lookup.c (pushdecl_maybe_friend_1): Likewise. + +2012-04-21 Jan Hubicka <jh@suse.cz> + + * method.c (make_alias_for): Do not set TREE_SYMBOL_REFERENCED. + * decl2.c (mark_needed): Likewise. + (decl_needed_p): Do not test TREE_SYMBOL_REFERENCED. + + * decl2.c (cxx_callgraph_analyze_expr): Remove. + * cp-objcp-common.h (LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR): Remove. + * cp-tree.h (cxx_callgraph_analyze_expr): Remove. + +2012-04-21 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR 35441 + * typeck.c (cp_build_function_call_vec): Do not pretty-print + expressions when caret is enabled. + +2012-04-20 Jan Hubicka <jh@suse.cz> + + PR target/53042 + * decl2.c (maybe_emit_vtables): Do not initialize same_comdat_group + list when target has no support for it. + +2012-04-20 Michael Matz <matz@suse.de> + + * error.c (pedwarn_cxx98): Move va_end call after user + of the va_list. + +2012-04-18 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/52422 + * cp-tree.h (build_addr_func, decay_conversion, + get_member_function_from_ptrfunc, + build_m_component_ref, convert_member_func_to_ptr): + Add tsubst_flags_t parameter. + * typeck.c (cp_default_conversion): Add. + (decay_conversion, default_conversion, + get_member_function_from_ptrfunc, convert_member_func_to_ptr): + Add tsubst_flags_t parameter and use it throughout. + (cp_build_indirect_ref, cp_build_array_ref, + cp_build_function_call_vec, convert_arguments, build_x_binary_op, + cp_build_binary_op, cp_build_unary_op, build_reinterpret_cast_1, + build_const_cast_1, expand_ptrmemfunc_cst, + convert_for_initialization): Adjust. + * init.c (build_vec_init): Adjust. + * decl.c (grok_reference_init, get_atexit_node): Likewise. + * rtti.c (build_dynamic_cast_1, tinfo_base_init): Likewise. + * except.c (build_throw): Likewise. + * typeck2.c (build_x_arrow): Likewise. + (build_m_component_ref): Add tsubst_flags_t parameter and + use it throughout. + * pt.c (convert_nontype_argument): Adjust. + * semantics.c (finish_asm_stmt, maybe_add_lambda_conv_op): Likewise. + * decl2.c (build_offset_ref_call_from_tree): Likewise. + * call.c (build_addr_func): Add tsubst_flags_t parameter and + use it throughout. + (build_call_a, build_conditional_expr_1, build_new_op_1, + convert_like_real, convert_arg_to_ellipsis, build_over_call, + build_special_member_call): Adjust. + * cvt.c (cp_convert_to_pointer, force_rvalue, + build_expr_type_conversion): Likewise. + +2012-04-17 Tom de Vries <tom@codesourcery.com> + + * cp-gimplify.c (begin_bc_block): Add location parameter and use as + location argument to create_artificial_label. + (finish_bc_block): Change return type to void. Remove body_seq + parameter, and add block parameter. Append label to STMT_LIST and + return in block. + (gimplify_cp_loop, gimplify_for_stmt, gimplify_while_stmt) + (gimplify_do_stmt, gimplify_switch_stmt): Remove function. + (genericize_cp_loop, genericize_for_stmt, genericize_while_stmt) + (genericize_do_stmt, genericize_switch_stmt, genericize_continue_stmt) + (genericize_break_stmt, genericize_omp_for_stmt): New function. + (cp_gimplify_omp_for): Remove bc_continue processing. + (cp_gimplify_expr): Genericize VEC_INIT_EXPR. + (cp_gimplify_expr): Mark FOR_STMT, WHILE_STMT, DO_STMT, SWITCH_STMT, + CONTINUE_STMT, and BREAK_STMT as unreachable. + (cp_genericize_r): Genericize FOR_STMT, WHILE_STMT, DO_STMT, + SWITCH_STMT, CONTINUE_STMT, BREAK_STMT and OMP_FOR. + (cp_genericize_tree): New function, factored out of ... + (cp_genericize): ... this function. + +2012-04-17 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/52599 + * semantics.c (build_constexpr_constructor_member_initializers): + Check for function-try-block as function-body. + +2012-04-17 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/53003 + * parser.c (cp_parser_member_declaration): Check that + initializer_token_start is non null before dereferencing it. + +2012-04-16 Jason Merrill <jason@redhat.com> + + PR c++/38543 + * pt.c (determine_specialization): Instead of comparing the number + of parms, check that tsubst gives the right answer. + + PR c++/52008 + * pt.c (process_partial_specialization): Complain about a partial + specialization with fewer args than primary template parms. + + PR c++/50830 + * pt.c (convert_template_argument): Handle template template + argument packs. + + PR c++/50303 + * pt.c (tsubst_pack_expansion): Use tsubst_expr for template + template parameters. + +2012-04-16 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/49152 + * call.c (op_error): Print types; when flag_diagnostics_show_caret + is false print expressions too. + (op_error_string): Add. + +2012-04-16 Jason Merrill <jason@redhat.com> + + PR c++/51148 + * friend.c (make_friend_class): Call check_for_bare_parameter_packs. + +2012-04-16 Jan Hubicka <jh@suse.cz> + + * decl2.c (collect_candidates_for_java_method_alias): Use FOR_EACH + walkers to walk cgraph and varpool. + +2012-04-15 Jason Merrill <jason@redhat.com> + + PR c++/47220 + * pt.c (coerce_template_parameter_pack): Check for error_mark_node. + + PR c++/52292 + PR c++/52380 + * pt.c (coerce_template_parms): Even if we aren't converting we + want to expand argument packs. + + PR c++/52706 + * mangle.c (write_type): nullptr_t is a builtin type. + +2012-04-14 Jan Hubicka <jh@suse.cz> + + * tree.c: Update field referenced for new cgraph/varpool layout. + * decl2.c: Likewise. + +2012-04-13 Jason Merrill <jason@redhat.com> + + PR c++/52824 + * pt.c (any_pack_expanson_args_p): New. + (coerce_template_parms): Use it. + + PR c++/52905 + * call.c (joust): Handle comparing list and non-list ctors. + + PR c++/52915 + * decl2.c (finish_anon_union): Use cp_finish_decl. + * error.c (dump_function_name): Avoid showing anonymous "name". + +2012-04-11 Fabien Chêne <fabien@gcc.gnu.org> + + PR c++/52465 + * parser.c (cp_parser_class_name): Call strip_using_decl and + return the target decl. + * name-lookup.c (strip_using_decl): Returns NULL_TREE if the decl + to be stripped is NULL_TREE. + (qualify_lookup): Call strip_using_decl and perform some checks on + the target decl. + +2012-04-11 Jason Merrill <jason@redhat.com> + + PR debug/45088 + * decl.c (grokdeclarator): Strip the injected-class-name typedef + if we are building a declaration or compound type. + + PR c++/52906 + * decl.c (check_tag_decl): Don't complain about attributes if we + don't even have a type. + +2012-04-10 Manuel López-Ibáñez <manu@gcc.gnu.org> + + * cvt.c (convert_to_void): Update comment. + 2012-04-05 Jason Merrill <jason@redhat.com> PR c++/52596 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 3c3dabb74a0..4223f6cb16e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -263,7 +263,7 @@ check_dtor_name (tree basetype, tree name) pointer-to-member function. */ tree -build_addr_func (tree function) +build_addr_func (tree function, tsubst_flags_t complain) { tree type = TREE_TYPE (function); @@ -275,12 +275,13 @@ build_addr_func (tree function) { tree object = build_address (TREE_OPERAND (function, 0)); return get_member_function_from_ptrfunc (&object, - TREE_OPERAND (function, 1)); + TREE_OPERAND (function, 1), + complain); } function = build_address (function); } else - function = decay_conversion (function); + function = decay_conversion (function, complain); return function; } @@ -341,7 +342,7 @@ build_call_a (tree function, int n, tree *argarray) tree fntype; int i; - function = build_addr_func (function); + function = build_addr_func (function, tf_warning_or_error); gcc_assert (TYPE_PTR_P (TREE_TYPE (function))); fntype = TREE_TYPE (TREE_TYPE (function)); @@ -4149,6 +4150,28 @@ build_op_call (tree obj, VEC(tree,gc) **args, tsubst_flags_t complain) return ret; } +/* Called by op_error to prepare format strings suitable for the error + function. It concatenates a prefix (controlled by MATCH), ERRMSG, + and a suffix (controlled by NTYPES). */ + +static const char * +op_error_string (const char *errmsg, int ntypes, bool match) +{ + const char *msg; + + const char *msgp = concat (match ? G_("ambiguous overload for ") + : G_("no match for "), errmsg, NULL); + + if (ntypes == 3) + msg = concat (msgp, G_(" (operand types are %qT, %qT, and %qT)"), NULL); + else if (ntypes == 2) + msg = concat (msgp, G_(" (operand types are %qT and %qT)"), NULL); + else + msg = concat (msgp, G_(" (operand type is %qT)"), NULL); + + return msg; +} + static void op_error (enum tree_code code, enum tree_code code2, tree arg1, tree arg2, tree arg3, bool match) @@ -4163,58 +4186,63 @@ op_error (enum tree_code code, enum tree_code code2, switch (code) { case COND_EXPR: - if (match) - error ("ambiguous overload for ternary %<operator?:%> " - "in %<%E ? %E : %E%>", arg1, arg2, arg3); + if (flag_diagnostics_show_caret) + error (op_error_string (G_("ternary %<operator?:%>"), 3, match), + TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3)); else - error ("no match for ternary %<operator?:%> " - "in %<%E ? %E : %E%>", arg1, arg2, arg3); + error (op_error_string (G_("ternary %<operator?:%> " + "in %<%E ? %E : %E%>"), 3, match), + arg1, arg2, arg3, + TREE_TYPE (arg1), TREE_TYPE (arg2), TREE_TYPE (arg3)); break; case POSTINCREMENT_EXPR: case POSTDECREMENT_EXPR: - if (match) - error ("ambiguous overload for %<operator%s%> in %<%E%s%>", - opname, arg1, opname); + if (flag_diagnostics_show_caret) + error (op_error_string (G_("%<operator%s%>"), 1, match), + opname, TREE_TYPE (arg1)); else - error ("no match for %<operator%s%> in %<%E%s%>", - opname, arg1, opname); + error (op_error_string (G_("%<operator%s%> in %<%E%s%>"), 1, match), + opname, arg1, opname, TREE_TYPE (arg1)); break; case ARRAY_REF: - if (match) - error ("ambiguous overload for %<operator[]%> in %<%E[%E]%>", - arg1, arg2); + if (flag_diagnostics_show_caret) + error (op_error_string (G_("%<operator[]%>"), 2, match), + TREE_TYPE (arg1), TREE_TYPE (arg2)); else - error ("no match for %<operator[]%> in %<%E[%E]%>", - arg1, arg2); + error (op_error_string (G_("%<operator[]%> in %<%E[%E]%>"), 2, match), + arg1, arg2, TREE_TYPE (arg1), TREE_TYPE (arg2)); break; case REALPART_EXPR: case IMAGPART_EXPR: - if (match) - error ("ambiguous overload for %qs in %<%s %E%>", - opname, opname, arg1); + if (flag_diagnostics_show_caret) + error (op_error_string (G_("%qs"), 1, match), + opname, TREE_TYPE (arg1)); else - error ("no match for %qs in %<%s %E%>", - opname, opname, arg1); + error (op_error_string (G_("%qs in %<%s %E%>"), 1, match), + opname, opname, arg1, TREE_TYPE (arg1)); break; default: if (arg2) - if (match) - error ("ambiguous overload for %<operator%s%> in %<%E %s %E%>", - opname, arg1, opname, arg2); - else - error ("no match for %<operator%s%> in %<%E %s %E%>", - opname, arg1, opname, arg2); + if (flag_diagnostics_show_caret) + error (op_error_string (G_("%<operator%s%>"), 2, match), + opname, TREE_TYPE (arg1), TREE_TYPE (arg2)); + else + error (op_error_string (G_("%<operator%s%> in %<%E %s %E%>"), + 2, match), + opname, arg1, opname, arg2, + TREE_TYPE (arg1), TREE_TYPE (arg2)); else - if (match) - error ("ambiguous overload for %<operator%s%> in %<%s%E%>", - opname, opname, arg1); - else - error ("no match for %<operator%s%> in %<%s%E%>", - opname, opname, arg1); + if (flag_diagnostics_show_caret) + error (op_error_string (G_("%<operator%s%>"), 1, match), + opname, TREE_TYPE (arg1)); + else + error (op_error_string (G_("%<operator%s%> in %<%s%E%>"), + 1, match), + opname, opname, arg1, TREE_TYPE (arg1)); break; } } @@ -4307,7 +4335,7 @@ build_conditional_expr_1 (tree arg1, tree arg2, tree arg3, if (!arg2) { if (complain & tf_error) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids omitting the middle term of a ?: expression"); /* Make sure that lvalues remain lvalues. See g++.oliva/ext1.C. */ @@ -4346,9 +4374,9 @@ build_conditional_expr_1 (tree arg1, tree arg2, tree arg3, since it can't have any effect and since decay_conversion does not handle that case gracefully. */ if (!VOID_TYPE_P (arg2_type)) - arg2 = decay_conversion (arg2); + arg2 = decay_conversion (arg2, complain); if (!VOID_TYPE_P (arg3_type)) - arg3 = decay_conversion (arg3); + arg3 = decay_conversion (arg3, complain); arg2_type = TREE_TYPE (arg2); arg3_type = TREE_TYPE (arg3); @@ -5236,7 +5264,7 @@ build_new_op_1 (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, case MEMBER_REF: return build_m_component_ref (cp_build_indirect_ref (arg1, RO_NULL, complain), - arg2); + arg2, complain); /* The caller will deal with these. */ case ADDR_EXPR: @@ -5780,7 +5808,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, /* Build up the initializer_list object. */ totype = complete_type (totype); field = next_initializable_field (TYPE_FIELDS (totype)); - CONSTRUCTOR_APPEND_ELT (vec, field, decay_conversion (array)); + CONSTRUCTOR_APPEND_ELT (vec, field, decay_conversion (array, complain)); field = next_initializable_field (DECL_CHAIN (field)); CONSTRUCTOR_APPEND_ELT (vec, field, size_int (len)); new_ctor = build_constructor (totype, vec); @@ -5817,7 +5845,10 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, switch (convs->kind) { case ck_rvalue: - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); + if (expr == error_mark_node) + return error_mark_node; + if (! MAYBE_CLASS_TYPE_P (totype)) return expr; /* Else fall through. */ @@ -5943,7 +5974,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, } case ck_lvalue: - return decay_conversion (expr); + return decay_conversion (expr, complain); case ck_qual: /* Warn about deprecated conversion if appropriate. */ @@ -5987,7 +6018,7 @@ convert_arg_to_ellipsis (tree arg) The lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard conversions are performed. */ - arg = decay_conversion (arg); + arg = decay_conversion (arg, tf_warning_or_error); arg_type = TREE_TYPE (arg); /* [expr.call] @@ -6314,7 +6345,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) errors will be deferred until the template is instantiated. */ if (processing_template_decl) { - tree expr; + tree expr, addr; tree return_type; const tree *argarray; unsigned int nargs; @@ -6336,9 +6367,12 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) alcarray[ix + 1] = arg; argarray = alcarray; } - expr = build_call_array_loc (input_location, - return_type, build_addr_func (fn), nargs, - argarray); + + addr = build_addr_func (fn, complain); + if (addr == error_mark_node) + return error_mark_node; + expr = build_call_array_loc (input_location, return_type, + addr, nargs, argarray); if (TREE_THIS_VOLATILE (fn) && cfun) current_function_returns_abnormally = 1; return convert_from_reference (expr); @@ -6755,7 +6789,11 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) TREE_TYPE (fn) = t; } else - fn = build_addr_func (fn); + { + fn = build_addr_func (fn, complain); + if (fn == error_mark_node) + return error_mark_node; + } return build_cxx_call (fn, nargs, argarray); } @@ -6976,7 +7014,9 @@ build_special_member_call (tree instance, tree name, VEC(tree,gc) **args, or destructor, then we fetch the VTT directly. Otherwise, we look it up using the VTT we were given. */ vtt = DECL_CHAIN (CLASSTYPE_VTABLES (current_class_type)); - vtt = decay_conversion (vtt); + vtt = decay_conversion (vtt, complain); + if (vtt == error_mark_node) + return error_mark_node; vtt = build3 (COND_EXPR, TREE_TYPE (vtt), build2 (EQ_EXPR, boolean_type_node, current_in_charge_parm, integer_zero_node), @@ -8011,6 +8051,12 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn) int static_1 = DECL_STATIC_FUNCTION_P (cand1->fn); int static_2 = DECL_STATIC_FUNCTION_P (cand2->fn); + if (DECL_CONSTRUCTOR_P (cand1->fn) + && is_list_ctor (cand1->fn) != is_list_ctor (cand2->fn)) + /* We're comparing a near-match list constructor and a near-match + non-list constructor. Just treat them as unordered. */ + return 0; + gcc_assert (static_1 != static_2); if (static_1) diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index e06c5454c7e..416c640c68c 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -34,6 +34,11 @@ along with GCC; see the file COPYING3. If not see #include "flags.h" #include "splay-tree.h" +/* Forward declarations. */ + +static tree cp_genericize_r (tree *, int *, void *); +static void cp_genericize_tree (tree*); + /* Local declarations. */ enum bc_t { bc_break = 0, bc_continue = 1 }; @@ -45,37 +50,36 @@ static tree bc_label[2]; /* Begin a scope which can be exited by a break or continue statement. BC indicates which. - Just creates a label and pushes it into the current context. */ + Just creates a label with location LOCATION and pushes it into the current + context. */ static tree -begin_bc_block (enum bc_t bc) +begin_bc_block (enum bc_t bc, location_t location) { - tree label = create_artificial_label (input_location); + tree label = create_artificial_label (location); DECL_CHAIN (label) = bc_label[bc]; bc_label[bc] = label; return label; } /* Finish a scope which can be exited by a break or continue statement. - LABEL was returned from the most recent call to begin_bc_block. BODY is + LABEL was returned from the most recent call to begin_bc_block. BLOCK is an expression for the contents of the scope. If we saw a break (or continue) in the scope, append a LABEL_EXPR to - body. Otherwise, just forget the label. */ + BLOCK. Otherwise, just forget the label. */ -static gimple_seq -finish_bc_block (enum bc_t bc, tree label, gimple_seq body) +static void +finish_bc_block (tree *block, enum bc_t bc, tree label) { gcc_assert (label == bc_label[bc]); if (TREE_USED (label)) - { - gimple_seq_add_stmt (&body, gimple_build_label (label)); - } + append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label), + block); bc_label[bc] = DECL_CHAIN (label); DECL_CHAIN (label) = NULL_TREE; - return body; } /* Get the LABEL_EXPR to represent a break or continue statement @@ -183,173 +187,207 @@ genericize_if_stmt (tree *stmt_p) evaluated before the loop body as in while and for loops, or after the loop body as in do-while loops. */ -static gimple_seq -gimplify_cp_loop (tree cond, tree body, tree incr, bool cond_is_first) +static void +genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, + tree incr, bool cond_is_first, int *walk_subtrees, + void *data) { - gimple top, entry, stmt; - gimple_seq stmt_list, body_seq, incr_seq, exit_seq; - tree cont_block, break_block; - location_t stmt_locus; + tree blab, clab; + tree entry = NULL, exit = NULL, t; + tree stmt_list = NULL; + + blab = begin_bc_block (bc_break, start_locus); + clab = begin_bc_block (bc_continue, start_locus); - stmt_locus = input_location; - stmt_list = NULL; - body_seq = NULL; - incr_seq = NULL; - exit_seq = NULL; - entry = NULL; + if (incr && EXPR_P (incr)) + SET_EXPR_LOCATION (incr, start_locus); - break_block = begin_bc_block (bc_break); - cont_block = begin_bc_block (bc_continue); + cp_walk_tree (&cond, cp_genericize_r, data, NULL); + cp_walk_tree (&body, cp_genericize_r, data, NULL); + cp_walk_tree (&incr, cp_genericize_r, data, NULL); + *walk_subtrees = 0; /* If condition is zero don't generate a loop construct. */ if (cond && integer_zerop (cond)) { - top = NULL; if (cond_is_first) { - stmt = gimple_build_goto (get_bc_label (bc_break)); - gimple_set_location (stmt, stmt_locus); - gimple_seq_add_stmt (&stmt_list, stmt); + t = build1_loc (start_locus, GOTO_EXPR, void_type_node, + get_bc_label (bc_break)); + append_to_statement_list (t, &stmt_list); } } else { - /* If we use a LOOP_EXPR here, we have to feed the whole thing - back through the main gimplifier to lower it. Given that we - have to gimplify the loop body NOW so that we can resolve - break/continue stmts, seems easier to just expand to gotos. */ - top = gimple_build_label (create_artificial_label (stmt_locus)); + /* Expand to gotos, just like c_finish_loop. TODO: Use LOOP_EXPR. */ + tree top = build1 (LABEL_EXPR, void_type_node, + create_artificial_label (start_locus)); /* If we have an exit condition, then we build an IF with gotos either out of the loop, or to the top of it. If there's no exit condition, then we just build a jump back to the top. */ + exit = build1 (GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL (top)); + if (cond && !integer_nonzerop (cond)) { - if (cond != error_mark_node) - { - gimplify_expr (&cond, &exit_seq, NULL, is_gimple_val, fb_rvalue); - stmt = gimple_build_cond (NE_EXPR, cond, - build_int_cst (TREE_TYPE (cond), 0), - gimple_label_label (top), - get_bc_label (bc_break)); - gimple_seq_add_stmt (&exit_seq, stmt); - } - + /* Canonicalize the loop condition to the end. This means + generating a branch to the loop condition. Reuse the + continue label, if possible. */ if (cond_is_first) { if (incr) { - entry = gimple_build_label - (create_artificial_label (stmt_locus)); - stmt = gimple_build_goto (gimple_label_label (entry)); + entry = build1 (LABEL_EXPR, void_type_node, + create_artificial_label (start_locus)); + t = build1_loc (start_locus, GOTO_EXPR, void_type_node, + LABEL_EXPR_LABEL (entry)); } else - stmt = gimple_build_goto (get_bc_label (bc_continue)); - gimple_set_location (stmt, stmt_locus); - gimple_seq_add_stmt (&stmt_list, stmt); + t = build1_loc (start_locus, GOTO_EXPR, void_type_node, + get_bc_label (bc_continue)); + append_to_statement_list (t, &stmt_list); } - } - else - { - stmt = gimple_build_goto (gimple_label_label (top)); - gimple_seq_add_stmt (&exit_seq, stmt); - } - } - gimplify_stmt (&body, &body_seq); - gimplify_stmt (&incr, &incr_seq); + t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break)); + exit = fold_build3_loc (start_locus, + COND_EXPR, void_type_node, cond, exit, t); + } - body_seq = finish_bc_block (bc_continue, cont_block, body_seq); + append_to_statement_list (top, &stmt_list); + } - gimple_seq_add_stmt (&stmt_list, top); - gimple_seq_add_seq (&stmt_list, body_seq); - gimple_seq_add_seq (&stmt_list, incr_seq); - gimple_seq_add_stmt (&stmt_list, entry); - gimple_seq_add_seq (&stmt_list, exit_seq); + append_to_statement_list (body, &stmt_list); + finish_bc_block (&stmt_list, bc_continue, clab); + append_to_statement_list (incr, &stmt_list); + append_to_statement_list (entry, &stmt_list); + append_to_statement_list (exit, &stmt_list); + finish_bc_block (&stmt_list, bc_break, blab); - annotate_all_with_location (stmt_list, stmt_locus); + if (stmt_list == NULL_TREE) + stmt_list = build1 (NOP_EXPR, void_type_node, integer_zero_node); - return finish_bc_block (bc_break, break_block, stmt_list); + *stmt_p = stmt_list; } -/* Gimplify a FOR_STMT node. Move the stuff in the for-init-stmt into the - prequeue and hand off to gimplify_cp_loop. */ +/* Genericize a FOR_STMT node *STMT_P. */ static void -gimplify_for_stmt (tree *stmt_p, gimple_seq *pre_p) +genericize_for_stmt (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; + tree expr = NULL; + tree loop; + tree init = FOR_INIT_STMT (stmt); - if (FOR_INIT_STMT (stmt)) - gimplify_and_add (FOR_INIT_STMT (stmt), pre_p); + if (init) + { + cp_walk_tree (&init, cp_genericize_r, data, NULL); + append_to_statement_list (init, &expr); + } - gimple_seq_add_seq (pre_p, - gimplify_cp_loop (FOR_COND (stmt), FOR_BODY (stmt), - FOR_EXPR (stmt), 1)); - *stmt_p = NULL_TREE; + genericize_cp_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt), + FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees, data); + append_to_statement_list (loop, &expr); + *stmt_p = expr; } -/* Gimplify a WHILE_STMT node. */ +/* Genericize a WHILE_STMT node *STMT_P. */ static void -gimplify_while_stmt (tree *stmt_p, gimple_seq *pre_p) +genericize_while_stmt (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; - gimple_seq_add_seq (pre_p, - gimplify_cp_loop (WHILE_COND (stmt), WHILE_BODY (stmt), - NULL_TREE, 1)); - *stmt_p = NULL_TREE; + genericize_cp_loop (stmt_p, EXPR_LOCATION (stmt), WHILE_COND (stmt), + WHILE_BODY (stmt), NULL_TREE, 1, walk_subtrees, data); } -/* Gimplify a DO_STMT node. */ +/* Genericize a DO_STMT node *STMT_P. */ static void -gimplify_do_stmt (tree *stmt_p, gimple_seq *pre_p) +genericize_do_stmt (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; - gimple_seq_add_seq (pre_p, - gimplify_cp_loop (DO_COND (stmt), DO_BODY (stmt), - NULL_TREE, 0)); - *stmt_p = NULL_TREE; + genericize_cp_loop (stmt_p, EXPR_LOCATION (stmt), DO_COND (stmt), + DO_BODY (stmt), NULL_TREE, 0, walk_subtrees, data); } -/* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */ +/* Genericize a SWITCH_STMT node *STMT_P by turning it into a SWITCH_EXPR. */ static void -gimplify_switch_stmt (tree *stmt_p, gimple_seq *pre_p) +genericize_switch_stmt (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; - tree break_block, body, t; - location_t stmt_locus = input_location; - gimple_seq seq = NULL; + tree break_block, body, cond, type; + location_t stmt_locus = EXPR_LOCATION (stmt); - break_block = begin_bc_block (bc_break); + break_block = begin_bc_block (bc_break, stmt_locus); body = SWITCH_STMT_BODY (stmt); if (!body) body = build_empty_stmt (stmt_locus); + cond = SWITCH_STMT_COND (stmt); + type = SWITCH_STMT_TYPE (stmt); - t = build3 (SWITCH_EXPR, SWITCH_STMT_TYPE (stmt), - SWITCH_STMT_COND (stmt), body, NULL_TREE); - SET_EXPR_LOCATION (t, stmt_locus); - gimplify_and_add (t, &seq); + cp_walk_tree (&body, cp_genericize_r, data, NULL); + cp_walk_tree (&cond, cp_genericize_r, data, NULL); + cp_walk_tree (&type, cp_genericize_r, data, NULL); + *walk_subtrees = 0; - seq = finish_bc_block (bc_break, break_block, seq); - gimple_seq_add_seq (pre_p, seq); - *stmt_p = NULL_TREE; + *stmt_p = build3_loc (stmt_locus, SWITCH_EXPR, type, cond, body, NULL_TREE); + finish_bc_block (stmt_p, bc_break, break_block); +} + +/* Genericize a CONTINUE_STMT node *STMT_P. */ + +static void +genericize_continue_stmt (tree *stmt_p) +{ + tree stmt_list = NULL; + tree pred = build_predict_expr (PRED_CONTINUE, NOT_TAKEN); + tree label = get_bc_label (bc_continue); + location_t location = EXPR_LOCATION (*stmt_p); + tree jump = build1_loc (location, GOTO_EXPR, void_type_node, label); + append_to_statement_list (pred, &stmt_list); + append_to_statement_list (jump, &stmt_list); + *stmt_p = stmt_list; } -/* Hook into the middle of gimplifying an OMP_FOR node. This is required - in order to properly gimplify CONTINUE statements. Here we merely - manage the continue stack; the rest of the job is performed by the - regular gimplifier. */ +/* Genericize a BREAK_STMT node *STMT_P. */ + +static void +genericize_break_stmt (tree *stmt_p) +{ + tree label = get_bc_label (bc_break); + location_t location = EXPR_LOCATION (*stmt_p); + *stmt_p = build1_loc (location, GOTO_EXPR, void_type_node, label); +} + +/* Genericize a OMP_FOR node *STMT_P. */ + +static void +genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data) +{ + tree stmt = *stmt_p; + location_t locus = EXPR_LOCATION (stmt); + tree clab = begin_bc_block (bc_continue, locus); + + cp_walk_tree (&OMP_FOR_BODY (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_INIT (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_COND (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_INCR (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_genericize_r, data, NULL); + *walk_subtrees = 0; + + finish_bc_block (&OMP_FOR_BODY (stmt), bc_continue, clab); +} + +/* Hook into the middle of gimplifying an OMP_FOR node. */ static enum gimplify_status cp_gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { tree for_stmt = *expr_p; - tree cont_block; - gimple stmt; gimple_seq seq = NULL; /* Protect ourselves from recursion. */ @@ -357,18 +395,7 @@ cp_gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) return GS_UNHANDLED; OMP_FOR_GIMPLIFYING_P (for_stmt) = 1; - /* Note that while technically the continue label is enabled too soon - here, we should have already diagnosed invalid continues nested within - statement expressions within the INIT, COND, or INCR expressions. */ - cont_block = begin_bc_block (bc_continue); - gimplify_and_add (for_stmt, &seq); - stmt = gimple_seq_last_stmt (seq); - if (gimple_code (stmt) == GIMPLE_OMP_FOR) - gimple_omp_set_body (stmt, finish_bc_block (bc_continue, cont_block, - gimple_omp_body (stmt))); - else - seq = finish_bc_block (bc_continue, cont_block, seq); gimple_seq_add_seq (pre_p, seq); OMP_FOR_GIMPLIFYING_P (for_stmt) = 0; @@ -528,6 +555,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) init, VEC_INIT_EXPR_VALUE_INIT (*expr_p), from_array, tf_warning_or_error); + cp_genericize_tree (expr_p); ret = GS_OK; input_location = loc; } @@ -634,42 +662,17 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) gcc_unreachable (); case FOR_STMT: - gimplify_for_stmt (expr_p, pre_p); - ret = GS_OK; - break; - case WHILE_STMT: - gimplify_while_stmt (expr_p, pre_p); - ret = GS_OK; - break; - case DO_STMT: - gimplify_do_stmt (expr_p, pre_p); - ret = GS_OK; - break; - case SWITCH_STMT: - gimplify_switch_stmt (expr_p, pre_p); - ret = GS_OK; - break; + case CONTINUE_STMT: + case BREAK_STMT: + gcc_unreachable (); case OMP_FOR: ret = cp_gimplify_omp_for (expr_p, pre_p); break; - case CONTINUE_STMT: - gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_CONTINUE, NOT_TAKEN)); - gimple_seq_add_stmt (pre_p, gimple_build_goto (get_bc_label (bc_continue))); - *expr_p = NULL_TREE; - ret = GS_ALL_DONE; - break; - - case BREAK_STMT: - gimple_seq_add_stmt (pre_p, gimple_build_goto (get_bc_label (bc_break))); - *expr_p = NULL_TREE; - ret = GS_ALL_DONE; - break; - case EXPR_STMT: gimplify_expr_stmt (expr_p); ret = GS_OK; @@ -1102,17 +1105,45 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) } else if (TREE_CODE (stmt) == CONVERT_EXPR) gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt)); + else if (TREE_CODE (stmt) == FOR_STMT) + genericize_for_stmt (stmt_p, walk_subtrees, data); + else if (TREE_CODE (stmt) == WHILE_STMT) + genericize_while_stmt (stmt_p, walk_subtrees, data); + else if (TREE_CODE (stmt) == DO_STMT) + genericize_do_stmt (stmt_p, walk_subtrees, data); + else if (TREE_CODE (stmt) == SWITCH_STMT) + genericize_switch_stmt (stmt_p, walk_subtrees, data); + else if (TREE_CODE (stmt) == CONTINUE_STMT) + genericize_continue_stmt (stmt_p); + else if (TREE_CODE (stmt) == BREAK_STMT) + genericize_break_stmt (stmt_p); + else if (TREE_CODE (stmt) == OMP_FOR) + genericize_omp_for_stmt (stmt_p, walk_subtrees, data); pointer_set_insert (p_set, *stmt_p); return NULL; } +/* Lower C++ front end trees to GENERIC in T_P. */ + +static void +cp_genericize_tree (tree* t_p) +{ + struct cp_genericize_data wtd; + + wtd.p_set = pointer_set_create (); + wtd.bind_expr_stack = NULL; + wtd.omp_ctx = NULL; + cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL); + pointer_set_destroy (wtd.p_set); + VEC_free (tree, heap, wtd.bind_expr_stack); +} + void cp_genericize (tree fndecl) { tree t; - struct cp_genericize_data wtd; /* Fix up the types of parms passed by invisible reference. */ for (t = DECL_ARGUMENTS (fndecl); t; t = DECL_CHAIN (t)) @@ -1163,12 +1194,7 @@ cp_genericize (tree fndecl) /* We do want to see every occurrence of the parms, so we can't just use walk_tree's hash functionality. */ - wtd.p_set = pointer_set_create (); - wtd.bind_expr_stack = NULL; - wtd.omp_ctx = NULL; - cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_genericize_r, &wtd, NULL); - pointer_set_destroy (wtd.p_set); - VEC_free (tree, heap, wtd.bind_expr_stack); + cp_genericize_tree (&DECL_SAVED_TREE (fndecl)); /* Do everything else. */ c_genericize (fndecl); diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index c668ad8bcad..06cc796050b 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -110,9 +110,6 @@ extern void cp_common_init_ts (void); #undef LANG_HOOKS_TREE_DUMP_TYPE_QUALS_FN #define LANG_HOOKS_TREE_DUMP_TYPE_QUALS_FN cp_type_quals -#undef LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR -#define LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR cxx_callgraph_analyze_expr - #undef LANG_HOOKS_MAKE_TYPE #define LANG_HOOKS_MAKE_TYPE cxx_make_type #undef LANG_HOOKS_TYPE_FOR_MODE diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index db5e8a5e084..429ac2c5c74 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4854,7 +4854,7 @@ extern bool check_dtor_name (tree, tree); extern tree build_conditional_expr (tree, tree, tree, tsubst_flags_t); -extern tree build_addr_func (tree); +extern tree build_addr_func (tree, tsubst_flags_t); extern void set_flags_from_callee (tree); extern tree build_call_a (tree, int, tree*); extern tree build_call_n (tree, int, ...); @@ -5136,7 +5136,6 @@ extern tree cp_build_parm_decl (tree, tree); extern tree get_guard (tree); extern tree get_guard_cond (tree); extern tree set_guard (tree); -extern tree cxx_callgraph_analyze_expr (tree *, int *); extern void mark_needed (tree); extern bool decl_needed_p (tree); extern void note_vague_linkage_fn (tree); @@ -5782,7 +5781,7 @@ extern tree cxx_sizeof_or_alignof_type (tree, enum tree_code, bool); extern tree cxx_sizeof_nowarn (tree); extern tree is_bitfield_expr_with_lowered_type (const_tree); extern tree unlowered_expr_type (const_tree); -extern tree decay_conversion (tree); +extern tree decay_conversion (tree, tsubst_flags_t); extern tree build_class_member_access_expr (tree, tree, tree, bool, tsubst_flags_t); extern tree finish_class_member_access_expr (tree, tree, bool, @@ -5794,7 +5793,7 @@ extern tree cp_build_indirect_ref (tree, ref_operator, extern tree build_array_ref (location_t, tree, tree); extern tree cp_build_array_ref (location_t, tree, tree, tsubst_flags_t); -extern tree get_member_function_from_ptrfunc (tree *, tree); +extern tree get_member_function_from_ptrfunc (tree *, tree, tsubst_flags_t); extern tree cp_build_function_call (tree, tree, tsubst_flags_t); extern tree cp_build_function_call_nary (tree, tsubst_flags_t, ...) ATTRIBUTE_SENTINEL; @@ -5865,7 +5864,7 @@ extern tree build_nop (tree, tree); extern tree non_reference (tree); extern tree lookup_anon_field (tree, tree); extern bool invalid_nonstatic_memfn_p (const_tree, tsubst_flags_t); -extern tree convert_member_func_to_ptr (tree, tree); +extern tree convert_member_func_to_ptr (tree, tree, tsubst_flags_t); extern tree convert_ptrmem (tree, tree, bool, bool, tsubst_flags_t); extern int lvalue_or_else (tree, enum lvalue_use, @@ -5895,7 +5894,7 @@ extern tree digest_init (tree, tree, tsubst_flags_t); extern tree digest_init_flags (tree, tree, int); extern tree build_scoped_ref (tree, tree, tree *); extern tree build_x_arrow (tree, tsubst_flags_t); -extern tree build_m_component_ref (tree, tree); +extern tree build_m_component_ref (tree, tree, tsubst_flags_t); extern tree build_functional_cast (tree, tree, tsubst_flags_t); extern tree add_exception_specifier (tree, tree, int); extern tree merge_exception_specifiers (tree, tree, tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index c411a47f0a8..09a589efd02 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1,7 +1,7 @@ /* Language-level data type conversion for GNU C++. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011 Free Software Foundation, Inc. + 2011, 2012 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -109,7 +109,7 @@ cp_convert_to_pointer (tree type, tree expr) { if (TYPE_PTRMEMFUNC_P (intype) || TREE_CODE (intype) == METHOD_TYPE) - return convert_member_func_to_ptr (type, expr); + return convert_member_func_to_ptr (type, expr, tf_warning_or_error); if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) return build_nop (type, expr); intype = TREE_TYPE (expr); @@ -188,7 +188,8 @@ cp_convert_to_pointer (tree type, tree expr) { tree object = TREE_OPERAND (expr, 0); return get_member_function_from_ptrfunc (&object, - TREE_OPERAND (expr, 1)); + TREE_OPERAND (expr, 1), + tf_warning_or_error); } } error ("cannot convert %qE from type %qT to type %qT", @@ -550,7 +551,7 @@ force_rvalue (tree expr, tsubst_flags_t complain) expr = build_cplus_new (type, expr, complain); } else - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); return expr; } @@ -1108,7 +1109,7 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) - an expression with TREE_NO_WARNING set. (For an example of such expressions, see build_over_call in call.c.) - automatic dereferencing of references, since the user cannot - control it. (See also warn_if_unused_value() in stmt.c.) */ + control it. (See also warn_if_unused_value() in c-common.c.) */ if (warn_unused_value && implicit != ICV_CAST && (complain & tf_warning) @@ -1495,7 +1496,8 @@ build_expr_type_conversion (int desires, tree expr, bool complain) case FUNCTION_TYPE: case ARRAY_TYPE: - return (desires & WANT_POINTER) ? decay_conversion (expr) + return (desires & WANT_POINTER) ? decay_conversion (expr, + tf_warning_or_error) : NULL_TREE; case COMPLEX_TYPE: diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e2f01d51ab7..870b6b3092c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4193,7 +4193,7 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) SET_ANON_AGGR_TYPE_P (declared_type); if (TREE_CODE (declared_type) != UNION_TYPE && !in_system_header) - pedwarn (input_location, OPT_pedantic, "ISO C++ prohibits anonymous structs"); + pedwarn (input_location, OPT_Wpedantic, "ISO C++ prohibits anonymous structs"); } else @@ -4224,7 +4224,7 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) error ("%<constexpr%> cannot be used for type declarations"); } - if (declspecs->attributes && warn_attributes) + if (declspecs->attributes && warn_attributes && declared_type) { location_t loc; if (!CLASS_TYPE_P (declared_type) @@ -4668,7 +4668,7 @@ grok_reference_init (tree decl, tree type, tree init, int flags) if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE) /* Note: default conversion is only called in very special cases. */ - init = decay_conversion (init); + init = decay_conversion (init, tf_warning_or_error); /* Convert INIT to the reference type TYPE. This may involve the creation of a temporary, whose lifetime must be the same as that @@ -6535,7 +6535,7 @@ get_atexit_node (void) atexit_fndecl = build_library_fn_ptr (name, fn_type); mark_used (atexit_fndecl); pop_lang_context (); - atexit_node = decay_conversion (atexit_fndecl); + atexit_node = decay_conversion (atexit_fndecl, tf_warning_or_error); return atexit_node; } @@ -7877,7 +7877,7 @@ check_static_variable_definition (tree decl, tree type) "static member %qD", decl); else if (!INTEGRAL_OR_ENUMERATION_TYPE_P (type)) - pedwarn (input_location, OPT_pedantic, "ISO C++ forbids initialization of member constant " + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids initialization of member constant " "%qD of non-integral type %qT", decl, type); return 0; @@ -8050,9 +8050,9 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain) else if (in_system_header) /* Allow them in system headers because glibc uses them. */; else if (name) - pedwarn (input_location, OPT_pedantic, "ISO C++ forbids zero-size array %qD", name); + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids zero-size array %qD", name); else - pedwarn (input_location, OPT_pedantic, "ISO C++ forbids zero-size array"); + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids zero-size array"); } } else if (TREE_CONSTANT (size) @@ -8178,7 +8178,7 @@ create_array_type_for_decl (tree name, tree type, tree size) /* 8.3.4/1: If the type of the identifier of D contains the auto type-specifier, the program is ill-formed. */ if (pedantic && type_uses_auto (type)) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "declaration of %qD as array of %<auto%>", name); /* If there are some types which cannot be array elements, @@ -8773,7 +8773,7 @@ grokdeclarator (const cp_declarator *declarator, else if (! is_main) permerror (input_location, "ISO C++ forbids declaration of %qs with no type", name); else if (pedantic) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids declaration of %qs with no type", name); else warning (OPT_Wreturn_type, @@ -8792,7 +8792,7 @@ grokdeclarator (const cp_declarator *declarator, explicit_int128 = false; } else if (pedantic && ! in_system_header) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ does not support %<__int128%> for %qs", name); } @@ -8843,7 +8843,7 @@ grokdeclarator (const cp_declarator *declarator, ok = 1; if (!explicit_int && !defaulted_int && !explicit_char && !explicit_int128 && pedantic) { - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "long, short, signed or unsigned used invalidly for %qs", name); if (flag_pedantic_errors) @@ -8943,6 +8943,17 @@ grokdeclarator (const cp_declarator *declarator, error ("qualifiers are not allowed on declaration of %<operator %T%>", ctor_return_type); + /* If we're using the injected-class-name to form a compound type or a + declaration, replace it with the underlying class so we don't get + redundant typedefs in the debug output. But if we are returning the + type unchanged, leave it alone so that it's available to + maybe_get_template_decl_from_type_decl. */ + if (CLASS_TYPE_P (type) + && DECL_SELF_REFERENCE_P (TYPE_NAME (type)) + && type == TREE_TYPE (TYPE_NAME (type)) + && (declarator || type_quals)) + type = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); + type_quals |= cp_type_quals (type); type = cp_build_qualified_type_real (type, type_quals, ((typedef_decl && !DECL_ARTIFICIAL (typedef_decl) @@ -10343,11 +10354,11 @@ grokdeclarator (const cp_declarator *declarator, && pedantic) { if (storage_class == sc_static) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "%<static%> specified invalid for function %qs " "declared out of global scope", name); else - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "%<inline%> specifier invalid for function %qs " "declared out of global scope", name); } @@ -10441,7 +10452,7 @@ grokdeclarator (const cp_declarator *declarator, } if (storage_class == sc_extern && pedantic) { - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "cannot explicitly declare member %q#D to have " "extern linkage", decl); storage_class = sc_none; @@ -11407,7 +11418,7 @@ grok_op_properties (tree decl, bool complain) if (operator_code == POSTINCREMENT_EXPR || operator_code == POSTDECREMENT_EXPR) { - pedwarn (input_location, OPT_pedantic, "%qD cannot have default arguments", + pedwarn (input_location, OPT_Wpedantic, "%qD cannot have default arguments", decl); } else diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index b048ac7b3cd..34c969c31fc 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1,7 +1,7 @@ /* Process declarations and variables for C++ compiler. Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, - 2011 Free Software Foundation, Inc. + 2011, 2012 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -1456,12 +1456,7 @@ finish_anon_union (tree anon_union_decl) } pushdecl (anon_union_decl); - if (building_stmt_list_p () - && at_function_scope_p ()) - add_decl_expr (anon_union_decl); - else if (!processing_template_decl) - rest_of_decl_compilation (anon_union_decl, - toplevel_bindings_p (), at_eof); + cp_finish_decl (anon_union_decl, NULL_TREE, false, NULL_TREE, 0); } /* Auxiliary functions to make type signatures for @@ -1682,6 +1677,7 @@ maybe_make_one_only (tree decl) DECL_COMDAT (decl) = 1; /* Mark it needed so we don't forget to emit it. */ mark_decl_referenced (decl); + TREE_USED (decl) = 1; } } } @@ -1787,10 +1783,7 @@ var_finalized_p (tree var) void mark_needed (tree decl) { - /* It's possible that we no longer need to set - TREE_SYMBOL_REFERENCED here directly, but doing so is - harmless. */ - TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) = 1; + TREE_USED (decl) = 1; mark_decl_referenced (decl); } @@ -1816,9 +1809,7 @@ decl_needed_p (tree decl) return true; /* If this entity was used, let the back end see it; it will decide whether or not to emit it into the object file. */ - if (TREE_USED (decl) - || (DECL_ASSEMBLER_NAME_SET_P (decl) - && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) + if (TREE_USED (decl)) return true; /* Functions marked "dllexport" must be emitted so that they are visible to other DLLs. */ @@ -1899,11 +1890,11 @@ maybe_emit_vtables (tree ctype) actually marking the variable as written. */ if (flag_syntax_only) TREE_ASM_WRITTEN (vtbl) = 1; - else if (DECL_COMDAT (vtbl)) + else if (DECL_ONE_ONLY (vtbl)) { current = varpool_node (vtbl); if (last) - last->same_comdat_group = current; + last->symbol.same_comdat_group = (symtab_node) current; last = current; if (!first) first = current; @@ -1911,7 +1902,7 @@ maybe_emit_vtables (tree ctype) } if (first != last) - last->same_comdat_group = first; + last->symbol.same_comdat_group = (symtab_node)first; /* Since we're writing out the vtable here, also write the debug info. */ @@ -3441,44 +3432,6 @@ generate_ctor_and_dtor_functions_for_priority (splay_tree_node n, void * data) return 0; } -/* Called via LANGHOOK_CALLGRAPH_ANALYZE_EXPR. It is supposed to mark - decls referenced from front-end specific constructs; it will be called - only for language-specific tree nodes. - - Here we must deal with member pointers. */ - -tree -cxx_callgraph_analyze_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED) -{ - tree t = *tp; - - switch (TREE_CODE (t)) - { - case PTRMEM_CST: - if (TYPE_PTRMEMFUNC_P (TREE_TYPE (t))) - cgraph_mark_address_taken_node ( - cgraph_get_create_node (PTRMEM_CST_MEMBER (t))); - break; - case BASELINK: - if (TREE_CODE (BASELINK_FUNCTIONS (t)) == FUNCTION_DECL) - cgraph_mark_address_taken_node ( - cgraph_get_create_node (BASELINK_FUNCTIONS (t))); - break; - case VAR_DECL: - if (DECL_CONTEXT (t) - && flag_use_repository - && TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL) - /* If we need a static variable in a function, then we - need the containing function. */ - mark_decl_referenced (DECL_CONTEXT (t)); - break; - default: - break; - } - - return NULL; -} - /* Java requires that we be able to reference a local address for a method, and not be confused by PLT entries. If hidden aliases are supported, collect and return all the functions for which we should @@ -3494,9 +3447,9 @@ collect_candidates_for_java_method_aliases (void) return candidates; #endif - for (node = cgraph_nodes; node ; node = node->next) + FOR_EACH_FUNCTION (node) { - tree fndecl = node->decl; + tree fndecl = node->symbol.decl; if (DECL_CONTEXT (fndecl) && TYPE_P (DECL_CONTEXT (fndecl)) @@ -3528,9 +3481,9 @@ build_java_method_aliases (struct pointer_set_t *candidates) return; #endif - for (node = cgraph_nodes; node ; node = node->next) + FOR_EACH_FUNCTION (node) { - tree fndecl = node->decl; + tree fndecl = node->symbol.decl; if (TREE_ASM_WRITTEN (fndecl) && pointer_set_contains (candidates, fndecl)) @@ -3711,7 +3664,7 @@ collect_all_refs (const char *source_file) static bool clear_decl_external (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) { - DECL_EXTERNAL (node->decl) = 0; + DECL_EXTERNAL (node->symbol.decl) = 0; return false; } @@ -3950,10 +3903,10 @@ cp_write_global_declarations (void) /* If we mark !DECL_EXTERNAL one of the symbols in some comdat group, we need to mark all symbols in the same comdat group that way. */ - if (node->same_comdat_group) - for (next = node->same_comdat_group; + if (node->symbol.same_comdat_group) + for (next = cgraph (node->symbol.same_comdat_group); next != node; - next = next->same_comdat_group) + next = cgraph (next->symbol.same_comdat_group)) cgraph_for_node_and_aliases (next, clear_decl_external, NULL, true); } @@ -4180,7 +4133,8 @@ build_offset_ref_call_from_tree (tree fn, VEC(tree,gc) **args) { tree object_addr = cp_build_addr_expr (object, tf_warning_or_error); fn = TREE_OPERAND (fn, 1); - fn = get_member_function_from_ptrfunc (&object_addr, fn); + fn = get_member_function_from_ptrfunc (&object_addr, fn, + tf_warning_or_error); VEC_safe_insert (tree, gc, *args, 0, object_addr); } diff --git a/gcc/cp/error.c b/gcc/cp/error.c index ee8f0e082a5..6595063637b 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1556,6 +1556,8 @@ dump_function_name (tree t, int flags) { if (LAMBDA_TYPE_P (DECL_CONTEXT (t))) name = get_identifier ("<lambda>"); + else if (TYPE_ANONYMOUS_P (DECL_CONTEXT (t))) + name = get_identifier ("<constructor>"); else name = constructor_name (DECL_CONTEXT (t)); } @@ -3304,7 +3306,7 @@ maybe_warn_cpp0x (cpp0x_warn_str str) "only available with -std=c++11 or -std=gnu++11"); break; case CPP0X_INLINE_NAMESPACES: - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "inline namespaces " "only available with -std=c++11 or -std=gnu++11"); break; @@ -3350,13 +3352,15 @@ pedwarn_cxx98 (location_t location, int opt, const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; + bool ret; va_start (ap, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &ap, location, (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING); diagnostic.option_index = opt; + ret = report_diagnostic (&diagnostic); va_end (ap); - return report_diagnostic (&diagnostic); + return ret; } /* Issue a diagnostic that NAME cannot be found in SCOPE. DECL is what diff --git a/gcc/cp/except.c b/gcc/cp/except.c index c56dc2c734b..d39cfa6abd3 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1,6 +1,6 @@ /* Handle exceptional things in C++. Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc. Contributed by Michael Tiemann <tiemann@cygnus.com> Rewritten by Mike Stump <mrs@cygnus.com>, based upon an @@ -850,7 +850,7 @@ build_throw (tree exp) } else { - tmp = decay_conversion (exp); + tmp = decay_conversion (exp, tf_warning_or_error); if (tmp == error_mark_node) return error_mark_node; exp = build2 (INIT_EXPR, temp_type, object, tmp); diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index e532a30e3a3..98cde9a1d05 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -232,13 +232,16 @@ make_friend_class (tree type, tree friend_type, bool complain) So don't complain in C++0x mode. */ if (cxx_dialect < cxx0x) - pedwarn (input_location, complain ? 0 : OPT_pedantic, + pedwarn (input_location, complain ? 0 : OPT_Wpedantic, "invalid type %qT declared %<friend%>", friend_type); return; } friend_type = cv_unqualified (friend_type); + if (check_for_bare_parameter_packs (friend_type)) + return; + if (friend_depth) /* If the TYPE is a template then it makes sense for it to be friends with itself; this means that each instantiation is diff --git a/gcc/cp/init.c b/gcc/cp/init.c index bcb5ab7a23b..d4c357facd7 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1,7 +1,7 @@ /* Handle initialization things in C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011 Free Software Foundation, Inc. + 2011, 2012 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -3194,7 +3194,10 @@ build_vec_init (tree base, tree maxindex, tree init, if (TREE_CODE (atype) == ARRAY_TYPE) { ptype = build_pointer_type (type); - base = cp_convert (ptype, decay_conversion (base)); + base = decay_conversion (base, complain); + if (base == error_mark_node) + return error_mark_node; + base = cp_convert (ptype, base); } else ptype = atype; @@ -3243,7 +3246,9 @@ build_vec_init (tree base, tree maxindex, tree init, { if (lvalue_kind (init) & clk_rvalueref) xvalue = true; - base2 = decay_conversion (init); + base2 = decay_conversion (init, complain); + if (base2 == error_mark_node) + return error_mark_node; itype = TREE_TYPE (base2); base2 = get_temp_regvar (itype, base2); itype = TREE_TYPE (itype); diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 1536828a32c..d00df1fe49a 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2023,6 +2023,8 @@ write_type (tree type) case NULLPTR_TYPE: write_string ("Dn"); + if (abi_version_at_least (7)) + ++is_builtin_type; break; case TYPEOF_TYPE: diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 79bed4a053f..cea44d491d3 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -244,7 +244,6 @@ make_alias_for (tree target, tree newid) TREE_ADDRESSABLE (alias) = 1; TREE_USED (alias) = 1; SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias)); - TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; return alias; } diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 886a7b13930..3693f7b2db9 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1,5 +1,5 @@ /* Definitions for C++ name lookup routines. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net> @@ -400,6 +400,9 @@ pop_binding (tree id, tree decl) tree strip_using_decl (tree decl) { + if (decl == NULL_TREE) + return NULL_TREE; + while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl)) decl = USING_DECL_DECLS (decl); return decl; @@ -763,7 +766,7 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend) else if (t == wchar_decl_node) { if (! DECL_IN_SYSTEM_HEADER (x)) - pedwarn (input_location, OPT_pedantic, "redeclaration of %<wchar_t%> as %qT", + pedwarn (input_location, OPT_Wpedantic, "redeclaration of %<wchar_t%> as %qT", TREE_TYPE (x)); /* Throw away the redeclaration. */ @@ -4115,9 +4118,13 @@ qualify_lookup (tree val, int flags) return false; if ((flags & LOOKUP_PREFER_NAMESPACES) && TREE_CODE (val) == NAMESPACE_DECL) return true; - if ((flags & LOOKUP_PREFER_TYPES) - && (TREE_CODE (val) == TYPE_DECL || TREE_CODE (val) == TEMPLATE_DECL)) - return true; + if (flags & LOOKUP_PREFER_TYPES) + { + tree target_val = strip_using_decl (val); + if (TREE_CODE (target_val) == TYPE_DECL + || TREE_CODE (target_val) == TEMPLATE_DECL) + return true; + } if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES)) return false; /* Look through lambda things that we shouldn't be able to see. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index eac60f13572..3b5a476cdd0 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4011,7 +4011,7 @@ cp_parser_primary_expression (cp_parser *parser, && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { /* Statement-expressions are not allowed by the standard. */ - pedwarn (token->location, OPT_pedantic, + pedwarn (token->location, OPT_Wpedantic, "ISO C++ forbids braced-groups within expressions"); /* And they're not allowed outside of a function-body; you @@ -5550,7 +5550,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, { /* Warn the user that a compound literal is not allowed in standard C++. */ - pedwarn (input_location, OPT_pedantic, "ISO C++ forbids compound-literals"); + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids compound-literals"); /* For simplicity, we disallow compound literals in constant-expressions. We could allow compound literals of integer type, whose @@ -6393,7 +6393,7 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p, expressions. So pedwarn if alignof is used with a non- type expression. However, __alignof__ is ok. */ if (!strcmp (IDENTIFIER_POINTER (token->u.value), "alignof")) - pedwarn (token->location, OPT_pedantic, + pedwarn (token->location, OPT_Wpedantic, "ISO C++ does not allow %<alignof%> " "with a non-type"); @@ -7434,7 +7434,7 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr) if (cp_parser_allow_gnu_extensions_p (parser) && token->type == CPP_COLON) { - pedwarn (token->location, OPT_pedantic, + pedwarn (token->location, OPT_Wpedantic, "ISO C++ does not allow ?: with omitted middle operand"); /* Implicit true clause. */ expr = NULL_TREE; @@ -8238,7 +8238,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) { /* An explicit expression exists. */ cp_lexer_consume_token (parser->lexer); - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ does not allow initializers " "in lambda expression capture lists"); capture_init_expr = cp_parser_assignment_expression (parser, @@ -8368,7 +8368,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) parameter-declaration-clause of a lambda-declarator. */ for (t = param_list; t; t = TREE_CHAIN (t)) if (TREE_PURPOSE (t)) - pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), OPT_pedantic, + pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), OPT_Wpedantic, "default argument specified for lambda parameter"); cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); @@ -8939,7 +8939,7 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, return error_mark_node; if (DECL_DECLARED_CONSTEXPR_P (current_function_decl) && !function_body) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "compound-statement in constexpr function"); /* Begin the compound-statement. */ compound_stmt = begin_compound_stmt (in_try ? BCS_TRY_BLOCK : 0); @@ -9910,7 +9910,7 @@ cp_parser_jump_statement (cp_parser* parser) if (cp_lexer_next_token_is (parser->lexer, CPP_MULT)) { /* Issue a warning about this use of a GNU extension. */ - pedwarn (token->location, OPT_pedantic, "ISO C++ forbids computed gotos"); + pedwarn (token->location, OPT_Wpedantic, "ISO C++ forbids computed gotos"); /* Consume the '*' token. */ cp_lexer_consume_token (parser->lexer); /* Parse the dependent expression. */ @@ -10055,7 +10055,7 @@ cp_parser_declaration_seq_opt (cp_parser* parser) invalid. Allow it unless we're being pedantic. */ cp_lexer_consume_token (parser->lexer); if (!in_system_header) - pedwarn (input_location, OPT_pedantic, "extra %<;%>"); + pedwarn (input_location, OPT_Wpedantic, "extra %<;%>"); continue; } @@ -14362,7 +14362,7 @@ cp_parser_enum_specifier (cp_parser* parser) { /* Are template enums allowed in ISO? */ if (template_parm_scope_p ()) - pedwarn (type_start_token->location, OPT_pedantic, + pedwarn (type_start_token->location, OPT_Wpedantic, "%qD is an enumeration template", name); /* ignore a typename reference, for it will be solved by name in start_enum. */ @@ -14615,7 +14615,7 @@ cp_parser_enumerator_list (cp_parser* parser, tree type) if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)) { if (cxx_dialect < cxx0x && !in_system_header) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "comma at end of enumerator list"); break; } @@ -17634,7 +17634,7 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON) { /* Warn the user that they are using an extension. */ - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ does not allow designated initializers"); /* Consume the identifier. */ designator = cp_lexer_consume_token (parser->lexer)->u.value; @@ -17648,7 +17648,7 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ) { /* Warn the user that they are using an extension. */ - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ does not allow C99 designated initializers"); /* Consume the `.'. */ cp_lexer_consume_token (parser->lexer); @@ -17845,6 +17845,8 @@ cp_parser_class_name (cp_parser *parser, decl = TYPE_NAME (decl); } + decl = strip_using_decl (decl); + /* Check to see that it is really the name of a class. */ if (TREE_CODE (decl) == TEMPLATE_ID_EXPR && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE @@ -18862,7 +18864,7 @@ cp_parser_member_declaration (cp_parser* parser) { cp_token *token = cp_lexer_peek_token (parser->lexer); if (!in_system_header_at (token->location)) - pedwarn (token->location, OPT_pedantic, "extra %<;%>"); + pedwarn (token->location, OPT_Wpedantic, "extra %<;%>"); } else { @@ -18880,7 +18882,7 @@ cp_parser_member_declaration (cp_parser* parser) /* If the `friend' keyword was present, the friend must be introduced with a class-key. */ if (!declares_class_or_enum && cxx_dialect < cxx0x) - pedwarn (decl_spec_token_start->location, OPT_pedantic, + pedwarn (decl_spec_token_start->location, OPT_Wpedantic, "in C++03 a class-key must be used " "when declaring a friend"); /* In this case: @@ -19107,7 +19109,7 @@ cp_parser_member_declaration (cp_parser* parser) possible that this fact is an oversight in the standard, since a pure function may be defined outside of the class-specifier. */ - if (initializer) + if (initializer && initializer_token_start) error_at (initializer_token_start->location, "pure-specifier on function-definition"); decl = cp_parser_save_member_function_body (parser, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ee38254bd8c..636909db5c0 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -943,7 +943,7 @@ maybe_process_partial_specialization (tree type) /* Someday C++0x may allow for enum template specialization. */ if (cxx_dialect > cxx98 && TREE_CODE (type) == ENUMERAL_TYPE && CLASS_TYPE_P (context) && CLASSTYPE_USE_TEMPLATE (context)) - pedwarn (input_location, OPT_pedantic, "template specialization " + pedwarn (input_location, OPT_Wpedantic, "template specialization " "of %qD not allowed by ISO C++", type); else { @@ -1839,6 +1839,7 @@ determine_specialization (tree template_id, { tree decl_arg_types; tree fn_arg_types; + tree insttype; /* In case of explicit specialization, we need to check if the number of template headers appearing in the specialization @@ -1900,15 +1901,6 @@ determine_specialization (tree template_id, fn_arg_types = skip_artificial_parms_for (fn, fn_arg_types); - /* Check that the number of function parameters matches. - For example, - template <class T> void f(int i = 0); - template <> void f<int>(); - The specialization f<int> is invalid but is not caught - by get_bindings below. */ - if (list_length (fn_arg_types) != list_length (decl_arg_types)) - continue; - /* Function templates cannot be specializations; there are no partial specializations of functions. Therefore, if the type of DECL does not match FN, there is no @@ -1929,6 +1921,15 @@ determine_specialization (tree template_id, specialize TMPL will produce DECL. */ continue; + /* Make sure that the deduced arguments actually work. */ + insttype = tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE); + if (insttype == error_mark_node) + continue; + fn_arg_types + = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (insttype)); + if (!compparms (fn_arg_types, decl_arg_types)) + continue; + /* Save this template, and the arguments deduced. */ templates = tree_cons (targs, fn, templates); } @@ -4376,6 +4377,18 @@ process_partial_specialization (tree decl) (maintmpl))))) error ("partial specialization %qT does not specialize any template arguments", type); + /* A partial specialization that replaces multiple parameters of the + primary template with a pack expansion is less specialized for those + parameters. */ + if (nargs < DECL_NTPARMS (maintmpl)) + { + error ("partial specialization is not more specialized than the " + "primary template because it replaces multiple parameters " + "with a pack expansion"); + inform (DECL_SOURCE_LOCATION (maintmpl), "primary template here"); + return decl; + } + /* [temp.class.spec] A partially specialized non-type argument expression shall not @@ -5679,7 +5692,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) value_dependent_expression_p. */ if (TYPE_PTROBV_P (type) && TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE) - expr = decay_conversion (expr); + { + expr = decay_conversion (expr, complain); + if (expr == error_mark_node) + return error_mark_node; + } /* If we are in a template, EXPR may be non-dependent, but still have a syntactic, rather than semantic, form. For example, EXPR @@ -5887,7 +5904,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) } } - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); if (expr == error_mark_node) return error_mark_node; @@ -5972,7 +5989,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) context information to decay the pointer. */ if (!type_unknown_p (expr_type)) { - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); if (expr == error_mark_node) return error_mark_node; } @@ -6416,7 +6433,7 @@ convert_template_argument (tree parm, if (cxx_dialect >= cxx0x) /* OK under DR 1004. */; else if (complain & tf_warning_or_error) - pedwarn (input_location, OPT_pedantic, "injected-class-name %qD" + pedwarn (input_location, OPT_Wpedantic, "injected-class-name %qD" " used as template template argument", TYPE_NAME (arg)); else if (flag_pedantic_errors) t = arg; @@ -6428,6 +6445,7 @@ convert_template_argument (tree parm, is_tmpl_type = ((TREE_CODE (arg) == TEMPLATE_DECL && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL) + || (requires_tmpl_type && TREE_CODE (arg) == TYPE_ARGUMENT_PACK) || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE); @@ -6499,7 +6517,9 @@ convert_template_argument (tree parm, { if (requires_tmpl_type) { - if (TREE_CODE (TREE_TYPE (arg)) == UNBOUND_CLASS_TEMPLATE) + if (template_parameter_pack_p (parm) && ARGUMENT_PACK_P (orig_arg)) + val = orig_arg; + else if (TREE_CODE (TREE_TYPE (arg)) == UNBOUND_CLASS_TEMPLATE) /* The number of argument required is not known yet. Just accept it for now. */ val = TREE_TYPE (arg); @@ -6697,7 +6717,12 @@ coerce_template_parameter_pack (tree parms, TREE_VEC_ELT (packed_types, arg_idx - parm_idx); } - if (arg != error_mark_node) + if (arg == error_mark_node) + { + if (complain & tf_error) + error ("template argument %d is invalid", arg_idx + 1); + } + else arg = convert_template_argument (actual_parm, arg, new_args, complain, parm_idx, in_decl); @@ -6725,6 +6750,20 @@ coerce_template_parameter_pack (tree parms, return argument_pack; } +/* Returns true if the template argument vector ARGS contains + any pack expansions, false otherwise. */ + +static bool +any_pack_expanson_args_p (tree args) +{ + int i; + if (args) + for (i = 0; i < TREE_VEC_LENGTH (args); ++i) + if (PACK_EXPANSION_P (TREE_VEC_ELT (args, i))) + return true; + return false; +} + /* Convert all template arguments to their appropriate types, and return a vector containing the innermost resulting template arguments. If any error occurs, return error_mark_node. Error and @@ -6790,6 +6829,7 @@ coerce_template_parms (tree parms, if ((nargs > nparms && !variadic_p) || (nargs < nparms - variadic_p && require_all_args + && !any_pack_expanson_args_p (inner_args) && (!use_default_args || (TREE_VEC_ELT (parms, nargs) != error_mark_node && !TREE_PURPOSE (TREE_VEC_ELT (parms, nargs)))))) @@ -6867,7 +6907,7 @@ coerce_template_parms (tree parms, { /* We don't know how many args we have yet, just use the unconverted ones for now. */ - new_inner_args = args; + new_inner_args = inner_args; break; } } @@ -9498,7 +9538,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, } /* Substitute into the PATTERN with the altered arguments. */ - if (TREE_CODE (t) == EXPR_PACK_EXPANSION) + if (!TYPE_P (pattern)) TREE_VEC_ELT (result, i) = tsubst_expr (pattern, args, complain, in_decl, /*integral_constant_expression_p=*/false); @@ -17869,7 +17909,7 @@ do_decl_instantiation (tree decl, tree storage) else if (storage == ridpointers[(int) RID_EXTERN]) { if (!in_system_header && (cxx_dialect == cxx98)) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ 1998 forbids the use of %<extern%> on explicit " "instantiations"); extern_p = 1; @@ -17966,12 +18006,12 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain) if (storage == ridpointers[(int) RID_EXTERN]) { if (cxx_dialect == cxx98) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ 1998 forbids the use of %<extern%> on " "explicit instantiations"); } else - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids the use of %qE" " on explicit instantiations", storage); } diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 2ca8fa511fa..92427648497 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -551,7 +551,7 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst_flags_t complain) if (tc == POINTER_TYPE) { - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); exprtype = TREE_TYPE (expr); /* If T is a pointer type, v shall be an rvalue of a pointer to @@ -936,7 +936,8 @@ tinfo_base_init (tinfo_s *ti, tree target) v = VEC_alloc (constructor_elt, gc, 2); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, vtable_ptr); - CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, decay_conversion (name_decl)); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + decay_conversion (name_decl, tf_warning_or_error)); init = build_constructor (init_list_type_node, v); TREE_CONSTANT (init) = 1; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 9bdd2ee1c89..a621f25a4f4 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1382,7 +1382,7 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands, for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t)) { constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); - operand = decay_conversion (TREE_VALUE (t)); + operand = decay_conversion (TREE_VALUE (t), tf_warning_or_error); /* If the type of the operand hasn't been determined (e.g., because it involves an overloaded function), then issue @@ -5921,6 +5921,12 @@ build_constexpr_constructor_member_initializers (tree type, tree body) break; } } + else if (TREE_CODE (body) == TRY_BLOCK) + { + error ("body of %<constexpr%> constructor cannot be " + "a function-try-block"); + return error_mark_node; + } else if (EXPR_P (body)) ok = build_data_member_initialization (body, &vec); else @@ -9359,7 +9365,7 @@ maybe_add_lambda_conv_op (tree type) body = begin_function_body (); compound_stmt = begin_compound_stmt (0); - finish_return_stmt (decay_conversion (statfn)); + finish_return_stmt (decay_conversion (statfn, tf_warning_or_error)); finish_compound_stmt (compound_stmt); finish_function_body (body); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 05777594e54..96a403fce6b 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3508,7 +3508,7 @@ cp_fix_function_decl_p (tree decl) /* Don't fix same_body aliases. Although they don't have their own CFG, they share it with what they alias to. */ if (!node || !node->alias - || !VEC_length (ipa_ref_t, node->ref_list.references)) + || !VEC_length (ipa_ref_t, node->symbol.ref_list.references)) return true; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index d2ed940cbc0..3aabbe95c56 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -605,17 +605,17 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2, switch (operation) { case CPO_COMPARISON: - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids comparison between " "pointer of type %<void *%> and pointer-to-function"); break; case CPO_CONVERSION: - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids conversion between " "pointer of type %<void *%> and pointer-to-function"); break; case CPO_CONDITIONAL_EXPR: - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids conditional expression between " "pointer of type %<void *%> and pointer-to-function"); break; @@ -1526,7 +1526,7 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, bool complain) if (TREE_CODE (type) == METHOD_TYPE) { if (complain) - pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpointer_arith, + pedwarn (input_location, pedantic ? OPT_Wpedantic : OPT_Wpointer_arith, "invalid application of %qs to a member function", operator_name_info[(int) op].name); value = size_one_node; @@ -1818,7 +1818,7 @@ unlowered_expr_type (const_tree exp) that the return value is no longer an lvalue. */ tree -decay_conversion (tree exp) +decay_conversion (tree exp, tsubst_flags_t complain) { tree type; enum tree_code code; @@ -1832,7 +1832,8 @@ decay_conversion (tree exp) exp = resolve_nondeduced_context (exp); if (type_unknown_p (exp)) { - cxx_incomplete_type_error (exp, TREE_TYPE (exp)); + if (complain & tf_error) + cxx_incomplete_type_error (exp, TREE_TYPE (exp)); return error_mark_node; } @@ -1851,13 +1852,14 @@ decay_conversion (tree exp) code = TREE_CODE (type); if (code == VOID_TYPE) { - error ("void value not ignored as it ought to be"); + if (complain & tf_error) + error ("void value not ignored as it ought to be"); return error_mark_node; } - if (invalid_nonstatic_memfn_p (exp, tf_warning_or_error)) + if (invalid_nonstatic_memfn_p (exp, complain)) return error_mark_node; if (code == FUNCTION_TYPE || is_overloaded_fn (exp)) - return cp_build_addr_expr (exp, tf_warning_or_error); + return cp_build_addr_expr (exp, complain); if (code == ARRAY_TYPE) { tree adr; @@ -1869,7 +1871,9 @@ decay_conversion (tree exp) if (TREE_CODE (exp) == COMPOUND_EXPR) { - tree op1 = decay_conversion (TREE_OPERAND (exp, 1)); + tree op1 = decay_conversion (TREE_OPERAND (exp, 1), complain); + if (op1 == error_mark_node) + return error_mark_node; return build2 (COMPOUND_EXPR, TREE_TYPE (op1), TREE_OPERAND (exp, 0), op1); } @@ -1877,7 +1881,8 @@ decay_conversion (tree exp) if (!lvalue_p (exp) && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp))) { - error ("invalid use of non-lvalue array"); + if (complain & tf_error) + error ("invalid use of non-lvalue array"); return error_mark_node; } @@ -1892,7 +1897,7 @@ decay_conversion (tree exp) } /* This way is better for a COMPONENT_REF since it can simplify the offset for a component. */ - adr = cp_build_addr_expr (exp, tf_warning_or_error); + adr = cp_build_addr_expr (exp, complain); return cp_convert (ptrtype, adr); } @@ -1931,8 +1936,8 @@ decay_conversion (tree exp) applied to both operands to a binary operator before determining what additional conversions should apply. */ -tree -default_conversion (tree exp) +static tree +cp_default_conversion (tree exp, tsubst_flags_t complain) { /* Check for target-specific promotions. */ tree promoted_type = targetm.promoted_type (TREE_TYPE (exp)); @@ -1944,11 +1949,19 @@ default_conversion (tree exp) else if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (exp))) exp = perform_integral_promotions (exp); /* Perform the other conversions. */ - exp = decay_conversion (exp); + exp = decay_conversion (exp, complain); return exp; } +/* C version. */ + +tree +default_conversion (tree exp) +{ + return cp_default_conversion (exp, tf_warning_or_error); +} + /* EXPR is an expression with an integral or enumeration type. Perform the integral promotions in [conv.prom], and return the converted value. */ @@ -2758,14 +2771,14 @@ cp_build_indirect_ref (tree ptr, ref_operator errorstring, { tree pointer, type; - if (ptr == error_mark_node) - return error_mark_node; - if (ptr == current_class_ptr) return current_class_ref; pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE - ? ptr : decay_conversion (ptr)); + ? ptr : decay_conversion (ptr, complain)); + if (pointer == error_mark_node) + return error_mark_node; + type = TREE_TYPE (pointer); if (POINTER_TYPE_P (type)) @@ -2948,7 +2961,7 @@ cp_build_array_ref (location_t loc, tree array, tree idx, } if (!lvalue_p (array) && (complain & tf_error)) - pedwarn (loc, OPT_pedantic, + pedwarn (loc, OPT_Wpedantic, "ISO C++ forbids subscripting non-lvalue array"); /* Note in C++ it is valid to subscript a `register' array, since @@ -2982,8 +2995,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx, } { - tree ar = default_conversion (array); - tree ind = default_conversion (idx); + tree ar = cp_default_conversion (array, complain); + tree ind = cp_default_conversion (idx, complain); /* Put the integer in IND to simplify error checking. */ if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE) @@ -2993,8 +3006,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx, ind = temp; } - if (ar == error_mark_node) - return ar; + if (ar == error_mark_node || ind == error_mark_node) + return error_mark_node; if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE) { @@ -3040,7 +3053,8 @@ build_array_ref (location_t loc, tree array, tree idx) later has the right member. */ tree -get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) +get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, + tsubst_flags_t complain) { if (TREE_CODE (function) == OFFSET_REF) function = TREE_OPERAND (function, 1); @@ -3059,13 +3073,14 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) /* Extracting the function address from a pmf is only allowed with -Wno-pmf-conversions. It only works for pmf constants. */ - e1 = build_addr_func (PTRMEM_CST_MEMBER (function)); + e1 = build_addr_func (PTRMEM_CST_MEMBER (function), complain); e1 = convert (fntype, e1); return e1; } else { - error ("object missing in use of %qE", function); + if (complain & tf_error) + error ("object missing in use of %qE", function); return error_mark_node; } } @@ -3085,25 +3100,32 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) case ptrmemfunc_vbit_in_pfn: e1 = cp_build_binary_op (input_location, BIT_AND_EXPR, idx, integer_one_node, - tf_warning_or_error); + complain); idx = cp_build_binary_op (input_location, MINUS_EXPR, idx, integer_one_node, - tf_warning_or_error); + complain); + if (idx == error_mark_node) + return error_mark_node; break; case ptrmemfunc_vbit_in_delta: e1 = cp_build_binary_op (input_location, BIT_AND_EXPR, delta, integer_one_node, - tf_warning_or_error); + complain); delta = cp_build_binary_op (input_location, RSHIFT_EXPR, delta, integer_one_node, - tf_warning_or_error); + complain); + if (delta == error_mark_node) + return error_mark_node; break; default: gcc_unreachable (); } + if (e1 == error_mark_node) + return error_mark_node; + /* Convert down to the right base before using the instance. A special case is that in a pointer to member of class C, C may be incomplete. In that case, the function will of course be @@ -3117,7 +3139,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)), basetype, ba_check, NULL); instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype, - 1, tf_warning_or_error); + 1, complain); if (instance_ptr == error_mark_node) return error_mark_node; } @@ -3130,7 +3152,10 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) /* Next extract the vtable pointer from the object. */ vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node), instance_ptr); - vtbl = cp_build_indirect_ref (vtbl, RO_NULL, tf_warning_or_error); + vtbl = cp_build_indirect_ref (vtbl, RO_NULL, complain); + if (vtbl == error_mark_node) + return error_mark_node; + /* If the object is not dynamic the access invokes undefined behavior. As it is not executed in this case silence the spurious warnings it may provoke. */ @@ -3138,17 +3163,21 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) /* Finally, extract the function pointer from the vtable. */ e2 = fold_build_pointer_plus_loc (input_location, vtbl, idx); - e2 = cp_build_indirect_ref (e2, RO_NULL, tf_warning_or_error); + e2 = cp_build_indirect_ref (e2, RO_NULL, complain); + if (e2 == error_mark_node) + return error_mark_node; TREE_CONSTANT (e2) = 1; /* When using function descriptors, the address of the vtable entry is treated as a function pointer. */ if (TARGET_VTABLE_USES_DESCRIPTORS) e2 = build1 (NOP_EXPR, TREE_TYPE (e2), - cp_build_addr_expr (e2, tf_warning_or_error)); + cp_build_addr_expr (e2, complain)); e2 = fold_convert (TREE_TYPE (e3), e2); - e1 = build_conditional_expr (e1, e2, e3, tf_warning_or_error); + e1 = build_conditional_expr (e1, e2, e3, complain); + if (e1 == error_mark_node) + return error_mark_node; /* Make sure this doesn't get evaluated first inside one of the branches of the COND_EXPR. */ @@ -3258,16 +3287,16 @@ cp_build_function_call_vec (tree function, VEC(tree,gc) **params, /* Convert anything with function type to a pointer-to-function. */ if (DECL_MAIN_P (function) && (complain & tf_error)) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids calling %<::main%> from within program"); - function = build_addr_func (function); + function = build_addr_func (function, complain); } else { fndecl = NULL_TREE; - function = build_addr_func (function); + function = build_addr_func (function, complain); } if (function == error_mark_node) @@ -3293,7 +3322,18 @@ cp_build_function_call_vec (tree function, VEC(tree,gc) **params, || TREE_CODE (function) == TEMPLATE_ID_EXPR)) { if (complain & tf_error) - error ("%qE cannot be used as a function", original); + { + if (!flag_diagnostics_show_caret) + error_at (input_location, + "%qE cannot be used as a function", original); + else if (DECL_P (original)) + error_at (input_location, + "%qD cannot be used as a function", original); + else + error_at (input_location, + "expression cannot be used as a function"); + } + return error_mark_node; } @@ -3432,7 +3472,7 @@ convert_arguments (tree typelist, VEC(tree,gc) **values, tree fndecl, if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE) - val = decay_conversion (val); + val = decay_conversion (val, complain); } if (val == error_mark_node) @@ -3559,7 +3599,7 @@ build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code, } if (code == DOTSTAR_EXPR) - expr = build_m_component_ref (arg1, arg2); + expr = build_m_component_ref (arg1, arg2, complain); else expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE, overload, complain); @@ -3723,16 +3763,16 @@ cp_build_binary_op (location_t location, || code == TRUTH_XOR_EXPR) { if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0))) - op0 = decay_conversion (op0); + op0 = decay_conversion (op0, complain); if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1))) - op1 = decay_conversion (op1); + op1 = decay_conversion (op1, complain); } else { if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0))) - op0 = default_conversion (op0); + op0 = cp_default_conversion (op0, complain); if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1))) - op1 = default_conversion (op1); + op1 = cp_default_conversion (op1, complain); } /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ @@ -4895,9 +4935,9 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain) { /* ARM $3.4 */ /* Apparently a lot of autoconf scripts for C++ packages do this, - so only complain if -pedantic. */ + so only complain if -Wpedantic. */ if (complain & (flag_pedantic_errors ? tf_error : tf_warning)) - pedwarn (input_location, OPT_pedantic, + pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids taking address of function %<::main%>"); else if (flag_pedantic_errors) return error_mark_node; @@ -5129,7 +5169,11 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert, { code = CONJ_EXPR; if (!noconvert) - arg = default_conversion (arg); + { + arg = cp_default_conversion (arg, complain); + if (arg == error_mark_node) + return error_mark_node; + } } else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM | WANT_VECTOR_OR_COMPLEX, @@ -5143,7 +5187,11 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert, if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true))) errstring = _("wrong type argument to abs"); else if (!noconvert) - arg = default_conversion (arg); + { + arg = cp_default_conversion (arg, complain); + if (arg == error_mark_node) + return error_mark_node; + } break; case CONJ_EXPR: @@ -5151,7 +5199,11 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert, if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true))) errstring = _("wrong type argument to conjugation"); else if (!noconvert) - arg = default_conversion (arg); + { + arg = cp_default_conversion (arg, complain); + if (arg == error_mark_node) + return error_mark_node; + } break; case TRUTH_NOT_EXPR: @@ -6129,7 +6181,7 @@ build_static_cast (tree type, tree expr, tsubst_flags_t complain) converted expression. */ tree -convert_member_func_to_ptr (tree type, tree expr) +convert_member_func_to_ptr (tree type, tree expr, tsubst_flags_t complain) { tree intype; tree decl; @@ -6138,21 +6190,27 @@ convert_member_func_to_ptr (tree type, tree expr) gcc_assert (TYPE_PTRMEMFUNC_P (intype) || TREE_CODE (intype) == METHOD_TYPE); + if (!(complain & tf_warning_or_error)) + return error_mark_node; + if (pedantic || warn_pmf2ptr) - pedwarn (input_location, pedantic ? OPT_pedantic : OPT_Wpmf_conversions, + pedwarn (input_location, pedantic ? OPT_Wpedantic : OPT_Wpmf_conversions, "converting from %qT to %qT", intype, type); if (TREE_CODE (intype) == METHOD_TYPE) - expr = build_addr_func (expr); + expr = build_addr_func (expr, complain); else if (TREE_CODE (expr) == PTRMEM_CST) expr = build_address (PTRMEM_CST_MEMBER (expr)); else { decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0); decl = build_address (decl); - expr = get_member_function_from_ptrfunc (&decl, expr); + expr = get_member_function_from_ptrfunc (&decl, expr, complain); } + if (expr == error_mark_node) + return error_mark_node; + return build_nop (type, expr); } @@ -6230,12 +6288,12 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, && TYPE_PTR_P (type) && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE || VOID_TYPE_P (TREE_TYPE (type)))) - return convert_member_func_to_ptr (type, expr); + return convert_member_func_to_ptr (type, expr, complain); /* If the cast is not to a reference type, the lvalue-to-rvalue, array-to-pointer, and function-to-pointer conversions are performed. */ - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */ @@ -6474,12 +6532,17 @@ build_const_cast_1 (tree dst_type, tree expr, tsubst_flags_t complain, if (reference_type) { expr = cp_build_addr_expr (expr, complain); + if (expr == error_mark_node) + return error_mark_node; expr = build_nop (reference_type, expr); return convert_from_reference (expr); } else { - expr = decay_conversion (expr); + expr = decay_conversion (expr, complain); + if (expr == error_mark_node) + return error_mark_node; + /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue. Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */ @@ -7333,7 +7396,8 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn) /*c_cast_p=*/0, tf_warning_or_error); if (!DECL_VIRTUAL_P (fn)) - *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn)); + *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), + build_addr_func (fn, tf_warning_or_error)); else { /* If we're dealing with a virtual function, we have to adjust 'this' @@ -7667,7 +7731,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags, && (TREE_CODE (type) != REFERENCE_TYPE || TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)) || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE) - rhs = decay_conversion (rhs); + rhs = decay_conversion (rhs, complain); rhstype = TREE_TYPE (rhs); coder = TREE_CODE (rhstype); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index f9b525cba40..af72851a2ef 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1,7 +1,8 @@ /* Report error messages, build initializers, and perform some front-end optimizations for C++ compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) @@ -1528,7 +1529,7 @@ build_x_arrow (tree expr, tsubst_flags_t complain) last_rval = convert_from_reference (last_rval); } else - last_rval = decay_conversion (expr); + last_rval = decay_conversion (expr, complain); if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE) { @@ -1557,7 +1558,7 @@ build_x_arrow (tree expr, tsubst_flags_t complain) already been checked out to be of aggregate type. */ tree -build_m_component_ref (tree datum, tree component) +build_m_component_ref (tree datum, tree component, tsubst_flags_t complain) { tree ptrmem_type; tree objtype; @@ -1574,18 +1575,18 @@ build_m_component_ref (tree datum, tree component) ptrmem_type = TREE_TYPE (component); if (!TYPE_PTR_TO_MEMBER_P (ptrmem_type)) { - error ("%qE cannot be used as a member pointer, since it is of " - "type %qT", - component, ptrmem_type); + if (complain & tf_error) + error ("%qE cannot be used as a member pointer, since it is of " + "type %qT", component, ptrmem_type); return error_mark_node; } objtype = TYPE_MAIN_VARIANT (TREE_TYPE (datum)); if (! MAYBE_CLASS_TYPE_P (objtype)) { - error ("cannot apply member pointer %qE to %qE, which is of " - "non-class type %qT", - component, datum, objtype); + if (complain & tf_error) + error ("cannot apply member pointer %qE to %qE, which is of " + "non-class type %qT", component, datum, objtype); return error_mark_node; } @@ -1605,9 +1606,9 @@ build_m_component_ref (tree datum, tree component) if (!binfo) { mismatch: - error ("pointer to member type %qT incompatible with object " - "type %qT", - type, objtype); + if (complain & tf_error) + error ("pointer to member type %qT incompatible with object " + "type %qT", type, objtype); return error_mark_node; } else if (binfo == error_mark_node) @@ -1631,14 +1632,20 @@ build_m_component_ref (tree datum, tree component) /* Convert object to the correct base. */ if (binfo) - datum = build_base_path (PLUS_EXPR, datum, binfo, 1, - tf_warning_or_error); + { + datum = build_base_path (PLUS_EXPR, datum, binfo, 1, complain); + if (datum == error_mark_node) + return error_mark_node; + } /* Build an expression for "object + offset" where offset is the value stored in the pointer-to-data-member. */ ptype = build_pointer_type (type); datum = fold_build_pointer_plus (fold_convert (ptype, datum), component); - datum = cp_build_indirect_ref (datum, RO_NULL, tf_warning_or_error); + datum = cp_build_indirect_ref (datum, RO_NULL, complain); + if (datum == error_mark_node) + return error_mark_node; + /* If the object expression was an rvalue, return an rvalue. */ if (!is_lval) datum = move (datum); diff --git a/gcc/cse.c b/gcc/cse.c index 5c32336c596..b7db827cf30 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -2622,7 +2622,7 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse) if (GET_MODE (x) != GET_MODE (y)) return 0; - /* MEMs refering to different address space are not equivalent. */ + /* MEMs referring to different address space are not equivalent. */ if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) return 0; diff --git a/gcc/dbgcnt.def b/gcc/dbgcnt.def index e3ac8eaf1ae..439f3e18a02 100644 --- a/gcc/dbgcnt.def +++ b/gcc/dbgcnt.def @@ -184,3 +184,4 @@ DEBUG_COUNTER (sms_sched_loop) DEBUG_COUNTER (store_motion) DEBUG_COUNTER (split_for_sched2) DEBUG_COUNTER (tail_call) +DEBUG_COUNTER (ira_move) diff --git a/gcc/dce.c b/gcc/dce.c index a36ac61dea8..c706296c663 100644 --- a/gcc/dce.c +++ b/gcc/dce.c @@ -807,6 +807,7 @@ word_dce_process_block (basic_block bb, bool redo_out) bitmap local_live = BITMAP_ALLOC (&dce_tmp_bitmap_obstack); rtx insn; bool block_changed; + struct dead_debug debug; if (redo_out) { @@ -828,11 +829,24 @@ word_dce_process_block (basic_block bb, bool redo_out) } bitmap_copy (local_live, DF_WORD_LR_OUT (bb)); + dead_debug_init (&debug, NULL); FOR_BB_INSNS_REVERSE (bb, insn) - if (NONDEBUG_INSN_P (insn)) + if (DEBUG_INSN_P (insn)) + { + df_ref *use_rec; + for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++) + if (DF_REF_REGNO (*use_rec) >= FIRST_PSEUDO_REGISTER + && (GET_MODE_SIZE (GET_MODE (DF_REF_REAL_REG (*use_rec))) + == 2 * UNITS_PER_WORD) + && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (*use_rec)) + && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (*use_rec) + 1)) + dead_debug_add (&debug, *use_rec, DF_REF_REGNO (*use_rec)); + } + else if (INSN_P (insn)) { bool any_changed; + /* No matter if the instruction is needed or not, we remove any regno in the defs from the live set. */ any_changed = df_word_lr_simulate_defs (insn, local_live); @@ -844,6 +858,15 @@ word_dce_process_block (basic_block bb, bool redo_out) if (marked_insn_p (insn)) df_word_lr_simulate_uses (insn, local_live); + if (debug.used && !bitmap_empty_p (debug.used)) + { + df_ref *def_rec; + + for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++) + dead_debug_insert_temp (&debug, DF_REF_REGNO (*def_rec), insn, + DEBUG_TEMP_BEFORE_WITH_VALUE); + } + if (dump_file) { fprintf (dump_file, "finished processing insn %d live out = ", @@ -856,6 +879,7 @@ word_dce_process_block (basic_block bb, bool redo_out) if (block_changed) bitmap_copy (DF_WORD_LR_IN (bb), local_live); + dead_debug_finish (&debug, NULL); BITMAP_FREE (local_live); return block_changed; } @@ -873,6 +897,7 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au) rtx insn; bool block_changed; df_ref *def_rec; + struct dead_debug debug; if (redo_out) { @@ -896,22 +921,36 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au) bitmap_copy (local_live, DF_LR_OUT (bb)); df_simulate_initialize_backwards (bb, local_live); + dead_debug_init (&debug, NULL); FOR_BB_INSNS_REVERSE (bb, insn) - if (INSN_P (insn)) + if (DEBUG_INSN_P (insn)) + { + df_ref *use_rec; + for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++) + if (!bitmap_bit_p (local_live, DF_REF_REGNO (*use_rec)) + && !bitmap_bit_p (au, DF_REF_REGNO (*use_rec))) + dead_debug_add (&debug, *use_rec, DF_REF_REGNO (*use_rec)); + } + else if (INSN_P (insn)) { bool needed = marked_insn_p (insn); /* The insn is needed if there is someone who uses the output. */ if (!needed) for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++) - if (bitmap_bit_p (local_live, DF_REF_REGNO (*def_rec)) - || bitmap_bit_p (au, DF_REF_REGNO (*def_rec))) - { - needed = true; - mark_insn (insn, true); - break; - } + { + dead_debug_insert_temp (&debug, DF_REF_REGNO (*def_rec), insn, + DEBUG_TEMP_BEFORE_WITH_VALUE); + + if (bitmap_bit_p (local_live, DF_REF_REGNO (*def_rec)) + || bitmap_bit_p (au, DF_REF_REGNO (*def_rec))) + { + needed = true; + mark_insn (insn, true); + break; + } + } /* No matter if the instruction is needed or not, we remove any regno in the defs from the live set. */ @@ -923,6 +962,7 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au) df_simulate_uses (insn, local_live); } + dead_debug_finish (&debug, NULL); df_simulate_finalize_backwards (bb, local_live); block_changed = !bitmap_equal_p (local_live, DF_LR_IN (bb)); diff --git a/gcc/df-problems.c b/gcc/df-problems.c index c9fc91bd376..e04daceccab 100644 --- a/gcc/df-problems.c +++ b/gcc/df-problems.c @@ -2886,25 +2886,6 @@ df_whole_mw_reg_unused_p (struct df_mw_hardreg *mws, } -/* Node of a linked list of uses of dead REGs in debug insns. */ -struct dead_debug_use -{ - df_ref use; - struct dead_debug_use *next; -}; - -/* Linked list of the above, with a bitmap of the REGs in the - list. */ -struct dead_debug -{ - struct dead_debug_use *head; - bitmap used; - bitmap to_rescan; -}; - -static void dead_debug_reset (struct dead_debug *, unsigned int); - - /* Set the REG_UNUSED notes for the multiword hardreg defs in INSN based on the bits in LIVE. Do not generate notes for registers in artificial uses. DO_NOT_GEN is updated so that REG_DEAD notes are @@ -2930,7 +2911,7 @@ df_set_unused_notes_for_mw (rtx insn, struct df_mw_hardreg *mws, { unsigned int regno = mws->start_regno; df_set_note (REG_UNUSED, insn, mws->mw_reg); - dead_debug_reset (debug, regno); + dead_debug_insert_temp (debug, regno, insn, DEBUG_TEMP_AFTER_WITH_REG); #ifdef REG_DEAD_DEBUGGING df_print_note ("adding 1: ", insn, REG_NOTES (insn)); @@ -2945,7 +2926,7 @@ df_set_unused_notes_for_mw (rtx insn, struct df_mw_hardreg *mws, && !bitmap_bit_p (artificial_uses, r)) { df_set_note (REG_UNUSED, insn, regno_reg_rtx[r]); - dead_debug_reset (debug, r); + dead_debug_insert_temp (debug, r, insn, DEBUG_TEMP_AFTER_WITH_REG); #ifdef REG_DEAD_DEBUGGING df_print_note ("adding 2: ", insn, REG_NOTES (insn)); #endif @@ -3013,12 +2994,12 @@ df_set_dead_notes_for_mw (rtx insn, struct df_mw_hardreg *mws, if (df_whole_mw_reg_dead_p (mws, live, artificial_uses, do_not_gen)) { - /* Add a dead note for the entire multi word register. */ if (is_debug) { *added_notes_p = true; return; } + /* Add a dead note for the entire multi word register. */ df_set_note (REG_DEAD, insn, mws->mw_reg); #ifdef REG_DEAD_DEBUGGING df_print_note ("adding 1: ", insn, REG_NOTES (insn)); @@ -3072,7 +3053,7 @@ df_create_unused_note (rtx insn, df_ref def, rtx reg = (DF_REF_LOC (def)) ? *DF_REF_REAL_LOC (def): DF_REF_REG (def); df_set_note (REG_UNUSED, insn, reg); - dead_debug_reset (debug, dregno); + dead_debug_insert_temp (debug, dregno, insn, DEBUG_TEMP_AFTER_WITH_REG); #ifdef REG_DEAD_DEBUGGING df_print_note ("adding 3: ", insn, REG_NOTES (insn)); #endif @@ -3083,7 +3064,7 @@ df_create_unused_note (rtx insn, df_ref def, /* Initialize DEBUG to an empty list, and clear USED, if given. */ -static inline void +void dead_debug_init (struct dead_debug *debug, bitmap used) { debug->head = NULL; @@ -3093,32 +3074,83 @@ dead_debug_init (struct dead_debug *debug, bitmap used) bitmap_clear (used); } -/* Reset all debug insns with pending uses. Release the bitmap in it, - unless it is USED. USED must be the same bitmap passed to - dead_debug_init. */ -static inline void -dead_debug_finish (struct dead_debug *debug, bitmap used) +/* Reset all debug uses in HEAD, and clear DEBUG->to_rescan bits of + each reset insn. DEBUG is not otherwise modified. If HEAD is + DEBUG->head, DEBUG->head will be set to NULL at the end. + Otherwise, entries from DEBUG->head that pertain to reset insns + will be removed, and only then rescanned. */ + +static void +dead_debug_reset_uses (struct dead_debug *debug, struct dead_debug_use *head) { - struct dead_debug_use *head; - rtx insn = NULL; + bool got_head = (debug->head == head); + bitmap rescan; + struct dead_debug_use **tailp = &debug->head; + struct dead_debug_use *cur; + bitmap_iterator bi; + unsigned int uid; - if (debug->used != used) - BITMAP_FREE (debug->used); + if (got_head) + rescan = NULL; + else + rescan = BITMAP_ALLOC (NULL); - while ((head = debug->head)) + while (head) { + struct dead_debug_use *next = head->next; + rtx insn; + insn = DF_REF_INSN (head->use); - if (!head->next || DF_REF_INSN (head->next->use) != insn) + if (!next || DF_REF_INSN (next->use) != insn) { INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); - df_insn_rescan_debug_internal (insn); + if (got_head) + df_insn_rescan_debug_internal (insn); + else + bitmap_set_bit (rescan, INSN_UID (insn)); if (debug->to_rescan) bitmap_clear_bit (debug->to_rescan, INSN_UID (insn)); } - debug->head = head->next; XDELETE (head); + head = next; + } + + if (got_head) + { + debug->head = NULL; + return; + } + + while ((cur = *tailp)) + if (bitmap_bit_p (rescan, INSN_UID (DF_REF_INSN (cur->use)))) + { + *tailp = cur->next; + XDELETE (cur); + } + else + tailp = &cur->next; + + EXECUTE_IF_SET_IN_BITMAP (rescan, 0, uid, bi) + { + struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid); + if (insn_info) + df_insn_rescan_debug_internal (insn_info->insn); } + BITMAP_FREE (rescan); +} + +/* Reset all debug insns with pending uses. Release the bitmap in it, + unless it is USED. USED must be the same bitmap passed to + dead_debug_init. */ +void +dead_debug_finish (struct dead_debug *debug, bitmap used) +{ + if (debug->used != used) + BITMAP_FREE (debug->used); + + dead_debug_reset_uses (debug, debug->head); + if (debug->to_rescan) { bitmap_iterator bi; @@ -3134,54 +3166,9 @@ dead_debug_finish (struct dead_debug *debug, bitmap used) } } -/* Reset DEBUG_INSNs with pending uses of DREGNO. */ -static void -dead_debug_reset (struct dead_debug *debug, unsigned int dregno) -{ - struct dead_debug_use **tailp = &debug->head; - struct dead_debug_use **insnp = &debug->head; - struct dead_debug_use *cur; - rtx insn; - - if (!debug->used || !bitmap_clear_bit (debug->used, dregno)) - return; - - while ((cur = *tailp)) - { - if (DF_REF_REGNO (cur->use) == dregno) - { - *tailp = cur->next; - insn = DF_REF_INSN (cur->use); - INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); - if (debug->to_rescan == NULL) - debug->to_rescan = BITMAP_ALLOC (NULL); - bitmap_set_bit (debug->to_rescan, INSN_UID (insn)); - XDELETE (cur); - /* If the current use isn't the first one attached to INSN, go back - to this first use. We assume that the uses attached to an insn - are adjacent. */ - if (tailp != insnp && DF_REF_INSN ((*insnp)->use) == insn) - tailp = insnp; - /* Then remove all the other uses attached to INSN. */ - while ((cur = *tailp) && DF_REF_INSN (cur->use) == insn) - { - *tailp = cur->next; - XDELETE (cur); - } - insnp = tailp; - } - else - { - if (DF_REF_INSN ((*insnp)->use) != DF_REF_INSN (cur->use)) - insnp = tailp; - tailp = &(*tailp)->next; - } - } -} - /* Add USE to DEBUG. It must be a dead reference to UREGNO in a debug insn. Create a bitmap for DEBUG as needed. */ -static inline void +void dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno) { struct dead_debug_use *newddu = XNEW (struct dead_debug_use); @@ -3197,23 +3184,27 @@ dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno) } /* If UREGNO is referenced by any entry in DEBUG, emit a debug insn - before INSN that binds the REG to a debug temp, and replace all - uses of UREGNO in DEBUG with uses of the debug temp. INSN must be - the insn where UREGNO dies. */ -static inline void -dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno, - rtx insn) + before or after INSN (depending on WHERE), that binds a debug temp + to the widest-mode use of UREGNO, if WHERE is *_WITH_REG, or the + value stored in UREGNO by INSN otherwise, and replace all uses of + UREGNO in DEBUG with uses of the debug temp. INSN must be where + UREGNO dies, if WHERE is *_BEFORE_*, or where it is set otherwise. + Return the number of debug insns emitted. */ +int +dead_debug_insert_temp (struct dead_debug *debug, unsigned int uregno, + rtx insn, enum debug_temp_where where) { struct dead_debug_use **tailp = &debug->head; struct dead_debug_use *cur; struct dead_debug_use *uses = NULL; struct dead_debug_use **usesp = &uses; rtx reg = NULL; + rtx breg; rtx dval; rtx bind; if (!debug->used || !bitmap_clear_bit (debug->used, uregno)) - return; + return 0; /* Move all uses of uregno from debug->head to uses, setting mode to the widest referenced mode. */ @@ -3237,17 +3228,114 @@ dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno, /* We may have dangling bits in debug->used for registers that were part of a multi-register use, one component of which has been reset. */ if (reg == NULL) - return; + { + gcc_checking_assert (!uses); + return 0; + } + + gcc_checking_assert (uses); + + breg = reg; + /* Recover the expression INSN stores in REG. */ + if (where == DEBUG_TEMP_BEFORE_WITH_VALUE) + { + rtx set = single_set (insn); + rtx dest, src; + + if (set) + { + dest = SET_DEST (set); + src = SET_SRC (set); + /* Lose if the REG-setting insn is a CALL. */ + if (GET_CODE (src) == CALL) + { + while (uses) + { + cur = uses->next; + XDELETE (uses); + uses = cur; + } + return 0; + } + } + + /* ??? Should we try to extract it from a PARALLEL? */ + if (!set) + breg = NULL; + /* Cool, it's the same REG, we can use SRC. */ + else if (dest == reg) + breg = copy_rtx (src); + else if (REG_P (dest)) + { + /* Hmm... Something's fishy, we should be setting REG here. */ + if (REGNO (dest) != REGNO (reg)) + breg = NULL; + /* Ok, it's the same (hardware) REG, but with a different + mode, so SUBREG it. */ + else + breg = lowpart_subreg (GET_MODE (reg), copy_rtx (src), + GET_MODE (dest)); + } + else if (GET_CODE (dest) == SUBREG) + { + /* We should be setting REG here. Lose. */ + if (REGNO (SUBREG_REG (dest)) != REGNO (reg)) + breg = NULL; + /* Lose if we're setting something other than the lowpart of + REG. */ + else if (!subreg_lowpart_p (dest)) + breg = NULL; + /* If we're not overwriting all the hardware registers that + setting REG in its mode would, we won't know what to bind + the debug temp to. */ + else if (REGNO (reg) < FIRST_PSEUDO_REGISTER + && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] + != hard_regno_nregs[REGNO (reg)][GET_MODE (dest)])) + breg = NULL; + /* Yay, we can use SRC, just adjust its mode. */ + else + breg = lowpart_subreg (GET_MODE (reg), copy_rtx (src), + GET_MODE (dest)); + } + /* Oh well, we're out of luck. */ + else + breg = NULL; + + /* We couldn't figure out the value stored in REG, so reset all + of its pending debug uses. */ + if (!breg) + { + dead_debug_reset_uses (debug, uses); + return 0; + } + } + + /* If there's a single (debug) use of an otherwise unused REG, and + the debug use is not part of a larger expression, then it + probably doesn't make sense to introduce a new debug temp. */ + if (where == DEBUG_TEMP_AFTER_WITH_REG && !uses->next) + { + rtx next = DF_REF_INSN (uses->use); + + if (DEBUG_INSN_P (next) && reg == INSN_VAR_LOCATION_LOC (next)) + { + XDELETE (uses); + return 0; + } + } /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */ dval = make_debug_expr_from_rtl (reg); /* Emit a debug bind insn before the insn in which reg dies. */ bind = gen_rtx_VAR_LOCATION (GET_MODE (reg), - DEBUG_EXPR_TREE_DECL (dval), reg, + DEBUG_EXPR_TREE_DECL (dval), breg, VAR_INIT_STATUS_INITIALIZED); - bind = emit_debug_insn_before (bind, insn); + if (where == DEBUG_TEMP_AFTER_WITH_REG) + bind = emit_debug_insn_after (bind, insn); + else + bind = emit_debug_insn_before (bind, insn); df_insn_rescan (bind); /* Adjust all uses. */ @@ -3265,6 +3353,8 @@ dead_debug_insert_before (struct dead_debug *debug, unsigned int uregno, uses = cur->next; XDELETE (cur); } + + return 1; } /* Recompute the REG_DEAD and REG_UNUSED notes and compute register @@ -3453,13 +3543,19 @@ df_note_bb_compute (unsigned int bb_index, { if (debug_insn > 0) { - dead_debug_add (&debug, use, uregno); + /* We won't add REG_UNUSED or REG_DEAD notes for + these, so we don't have to mess with them in + debug insns either. */ + if (!bitmap_bit_p (artificial_uses, uregno) + && !df_ignore_stack_reg (uregno)) + dead_debug_add (&debug, use, uregno); continue; } break; } else - dead_debug_insert_before (&debug, uregno, insn); + dead_debug_insert_temp (&debug, uregno, insn, + DEBUG_TEMP_BEFORE_WITH_REG); if ( (!(DF_REF_FLAGS (use) & (DF_REF_MW_HARDREG | DF_REF_READ_WRITE))) @@ -1101,4 +1101,46 @@ extern void union_defs (df_ref, struct web_entry *, unsigned int *used, struct web_entry *, bool (*fun) (struct web_entry *, struct web_entry *)); +/* Debug uses of dead regs. */ + +/* Node of a linked list of uses of dead REGs in debug insns. */ +struct dead_debug_use +{ + df_ref use; + struct dead_debug_use *next; +}; + +/* Linked list of the above, with a bitmap of the REGs in the + list. */ +struct dead_debug +{ + struct dead_debug_use *head; + bitmap used; + bitmap to_rescan; +}; + +/* This type controls the behavior of dead_debug_insert_temp WRT + UREGNO and INSN. */ +enum debug_temp_where + { + /* Bind a newly-created debug temporary to a REG for UREGNO, and + insert the debug insn before INSN. REG is expected to die at + INSN. */ + DEBUG_TEMP_BEFORE_WITH_REG = -1, + /* Bind a newly-created debug temporary to the value INSN stores + in REG, and insert the debug insn before INSN. */ + DEBUG_TEMP_BEFORE_WITH_VALUE = 0, + /* Bind a newly-created debug temporary to a REG for UREGNO, and + insert the debug insn after INSN. REG is expected to be set at + INSN. */ + DEBUG_TEMP_AFTER_WITH_REG = 1 + }; + +extern void dead_debug_init (struct dead_debug *, bitmap); +extern void dead_debug_finish (struct dead_debug *, bitmap); +extern void dead_debug_add (struct dead_debug *, df_ref, unsigned int); +extern int dead_debug_insert_temp (struct dead_debug *, + unsigned int uregno, rtx insn, + enum debug_temp_where); + #endif /* GCC_DF_H */ diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index a68d6ce88ee..4496803f2ff 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -78,6 +78,35 @@ file_name_as_prefix (const char *f) +/* Return the value of the getenv("COLUMNS") as an integer. If the + value is not set to a positive integer, then return INT_MAX. */ +static int +getenv_columns (void) +{ + const char * s = getenv ("COLUMNS"); + if (s != NULL) { + int n = atoi (s); + if (n > 0) + return n; + } + return INT_MAX; +} + +/* Set caret_max_width to value. */ +void +diagnostic_set_caret_max_width (diagnostic_context *context, int value) +{ + /* One minus to account for the leading empty space. */ + value = value ? value - 1 + : (isatty (fileno (context->printer->buffer->stream)) + ? getenv_columns () - 1: INT_MAX); + + if (value <= 0) + value = INT_MAX; + + context->caret_max_width = value; +} + /* Initialize the diagnostic message outputting machinery. */ void diagnostic_initialize (diagnostic_context *context, int n_opts) @@ -100,6 +129,8 @@ diagnostic_initialize (diagnostic_context *context, int n_opts) context->classify_diagnostic = XNEWVEC (diagnostic_t, n_opts); for (i = 0; i < n_opts; i++) context->classify_diagnostic[i] = DK_UNSPECIFIED; + context->show_caret = false; + diagnostic_set_caret_max_width (context, pp_line_cutoff (context->printer)); context->show_option_requested = false; context->abort_on_error = false; context->show_column = false; @@ -196,6 +227,72 @@ diagnostic_build_prefix (diagnostic_context *context, : build_message_string ("%s:%d: %s", s.file, s.line, text)); } +/* If LINE is longer than MAX_WIDTH, and COLUMN is not smaller than + MAX_WIDTH by some margin, then adjust the start of the line such + that the COLUMN is smaller than MAX_WIDTH minus the margin. The + margin is either 10 characters or the difference between the column + and the length of the line, whatever is smaller. */ +static const char * +adjust_line (const char *line, int max_width, int *column_p) +{ + int right_margin = 10; + int line_width = strlen (line); + int column = *column_p; + + right_margin = MIN(line_width - column, right_margin); + right_margin = max_width - right_margin; + if (line_width >= max_width && column > right_margin) + { + line += column - right_margin; + *column_p = right_margin; + } + return line; +} + +/* Print the physical source line corresponding to the location of + this diagnostics, and a caret indicating the precise column. */ +void +diagnostic_show_locus (diagnostic_context * context, + const diagnostic_info *diagnostic) +{ + const char *line; + char *buffer; + expanded_location s; + int max_width; + const char *saved_prefix; + + + if (!context->show_caret + || diagnostic->location <= BUILTINS_LOCATION) + return; + + s = expand_location(diagnostic->location); + line = location_get_source_line (s); + if (line == NULL) + return; + + max_width = context->caret_max_width; + line = adjust_line (line, max_width, &(s.column)); + + pp_newline (context->printer); + saved_prefix = pp_get_prefix (context->printer); + pp_set_prefix (context->printer, NULL); + pp_character (context->printer, ' '); + while (max_width > 0 && *line != '\0') + { + char c = *line == '\t' ? ' ' : *line; + pp_character (context->printer, c); + max_width--; + line++; + } + pp_newline (context->printer); + /* pp_printf does not implement %*c. */ + buffer = XALLOCAVEC (char, s.column + 3); + snprintf (buffer, s.column + 3, " %*c", s.column, '^'); + pp_string (context->printer, buffer); + pp_set_prefix (context->printer, saved_prefix); +} + /* Take any action which is expected to happen after the diagnostic is written out. This function does not always return. */ static void @@ -547,6 +644,7 @@ diagnostic_report_diagnostic (diagnostic_context *context, pp_format (context->printer, &diagnostic->message); (*diagnostic_starter (context)) (context, diagnostic); pp_output_formatted_text (context->printer); + diagnostic_show_locus (context, diagnostic); (*diagnostic_finalizer (context)) (context, diagnostic); pp_flush (context->printer); diagnostic_action_after_output (context, diagnostic); @@ -616,6 +714,7 @@ emit_diagnostic (diagnostic_t kind, location_t location, int opt, { diagnostic_info diagnostic; va_list ap; + bool ret; va_start (ap, gmsgid); if (kind == DK_PERMERROR) @@ -629,9 +728,10 @@ emit_diagnostic (diagnostic_t kind, location_t location, int opt, if (kind == DK_WARNING || kind == DK_PEDWARN) diagnostic.option_index = opt; } - va_end (ap); - return report_diagnostic (&diagnostic); + ret = report_diagnostic (&diagnostic); + va_end (ap); + return ret; } /* An informative note at LOCATION. Use this for additional details on an error @@ -673,13 +773,15 @@ warning (int opt, const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; + bool ret; va_start (ap, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_WARNING); diagnostic.option_index = opt; + ret = report_diagnostic (&diagnostic); va_end (ap); - return report_diagnostic (&diagnostic); + return ret; } /* A warning at LOCATION. Use this for code which is correct according to the @@ -691,12 +793,14 @@ warning_at (location_t location, int opt, const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; + bool ret; va_start (ap, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_WARNING); diagnostic.option_index = opt; + ret = report_diagnostic (&diagnostic); va_end (ap); - return report_diagnostic (&diagnostic); + return ret; } /* A "pedantic" warning at LOCATION: issues a warning unless @@ -705,10 +809,10 @@ warning_at (location_t location, int opt, const char *gmsgid, ...) language standard, if you have chosen not to make them errors. Note that these diagnostics are issued independent of the setting - of the -pedantic command-line switch. To get a warning enabled + of the -Wpedantic command-line switch. To get a warning enabled only with that switch, use either "if (pedantic) pedwarn - (OPT_pedantic,...)" or just "pedwarn (OPT_pedantic,..)". To get a - pedwarn independently of the -pedantic switch use "pedwarn (0,...)". + (OPT_Wpedantic,...)" or just "pedwarn (OPT_Wpedantic,..)". To get a + pedwarn independently of the -Wpedantic switch use "pedwarn (0,...)". Returns true if the warning was printed, false if it was inhibited. */ @@ -717,12 +821,14 @@ pedwarn (location_t location, int opt, const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; + bool ret; va_start (ap, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_PEDWARN); diagnostic.option_index = opt; + ret = report_diagnostic (&diagnostic); va_end (ap); - return report_diagnostic (&diagnostic); + return ret; } /* A "permissive" error at LOCATION: issues an error unless @@ -737,13 +843,15 @@ permerror (location_t location, const char *gmsgid, ...) { diagnostic_info diagnostic; va_list ap; + bool ret; va_start (ap, gmsgid); diagnostic_set_info (&diagnostic, gmsgid, &ap, location, permissive_error_kind (global_dc)); diagnostic.option_index = permissive_error_option (global_dc); + ret = report_diagnostic (&diagnostic); va_end (ap); - return report_diagnostic (&diagnostic); + return ret; } /* A hard error: the code is definitely ill-formed, and an object file diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index 4b1265b7886..63eb3852958 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -99,6 +99,13 @@ struct diagnostic_context int *push_list; int n_push; + /* True if we should print the source line with a caret indicating + the location. */ + bool show_caret; + + /* Maximum width of the source line printed. */ + int caret_max_width; + /* True if we should print the command line option which controls each diagnostic, if known. */ bool show_option_requested; @@ -254,6 +261,7 @@ extern diagnostic_context *global_dc; extern void diagnostic_initialize (diagnostic_context *, int); extern void diagnostic_finish (diagnostic_context *); extern void diagnostic_report_current_module (diagnostic_context *, location_t); +extern void diagnostic_show_locus (diagnostic_context *, const diagnostic_info *); /* Force diagnostics controlled by OPTIDX to be kind KIND. */ extern diagnostic_t diagnostic_classify_diagnostic (diagnostic_context *, @@ -275,6 +283,8 @@ extern void diagnostic_set_info_translated (diagnostic_info *, const char *, extern char *diagnostic_build_prefix (diagnostic_context *, diagnostic_info *); void default_diagnostic_starter (diagnostic_context *, diagnostic_info *); void default_diagnostic_finalizer (diagnostic_context *, diagnostic_info *); +void diagnostic_set_caret_max_width (diagnostic_context *context, int value); + /* Pure text formatting support functions. */ extern char *file_name_as_prefix (const char *); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index bb4382584bc..dd08845fb9b 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -5372,6 +5372,10 @@ typeinfo node and exception handling will break. @end table +To specify multiple attributes, separate them by commas within the +double parentheses: for example, @samp{__attribute__ ((aligned (16), +packed))}. + @subsection ARM Type Attributes On those ARM targets that support @code{dllimport} (such as Symbian @@ -5427,10 +5431,6 @@ Currently @option{-m[no-]ms-bitfields} is provided for the Microsoft Windows X86 compilers to match the native Microsoft compiler. @end table -To specify multiple attributes, separate them by commas within the -double parentheses: for example, @samp{__attribute__ ((aligned (16), -packed))}. - @anchor{PowerPC Type Attributes} @subsection PowerPC Type Attributes @@ -8535,12 +8535,17 @@ Similar to @code{__builtin_powi}, except the argument and return types are @code{long double}. @end deftypefn -@deftypefn {Built-in Function} int32_t __builtin_bswap32 (int32_t x) +@deftypefn {Built-in Function} int16_t __builtin_bswap16 (int16_t x) Returns @var{x} with the order of the bytes reversed; for example, -@code{0xaabbccdd} becomes @code{0xddccbbaa}. Byte here always means +@code{0xaabb} becomes @code{0xbbaa}. Byte here always means exactly 8 bits. @end deftypefn +@deftypefn {Built-in Function} int32_t __builtin_bswap32 (int32_t x) +Similar to @code{__builtin_bswap16}, except the argument and return types +are 32-bit. +@end deftypefn + @deftypefn {Built-in Function} int64_t __builtin_bswap64 (int64_t x) Similar to @code{__builtin_bswap32}, except the argument and return types are 64-bit. @@ -13426,7 +13431,6 @@ float __builtin_rsqrtf (float); double __builtin_recipdiv (double, double); double __builtin_rsqrt (double); long __builtin_bpermd (long, long); -int __builtin_bswap16 (int); @end smallexample The @code{vec_rsqrt}, @code{__builtin_rsqrt}, and diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 6da6c094751..dced7a9f74c 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -3685,19 +3685,20 @@ does not provide a definition that will confuse @command{configure}. If this error occurs during stage2 or later, then the problem most likely is the version of Make (see above). -The native @command{as} and @command{ld} are recommended for bootstrapping -on AIX@. The GNU Assembler, GNU Linker, and GNU Binutils version 2.20 -is required to bootstrap on AIX 5@. The native AIX tools do -interoperate with GCC@. +The native @command{as} and @command{ld} are recommended for +bootstrapping on AIX@. The GNU Assembler, GNU Linker, and GNU +Binutils version 2.20 is the minimum level that supports bootstrap on +AIX 5@. The GNU Assembler has not been updated to support AIX 6@ or +AIX 7. The native AIX tools do interoperate with GCC@. AIX 5.3 TL10, AIX 6.1 TL05 and AIX 7.1 TL00 introduced an AIX assembler change that sometimes produces corrupt assembly files causing AIX linker errors. The bug breaks GCC bootstrap on AIX and can cause compilation failures with existing GCC installations. An AIX iFix for AIX 5.3 is available (APAR IZ98385 for AIX 5.3 TL10, APAR -IZ98477 for AIX 5.3 TL11 and IZ98134 for AIX 5.3 TL12). Fixes for AIX -6.1 (APAR IZ98732 for AIX 6.1 TL05 and APAR IZ98861 for AIX 6.1 TL06) -and AIX 7.1 are in verification and packaging phases. +IZ98477 for AIX 5.3 TL11 and IZ98134 for AIX 5.3 TL12). AIX 5.3 TL11 SP8, +AIX 5.3 TL12 SP5, AIX 6.1 TL04 SP11, AIX 6.1 TL05 SP7, AIX 6.1 TL06 SP6, +AIX 6.1 TL07 and AIX 7.1 TL01 should include the fix. Building @file{libstdc++.a} requires a fix for an AIX Assembler bug APAR IY26685 (AIX 4.3) or APAR IY25528 (AIX 5.1). It also requires a diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 09d49c74172..0636a2b5d3f 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -39,7 +39,7 @@ included in the gfdl(7) man page. @c man begin SYNOPSIS gcc [@option{-c}|@option{-S}|@option{-E}] [@option{-std=}@var{standard}] [@option{-g}] [@option{-pg}] [@option{-O}@var{level}] - [@option{-W}@var{warn}@dots{}] [@option{-pedantic}] + [@option{-W}@var{warn}@dots{}] [@option{-Wpedantic}] [@option{-I}@var{dir}@dots{}] [@option{-L}@var{dir}@dots{}] [@option{-D}@var{macro}[=@var{defn}]@dots{}] [@option{-U}@var{macro}] [@option{-f}@var{option}@dots{}] [@option{-m}@var{machine-option}@dots{}] @@ -113,7 +113,7 @@ Many options have long names starting with @samp{-f} or with @samp{-W}---for example, @option{-fmove-loop-invariants}, @option{-Wformat} and so on. Most of these have both positive and negative forms; the negative form of -@option{-ffoo} would be @option{-fno-foo}. This manual documents +@option{-ffoo} is @option{-fno-foo}. This manual documents only one of these two forms, whichever one is not the default. @c man end @@ -230,11 +230,11 @@ Objective-C and Objective-C++ Dialects}. @xref{Language Independent Options,,Options to Control Diagnostic Messages Formatting}. @gccoptlist{-fmessage-length=@var{n} @gol -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]} @gol --fno-diagnostics-show-option} +-fno-diagnostics-show-option -fno-diagnostics-show-caret} @item Warning Options @xref{Warning Options,,Options to Request or Suppress Warnings}. -@gccoptlist{-fsyntax-only -fmax-errors=@var{n} -pedantic @gol +@gccoptlist{-fsyntax-only -fmax-errors=@var{n} -Wpedantic @gol -pedantic-errors @gol -w -Wextra -Wall -Waddress -Waggregate-return -Warray-bounds @gol -Wno-attributes -Wno-builtin-macro-redefined @gol @@ -1182,11 +1182,11 @@ has not been used at all). @item -pass-exit-codes @opindex pass-exit-codes -Normally the @command{gcc} program will exit with the code of 1 if any +Normally the @command{gcc} program exits with the code of 1 if any phase of the compiler returns a non-success return code. If you specify -@option{-pass-exit-codes}, the @command{gcc} program will instead return with -numerically highest error produced by any phase that returned an error -indication. The C, C++, and Fortran frontends return 4, if an internal +@option{-pass-exit-codes}, the @command{gcc} program instead returns with +the numerically highest error produced by any phase returning an error +indication. The C, C++, and Fortran front ends return 4 if an internal compiler error is encountered. @end table @@ -1265,11 +1265,11 @@ no trouble. @opindex help Print (on the standard output) a description of the command-line options understood by @command{gcc}. If the @option{-v} option is also specified -then @option{--help} will also be passed on to the various processes +then @option{--help} is also passed on to the various processes invoked by @command{gcc}, so that they can display the command-line options they accept. If the @option{-Wextra} option has also been specified (prior to the @option{--help} option), then command-line options that -have no documentation associated with them will also be displayed. +have no documentation associated with them are also displayed. @item --target-help @opindex target-help @@ -1284,30 +1284,30 @@ and qualifiers. These are the supported classes: @table @asis @item @samp{optimizers} -This will display all of the optimization options supported by the +Display all of the optimization options supported by the compiler. @item @samp{warnings} -This will display all of the options controlling warning messages +Display all of the options controlling warning messages produced by the compiler. @item @samp{target} -This will display target-specific options. Unlike the +Display target-specific options. Unlike the @option{--target-help} option however, target-specific options of the -linker and assembler will not be displayed. This is because those +linker and assembler are not displayed. This is because those tools do not currently support the extended @option{--help=} syntax. @item @samp{params} -This will display the values recognized by the @option{--param} +Display the values recognized by the @option{--param} option. @item @var{language} -This will display the options supported for @var{language}, where +Display the options supported for @var{language}, where @var{language} is the name of one of the languages supported in this version of GCC@. @item @samp{common} -This will display the options that are common to all languages. +Display the options that are common to all languages. @end table These are the supported qualifiers: @@ -1356,7 +1356,7 @@ optimization options the following can be used: @end smallexample The @option{--help=} option can be repeated on the command line. Each -successive use will display its requested class of options, skipping +successive use displays its requested class of options, skipping those that have already been displayed. If the @option{-Q} option appears on the command line before the @@ -1413,8 +1413,9 @@ list. gcc -c t.c -wrapper gdb,--args @end smallexample -This will invoke all subprograms of @command{gcc} under -@samp{gdb --args}, thus the invocation of @command{cc1} will be +@noindent +This invokes all subprograms of @command{gcc} under +@samp{gdb --args}, thus the invocation of @command{cc1} is @samp{gdb --args cc1 @dots{}}. @item -fplugin=@var{name}.so @@ -1516,7 +1517,7 @@ such as @code{__unix__} and @code{__vax__} are also available, with or without @option{-ansi}. The @option{-ansi} option does not cause non-ISO programs to be -rejected gratuitously. For that, @option{-pedantic} is required in +rejected gratuitously. For that, @option{-Wpedantic} is required in addition to @option{-ansi}. @xref{Warning Options}. The macro @code{__STRICT_ANSI__} is predefined when the @option{-ansi} @@ -1525,7 +1526,7 @@ from declaring certain functions or defining certain macros that the ISO standard doesn't call for; this is to avoid interfering with any programs that might use these names for other things. -Functions that would normally be built in but do not have semantics +Functions that are normally built in but do not have semantics defined by ISO C (such as @code{alloca} and @code{ffs}) are not built-in functions when @option{-ansi} is used. @xref{Other Builtins,,Other built-in functions provided by GCC}, for details of the functions @@ -1539,8 +1540,8 @@ is currently only supported when compiling C or C++. The compiler can accept several base standards, such as @samp{c90} or @samp{c++98}, and GNU dialects of those standards, such as -@samp{gnu90} or @samp{gnu++98}. By specifying a base standard, the -compiler will accept all programs following that standard and those +@samp{gnu90} or @samp{gnu++98}. When a base standard is specified, the +compiler accepts all programs following that standard plus those using GNU extensions that do not contradict it. For example, @option{-std=c90} turns off certain features of GCC that are incompatible with ISO C90, such as the @code{asm} and @code{typeof} @@ -1550,10 +1551,10 @@ expression. On the other hand, by specifying a GNU dialect of a standard, all features the compiler support are enabled, even when those features change the meaning of the base standard and some strict-conforming programs may be rejected. The particular standard -is used by @option{-pedantic} to identify which features are GNU +is used by @option{-Wpedantic} to identify which features are GNU extensions given that version of the standard. For example -@option{-std=gnu90 -pedantic} warns about C++ style @samp{//} -comments, while @option{-std=gnu99 -pedantic} does not. +@option{-std=gnu90 -Wpedantic} warns about C++ style @samp{//} +comments, while @option{-std=gnu99 -Wpedantic} does not. A value for this option must be provided; possible values are @@ -1764,8 +1765,8 @@ have support for @option{-pthread}. @item -fgnu-tm @opindex fgnu-tm -When the option @option{-fgnu-tm} is specified, the compiler will -generate code for the Linux variant of Intel's current Transactional +When the option @option{-fgnu-tm} is specified, the compiler +generates code for the Linux variant of Intel's current Transactional Memory ABI specification document (Revision 1.1, May 6 2009). This is an experimental feature whose interface may change in future versions of GCC, as the official specification changes. Please note that not @@ -1938,8 +1939,8 @@ around bugs in the access control code. Check that the pointer returned by @code{operator new} is non-null before attempting to modify the storage allocated. This check is normally unnecessary because the C++ standard specifies that -@code{operator new} will only return @code{0} if it is declared -@samp{throw()}, in which case the compiler will always check the +@code{operator new} only returns @code{0} if it is declared +@samp{throw()}, in which case the compiler always checks the return value even without this option. In all other cases, when @code{operator new} has a non-empty exception specification, memory exhaustion is signalled by throwing @code{std::bad_alloc}. See also @@ -1952,7 +1953,7 @@ common segment, as C does. This saves space in the executable at the cost of not diagnosing duplicate definitions. If you compile with this flag and your program mysteriously crashes after @code{main()} has completed, you may have an object that is being destroyed twice because -two definitions were merged. +two definitions are merged. This option is no longer useful on most targets, now that support has been added for putting variables into BSS without making them common. @@ -2014,8 +2015,8 @@ at run time. This option violates the C++ standard, but may be useful for reducing code size in production builds, much like defining @samp{NDEBUG}. This does not give user code permission to throw exceptions in violation of the exception specifications; the compiler -will still optimize based on the specifications, so throwing an -unexpected exception will result in undefined behavior. +still optimizes based on the specifications, so throwing an +unexpected exception results in undefined behavior at run time. @item -ffor-scope @itemx -fno-for-scope @@ -2049,17 +2050,17 @@ implicitly (i.e.@: by use); only emit code for explicit instantiations. @opindex fno-implicit-inline-templates Don't emit code for implicit instantiations of inline templates, either. The default is to handle inlines differently so that compiles with and -without optimization will need the same set of explicit instantiations. +without optimization need the same set of explicit instantiations. @item -fno-implement-inlines @opindex fno-implement-inlines To save space, do not emit out-of-line copies of inline functions -controlled by @samp{#pragma implementation}. This will cause linker +controlled by @samp{#pragma implementation}. This causes linker errors if these functions are not inlined everywhere they are called. @item -fms-extensions @opindex fms-extensions -Disable pedantic warnings about constructs used in MFC, such as implicit +Disable Wpedantic warnings about constructs used in MFC, such as implicit int and getting a pointer to member function via non-standard syntax. @item -fno-nonansi-builtins @@ -2070,14 +2071,14 @@ ANSI/ISO C@. These include @code{ffs}, @code{alloca}, @code{_exit}, @item -fnothrow-opt @opindex fnothrow-opt -Treat a @code{throw()} exception specification as though it were a +Treat a @code{throw()} exception specification as if it were a @code{noexcept} specification to reduce or eliminate the text size overhead relative to a function with no exception specification. If the function has local variables of types with non-trivial -destructors, the exception specification will actually make the +destructors, the exception specification actually makes the function smaller because the EH cleanups for those variables can be optimized away. The semantic effect is that an exception thrown out of -a function with such an exception specification will result in a call +a function with such an exception specification results in a call to @code{terminate} rather than @code{unexpected}. @item -fno-operator-names @@ -2095,21 +2096,21 @@ a name having multiple meanings within a class. @item -fpermissive @opindex fpermissive Downgrade some diagnostics about nonconformant code from errors to -warnings. Thus, using @option{-fpermissive} will allow some +warnings. Thus, using @option{-fpermissive} allows some nonconforming code to compile. @item -fno-pretty-templates @opindex fno-pretty-templates When an error message refers to a specialization of a function -template, the compiler will normally print the signature of the +template, the compiler normally prints the signature of the template followed by the template arguments and any typedefs or typenames in the signature (e.g. @code{void f(T) [with T = int]} rather than @code{void f(int)}) so that it's clear which template is involved. When an error message refers to a specialization of a class -template, the compiler will omit any template arguments that match +template, the compiler omits any template arguments that match the default template arguments for that template. If either of these behaviors make it harder to understand the error message rather than -easier, using @option{-fno-pretty-templates} will disable them. +easier, you can use @option{-fno-pretty-templates} to disable them. @item -frepo @opindex frepo @@ -2123,7 +2124,7 @@ Disable generation of information about every class with virtual functions for use by the C++ run-time type identification features (@samp{dynamic_cast} and @samp{typeid}). If you don't use those parts of the language, you can save some space by using this flag. Note that -exception handling uses the same information, but it will generate it as +exception handling uses the same information, but G++ generates it as needed. The @samp{dynamic_cast} operator can still be used for casts that do not require run-time type information, i.e.@: casts to @code{void *} or to unambiguous base classes. @@ -2168,20 +2169,20 @@ thread-safe. Register destructors for objects with static storage duration with the @code{__cxa_atexit} function rather than the @code{atexit} function. This option is required for fully standards-compliant handling of static -destructors, but will only work if your C library supports +destructors, but only works if your C library supports @code{__cxa_atexit}. @item -fno-use-cxa-get-exception-ptr @opindex fno-use-cxa-get-exception-ptr Don't use the @code{__cxa_get_exception_ptr} runtime routine. This -will cause @code{std::uncaught_exception} to be incorrect, but is necessary +causes @code{std::uncaught_exception} to be incorrect, but is necessary if the runtime routine is not available. @item -fvisibility-inlines-hidden @opindex fvisibility-inlines-hidden This switch declares that the user does not attempt to compare pointers to inline functions or methods where the addresses of the two functions -were taken in different shared objects. +are taken in different shared objects. The effect of this is that GCC may, effectively, mark inline methods with @code{__attribute__ ((visibility ("hidden")))} so that they do not @@ -2199,7 +2200,7 @@ You may mark a method as having a visibility explicitly to negate the effect of the switch for that method. For example, if you do want to compare pointers to a particular inline method, you might mark it as having default visibility. Marking the enclosing class with explicit -visibility will have no effect. +visibility has no effect. Explicitly instantiated inline methods are unaffected by this option as their linkage might otherwise cross a shared library boundary. @@ -2222,9 +2223,9 @@ Types, but not their members, are not hidden by default. @item The One Definition Rule is relaxed for types without explicit -visibility specifications that are defined in more than one different -shared object: those declarations are permitted if they would have -been permitted when this option was not used. +visibility specifications that are defined in more than one +shared object: those declarations are permitted if they are +permitted when this option is not used. @end enumerate In new code it is better to use @option{-fvisibility=hidden} and @@ -2234,7 +2235,7 @@ on the Visual Studio behavior. Among the consequences of these changes are that static data members of the same type with the same name but defined in different shared -objects will be different, so changing one will not change the other; +objects are different, so changing one does not change the other; and that pointers to function members defined in different shared objects may not compare equal. When this flag is given, it is a violation of the ODR to define types with the same name differently. @@ -2242,9 +2243,9 @@ violation of the ODR to define types with the same name differently. @item -fno-weak @opindex fno-weak Do not use weak symbol support, even if it is provided by the linker. -By default, G++ will use weak symbols if they are available. This +By default, G++ uses weak symbols if they are available. This option exists only for testing, and should not be used by end-users; -it will result in inferior code and has no benefits. This option may +it results in inferior code and has no benefits. This option may be removed in a future release of G++. @item -fmelt* @@ -2266,7 +2267,7 @@ have meanings only for C++ programs: @opindex fno-default-inline Do not assume @samp{inline} for functions defined inside a class scope. @xref{Optimize Options,,Options That Control Optimization}. Note that these -functions will have linkage like inline functions; they just won't be +functions have linkage like inline functions; they just aren't inlined by default. @item -Wabi @r{(C, Objective-C, C++ and Objective-C++ only)} @@ -2277,7 +2278,7 @@ vendor-neutral C++ ABI@. Although an effort has been made to warn about all such cases, there are probably some cases that are not warned about, even though G++ is generating incompatible code. There may also be cases where warnings are emitted even though the code that is generated -will be compatible. +is compatible. You should rewrite your code to avoid these warnings if you are concerned about the fact that code generated by G++ may not be binary @@ -2320,11 +2321,11 @@ struct B : public A @{ int f2 : 1; @}; @end smallexample @noindent -In this case, G++ will place @code{B::f2} into the same byte -as@code{A::f1}; other compilers will not. You can avoid this problem +In this case, G++ places @code{B::f2} into the same byte +as@code{A::f1}; other compilers do not. You can avoid this problem by explicitly padding @code{A} so that its size is a multiple of the -byte size on your platform; that will cause G++ and other compilers to -layout @code{B} identically. +byte size on your platform; that causes G++ and other compilers to +lay out @code{B} identically. @item Incorrect handling of tail-padding for virtual bases. G++ does not use @@ -2337,11 +2338,11 @@ struct C : public A, public virtual B @{@}; @end smallexample @noindent -In this case, G++ will not place @code{B} into the tail-padding for -@code{A}; other compilers will. You can avoid this problem by +In this case, G++ does not place @code{B} into the tail-padding for +@code{A}; other compilers do. You can avoid this problem by explicitly padding @code{A} so that its size is a multiple of its -alignment (ignoring virtual base classes); that will cause G++ and other -compilers to layout @code{C} identically. +alignment (ignoring virtual base classes); that causes G++ and other +compilers to lay out @code{C} identically. @item Incorrect handling of bit-fields with declared widths greater than that @@ -2353,7 +2354,7 @@ union U @{ int i : 4096; @}; @end smallexample @noindent -Assuming that an @code{int} does not have 4096 bits, G++ will make the +Assuming that an @code{int} does not have 4096 bits, G++ makes the union too small by the number of bits in an @code{int}. @item @@ -2371,7 +2372,7 @@ struct C : public B, public A @{@}; @end smallexample @noindent -G++ will place the @code{A} base class of @code{C} at a nonzero offset; +G++ places the @code{A} base class of @code{C} at a nonzero offset; it should be placed at offset zero. G++ mistakenly believes that the @code{A} data member of @code{B} is already at offset zero. @@ -2457,8 +2458,8 @@ the compiler to never throw an exception. @item -Wnon-virtual-dtor @r{(C++ and Objective-C++ only)} @opindex Wnon-virtual-dtor @opindex Wno-non-virtual-dtor -Warn when a class has virtual functions and accessible non-virtual -destructor, in which case it would be possible but unsafe to delete +Warn when a class has virtual functions and an accessible non-virtual +destructor, in which case it is possible but unsafe to delete an instance of a derived class through a pointer to the base class. This warning is also enabled if @option{-Weffc++} is specified. @@ -2478,7 +2479,8 @@ struct A @{ @}; @end smallexample -The compiler will rearrange the member initializers for @samp{i} +@noindent +The compiler rearranges the member initializers for @samp{i} and @samp{j} to match the declaration order of the members, emitting a warning to that effect. This warning is enabled by @option{-Wall}. @end table @@ -2588,7 +2590,8 @@ B* b; b->f(); @end smallexample -will fail to compile. +@noindent +fails to compile. @item -Wno-pmf-conversions @r{(C++ and Objective-C++ only)} @opindex Wno-pmf-conversions @@ -2601,7 +2604,7 @@ to a plain pointer. @opindex Wno-sign-promo Warn when overload resolution chooses a promotion from unsigned or enumerated type to a signed type, over a conversion to an unsigned type of -the same size. Previous versions of G++ would try to preserve +the same size. Previous versions of G++ tried to preserve unsignedness, but the standard mandates the current behavior. @smallexample @@ -2617,8 +2620,9 @@ main () @} @end smallexample -In this example, G++ will synthesize a default @samp{A& operator = -(const A&);}, while cfront will use the user-defined @samp{operator =}. +@noindent +In this example, G++ synthesizes a default @samp{A& operator = +(const A&);}, while cfront uses the user-defined @samp{operator =}. @end table @node Objective-C and Objective-C++ Dialect Options @@ -2660,7 +2664,7 @@ Use @var{class-name} as the name of the class to instantiate for each literal string specified with the syntax @code{@@"@dots{}"}. The default class name is @code{NXConstantString} if the GNU runtime is being used, and @code{NSConstantString} if the NeXT runtime is being used (see below). The -@option{-fconstant-cfstrings} option, if also present, will override the +@option{-fconstant-cfstrings} option, if also present, overrides the @option{-fconstant-string-class} setting and cause @code{@@"@dots{}"} literals to be laid out as constant CoreFoundation strings. @@ -2699,21 +2703,21 @@ machines, and Version 2 on 64-bit target machines. @opindex fobjc-call-cxx-cdtors For each Objective-C class, check if any of its instance variables is a C++ object with a non-trivial default constructor. If so, synthesize a -special @code{- (id) .cxx_construct} instance method which will run +special @code{- (id) .cxx_construct} instance method which runs non-trivial default constructors on any such instance variables, in order, and then return @code{self}. Similarly, check if any instance variable is a C++ object with a non-trivial destructor, and if so, synthesize a -special @code{- (void) .cxx_destruct} method which will run +special @code{- (void) .cxx_destruct} method which runs all such default destructors, in reverse order. The @code{- (id) .cxx_construct} and @code{- (void) .cxx_destruct} -methods thusly generated will only operate on instance variables +methods thusly generated only operate on instance variables declared in the current Objective-C class, and not those inherited from superclasses. It is the responsibility of the Objective-C runtime to invoke all such methods in an object's inheritance -hierarchy. The @code{- (id) .cxx_construct} methods will be invoked +hierarchy. The @code{- (id) .cxx_construct} methods are invoked by the runtime immediately after a new object instance is allocated; -the @code{- (void) .cxx_destruct} methods will be invoked immediately +the @code{- (void) .cxx_destruct} methods are invoked immediately before the runtime deallocates an object instance. As of this writing, only the NeXT runtime on Mac OS X 10.4 and later has @@ -2828,7 +2832,7 @@ being used. Warn if multiple methods with differing argument and/or return types are found for a given selector when attempting to send a message using this selector to a receiver of type @code{id} or @code{Class}. When this flag -is off (which is the default behavior), the compiler will omit such warnings +is off (which is the default behavior), the compiler omits such warnings if any differences found are confined to types that share the same size and alignment. @@ -2860,12 +2864,12 @@ value, if any. @cindex message formatting Traditionally, diagnostic messages have been formatted irrespective of -the output device's aspect (e.g.@: its width, @dots{}). The options described -below can be used to control the diagnostic messages formatting -algorithm, e.g.@: how many characters per line, how often source location -information should be reported. Right now, only the C++ front end can -honor these options. However it is expected, in the near future, that -the remaining front ends would be able to digest them correctly. +the output device's aspect (e.g.@: its width, @dots{}). You can use the +options described below +to control the formatting algorithm for diagnostic messages, +e.g.@: how many characters per line, how often source location +information should be reported. Note that some language front ends may not +honor these options. @table @gcctabopt @item -fmessage-length=@var{n} @@ -2873,11 +2877,11 @@ the remaining front ends would be able to digest them correctly. Try to format error messages so that they fit on lines of about @var{n} characters. The default is 72 characters for @command{g++} and 0 for the rest of the front ends supported by GCC@. If @var{n} is zero, then no -line-wrapping will be done; each error message will appear on a single +line-wrapping is done; each error message appears on a single line. -@opindex fdiagnostics-show-location @item -fdiagnostics-show-location=once +@opindex fdiagnostics-show-location Only meaningful in line-wrapping mode. Instructs the diagnostic messages reporter to emit @emph{once} source location information; that is, in case the message is too long to fit on a single physical line and has to @@ -2899,6 +2903,13 @@ command-line option that directly controls the diagnostic (if such an option is known to the diagnostic machinery). Specifying the @option{-fno-diagnostics-show-option} flag suppresses that behavior. +@item -fno-diagnostics-show-caret +@opindex fno-diagnostics-show-caret +@opindex fdiagnostics-show-caret +By default, each diagnostic emitted includes the original source line +and a caret '^' indicating the column. This option suppresses this +information. + @end table @node Warning Options @@ -2979,36 +2990,38 @@ language-specific options also refer to @ref{C++ Dialect Options} and @ref{Objective-C and Objective-C++ Dialect Options}. When an unrecognized warning option is requested (e.g., -@option{-Wunknown-warning}), GCC will emit a diagnostic stating +@option{-Wunknown-warning}), GCC emits a diagnostic stating that the option is not recognized. However, if the @option{-Wno-} form -is used, the behavior is slightly different: No diagnostic will be +is used, the behavior is slightly different: no diagnostic is produced for @option{-Wno-unknown-warning} unless other diagnostics are being produced. This allows the use of new @option{-Wno-} options -with old compilers, but if something goes wrong, the compiler will -warn that an unrecognized option was used. +with old compilers, but if something goes wrong, the compiler +warns that an unrecognized option is present. @table @gcctabopt -@item -pedantic +@item -Wpedantic +@itemx -pedantic @opindex pedantic +@opindex Wpedantic Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any @option{-std} option used. Valid ISO C and ISO C++ programs should compile properly with or without -this option (though a rare few will require @option{-ansi} or a +this option (though a rare few require @option{-ansi} or a @option{-std} option specifying the required version of ISO C)@. However, without this option, certain GNU extensions and traditional C and C++ features are supported as well. With this option, they are rejected. -@option{-pedantic} does not cause warning messages for use of the +@option{-Wpedantic} does not cause warning messages for use of the alternate keywords whose names begin and end with @samp{__}. Pedantic warnings are also disabled in the expression that follows @code{__extension__}. However, only system header files should use these escape routes; application programs should avoid them. @xref{Alternate Keywords}. -Some users try to use @option{-pedantic} to check programs for strict ISO +Some users try to use @option{-Wpedantic} to check programs for strict ISO C conformance. They soon find that it does not do quite what they want: it finds some non-ISO practices, but not all---only those for which ISO C @emph{requires} a diagnostic, and some others for which @@ -3016,14 +3029,14 @@ diagnostics have been added. A feature to report any failure to conform to ISO C might be useful in some instances, but would require considerable additional work and would -be quite different from @option{-pedantic}. We don't have plans to +be quite different from @option{-Wpedantic}. We don't have plans to support such a feature in the near future. Where the standard specified with @option{-std} represents a GNU extended dialect of C, such as @samp{gnu90} or @samp{gnu99}, there is a corresponding @dfn{base standard}, the version of ISO C on which the GNU -extended dialect is based. Warnings from @option{-pedantic} are given -where they are required by the base standard. (It would not make sense +extended dialect is based. Warnings from @option{-Wpedantic} are given +where they are required by the base standard. (It does not make sense for such warnings to be given only for features not in the specified GNU C dialect, since by definition the GNU dialects of C include all features the compiler supports with the given option, and there would be @@ -3031,7 +3044,7 @@ nothing to warn about.) @item -pedantic-errors @opindex pedantic-errors -Like @option{-pedantic}, except that errors are produced rather than +Like @option{-Wpedantic}, except that errors are produced rather than warnings. @item -Wall @@ -3155,8 +3168,8 @@ This warning is enabled by @option{-Wall}. @opindex Wno-coverage-mismatch Warn if feedback profiles do not match when using the @option{-fprofile-use} option. -If a source file was changed between @option{-fprofile-gen} and -@option{-fprofile-use}, the files with the profile feedback can fail +If a source file is changed between compiling with @option{-fprofile-gen} and +with @option{-fprofile-use}, the files with the profile feedback can fail to match the source file and GCC cannot use the profile feedback information. By default, this warning is enabled and is treated as an error. @option{-Wno-coverage-mismatch} can be used to disable the @@ -3192,7 +3205,7 @@ float area(float radius) @} @end group @end smallexample -the compiler will perform the entire computation with @code{double} +the compiler performs the entire computation with @code{double} because the floating-point literal is a @code{double}. @item -Wformat @@ -3217,8 +3230,8 @@ libc version 2.2. These include all ISO C90 and C99 features, as well as features from the Single Unix Specification and some BSD and GNU extensions. Other library implementations may not support all these features; GCC does not support warning about features that go beyond a -particular library's limitations. However, if @option{-pedantic} is used -with @option{-Wformat}, warnings will be given about format features not +particular library's limitations. However, if @option{-Wpedantic} is used +with @option{-Wformat}, warnings are given about format features not in the selected standard version (but not for @code{strfmon} formats, since those are not in any version of the C standard). @xref{C Dialect Options,,Options Controlling C Dialect}. @@ -3255,7 +3268,7 @@ Where the unused arguments lie between used arguments that are specified with @samp{$} operand number specifications, normally warnings are still given, since the implementation could not know what type to pass to @code{va_arg} to skip the unused arguments. However, -in the case of @code{scanf} formats, this option will suppress the +in the case of @code{scanf} formats, this option suppresses the warning if the unused arguments are all pointers, since the Single Unix Specification says that such unused arguments are allowed. @@ -3307,7 +3320,7 @@ can be disabled with the @option{-Wno-nonnull} option. Warn about uninitialized variables that are initialized with themselves. Note this option can only be used with the @option{-Wuninitialized} option. -For example, GCC will warn about @code{i} being uninitialized in the +For example, GCC warns about @code{i} being uninitialized in the following snippet only when @option{-Winit-self} has been specified: @smallexample @group @@ -3360,7 +3373,7 @@ Warn if the type of @samp{main} is suspicious. @samp{main} should be a function with external linkage, returning int, taking either zero arguments, two, or three arguments of appropriate types. This warning is enabled by default in C++ and is enabled by either @option{-Wall} -or @option{-pedantic}. +or @option{-Wpedantic}. @item -Wmissing-braces @opindex Wmissing-braces @@ -3413,11 +3426,11 @@ In C/C++, every @code{else} branch belongs to the innermost possible @code{if} statement, which in this example is @code{if (b)}. This is often not what the programmer expected, as illustrated in the above example by indentation the programmer chose. When there is the -potential for this confusion, GCC will issue a warning when this flag +potential for this confusion, GCC issues a warning when this flag is specified. To eliminate the warning, add explicit braces around the innermost @code{if} statement so there is no way the @code{else} -could belong to the enclosing @code{if}. The resulting code would -look like this: +can belong to the enclosing @code{if}. The resulting code +looks like this: @smallexample @group @@ -3433,10 +3446,10 @@ look like this: @end group @end smallexample -Also warn for dangerous uses of the -?: with omitted middle operand GNU extension. When the condition -in the ?: operator is a boolean expression the omitted value will -be always 1. Often the user expects it to be a value computed +Also warn for dangerous uses of the GNU extension to +@code{?:} with omitted middle operand. When the condition +in the @code{?}: operator is a boolean expression, the omitted value is +always 1. Often programmers expect it to be a value computed inside the conditional expression instead. This warning is enabled by @option{-Wall}. @@ -3621,8 +3634,8 @@ Warn whenever a statement computes a result that is explicitly not used. To suppress this warning cast the unused expression to @samp{void}. This includes an expression-statement or the left-hand side of a comma expression that contains no side effects. For example, -an expression such as @samp{x[i,j]} will cause a warning, while -@samp{x[(void)i,j]} will not. +an expression such as @samp{x[i,j]} causes a warning, while +@samp{x[(void)i,j]} does not. This warning is enabled by @option{-Wall}. @@ -3651,7 +3664,7 @@ elements of structure, union or array variables as well as for variables that are uninitialized or clobbered as a whole. They do not occur for variables or elements declared @code{volatile}. Because these warnings depend on optimization, the exact variables or elements -for which there are warnings will depend on the precise optimization +for which there are warnings depends on the precise optimization options and version of GCC used. Note that there may be no warning about a variable that is used only @@ -3664,11 +3677,11 @@ are printed. @opindex Wno-maybe-uninitialized For an automatic variable, if there exists a path from the function entry to a use of the variable that is initialized, but there exist -some other paths the variable is not initialized, the compiler will -emit a warning if it can not prove the uninitialized paths do not -happen at run time. These warnings are made optional because GCC is +some other paths for which the variable is not initialized, the compiler +emits a warning if it cannot prove the uninitialized paths are not +executed at run time. These warnings are made optional because GCC is not smart enough to see all the reasons why the code might be correct -despite appearing to have an error. Here is one example of how +in spite of appearing to have an error. Here is one example of how this can happen: @smallexample @@ -3691,7 +3704,7 @@ this can happen: @noindent If the value of @code{y} is always 1, 2 or 3, then @code{x} is always initialized, but GCC doesn't know this. To suppress the -warning, the user needs to provide a default case with assert(0) or +warning, you need to provide a default case with assert(0) or similar code. @cindex @code{longjmp} warnings @@ -3718,9 +3731,9 @@ This warning is enabled by @option{-Wall} or @option{-Wextra}. @cindex unknown pragmas, warning @cindex pragmas, warning of unknown Warn when a @code{#pragma} directive is encountered that is not understood by -GCC@. If this command-line option is used, warnings will even be issued +GCC@. If this command-line option is used, warnings are even issued for unknown pragmas in system header files. This is not the case if -the warnings were only enabled by the @option{-Wall} command-line option. +the warnings are only enabled by the @option{-Wall} command-line option. @item -Wno-pragmas @opindex Wno-pragmas @@ -3791,14 +3804,14 @@ easily give a false positive: a warning about code that is not actually a problem. To help focus on important issues, several warning levels are defined. No warnings are issued for the use of undefined signed overflow when estimating how many iterations a loop -will require, in particular when determining whether a loop will be +requires, in particular when determining whether a loop will be executed at all. @table @gcctabopt @item -Wstrict-overflow=1 Warn about cases that are both questionable and easy to avoid. For -example: @code{x + 1 > x}; with @option{-fstrict-overflow}, the -compiler will simplify this to @code{1}. This level of +example, with @option{-fstrict-overflow}, the compiler simplifies +@code{x + 1 > x} to @code{1}. This level of @option{-Wstrict-overflow} is enabled by @option{-Wall}; higher levels are not, and must be explicitly requested. @@ -3812,18 +3825,18 @@ zero. @option{-Wstrict-overflow} (with no level) is the same as @item -Wstrict-overflow=3 Also warn about other cases where a comparison is simplified. For -example: @code{x + 1 > 1} will be simplified to @code{x > 0}. +example: @code{x + 1 > 1} is simplified to @code{x > 0}. @item -Wstrict-overflow=4 Also warn about other simplifications not covered by the above cases. -For example: @code{(x * 10) / 5} will be simplified to @code{x * 2}. +For example: @code{(x * 10) / 5} is simplified to @code{x * 2}. @item -Wstrict-overflow=5 Also warn about cases where the compiler reduces the magnitude of a -constant involved in a comparison. For example: @code{x + 2 > y} will -be simplified to @code{x + 1 >= y}. This is reported only at the +constant involved in a comparison. For example: @code{x + 2 > y} is +simplified to @code{x + 1 >= y}. This is reported only at the highest warning level because this simplification applies to many -comparisons, so this warning level will give a very large number of +comparisons, so this warning level gives a very large number of false positives. @end table @@ -3879,7 +3892,7 @@ that they usually do not indicate real problems and would only make the compiler output harder to read. Using this command-line option tells GCC to emit warnings from system headers as if they occurred in user code. However, note that using @option{-Wall} in conjunction with this -option will @emph{not} warn about unknown pragmas in system +option does @emph{not} warn about unknown pragmas in system headers---for that, @option{-Wunknown-pragmas} must also be used. @item -Wtrampolines @@ -3906,7 +3919,7 @@ to compute (by analyzing the code, or in some other way) the maximum or likely maximum error that the computation introduces, and allow for it when performing comparisons (and when producing output, but that's a different problem). In particular, instead of testing for equality, you -would check to see whether the two values have ranges that overlap; and +should check to see whether the two values have ranges that overlap; and this is done with the relational operators, so equality comparisons are probably mistaken. @@ -3925,13 +3938,13 @@ but does not in ISO C@. @item In traditional C, some preprocessor directives did not exist. -Traditional preprocessors would only consider a line to be a directive +Traditional preprocessors only considered a line to be a directive if the @samp{#} appeared in column 1 on the line. Therefore @option{-Wtraditional} warns about directives that traditional C -understands but would ignore because the @samp{#} does not appear as the +understands but ignores because the @samp{#} does not appear as the first character on the line. It also suggests you hide directives like @samp{#pragma} not understood by traditional C by indenting them. Some -traditional implementations would not recognize @samp{#elif}, so it +traditional implementations do not recognize @samp{#elif}, so this option suggests avoiding it altogether. @item @@ -3986,13 +3999,13 @@ traditional C case. @item Conversions by prototypes between fixed/floating-point values and vice versa. The absence of these prototypes when compiling with traditional -C would cause serious problems. This is a subset of the possible -conversion warnings, for the full set use @option{-Wtraditional-conversion}. +C causes serious problems. This is a subset of the possible +conversion warnings; for the full set use @option{-Wtraditional-conversion}. @item Use of ISO C style function definitions. This warning intentionally is @emph{not} issued for prototype declarations or variadic functions -because these ISO C features will appear in your code when using +because these ISO C features appear in your code when using libiberty's traditional C compatibility macros, @code{PARAMS} and @code{VPARAMS}. This warning is also bypassed for nested functions because that feature is already a GCC extension and thus not relevant to @@ -4031,8 +4044,8 @@ Do not warn whenever an @samp{#else} or an @samp{#endif} are followed by text. @opindex Wno-shadow Warn whenever a local variable or type declaration shadows another variable, parameter, type, or class member (in C++), or whenever a built-in function -is shadowed. Note that in C++, the compiler will not warn if a local variable -shadows a struct/class/enum, but will warn if it shadows an explicit typedef. +is shadowed. Note that in C++, the compiler warns if a local variable +shadows an explicit typedef, but not if it shadows a struct/class/enum. @item -Wlarger-than=@var{len} @opindex Wlarger-than=@var{len} @@ -4090,9 +4103,9 @@ If the stack usage is (partly) dynamic and not bounded, it's: @item -Wunsafe-loop-optimizations @opindex Wunsafe-loop-optimizations @opindex Wno-unsafe-loop-optimizations -Warn if the loop cannot be optimized because the compiler could not +Warn if the loop cannot be optimized because the compiler cannot assume anything on the bounds of the loop indices. With -@option{-funsafe-loop-optimizations} warn if the compiler made +@option{-funsafe-loop-optimizations} warn if the compiler makes such assumptions. @item -Wno-pedantic-ms-format @r{(MinGW targets only)} @@ -4101,7 +4114,7 @@ such assumptions. Disables the warnings about non-ISO @code{printf} / @code{scanf} format width specifiers @code{I32}, @code{I64}, and @code{I} used on Windows targets depending on the MS runtime, when you are using the options @option{-Wformat} -and @option{-pedantic} without gnu-extensions. +and @option{-Wpedantic} without gnu-extensions. @item -Wpointer-arith @opindex Wpointer-arith @@ -4110,7 +4123,7 @@ Warn about anything that depends on the ``size of'' a function type or of @code{void}. GNU C assigns these types a size of 1, for convenience in calculations with @code{void *} pointers and pointers to functions. In C++, warn also when an arithmetic operation involves -@code{NULL}. This warning is also enabled by @option{-pedantic}. +@code{NULL}. This warning is also enabled by @option{-Wpedantic}. @item -Wtype-limits @opindex Wtype-limits @@ -4171,11 +4184,11 @@ two- or four-byte boundaries. @opindex Wno-write-strings When compiling C, give string constants the type @code{const char[@var{length}]} so that copying the address of one into a -non-@code{const} @code{char *} pointer will get a warning. These -warnings will help you find at compile time code that can try to write +non-@code{const} @code{char *} pointer produces a warning. These +warnings help you find at compile time code that can try to write into a string constant, but only if you have been very careful about -using @code{const} in declarations and prototypes. Otherwise, it will -just be a nuisance. This is why we did not make @option{-Wall} request +using @code{const} in declarations and prototypes. Otherwise, it is +just a nuisance. This is why we did not make @option{-Wall} request these warnings. When compiling C++, warn about the deprecated conversion from string @@ -4202,7 +4215,7 @@ conversions between signed and unsigned integers can be disabled by using @option{-Wno-sign-conversion}. For C++, also warn for confusing overload resolution for user-defined -conversions; and conversions that will never use a type conversion +conversions; and conversions that never use a type conversion operator: conversions to @code{void}, the same type, a base class or a reference to them. Warnings about conversions between signed and unsigned integers are disabled by default in C++ unless @@ -4304,7 +4317,7 @@ a warning.) @opindex Wattributes Do not warn if an unexpected @code{__attribute__} is used, such as unrecognized attributes, function attributes applied to variables, -etc. This will not stop errors for incorrect use of supported +etc. This does not stop errors for incorrect use of supported attributes. @item -Wno-builtin-macro-redefined @@ -4372,7 +4385,7 @@ or for inline functions, or for functions in anonymous namespaces. @opindex Wextra @opindex Wno-extra Warn if a structure's initializer has some fields missing. For -example, the following code would cause such a warning, because +example, the following code causes such a warning, because @code{x.h} is implicitly zero: @smallexample @@ -4381,7 +4394,7 @@ struct s x = @{ 3, 4 @}; @end smallexample This option does not warn about designated initializers, so the following -modification would not trigger a warning: +modification does not trigger a warning: @smallexample struct s @{ int f, g, h; @}; @@ -4398,7 +4411,7 @@ warnings without this one, use @option{-Wextra -Wno-missing-field-initializers}. @opindex Wno-format Warn about function pointers that might be candidates for @code{format} attributes. Note these are only possible candidates, not absolute ones. -GCC will guess that function pointers with @code{format} attributes that +GCC guesses that function pointers with @code{format} attributes that are used in assignment, initialization, parameter passing or return statements should have a corresponding @code{format} attribute in the resulting type. I.e.@: the left-hand side of the assignment or @@ -4406,9 +4419,9 @@ initialization, the type of the parameter variable, or the return type of the containing function respectively should also have a @code{format} attribute to avoid the warning. -GCC will also warn about function definitions that might be +GCC also warns about function definitions that might be candidates for @code{format} attributes. Again, these are only -possible candidates. GCC will guess that @code{format} attributes +possible candidates. GCC guesses that @code{format} attributes might be appropriate for any function that calls a function like @code{vprintf} or @code{vscanf}, but this might not always be the case, and some functions for which @code{format} attributes are @@ -4449,22 +4462,22 @@ It is hoped that future versions of the standards involved will correct this, which is why this option is not the default. You can switch the warning off for all characters by writing -@option{-Wnormalized=none}. You would only want to do this if you -were using some other normalization scheme (like ``D''), because +@option{-Wnormalized=none}. You should only do this if you +are using some other normalization scheme (like ``D''), because otherwise you can easily create bugs that are literally impossible to see. Some characters in ISO 10646 have distinct meanings but look identical in some fonts or display methodologies, especially once formatting has been applied. For instance @code{\u207F}, ``SUPERSCRIPT LATIN SMALL -LETTER N'', will display just like a regular @code{n} that has been +LETTER N'', displays just like a regular @code{n} that has been placed in a superscript. ISO 10646 defines the @dfn{NFKC} normalization scheme to convert all these into a standard form as -well, and GCC will warn if your code is not in NFKC if you use +well, and GCC warns if your code is not in NFKC if you use @option{-Wnormalized=nfkc}. This warning is comparable to warning about every identifier that contains the letter O because it might be confused with the digit 0, and so is not the default, but may be -useful as a local coding convention if the programming environment is -unable to be fixed to display these characters distinctly. +useful as a local coding convention if the programming environment +cannot be fixed to display these characters distinctly. @item -Wno-deprecated @opindex Wno-deprecated @@ -4505,7 +4518,7 @@ Warn if a structure is given the packed attribute, but the packed attribute has no effect on the layout or size of the structure. Such structures may be mis-aligned for little benefit. For instance, in this code, the variable @code{f.x} in @code{struct bar} -will be misaligned even though @code{struct bar} does not itself +is misaligned even though @code{struct bar} does not itself have the packed attribute: @smallexample @@ -4564,8 +4577,8 @@ Warn if an @code{extern} declaration is encountered within a function. @item -Winline @opindex Winline @opindex Wno-inline -Warn if a function can not be inlined and it was declared as inline. -Even with this option, the compiler will not warn about failures to +Warn if a function that is declared as inline cannot be inlined. +Even with this option, the compiler does not warn about failures to inline functions declared in system headers. The compiler uses a variety of heuristics to determine whether or not @@ -4615,7 +4628,7 @@ the search path but can't be used. @opindex Wlong-long @opindex Wno-long-long Warn if @samp{long long} type is used. This is enabled by either -@option{-pedantic} or @option{-Wtraditional} in ISO C90 and C++98 +@option{-Wpedantic} or @option{-Wtraditional} in ISO C90 and C++98 modes. To inhibit the warning messages, use @option{-Wno-long-long}. @item -Wvariadic-macros @@ -4641,7 +4654,7 @@ scalar type. @opindex Wvla @opindex Wno-vla Warn if variable length array is used in the code. -@option{-Wno-vla} will prevent the @option{-pedantic} warning of +@option{-Wno-vla} prevents the @option{-Wpedantic} warning of the variable length array. @item -Wvolatile-register-var @@ -4657,9 +4670,9 @@ and/or writes to register variables. This warning is enabled by @opindex Wno-disabled-optimization Warn if a requested optimization pass is disabled. This warning does not generally indicate that there is anything wrong with your code; it -merely indicates that GCC's optimizers were unable to handle the code +merely indicates that GCC's optimizers are unable to handle the code effectively. Often, the problem is that your code is too big or too -complex; GCC will refuse to optimize programs when the optimization +complex; GCC refuses to optimize programs when the optimization itself is likely to take inordinate amounts of time. @item -Wpointer-sign @r{(C and Objective-C only)} @@ -4667,14 +4680,14 @@ itself is likely to take inordinate amounts of time. @opindex Wno-pointer-sign Warn for pointer argument passing or assignment with different signedness. This option is only supported for C and Objective-C@. It is implied by -@option{-Wall} and by @option{-pedantic}, which can be disabled with +@option{-Wall} and by @option{-Wpedantic}, which can be disabled with @option{-Wno-pointer-sign}. @item -Wstack-protector @opindex Wstack-protector @opindex Wno-stack-protector This option is only active when @option{-fstack-protector} is active. It -warns about functions that will not be protected against stack smashing. +warns about functions that are not protected against stack smashing. @item -Wno-mudflap @opindex Wno-mudflap @@ -4695,15 +4708,15 @@ not count the trailing NUL@. In C90, the limit was 509 characters; in C99, it was raised to 4095. C++98 does not specify a normative minimum maximum, so we do not diagnose overlength strings in C++@. -This option is implied by @option{-pedantic}, and can be disabled with +This option is implied by @option{-Wpedantic}, and can be disabled with @option{-Wno-overlength-strings}. @item -Wunsuffixed-float-constants @r{(C and Objective-C only)} @opindex Wunsuffixed-float-constants -GCC will issue a warning for any floating constant that does not have -a suffix. When used together with @option{-Wsystem-headers} it will -warn about such constants in system header files. This can be useful +Issue a warning for any floating constant that does not have +a suffix. When used together with @option{-Wsystem-headers} it +warns about such constants in system header files. This can be useful when preparing code to use with the @code{FLOAT_CONST_DECIMAL64} pragma from the decimal floating-point extension to C99. @end table @@ -4725,7 +4738,7 @@ information. On most systems that use stabs format, @option{-g} enables use of extra debugging information that only GDB can use; this extra information -makes debugging work better in GDB but will probably make other debuggers +makes debugging work better in GDB but probably makes other debuggers crash or refuse to read the program. If you want to control for certain whether to generate the extra information, use @option{-gstabs+}, @option{-gstabs}, @@ -4736,8 +4749,8 @@ GCC allows you to use @option{-g} with produce surprising results: some variables you declared may not exist at all; flow of control may briefly move where you did not expect it; some statements may not be executed because they compute constant -results or their values were already at hand; some statements may -execute in different places because they were moved out of loops. +results or their values are already at hand; some statements may +execute in different places because they have been moved out of loops. Nevertheless it proves possible to debug optimized output. This makes it reasonable to use the optimizer for programs that might have bugs. @@ -4770,17 +4783,17 @@ Instead of emitting debugging information for a C++ class in only one object file, emit it in all object files using the class. This option should be used only with debuggers that are unable to handle the way GCC normally emits debugging information for classes because using this -option will increase the size of debugging information by as much as a +option increases the size of debugging information by as much as a factor of two. @item -fno-debug-types-section @opindex fno-debug-types-section @opindex fdebug-types-section -By default when using DWARF Version 4 or higher type DIEs will be put into -their own .debug_types section instead of making them part of the -.debug_info section. It is more efficient to put them in a separate -comdat sections since the linker will then be able to remove duplicates. -But not all DWARF consumers support .debug_types sections yet. +By default when using DWARF Version 4 or higher, type DIEs are put into +their own @code{.debug_types} section instead of making them part of the +@code{.debug_info} section. It is more efficient to put them in a separate +comdat sections since the linker can then remove duplicates. +But not all DWARF consumers support @code{.debug_types} sections yet. @item -gstabs+ @opindex gstabs+ @@ -4813,8 +4826,8 @@ assembler (GAS) to fail with an error. Produce debugging information in DWARF format (if that is supported). The value of @var{version} may be either 2, 3 or 4; the default version is 2. -Note that with DWARF Version 2 some ports require, and will always -use, some non-conflicting DWARF 3 extensions in the unwind tables. +Note that with DWARF Version 2, some ports require and always +use some non-conflicting DWARF 3 extensions in the unwind tables. Version 4 may require GDB 7.0 and @option{-fvar-tracking-assignments} for maximum benefit. @@ -4880,9 +4893,9 @@ debug level for DWARF. @item -gtoggle @opindex gtoggle -Turn off generation of debug info, if leaving out this option would have -generated it, or turn it on at level 2 otherwise. The position of this -argument in the command line does not matter, it takes effect after all +Turn off generation of debug info, if leaving out this option +generates it, or turn it on at level 2 otherwise. The position of this +argument in the command line does not matter; it takes effect after all other options are processed, and it does so only once, no matter how many times it is given. This is mainly intended to be used with @option{-fcompare-debug}. @@ -4891,7 +4904,7 @@ many times it is given. This is mainly intended to be used with @opindex fdump-final-insns Dump the final internal representation (RTL) to @var{file}. If the optional argument is omitted (or if @var{file} is @code{.}), the name -of the dump file will be determined by appending @code{.gkd} to the +of the dump file is determined by appending @code{.gkd} to the compilation output file name. @item -fcompare-debug@r{[}=@var{opts}@r{]} @@ -4917,7 +4930,7 @@ of the final representation and the second compilation, preventing even To verify full coverage during @option{-fcompare-debug} testing, set @env{GCC_COMPARE_DEBUG} to say @samp{-fcompare-debug-not-overridden}, -which GCC will reject as an invalid option in any actual compilation +which GCC rejects as an invalid option in any actual compilation (rather than preprocessing, assembly or linking). To get just a warning, setting @env{GCC_COMPARE_DEBUG} to @samp{-w%n-fcompare-debug not overridden} will do. @@ -4945,7 +4958,7 @@ generating DWARF 2 debugging information with @option{-gdwarf-2}. @item -femit-struct-debug-baseonly Emit debug information for struct-like types only when the base name of the compilation source file -matches the base name of file in which the struct was defined. +matches the base name of file in which the struct is defined. This option substantially reduces the size of debugging information, but at significant potential loss in type information to the debugger. @@ -4957,7 +4970,7 @@ This option works only with DWARF 2. @item -femit-struct-debug-reduced Emit debug information for struct-like types only when the base name of the compilation source file -matches the base name of file in which the type was defined, +matches the base name of file in which the type is defined, unless the struct is a template or defined in a system header. This option significantly reduces the size of debugging information, @@ -4969,13 +4982,13 @@ This option works only with DWARF 2. @item -femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]} Specify the struct-like types -for which the compiler will generate debug information. +for which the compiler generates debug information. The intent is to reduce duplicate struct debug information between different object files within the same program. This option is a detailed version of @option{-femit-struct-debug-reduced} and @option{-femit-struct-debug-baseonly}, -which will serve for most needs. +which serves for most needs. A specification has the syntax@* [@samp{dir:}|@samp{ind:}][@samp{ord:}|@samp{gen:}](@samp{any}|@samp{sys}|@samp{base}|@samp{none}) @@ -4984,7 +4997,7 @@ The optional first word limits the specification to structs that are used directly (@samp{dir:}) or used indirectly (@samp{ind:}). A struct type is used directly when it is the type of a variable, member. Indirect uses arise through pointers to structs. -That is, when use of an incomplete struct would be legal, the use is indirect. +That is, when use of an incomplete struct is valid, the use is indirect. An example is @samp{struct one direct; struct two * indirect;}. @@ -4997,14 +5010,14 @@ Other programming languages have generics, but @option{-femit-struct-debug-detailed} does not yet implement them. The third word specifies the source files for those -structs for which the compiler will emit debug information. +structs for which the compiler should emit debug information. The values @samp{none} and @samp{any} have the normal meaning. The value @samp{base} means that the base of name of the file in which the type declaration appears must match the base of the name of the main compilation file. -In practice, this means that -types declared in @file{foo.c} and @file{foo.h} will have debug information, -but types declared in other header will not. +In practice, this means that when compiling @file{foo.c}, debug information +is generated for types declared in that file and @file{foo.h}, +but not other header files. The value @samp{sys} means those types satisfying @samp{base} or declared in system or compiler headers. @@ -5179,8 +5192,8 @@ Produce a notes file that the @command{gcov} code-coverage utility show program coverage. Each source file's note file is called @file{@var{auxname}.gcno}. Refer to the @option{-fprofile-arcs} option above for a description of @var{auxname} and instructions on how to -generate test coverage data. Coverage data will match the source files -more closely, if you do not optimize. +generate test coverage data. Coverage data matches the source files +more closely if you do not optimize. @item -fdbg-cnt-list @opindex fdbg-cnt-list @@ -5572,7 +5585,7 @@ standard error. @item -dp @opindex dp Annotate the assembler output with a comment indicating which -pattern and alternative was used. The length of each instruction is +pattern and alternative is used. The length of each instruction is also printed. @item -dP @@ -5664,8 +5677,8 @@ Enable and control dumping of pass statistics in a separate file. The file name is generated by appending a suffix ending in @samp{.statistics} to the source file name, and the file is created in the same directory as the output file. If the @samp{-@var{option}} -form is used, @samp{-stats} will cause counters to be summed over the -whole compilation unit while @samp{-details} will dump every event as +form is used, @samp{-stats} causes counters to be summed over the +whole compilation unit while @samp{-details} dumps every event as the passes generate them. The default with no option is to sum counters for each function compiled. @@ -5679,7 +5692,7 @@ created in the same directory as the output file. If the @samp{-@var{options}} form is used, @var{options} is a list of @samp{-} separated options which control the details of the dump. Not all options are applicable to all dumps; those that are not -meaningful will be ignored. The following options are available +meaningful are ignored. The following options are available @table @samp @item address @@ -5748,7 +5761,7 @@ made by appending @file{.cfg} to the source file name. Dump the control flow graph of each function to a file in VCG format. The file name is made by appending @file{.vcg} to the source file name. Note that if the file contains more than one function, the generated file cannot -be used directly by VCG@. You will need to cut and paste each function's +be used directly by VCG@. You must cut and paste each function's graph into its own separate file first. @item ch @@ -5897,8 +5910,8 @@ that @option{-fdump-tree-vect-details} uses. @item -frandom-seed=@var{string} @opindex frandom-seed -This option provides a seed that GCC uses when it would otherwise use -random numbers. It is used to generate certain symbol names +This option provides a seed that GCC uses in place of +random numbers in generating certain symbol names that have to be different in every compiled file. It is also used to place unique stamps in coverage data files and the object files that produce them. You can use the @option{-frandom-seed} option to produce @@ -5929,7 +5942,7 @@ dependence info. @opindex save-temps Store the usual ``temporary'' intermediate files permanently; place them in the current directory and name them based on the source file. Thus, -compiling @file{foo.c} with @option{-c -save-temps} would produce files +compiling @file{foo.c} with @option{-c -save-temps} produces files @file{foo.i} and @file{foo.s}, as well as @file{foo.o}. This creates a preprocessed @file{foo.i} output file even though the compiler now normally uses an integrated preprocessor. @@ -5969,7 +5982,8 @@ gcc -save-temps=obj -c bar.c -o dir/xbar.o gcc -save-temps=obj foobar.c -o dir2/yfoobar @end smallexample -would create @file{foo.i}, @file{foo.s}, @file{dir/xbar.i}, +@noindent +creates @file{foo.i}, @file{foo.s}, @file{dir/xbar.i}, @file{dir/xbar.s}, @file{dir2/yfoobar.i}, @file{dir2/yfoobar.s}, and @file{dir2/yfoobar.o}. @@ -6022,7 +6036,7 @@ way to the end, in an attempt to improve debug information while optimizing. Use of @option{-gdwarf-4} is recommended along with it. It can be enabled even if var-tracking is disabled, in which case -annotations will be created and maintained, but discarded at the end. +annotations are created and maintained, but discarded at the end. @item -fvar-tracking-assignments-toggle @opindex fvar-tracking-assignments-toggle @@ -6079,7 +6093,7 @@ gcc -nostdlib @var{files}@dots{} `gcc -print-libgcc-file-name` @item -print-search-dirs @opindex print-search-dirs Print the name of the configured installation directory and a list of -program and library directories @command{gcc} will search---and don't do anything else. +program and library directories @command{gcc} searches---and don't do anything else. This is useful when @command{gcc} prints the error message @samp{installation problem, cannot exec cpp0: No such file or directory}. @@ -6091,7 +6105,7 @@ Don't forget the trailing @samp{/}. @item -print-sysroot @opindex print-sysroot -Print the target sysroot directory that will be used during +Print the target sysroot directory that is used during compilation. This is the target sysroot specified either at configure time or using the @option{--sysroot} option, possibly with an extra suffix that depends on compilation options. If no target sysroot is @@ -6120,14 +6134,14 @@ is used when GCC itself is being built.) @xref{Spec Files}. @item -feliminate-unused-debug-types @opindex feliminate-unused-debug-types -Normally, when producing DWARF 2 output, GCC will emit debugging +Normally, when producing DWARF 2 output, GCC emits debugging information for all types declared in a compilation unit, regardless of whether or not they are actually used in that compilation unit. Sometimes this is useful, such as if, in the debugger, you want to cast a value to a type that is not actually used in your program (but is declared). More often, however, this results in a significant amount of wasted space. -With this option, GCC will avoid producing debug symbol output +With this option, GCC avoids producing debug symbol output for types that are nowhere used in the source file being compiled. @end table @@ -6143,7 +6157,7 @@ cost of compilation and to make debugging produce the expected results. Statements are independent: if you stop the program with a breakpoint between statements, you can then assign a new value to any variable or change the program counter to any other statement in the -function and get exactly the results you would expect from the source +function and get exactly the results you expect from the source code. Turning on optimization flags makes the compiler attempt to improve @@ -6292,8 +6306,8 @@ the last such option is the one that is effective. Options of the form @option{-f@var{flag}} specify machine-independent flags. Most flags have both positive and negative forms; the negative -form of @option{-ffoo} would be @option{-fno-foo}. In the table -below, only one of the forms is listed---the one you typically will +form of @option{-ffoo} is @option{-fno-foo}. In the table +below, only one of the forms is listed---the one you typically use. You can figure out the other form by either removing @samp{no-} or adding it. @@ -6488,7 +6502,7 @@ Emit variables declared @code{static const} when optimization isn't turned on, even if the variables aren't referenced. GCC enables this option by default. If you want to force the compiler to -check if the variable was referenced, regardless of whether or not +check if a variable is referenced, regardless of whether or not optimization is turned on, use the @option{-fno-keep-static-consts} option. @item -fmerge-constants @@ -6511,7 +6525,7 @@ This option implies @option{-fmerge-constants}. In addition to arrays or initialized constant variables with integral or floating-point types. Languages like C or C++ require each variable, including multiple instances of the same variable in recursive calls, to have distinct locations, -so using this option will result in non-conforming +so using this option results in non-conforming behavior. @item -fmodulo-sched @@ -6522,9 +6536,9 @@ instructions by overlapping different iterations. @item -fmodulo-sched-allow-regmoves @opindex fmodulo-sched-allow-regmoves -Perform more aggressive SMS based modulo scheduling with register moves -allowed. By setting this flag certain anti-dependences edges will be -deleted which will trigger the generation of reg-moves based on the +Perform more aggressive SMS-based modulo scheduling with register moves +allowed. By setting this flag certain anti-dependences edges are +deleted, which triggers the generation of reg-moves based on the life-range analysis. This option is effective only with @option{-fmodulo-sched} enabled. @@ -6574,7 +6588,7 @@ string/heap functions, and some other associated constructs with range/validity tests. Modules so instrumented should be immune to buffer overflows, invalid heap use, and some other classes of C/C++ programming errors. The instrumentation relies on a separate runtime -library (@file{libmudflap}), which will be linked into a program if +library (@file{libmudflap}), which is linked into a program if @option{-fmudflap} is given at link time. Run-time behavior of the instrumented program is controlled by the @env{MUDFLAP_OPTIONS} environment variable. See @code{env MUDFLAP_OPTIONS=-help a.out} @@ -6613,7 +6627,7 @@ Enabled at levels @option{-O}, @option{-O2}, @option{-O3}, In common subexpression elimination (CSE), scan through jump instructions when the target of the jump is not reached by any other path. For example, when CSE encounters an @code{if} statement with an -@code{else} clause, CSE will follow the jump when the condition +@code{else} clause, CSE follows the jump when the condition tested is false. Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. @@ -6630,7 +6644,7 @@ Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. @item -frerun-cse-after-loop @opindex frerun-cse-after-loop -Re-run common subexpression elimination after loop optimizations has been +Re-run common subexpression elimination after loop optimizations are performed. Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. @@ -6649,17 +6663,17 @@ Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. @item -fgcse-lm @opindex fgcse-lm -When @option{-fgcse-lm} is enabled, global common subexpression elimination will -attempt to move loads that are only killed by stores into themselves. This +When @option{-fgcse-lm} is enabled, global common subexpression elimination +attempts to move loads that are only killed by stores into themselves. This allows a loop containing a load/store sequence to be changed to a load outside the loop, and a copy/store within the loop. -Enabled by default when gcse is enabled. +Enabled by default when @option{-fgcse} is enabled. @item -fgcse-sm @opindex fgcse-sm When @option{-fgcse-sm} is enabled, a store motion pass is run after -global common subexpression elimination. This pass will attempt to move +global common subexpression elimination. This pass attempts to move stores out of loops. When used in conjunction with @option{-fgcse-lm}, loops containing a load/store sequence can be changed to a load before the loop and a store after the loop. @@ -6682,11 +6696,11 @@ redundant spilling. @item -funsafe-loop-optimizations @opindex funsafe-loop-optimizations -If given, the loop optimizer will assume that loop indices do not +If given, the loop optimizer assumes that loop indices do not overflow, and that the loops with nontrivial exit condition are not infinite. This enables a wider range of loop optimizations even if the loop optimizer itself cannot prove that these assumptions are valid. -Using @option{-Wunsafe-loop-optimizations}, the compiler will warn you +If you use @option{-Wunsafe-loop-optimizations}, the compiler warns you if it finds this kind of loop. @item -fcrossjumping @@ -6910,8 +6924,8 @@ sense when scheduling before register allocation, i.e.@: with @itemx -fsched-stalled-insns=@var{n} @opindex fsched-stalled-insns Define how many insns (if any) can be moved prematurely from the queue -of stalled insns into the ready list, during the second scheduling pass. -@option{-fno-sched-stalled-insns} means that no insns will be moved +of stalled insns into the ready list during the second scheduling pass. +@option{-fno-sched-stalled-insns} means that no insns are moved prematurely, @option{-fsched-stalled-insns=0} means there is no limit on how many queued insns can be moved prematurely. @option{-fsched-stalled-insns} without a value is equivalent to @@ -6920,8 +6934,8 @@ on how many queued insns can be moved prematurely. @item -fsched-stalled-insns-dep @itemx -fsched-stalled-insns-dep=@var{n} @opindex fsched-stalled-insns-dep -Define how many insn groups (cycles) will be examined for a dependency -on a stalled insn that is candidate for premature removal from the queue +Define how many insn groups (cycles) are examined for a dependency +on a stalled insn that is a candidate for premature removal from the queue of stalled insns. This has an effect only during the second scheduling pass, and only if @option{-fsched-stalled-insns} is used. @option{-fno-sched-stalled-insns-dep} is equivalent to @@ -6988,9 +7002,9 @@ at @option{-O2} or higher. @item -freschedule-modulo-scheduled-loops @opindex freschedule-modulo-scheduled-loops -The modulo scheduling comes before the traditional scheduling, if a loop -was modulo scheduled we may want to prevent the later scheduling passes -from changing its schedule, we use this option to control that. +The modulo scheduling comes before the traditional scheduling. If a loop +is modulo scheduled you may want to prevent the later scheduling passes +from changing its schedule; use this option to control that. @item -fselective-scheduling @opindex fselective-scheduling @@ -7021,10 +7035,10 @@ rather than at the top of the function. This flag is enabled by default at @item -fcaller-saves @opindex fcaller-saves -Enable values to be allocated in registers that will be clobbered by +Enable allocation of values to registers that are clobbered by function calls, by emitting extra instructions to save and restore the registers around such calls. Such allocation is done only when it -seems to result in better code than would otherwise be produced. +seems to result in better code. This option is always enabled by default on certain machines, usually those which have no call-preserved registers to use instead. @@ -7040,7 +7054,7 @@ Enabled by default at @option{-O1} and higher. @item -fconserve-stack @opindex fconserve-stack -Attempt to minimize stack usage. The compiler will attempt to use less +Attempt to minimize stack usage. The compiler attempts to use less stack space, even if that makes the program slower. This option implies setting the @option{large-stack-frame} parameter to 100 and the @option{large-stack-frame-growth} parameter to 400. @@ -7118,7 +7132,7 @@ This flag is enabled by default at @option{-O2}, @option{-Os} and @option{-O3}. @item -fipa-cp-clone @opindex fipa-cp-clone Perform function cloning to make interprocedural constant propagation stronger. -When enabled, interprocedural constant propagation will perform function cloning +When enabled, interprocedural constant propagation performs function cloning when externally visible function can be called with constant arguments. Because this optimization can create multiple copies of functions, it may significantly increase code size @@ -7226,7 +7240,7 @@ DO J = 1, M ENDDO ENDDO @end smallexample -loop interchange will transform the loop as if the user had written: +loop interchange transforms the loop as if it were written: @smallexample DO I = 1, N DO J = 1, M @@ -7256,7 +7270,7 @@ DO I = 1, N A(I) = A(I) + C ENDDO @end smallexample -loop strip mining will transform the loop as if the user had written: +loop strip mining transforms the loop as if it were written: @smallexample DO II = 1, N, 51 DO I = II, min (II + 50, N) @@ -7283,7 +7297,7 @@ DO I = 1, N ENDDO ENDDO @end smallexample -loop blocking will transform the loop as if the user had written: +loop blocking transforms the loop as if it were written: @smallexample DO II = 1, N, 51 DO JJ = 1, M, 51 @@ -7296,7 +7310,7 @@ DO II = 1, N, 51 ENDDO @end smallexample which can be beneficial when @code{M} is larger than the caches, -because the innermost loop will iterate over a smaller amount of data +because the innermost loop iterates over a smaller amount of data which can be kept in the caches. This optimization applies to all the languages supported by GCC and is not limited to Fortran. To use this code transformation, GCC has to be configured with @option{--with-ppl} @@ -7341,7 +7355,7 @@ for (i = 0; i < N; i++) if (cond) A[i] = expr; @end smallexample -would be transformed to +is transformed to @smallexample for (i = 0; i < N; i++) A[i] = cond ? expr : A[i]; @@ -7394,7 +7408,7 @@ and the initialization loop is transformed into a call to memset zero. @item -ftree-loop-im @opindex ftree-loop-im Perform loop invariant motion on trees. This pass moves only invariants that -would be hard to handle at RTL level (function calls, operations that expand to +are hard to handle at RTL level (function calls, operations that expand to nontrivial sequences of insns). With @option{-funswitch-loops} it also moves operands of conditions that are invariant out of the loop, so that we can use just trivial invariantness analysis in loop unswitching. The pass also includes @@ -7516,8 +7530,8 @@ This optimization is enabled by default. @item -fvariable-expansion-in-unroller @opindex fvariable-expansion-in-unroller -With this option, the compiler will create multiple copies of some -local variables when unrolling a loop which can result in superior code. +With this option, the compiler creates multiple copies of some +local variables when unrolling a loop, which can result in superior code. @item -fpartial-inlining @opindex fpartial-inlining @@ -7561,10 +7575,10 @@ other, a few use both. @opindex fno-guess-branch-probability Do not guess branch probabilities using heuristics. -GCC will use heuristics to guess branch probabilities if they are +GCC uses heuristics to guess branch probabilities if they are not provided by profiling feedback (@option{-fprofile-arcs}). These heuristics are based on the control flow graph. If some branch probabilities -are specified by @samp{__builtin_expect}, then the heuristics will be +are specified by @samp{__builtin_expect}, then the heuristics are used to guess branch probabilities for the rest of the control flow graph, taking the @samp{__builtin_expect} info into account. The interactions between the heuristics and @samp{__builtin_expect} can be complex, and in @@ -7634,7 +7648,7 @@ int f() @{ The practice of reading from a different union member than the one most recently written to (called ``type-punning'') is common. Even with @option{-fstrict-aliasing}, type-punning is allowed, provided the memory -is accessed through the union type. So, the code above will work as +is accessed through the union type. So, the code above works as expected. @xref{Structures unions enumerations and bit-fields implementation}. However, this code might not: @smallexample @@ -7665,14 +7679,14 @@ The @option{-fstrict-aliasing} option is enabled at levels Allow the compiler to assume strict signed overflow rules, depending on the language being compiled. For C (and C++) this means that overflow when doing arithmetic with signed numbers is undefined, which -means that the compiler may assume that it will not happen. This -permits various optimizations. For example, the compiler will assume -that an expression like @code{i + 10 > i} will always be true for +means that the compiler may assume that it does not happen. This +permits various optimizations. For example, the compiler assumes +that an expression like @code{i + 10 > i} is always true for signed @code{i}. This assumption is only valid if signed overflow is undefined, as the expression is false if @code{i + 10} overflows when using twos complement arithmetic. When this option is in effect any -attempt to determine whether an operation on signed numbers will -overflow must be written carefully to not actually involve overflow. +attempt to determine whether an operation on signed numbers +overflows must be written carefully to not actually involve overflow. This option also allows the compiler to assume strict pointer semantics: given a pointer to an object, if adding an offset to that @@ -7701,11 +7715,11 @@ The @option{-fstrict-overflow} option is enabled at levels Align the start of functions to the next power-of-two greater than @var{n}, skipping up to @var{n} bytes. For instance, @option{-falign-functions=32} aligns functions to the next 32-byte -boundary, but @option{-falign-functions=24} would align to the next +boundary, but @option{-falign-functions=24} aligns to the next 32-byte boundary only if this can be done by skipping 23 bytes or less. @option{-fno-align-functions} and @option{-falign-functions=1} are -equivalent and mean that functions will not be aligned. +equivalent and mean that functions are not aligned. Some assemblers only support this flag when @var{n} is a power of two; in that case, it is rounded up. @@ -7723,7 +7737,7 @@ make code slower, because it must insert dummy operations for when the branch target is reached in the usual flow of the code. @option{-fno-align-labels} and @option{-falign-labels=1} are -equivalent and mean that labels will not be aligned. +equivalent and mean that labels are not aligned. If @option{-falign-loops} or @option{-falign-jumps} are applicable and are greater than this value, then their values are used instead. @@ -7737,12 +7751,12 @@ Enabled at levels @option{-O2}, @option{-O3}. @itemx -falign-loops=@var{n} @opindex falign-loops Align loops to a power-of-two boundary, skipping up to @var{n} bytes -like @option{-falign-functions}. The hope is that the loop will be -executed many times, which will make up for any execution of the dummy +like @option{-falign-functions}. If the loops are +executed many times, this makes up for any execution of the dummy operations. @option{-fno-align-loops} and @option{-falign-loops=1} are -equivalent and mean that loops will not be aligned. +equivalent and mean that loops are not aligned. If @var{n} is not specified or is zero, use a machine-dependent default. @@ -7757,7 +7771,7 @@ bytes like @option{-falign-functions}. In this case, no dummy operations need be executed. @option{-fno-align-jumps} and @option{-falign-jumps=1} are -equivalent and mean that loops will not be aligned. +equivalent and mean that loops are not aligned. If @var{n} is not specified or is zero, use a machine-dependent default. @@ -7776,7 +7790,7 @@ Enabled by default. Do not reorder top-level functions, variables, and @code{asm} statements. Output them in the same order that they appear in the input file. When this option is used, unreferenced static variables -will not be removed. This option is intended to support existing code +are not removed. This option is intended to support existing code that relies on a particular ordering. For new code, it is better to use attributes. @@ -7790,7 +7804,7 @@ Constructs webs as commonly used for register allocation purposes and assign each web individual pseudo register. This allows the register allocation pass to operate on pseudos directly, but also strengthens several other optimization passes, such as CSE, loop optimizer and trivial dead code remover. It can, -however, make debugging impossible, since variables will no longer stay in a +however, make debugging impossible, since variables no longer stay in a ``home register''. Enabled by default with @option{-funroll-loops}. @@ -8067,8 +8081,8 @@ Enabled at levels @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}. @opindex fprofile-correction Profiles collected using an instrumented binary for multi-threaded programs may be inconsistent due to missed counter updates. When this option is specified, -GCC will use heuristics to correct or smooth out such inconsistencies. By -default, GCC will emit an error message when an inconsistent profile is detected. +GCC uses heuristics to correct or smooth out such inconsistencies. By +default, GCC emits an error message when an inconsistent profile is detected. @item -fprofile-dir=@var{path} @opindex fprofile-dir @@ -8078,8 +8092,8 @@ This option affects only the profile data generated by @option{-fprofile-generate}, @option{-ftest-coverage}, @option{-fprofile-arcs} and used by @option{-fprofile-use} and @option{-fbranch-probabilities} and its related options. Both absolute and relative paths can be used. -By default, GCC will use the current directory as @var{path}, thus the -profile data file will appear in the same directory as the object file. +By default, GCC uses the current directory as @var{path}, thus the +profile data file appears in the same directory as the object file. @item -fprofile-generate @itemx -fprofile-generate=@var{path} @@ -8092,7 +8106,7 @@ compiling and when linking your program. The following options are enabled: @code{-fprofile-arcs}, @code{-fprofile-values}, @code{-fvpt}. -If @var{path} is specified, GCC will look at the @var{path} to find +If @var{path} is specified, GCC looks at the @var{path} to find the profile feedback data files. See @option{-fprofile-dir}. @item -fprofile-use @@ -8109,7 +8123,7 @@ match the source code. This error can be turned into a warning by using @option{-Wcoverage-mismatch}. Note this may result in poorly optimized code. -If @var{path} is specified, GCC will look at the @var{path} to find +If @var{path} is specified, GCC looks at the @var{path} to find the profile feedback data files. See @option{-fprofile-dir}. @end table @@ -8144,7 +8158,7 @@ operations are carried out in the precision of the registers and that it is unpredictable when rounding to the types specified in the source code takes place. When compiling C, if @option{-fexcess-precision=standard} is specified then excess -precision will follow the rules specified in ISO C99; in particular, +precision follows the rules specified in ISO C99; in particular, both casts and assignments cause values to be rounded to their semantic types (whereas @option{-ffloat-store} only affects assignments). This option is enabled by default for C if a strict @@ -8391,9 +8405,9 @@ using the knowledge about the value of the denominator. @opindex frename-registers Attempt to avoid false dependencies in scheduled code by making use of registers left over after register allocation. This optimization -will most benefit processors with lots of registers. Depending on the +most benefits processors with lots of registers. Depending on the debug information format adopted by the target, however, it can -make debugging impossible, since variables will no longer stay in +make debugging impossible, since variables no longer stay in a ``home register''. Enabled by default with @option{-funroll-loops} and @option{-fpeel-loops}. @@ -8458,10 +8472,10 @@ linkers with such optimizations. AIX may have these optimizations in the future. Only use these options when there are significant benefits from doing -so. When you specify these options, the assembler and linker will -create larger object and executable files and will also be slower. -You will not be able to use @code{gprof} on all systems if you -specify this option and you may have problems with debugging if +so. When you specify these options, the assembler and linker +create larger object and executable files and are also slower. +You cannot use @code{gprof} on all systems if you +specify this option, and you may have problems with debugging if you specify both this option and @option{-g}. @item -fbranch-target-load-optimize @@ -8509,8 +8523,9 @@ static int a, b, c; int foo (void) @{ return a + b + c; @} @end smallexample -would usually calculate the addresses of all three variables, but if you -compile it with @option{-fsection-anchors}, it will access the variables +@noindent +usually calculates the addresses of all three variables, but if you +compile it with @option{-fsection-anchors}, it accesses the variables from a common anchor point instead. The effect is similar to the following pseudocode (which isn't valid C): @@ -8527,7 +8542,7 @@ Not all targets support this option. @item --param @var{name}=@var{value} @opindex param In some places, GCC uses various constants to control the amount of -optimization that is done. For example, GCC will not inline functions +optimization that is done. For example, GCC does not inline functions that contain more than a certain number of instructions. You can control some of these constants on the command line using the @option{--param} option. @@ -8553,7 +8568,7 @@ probably small improvement in executable size. @item min-crossjump-insns The minimum number of instructions that must be matched at the end -of two blocks before crossjumping will be performed on them. This +of two blocks before crossjumping is performed on them. This value is ignored in the case where all instructions in the block being crossjumped from are matched. The default value is 5. @@ -8573,8 +8588,8 @@ unfactored. The default value is 8. @item max-delay-slot-insn-search The maximum number of instructions to consider when looking for an instruction to fill a delay slot. If more than this arbitrary number of -instructions is searched, the time savings from filling the delay slot -will be minimal so stop searching. Increasing values mean more +instructions are searched, the time savings from filling the delay slot +are minimal, so stop searching. Increasing values mean more aggressive optimization, making the compilation time increase with probably small improvement in execution time. @@ -8587,18 +8602,18 @@ should be removed when the delay slot code is rewritten to maintain the control-flow graph. @item max-gcse-memory -The approximate maximum amount of memory that will be allocated in +The approximate maximum amount of memory that can be allocated in order to perform the global common subexpression elimination optimization. If more memory than specified is required, the -optimization will not be done. +optimization is not done. @item max-gcse-insertion-ratio If the ratio of expression insertions to deletions is larger than this value -for any expression, then RTL PRE will insert or remove the expression and thus -leave partially redundant computations in the instruction stream. The default value is 20. +for any expression, then RTL PRE inserts or removes the expression and thus +leaves partially redundant computations in the instruction stream. The default value is 20. @item max-pending-list-length -The maximum number of pending dependencies scheduling will allow +The maximum number of pending dependencies scheduling allows before flushing the current state and starting over. Large functions with few branches or calls can create excessively large lists which needlessly consume memory and resources. @@ -8612,14 +8627,14 @@ compilation time. Several parameters control the tree inliner used in GCC@. This number sets the maximum number of instructions (counted in GCC's internal representation) in a single function that the tree inliner -will consider for inlining. This only affects functions declared +considers for inlining. This only affects functions declared inline and methods implemented in a class declaration (C++). The default value is 400. @item max-inline-insns-auto When you use @option{-finline-functions} (included in @option{-O3}), a lot of functions that would otherwise not be considered for inlining -by the compiler will be investigated. To those functions, a different +by the compiler are investigated. To those functions, a different (more restrictive) limit compared to functions declared inline can be applied. The default value is 40. @@ -8713,10 +8728,10 @@ late inlining. @item comdat-sharing-probability @itemx comdat-sharing-probability Probability (in percent) that C++ inline function with comdat visibility -will be shared across multiple compilation units. The default value is 20. +are shared across multiple compilation units. The default value is 20. @item min-vect-loop-bound -The minimum number of iterations under which a loop will not get vectorized +The minimum number of iterations under which a loop is not vectorized when @option{-ftree-vectorize} is used. The number of iterations after vectorization needs to be greater than the value specified by this option to allow vectorization. The default value is 0. @@ -8725,23 +8740,23 @@ to allow vectorization. The default value is 0. Scaling factor in calculation of maximum distance an expression can be moved by GCSE optimizations. This is currently supported only in the code hoisting pass. The bigger the ratio, the more aggressive code hoisting -will be with simple expressions, i.e., the expressions that have cost -less than @option{gcse-unrestricted-cost}. Specifying 0 will disable +is with simple expressions, i.e., the expressions that have cost +less than @option{gcse-unrestricted-cost}. Specifying 0 disables hoisting of simple expressions. The default value is 10. @item gcse-unrestricted-cost Cost, roughly measured as the cost of a single typical machine -instruction, at which GCSE optimizations will not constrain +instruction, at which GCSE optimizations do not constrain the distance an expression can travel. This is currently supported only in the code hoisting pass. The lesser the cost, -the more aggressive code hoisting will be. Specifying 0 will -allow all expressions to travel unrestricted distances. +the more aggressive code hoisting is. Specifying 0 +allows all expressions to travel unrestricted distances. The default value is 3. @item max-hoist-depth The depth of search in the dominator tree for expressions to hoist. This is used to avoid quadratic behavior in hoisting algorithm. -The value of 0 will avoid limiting the search, but may slow down compilation +The value of 0 does not limit on the search, but may slow down compilation of huge functions. The default value is 30. @item max-tail-merge-comparisons @@ -8827,8 +8842,8 @@ The maximum number of equalities in an Omega constraint system. The default value is 128. @item omega-max-wild-cards -The maximum number of wildcard variables that the Omega solver will -be able to insert. The default value is 18. +The maximum number of wildcard variables that the Omega solver is +able to insert. The default value is 18. @item omega-hash-table-size The size of the hash table in the Omega solver. The default value is @@ -8867,19 +8882,20 @@ function given basic block needs to have to be considered hot. @item max-predicted-iterations The maximum number of loop iterations we predict statically. This is useful -in cases where function contain single loop with known bound and other loop -with unknown. We predict the known number of iterations correctly, while +in cases where a function contains a single loop with known bound and +another loop with unknown bound. +The known number of iterations is predicted correctly, while the unknown number of iterations average to roughly 10. This means that the -loop without bounds would appear artificially cold relative to the other one. +loop without bounds appears artificially cold relative to the other one. @item align-threshold -Select fraction of the maximal frequency of executions of basic block in -function given basic block will get aligned. +Select fraction of the maximal frequency of executions of a basic block in +a function to align the basic block. @item align-loop-iterations -A loop expected to iterate at lest the selected number of iterations will get +A loop expected to iterate at least the selected number of iterations is aligned. @item tracer-dynamic-coverage @@ -8895,7 +8911,7 @@ ones) are much less balanced allowing the threshold to be larger value. @item tracer-max-code-growth Stop tail duplication once code growth has reached given percentage. This is -rather hokey argument, as most of the duplicates will be eliminated later in +a rather artificial limit, as most of the duplicates are eliminated later in cross jumping, so it may be set to much higher values than is the desired code growth. @@ -8907,7 +8923,7 @@ threshold (in percent). @item tracer-min-branch-ratio @itemx tracer-min-branch-ratio-feedback -Stop forward growth if the best edge do have probability lower than this +Stop forward growth if the best edge has probability lower than this threshold. Similarly to @option{tracer-dynamic-coverage} two values are present, one for @@ -9016,7 +9032,7 @@ The default value is 3. @item sched-spec-prob-cutoff The minimal probability of speculation success (in percents), so that -speculative insn will be scheduled. +speculative insns are scheduled. The default value is 40. @item sched-mem-true-dep-cost @@ -9029,7 +9045,7 @@ depth of search for available instructions. The default value is 50. @item selsched-max-sched-times -The maximum number of times that an instruction will be scheduled during +The maximum number of times that an instruction is scheduled during selective scheduling. This is the limit on the number of iterations through which the instruction may be pipelined. The default value is 2. @@ -9038,8 +9054,8 @@ The maximum number of best instructions in the ready list that are considered for renaming in the selective scheduler. The default value is 2. @item sms-min-sc -The minimum value of stage count that swing modulo scheduler will -generate. The default value is 2. +The minimum value of stage count that swing modulo scheduler +generates. The default value is 2. @item max-last-value-rtl The maximum size measured as number of RTLs that can be recorded in an expression @@ -9064,7 +9080,7 @@ SSA updater switches to a full update for those symbols. The default ratio is 3. @item ssp-buffer-size -The minimum size of buffers (i.e.@: arrays) that will receive stack smashing +The minimum size of buffers (i.e.@: arrays) that receive stack smashing protection when @option{-fstack-protection} is used. @item max-jump-thread-duplication-stmts @@ -9072,7 +9088,7 @@ Maximum number of statements allowed in a block that needs to be duplicated when threading jumps. @item max-fields-for-field-sensitive -Maximum number of fields in a structure we will treat in +Maximum number of fields in a structure treated in a field sensitive manner during pointer analysis. The default is zero for @option{-O0} and @option{-O1}, and 100 for @option{-Os}, @option{-O2}, and @option{-O3}. @@ -9111,7 +9127,7 @@ bugs in the canonical type system are causing compilation failures, set this value to 0 to disable canonical types. @item switch-conversion-max-branch-ratio -Switch initialization conversion will refuse to create arrays that are +Switch initialization conversion refuses to create arrays that are bigger than @option{switch-conversion-max-branch-ratio} times the number of branches in the switch. @@ -9123,13 +9139,13 @@ the enhanced partial redundancy elimination optimization can run away, consuming all of the memory available on the host machine. This parameter sets a limit on the length of the sets that are computed, which prevents the runaway behavior. Setting a value of 0 for -this parameter will allow an unlimited set length. +this parameter allows an unlimited set length. @item sccvn-max-scc-size Maximum size of a strongly connected component (SCC) during SCCVN processing. If this limit is hit, SCCVN processing for the whole -function will not be done and optimizations depending on it will -be disabled. The default maximum SCC size is 10000. +function is not done and optimizations depending on it are +disabled. The default maximum SCC size is 10000. @item ira-max-loops-num IRA uses regional register allocation by default. If a function @@ -9165,8 +9181,8 @@ parameter is 1000 for @option{-O1} and 10000 for @option{-O2} and above. @item loop-max-datarefs-for-datadeps Building data dapendencies is expensive for very large loops. This parameter limits the number of data references in loops that are -considered for data dependence analysis. These large loops will not -be handled then by the optimizations using loop data dependencies. +considered for data dependence analysis. These large loops are no +handled by the optimizations using loop data dependencies. The default value is 1000. @item max-vartrack-size @@ -9194,14 +9210,14 @@ the parameter is reserved exclusively for debug insns created by (non-overlapping) uids above it if the reserved range is exhausted. @item ipa-sra-ptr-growth-factor -IPA-SRA will replace a pointer to an aggregate with one or more new +IPA-SRA replaces a pointer to an aggregate with one or more new parameters only when their cumulative size is less or equal to @option{ipa-sra-ptr-growth-factor} times the size of the original pointer parameter. @item tm-max-aggregate-size When making copies of thread-local variables in a transaction, this -parameter specifies the size in bytes after which variables will be +parameter specifies the size in bytes after which variables are saved with the logging functions as opposed to save/restore code sequence pairs. This option only applies when using @option{-fgnu-tm}. @@ -9437,9 +9453,9 @@ or @option{-nodefaultlibs} is used. @item -nodefaultlibs @opindex nodefaultlibs Do not use the standard system libraries when linking. -Only the libraries you specify will be passed to the linker, options +Only the libraries you specify are passed to the linker, and options specifying linkage of the system libraries, such as @code{-static-libgcc} -or @code{-shared-libgcc}, will be ignored. +or @code{-shared-libgcc}, are ignored. The standard startup files are used normally, unless @option{-nostartfiles} is used. The compiler may generate calls to @code{memcmp}, @code{memset}, @code{memcpy} and @code{memmove}. @@ -9450,9 +9466,10 @@ mechanism when this option is specified. @item -nostdlib @opindex nostdlib Do not use the standard system startup files or libraries when linking. -No startup files and only the libraries you specify will be passed to -the linker, options specifying linkage of the system libraries, such as -@code{-static-libgcc} or @code{-shared-libgcc}, will be ignored. +No startup files and only the libraries you specify are passed to +the linker, and options specifying linkage of the system libraries, such as +@code{-static-libgcc} or @code{-shared-libgcc}, are ignored. + The compiler may generate calls to @code{memcmp}, @code{memset}, @code{memcpy} and @code{memmove}. These entries are usually resolved by entries in @@ -9476,16 +9493,17 @@ In most cases, you need @file{libgcc.a} even when you want to avoid other standard libraries. In other words, when you specify @option{-nostdlib} or @option{-nodefaultlibs} you should usually specify @option{-lgcc} as well. This ensures that you have no unresolved references to internal GCC -library subroutines. (For example, @samp{__main}, used to ensure C++ -constructors will be called; @pxref{Collect2,,@code{collect2}, gccint, +library subroutines. +(An example of such an internal subroutine is @samp{__main}, used to ensure C++ +constructors are called; @pxref{Collect2,,@code{collect2}, gccint, GNU Compiler Collection (GCC) Internals}.) @item -pie @opindex pie Produce a position independent executable on targets that support it. For predictable results, you must also specify the same set of options -that were used to generate code (@option{-fpie}, @option{-fPIE}, -or model suboptions) when you specify this option. +used for compilation (@option{-fpie}, @option{-fPIE}, +or model suboptions) when you specify this linker option. @item -rdynamic @opindex rdynamic @@ -9508,9 +9526,9 @@ libraries. On other systems, this option has no effect. @opindex shared Produce a shared object which can then be linked with other objects to form an executable. Not all systems support this option. For predictable -results, you must also specify the same set of options that were used to -generate code (@option{-fpic}, @option{-fPIC}, or model suboptions) -when you specify this option.@footnote{On some systems, @samp{gcc -shared} +results, you must also specify the same set of options used for compilation +(@option{-fpic}, @option{-fPIC}, or model suboptions) when +you specify this linker option.@footnote{On some systems, @samp{gcc -shared} needs to build supplementary stub code for constructors to work. On multi-libbed systems, @samp{gcc -shared} must select the correct support libraries to link against. Failing to supply the correct flags may lead @@ -9538,11 +9556,11 @@ executable, because C++ and Java programs typically use exceptions, so this is the right thing to do. If, instead, you use the GCC driver to create shared libraries, you may -find that they will not always be linked with the shared @file{libgcc}. +find that they are not always linked with the shared @file{libgcc}. If GCC finds, at its configuration time, that you have a non-GNU linker or a GNU linker that does not support option @option{--eh-frame-hdr}, -it will link the shared version of @file{libgcc} into shared libraries -by default. Otherwise, it will take advantage of the linker and optimize +it links the shared version of @file{libgcc} into shared libraries +by default. Otherwise, it takes advantage of the linker and optimizes away the linking with the shared version of @file{libgcc}, linking with the static version of libgcc by default. This allows exceptions to propagate through such shared libraries, without incurring relocation @@ -9555,10 +9573,10 @@ for the languages used in the program, or using the option @file{libgcc}. @item -static-libstdc++ -When the @command{g++} program is used to link a C++ program, it will -normally automatically link against @option{libstdc++}. If +When the @command{g++} program is used to link a C++ program, it +normally automatically links against @option{libstdc++}. If @file{libstdc++} is available as a shared library, and the -@option{-static} option is not used, then this will link against the +@option{-static} option is not used, then this links against the shared version of @file{libstdc++}. That is normally fine. However, it is sometimes useful to freeze the version of @file{libstdc++} used by the program without going all the way to a fully static link. The @@ -9639,7 +9657,7 @@ order; the standard system directories come after. If a standard system include directory, or a directory specified with @option{-isystem}, is also specified with @option{-I}, the @option{-I} -option will be ignored. The directory will still be searched but as a +option is ignored. The directory is still searched but as a system directory at its normal position in the system include chain. This is to ensure that GCC's procedure to fix buggy system headers and the ordering for the @code{include_next} directive are not inadvertently changed. @@ -9676,14 +9694,14 @@ without @samp{@var{machine}/@var{version}/} (@pxref{Target Options}). For each subprogram to be run, the compiler driver first tries the @option{-B} prefix, if any. If that name is not found, or if @option{-B} -was not specified, the driver tries two standard prefixes, +is not specified, the driver tries two standard prefixes, @file{/usr/lib/gcc/} and @file{/usr/local/lib/gcc/}. If neither of those results in a file name that is found, the unmodified program name is searched for using the directories specified in your @env{PATH} environment variable. -The compiler will check to see if the path provided by the @option{-B} -refers to a directory, and if necessary it will add a directory +The compiler checks to see if the path provided by the @option{-B} +refers to a directory, and if necessary it adds a directory separator character at the end of the path. @option{-B} prefixes that effectively specify directory names also apply @@ -9704,7 +9722,7 @@ Variables}. As a special kludge, if the path provided by @option{-B} is @file{[dir/]stage@var{N}/}, where @var{N} is a number in the range 0 to -9, then it will be replaced by @file{[dir/]include}. This is to help +9, then it is replaced by @file{[dir/]include}. This is to help with boot-strapping the compiler. @item -specs=@var{file} @@ -9719,18 +9737,18 @@ are processed in order, from left to right. @item --sysroot=@var{dir} @opindex sysroot Use @var{dir} as the logical root directory for headers and libraries. -For example, if the compiler would normally search for headers in -@file{/usr/include} and libraries in @file{/usr/lib}, it will instead -search @file{@var{dir}/usr/include} and @file{@var{dir}/usr/lib}. +For example, if the compiler normally searches for headers in +@file{/usr/include} and libraries in @file{/usr/lib}, it instead +searches @file{@var{dir}/usr/include} and @file{@var{dir}/usr/lib}. If you use both this option and the @option{-isysroot} option, then -the @option{--sysroot} option will apply to libraries, but the -@option{-isysroot} option will apply to header files. +the @option{--sysroot} option applies to libraries, but the +@option{-isysroot} option applies to header files. The GNU linker (beginning with version 2.16) has the necessary support for this option. If your linker does not support this option, the -header file aspect of @option{--sysroot} will still work, but the -library aspect will not. +header file aspect of @option{--sysroot} still works, but the +library aspect does not. @item -I- @opindex I- @@ -9749,7 +9767,7 @@ In addition, the @option{-I-} option inhibits the use of the current directory (where the current input file came from) as the first search directory for @samp{#include "@var{file}"}. There is no way to override this effect of @option{-I-}. With @option{-I.} you can specify -searching the directory that was current when the compiler was +searching the directory that is current when the compiler is invoked. That is not exactly the same as what the preprocessor does by default, but it is often satisfactory. @@ -9806,18 +9824,18 @@ Rename the spec string @var{old_name} to @var{new_name}. This tells the compiler to create, override or delete the named spec string. All lines after this directive up to the next directive or blank line are considered to be the text for the spec string. If this -results in an empty string then the spec will be deleted. (Or, if the -spec did not exist, then nothing will happen.) Otherwise, if the spec -does not currently exist a new spec will be created. If the spec does -exist then its contents will be overridden by the text of this +results in an empty string then the spec is deleted. (Or, if the +spec did not exist, then nothing happens.) Otherwise, if the spec +does not currently exist a new spec is created. If the spec does +exist then its contents are overridden by the text of this directive, unless the first character of that text is the @samp{+} -character, in which case the text will be appended to the spec. +character, in which case the text is appended to the spec. @item [@var{suffix}]: Creates a new @samp{[@var{suffix}] spec} pair. All lines after this directive and up to the next directive or blank line are considered to make up the spec string for the indicated suffix. When the compiler encounters an -input file with the named suffix, it will processes the spec string in +input file with the named suffix, it processes the spec string in order to work out how to compile that file. For example: @smallexample @@ -9855,7 +9873,7 @@ This causes an error messages saying: @end table GCC already has an extensive list of suffixes built into it. -This directive will add an entry to the end of the list of suffixes, but +This directive adds an entry to the end of the list of suffixes, but since the list is searched from the end backwards, it is effectively possible to override earlier entries using this technique. @@ -9925,7 +9943,7 @@ the last period). @item %d Marks the argument containing or following the @samp{%d} as a -temporary file name, so that that file will be deleted if GCC exits +temporary file name, so that that file is deleted if GCC exits successfully. Unlike @samp{%g}, this contributes no text to the argument. @@ -9943,15 +9961,15 @@ without regard to any appended suffix (which was therefore treated just like ordinary text), making such attacks more likely to succeed. @item %u@var{suffix} -Like @samp{%g}, but generates a new temporary file name even if -@samp{%u@var{suffix}} was already seen. +Like @samp{%g}, but generates a new temporary file name +each time it appears instead of once per compilation. @item %U@var{suffix} Substitutes the last file name generated with @samp{%u@var{suffix}}, generating a new one if there is no such last file name. In the absence of any @samp{%u@var{suffix}}, this is just like @samp{%g@var{suffix}}, except they don't share the same suffix @emph{space}, so @samp{%g.s @dots{} %U.s @dots{} %g.s @dots{} %U.s} -would involve the generation of two distinct file names, one +involves the generation of two distinct file names, one for each @samp{%g.s} and another for each @samp{%U.s}. Previously, @samp{%U} was simply substituted with a file name chosen for the previous @samp{%u}, without regard to any appended suffix. @@ -9981,7 +9999,7 @@ terminated by the next space or %. @item %w Marks the argument containing or following the @samp{%w} as the designated output file of this compilation. This puts the argument -into the sequence of arguments that @samp{%o} will substitute later. +into the sequence of arguments that @samp{%o} substitutes. @item %o Substitutes the names of all the output files, with spaces @@ -9989,8 +10007,8 @@ automatically placed around them. You should write spaces around the @samp{%o} as well or the results are undefined. @samp{%o} is for use in the specs for running the linker. Input files whose names have no recognized suffix are not compiled -at all, but they are included among the output files, so they will -be linked. +at all, but they are included among the output files, so they are +linked. @item %O Substitutes the suffix for object files. Note that this is @@ -9998,7 +10016,7 @@ handled specially when it immediately follows @samp{%g, %u, or %U}, because of the need for those to form complete file names. The handling is such that @samp{%O} is treated exactly as if it had already been substituted, except that @samp{%g, %u, and %U} do not currently -support additional @var{suffix} characters following @samp{%O} as they would +support additional @var{suffix} characters following @samp{%O} as they do following, for example, @samp{.o}. @item %p @@ -10062,30 +10080,30 @@ needed. @item %l Process the @code{link} spec. This is the spec for computing the -command line passed to the linker. Typically it will make use of the +command line passed to the linker. Typically it makes use of the @samp{%L %G %S %D and %E} sequences. @item %D Dump out a @option{-L} option for each directory that GCC believes might contain startup files. If the target supports multilibs then the -current multilib directory will be prepended to each of these paths. +current multilib directory is prepended to each of these paths. @item %L Process the @code{lib} spec. This is a spec string for deciding which -libraries should be included on the command line to the linker. +libraries are included on the command line to the linker. @item %G Process the @code{libgcc} spec. This is a spec string for deciding -which GCC support library should be included on the command line to the linker. +which GCC support library is included on the command line to the linker. @item %S Process the @code{startfile} spec. This is a spec for deciding which -object files should be the first ones passed to the linker. Typically +object files are the first ones passed to the linker. Typically this might be a file named @file{crt0.o}. @item %E Process the @code{endfile} spec. This is a spec string that specifies -the last object files that will be passed to the linker. +the last object files that are passed to the linker. @item %C Process the @code{cpp} spec. This is used to construct the arguments @@ -10107,8 +10125,8 @@ a single space. @item %<@code{S} Remove all occurrences of @code{-S} from the command line. Note---this command is position dependent. @samp{%} commands in the spec string -before this one will see @code{-S}, @samp{%} commands in the spec string -after this one will not. +before this one see @code{-S}, @samp{%} commands in the spec string +after this one do not. @item %:@var{function}(@var{args}) Call the named function @var{function}, passing it @var{args}. @@ -10203,12 +10221,12 @@ in the @option{--target-help} output. @end table @item %@{@code{S}@} -Substitutes the @code{-S} switch, if that switch was given to GCC@. -If that switch was not specified, this substitutes nothing. Note that +Substitutes the @code{-S} switch, if that switch is given to GCC@. +If that switch is not specified, this substitutes nothing. Note that the leading dash is omitted when specifying this option, and it is automatically inserted if the substitution is performed. Thus the spec -string @samp{%@{foo@}} would match the command-line option @option{-foo} -and would output the command-line option @option{-foo}. +string @samp{%@{foo@}} matches the command-line option @option{-foo} +and outputs the command-line option @option{-foo}. @item %W@{@code{S}@} Like %@{@code{S}@} but mark last argument supplied within as a file to be @@ -10219,8 +10237,8 @@ Substitutes all the switches specified to GCC whose names start with @code{-S}, but which also take an argument. This is used for switches like @option{-o}, @option{-D}, @option{-I}, etc. GCC considers @option{-o foo} as being -one switch whose names starts with @samp{o}. %@{o*@} would substitute this -text, including the space. Thus two arguments would be generated. +one switch whose name starts with @samp{o}. %@{o*@} substitutes this +text, including the space. Thus two arguments are generated. @item %@{@code{S}*&@code{T}*@} Like %@{@code{S}*@}, but preserve order of @code{S} and @code{T} options @@ -10229,18 +10247,18 @@ There can be any number of ampersand-separated variables; for each the wild card is optional. Useful for CPP as @samp{%@{D*&U*&A*@}}. @item %@{@code{S}:@code{X}@} -Substitutes @code{X}, if the @option{-S} switch was given to GCC@. +Substitutes @code{X}, if the @option{-S} switch is given to GCC@. @item %@{!@code{S}:@code{X}@} -Substitutes @code{X}, if the @option{-S} switch was @emph{not} given to GCC@. +Substitutes @code{X}, if the @option{-S} switch is @emph{not} given to GCC@. @item %@{@code{S}*:@code{X}@} Substitutes @code{X} if one or more switches whose names start with @code{-S} are specified to GCC@. Normally @code{X} is substituted only once, no matter how many such switches appeared. However, if @code{%*} -appears somewhere in @code{X}, then @code{X} will be substituted once +appears somewhere in @code{X}, then @code{X} is substituted once for each matching switch, with the @code{%*} replaced by the part of -that switch that matched the @code{*}. +that switch matching the @code{*}. @item %@{.@code{S}:@code{X}@} Substitutes @code{X}, if processing a file with suffix @code{S}. @@ -10255,7 +10273,7 @@ Substitutes @code{X}, if processing a file for language @code{S}. Substitutes @code{X}, if not processing a file for language @code{S}. @item %@{@code{S}|@code{P}:@code{X}@} -Substitutes @code{X} if either @code{-S} or @code{-P} was given to +Substitutes @code{X} if either @code{-S} or @code{-P} is given to GCC@. This may be combined with @samp{!}, @samp{.}, @samp{,}, and @code{*} sequences as well, although they have a stronger binding than the @samp{|}. If @code{%*} appears in @code{X}, all of the @@ -10268,7 +10286,8 @@ For example, a spec string like this: %@{.c:-foo@} %@{!.c:-bar@} %@{.c|d:-baz@} %@{!.c|d:-boggle@} @end smallexample -will output the following command-line options from the following input +@noindent +outputs the following command-line options from the following input command-line options: @smallexample @@ -10280,7 +10299,7 @@ jim.d -bar -boggle @item %@{S:X; T:Y; :D@} -If @code{S} was given to GCC, substitutes @code{X}; else if @code{T} was +If @code{S} is given to GCC, substitutes @code{X}; else if @code{T} is given to GCC, substitutes @code{Y}; else substitutes @code{D}. There can be as many clauses as you need. This may be combined with @code{.}, @code{,}, @code{!}, @code{|}, and @code{*} as needed. @@ -10457,7 +10476,7 @@ can be used by leaf functions without stack allocation. Values other than @samp{8} or @samp{16} are untested and unlikely to work. Note also that this option changes the ABI, compiling a program with a different stack offset than the libraries have been compiled with -will generally not work. +generally does not work. This option can be useful if you want to evaluate if a different stack offset would give you better code, but to actually use a different stack offset to build working programs, it is recommended to configure the @@ -10545,13 +10564,13 @@ Change the preferred SIMD mode to SImode. The default is The maximum alignment for SIMD vector mode types. @var{num} may be 4 or 8. The default is 8. Note that this is an ABI change, even though many library function -interfaces will be unaffected, if they don't use SIMD vector modes -in places where they affect size and/or alignment of relevant types. +interfaces are unaffected if they don't use SIMD vector modes +in places that affect size and/or alignment of relevant types. @item -msplit-vecmove-early @opindex msplit-vecmove-early Split vector moves into single word moves before reload. In theory this -could give better register allocation, but so far the reverse seems to be +can give better register allocation, but so far the reverse seems to be generally the case. @item -m1reg-@var{reg} @@ -10583,7 +10602,7 @@ Generate code for the specified ABI@. Permissible values are: @samp{apcs-gnu}, Generate a stack frame that is compliant with the ARM Procedure Call Standard for all functions, even if this is not strictly necessary for correct execution of the code. Specifying @option{-fomit-frame-pointer} -with this option will cause the stack frames not to be generated for +with this option causes the stack frames not to be generated for leaf functions. The default is @option{-mno-apcs-frame}. @item -mapcs @@ -10597,7 +10616,7 @@ This is a synonym for @option{-mapcs-frame}. Generate code to check the amount of stack space available upon entry to every function (that actually uses some stack space). If there is insufficient space available then either the function -@samp{__rt_stkovf_split_small} or @samp{__rt_stkovf_split_big} will be +@samp{__rt_stkovf_split_small} or @samp{__rt_stkovf_split_big} is called, depending upon the amount of stack space required. The runtime system is required to provide these functions. The default is @option{-mno-apcs-stack-check}, since this produces smaller code. @@ -10632,10 +10651,10 @@ configurations this option is meaningless. @opindex mno-sched-prolog Prevent the reordering of instructions in the function prologue, or the merging of those instruction with the instructions in the function's -body. This means that all functions will start with a recognizable set +body. This means that all functions start with a recognizable set of instructions (or in fact one of a choice from a small set of different function prologues), and this information can be used to -locate the start if functions inside an executable piece of code. The +locate the start of functions inside an executable piece of code. The default is @option{-msched-prolog}. @item -mfloat-abi=@var{name} @@ -10700,6 +10719,7 @@ assembly code. Permissible names are: @samp{arm2}, @samp{arm250}, @samp{cortex-m4}, @samp{cortex-m3}, @samp{cortex-m1}, @samp{cortex-m0}, +@samp{cortex-m0plus}, @samp{xscale}, @samp{iwmmxt}, @samp{iwmmxt2}, @samp{ep9312}, @samp{fa526}, @samp{fa626}, @samp{fa606te}, @samp{fa626te}, @samp{fmp626}, @samp{fa726te}. @@ -10720,8 +10740,8 @@ This option is very similar to the @option{-mcpu=} option, except that instead of specifying the actual target processor type, and hence restricting which instructions can be used, it specifies that GCC should tune the performance of the code as if the target were of the type -specified in this option, but still choosing the instructions that it -will generate based on the CPU specified by a @option{-mcpu=} option. +specified in this option, but still choosing the instructions it +generates based on the CPU specified by a @option{-mcpu=} option. For some ARM implementations better performance can be obtained by using this option. @@ -10776,7 +10796,7 @@ floating-point values. If the selected floating-point hardware includes the NEON extension (e.g. @option{-mfpu}=@samp{neon}), note that floating-point -operations will not be used by GCC's auto-vectorization pass unless +operations are not generated by GCC's auto-vectorization pass unless @option{-funsafe-math-optimizations} is also specified. This is because NEON hardware does not fully implement the IEEE 754 standard for floating-point arithmetic (in particular denormal values are treated as @@ -10791,7 +10811,7 @@ defined. @xref{Half-Precision}, for more information. @item -mstructure-size-boundary=@var{n} @opindex mstructure-size-boundary -The size of all structures and unions will be rounded up to a multiple +The sizes of all structures and unions are rounded up to a multiple of the number of bits set by this option. Permissible values are 8, 32 and 64. The default value varies for different toolchains. For the COFF targeted toolchain the default value is 8. A value of 64 is only allowed @@ -10806,7 +10826,7 @@ information using structures or unions. @item -mabort-on-noreturn @opindex mabort-on-noreturn Generate a call to the function @code{abort} at the end of a -@code{noreturn} function. It will be executed if the function tries to +@code{noreturn} function. It is executed if the function tries to return. @item -mlong-calls @@ -10816,22 +10836,22 @@ return. Tells the compiler to perform function calls by first loading the address of the function into a register and then performing a subroutine call on this register. This switch is needed if the target function -will lie outside of the 64 megabyte addressing range of the offset based +lies outside of the 64-megabyte addressing range of the offset-based version of subroutine call instruction. -Even if this switch is enabled, not all function calls will be turned +Even if this switch is enabled, not all function calls are turned into long calls. The heuristic is that static functions, functions that have the @samp{short-call} attribute, functions that are inside -the scope of a @samp{#pragma no_long_calls} directive and functions whose +the scope of a @samp{#pragma no_long_calls} directive, and functions whose definitions have already been compiled within the current compilation -unit, will not be turned into long calls. The exception to this rule is +unit are not turned into long calls. The exceptions to this rule are that weak function definitions, functions with the @samp{long-call} attribute or the @samp{section} attribute, and functions that are within -the scope of a @samp{#pragma long_calls} directive, will always be +the scope of a @samp{#pragma long_calls} directive are always turned into long calls. This feature is not enabled by default. Specifying -@option{-mno-long-calls} will restore the default behavior, as will +@option{-mno-long-calls} restores the default behavior, as does placing the function calls within the scope of a @samp{#pragma long_calls_off} directive. Note these switches have no effect on how the compiler generates code to handle function calls via function @@ -11086,8 +11106,8 @@ integers. The default branch cost is 0. @item -mcall-prologues @opindex mcall-prologues -Functions prologues/epilogues expanded as call to appropriate -subroutines. Code size will be smaller. +Functions prologues/epilogues are expanded as calls to appropriate +subroutines. Code size is smaller. @item -mint8 @opindex mint8 @@ -11100,7 +11120,7 @@ size. @item -mno-interrupts @opindex mno-interrupts Generated code is not compatible with hardware interrupts. -Code size will be smaller. +Code size is smaller. @item -mrelax @opindex mrelax @@ -11111,7 +11131,7 @@ linker command line when the linker is called. Jump relaxing is performed by the linker because jump offsets are not known before code is located. Therefore, the assembler code generated by the -compiler will be the same, but the instructions in the executable may +compiler is the same, but the instructions in the executable may differ from instructions in the assembler code. @item -mshort-calls @@ -11124,14 +11144,14 @@ See also the @code{-mrelax} command line option. @item -mstrict-X @opindex mstrict-X Use address register @code{X} in a way proposed by the hardware. This means -that @code{X} will only be used in indirect, post-increment or +that @code{X} is only used in indirect, post-increment or pre-decrement addressing. Without this option, the @code{X} register may be used in the same way as @code{Y} or @code{Z} which then is emulated by additional instructions. For example, loading a value with @code{X+const} addressing with a -small non-negative @code{const < 64} to a register @var{Rn} will be +small non-negative @code{const < 64} to a register @var{Rn} is performed as @example @@ -11177,9 +11197,9 @@ saved/restored in function or interrupt service routine prologue/epilogue. @item -For indirect calls to functions and computed goto, the linker will -generate @emph{stubs}. Stubs are jump pads sometimes also called -@emph{trampolines}. Thus, the indirect call/jump will jump to such a stub. +For indirect calls to functions and computed goto, the linker +generates @emph{stubs}. Stubs are jump pads sometimes also called +@emph{trampolines}. Thus, the indirect call/jump jumps to such a stub. The stub contains a direct jump to the desired address. @item @@ -11218,7 +11238,7 @@ init3_set_eind (void) The @code{__trampolines_start} symbol is defined in the linker script. @item -Stubs will be generated automatically by the linker if +Stubs are generated automatically by the linker if the following two conditions are met: @itemize @minus @@ -11233,7 +11253,7 @@ LDI r25, hi8(gs(@var{func})) @end itemize @item -The compiler will emit such @code{gs} modifiers for code labels in the +The compiler emits such @code{gs} modifiers for code labels in the following situations: @itemize @minus @item Taking address of a function or code label. @@ -11295,17 +11315,17 @@ registers with zero. @item If a @ref{AVR Named Address Spaces,named address space} other than -generic or @code{__flash} is used, then @code{RAMPZ} will be set +generic or @code{__flash} is used, then @code{RAMPZ} is set as needed before the operation. @item If the device supports RAM larger than 64@tie{KiB} and the compiler needs to change @code{RAMPZ} to accomplish an operation, @code{RAMPZ} -will be reset to zero after the operation. +is reset to zero after the operation. @item If the device comes with a specific @code{RAMP} register, the ISR -prologue/epilogue will save/restore that SFR and initialize it with +prologue/epilogue saves/restores that SFR and initializes it with zero in case the ISR code might (implicitly) use it. @item @@ -11330,7 +11350,7 @@ For even more AVR-specific built-in macros see @item __AVR_@var{Device}__ Setting @code{-mmcu=@var{device}} defines this built-in macro which reflects -the device's name. For example, @code{-mmcu=atmega8} will define the +the device's name. For example, @code{-mmcu=atmega8} defines the built-in macro @code{__AVR_ATmega8__}, @code{-mmcu=attiny261a} defines @code{__AVR_ATtiny261A__}, etc. @@ -11424,9 +11444,9 @@ can be one of @samp{bf512}, @samp{bf514}, @samp{bf516}, @samp{bf518}, @samp{bf561}, @samp{bf592}. The optional @var{sirevision} specifies the silicon revision of the target Blackfin processor. Any workarounds available for the targeted silicon revision -will be enabled. If @var{sirevision} is @samp{none}, no workarounds are enabled. +are enabled. If @var{sirevision} is @samp{none}, no workarounds are enabled. If @var{sirevision} is @samp{any}, all workarounds for the targeted processor -will be enabled. The @code{__SILICON_REVISION__} macro is defined to two +are enabled. The @code{__SILICON_REVISION__} macro is defined to two hexadecimal digits representing the major and minor numbers in the silicon revision. If @var{sirevision} is @samp{none}, the @code{__SILICON_REVISION__} is not defined. If @var{sirevision} is @samp{any}, the @@ -11459,7 +11479,7 @@ which might make debugging harder. @item -mspecld-anomaly @opindex mspecld-anomaly -When enabled, the compiler will ensure that the generated code does not +When enabled, the compiler ensures that the generated code does not contain speculative loads after jump instructions. If this option is used, @code{__WORKAROUND_SPECULATIVE_LOADS} is defined. @@ -11469,7 +11489,7 @@ Don't generate extra code to prevent speculative loads from occurring. @item -mcsync-anomaly @opindex mcsync-anomaly -When enabled, the compiler will ensure that the generated code does not +When enabled, the compiler ensures that the generated code does not contain CSYNC or SSYNC instructions too soon after conditional branches. If this option is used, @code{__WORKAROUND_SPECULATIVE_SYNCS} is defined. @@ -11514,14 +11534,14 @@ and calls. @item -mno-leaf-id-shared-library @opindex mno-leaf-id-shared-library Do not assume that the code being compiled won't link against any ID shared -libraries. Slower code will be generated for jump and call insns. +libraries. Slower code is generated for jump and call insns. @item -mshared-library-id=n @opindex mshared-library-id -Specified the identification number of the ID based shared library being -compiled. Specifying a value of 0 will generate more compact code, specifying -other values will force the allocation of that number to the current -library but is no more space or time efficient than omitting this option. +Specifies the identification number of the ID-based shared library being +compiled. Specifying a value of 0 generates more compact code; specifying +other values forces the allocation of that number to the current +library but is no more space- or time-efficient than omitting this option. @item -msep-data @opindex msep-data @@ -11546,7 +11566,7 @@ lies outside of the 24-bit addressing range of the offset-based version of subroutine call instruction. This feature is not enabled by default. Specifying -@option{-mno-long-calls} will restore the default behavior. Note these +@option{-mno-long-calls} restores the default behavior. Note these switches have no effect on how the compiler generates code to handle function calls via function pointers. @@ -11564,7 +11584,7 @@ not known to bind locally. It has no effect without @option{-mfdpic}. @item -mmulticore @opindex mmulticore Build standalone application for multicore Blackfin processor. Proper -start files and link scripts will be used to support multicore. +start files and link scripts are used to support multicore. This option defines @code{__BFIN_MULTICORE}. It can only be used with @option{-mcpu=bf561@r{[}-@var{sirevision}@r{]}}. It can be used with @option{-mcorea} or @option{-mcoreb}. If it's used without @@ -11579,14 +11599,14 @@ model is used. @opindex mcorea Build standalone application for Core A of BF561 when using one application per core programming model. Proper start files -and link scripts will be used to support Core A. This option +and link scripts are used to support Core A. This option defines @code{__BFIN_COREA}. It must be used with @option{-mmulticore}. @item -mcoreb @opindex mcoreb Build standalone application for Core B of BF561 when using one application per core programming model. Proper start files -and link scripts will be used to support Core B. This option +and link scripts are used to support Core B. This option defines @code{__BFIN_COREB}. When this option is used, coreb_main should be used instead of main. It must be used with @option{-mmulticore}. @@ -11594,7 +11614,7 @@ should be used instead of main. It must be used with @item -msdram @opindex msdram Build standalone application for SDRAM. Proper start files and -link scripts will be used to put the application into SDRAM. +link scripts are used to put the application into SDRAM. Loader should initialize SDRAM before loading the application into SDRAM. This option defines @code{__BFIN_SDRAM}. @@ -11828,8 +11848,8 @@ CR16C architecture does not support the far data model. These options are defined for all architectures running the Darwin operating system. -FSF GCC on Darwin does not create ``fat'' object files; it will create -an object file for the single architecture that it was built to +FSF GCC on Darwin does not create ``fat'' object files; it creates +an object file for the single architecture that GCC was built to target. Apple's GCC on Darwin does create ``fat'' files if multiple @option{-arch} options are used; it does so by running the compiler or linker multiple times and joining the results together with @@ -11841,14 +11861,14 @@ that GCC is targetting, like @option{-mcpu} or @option{-march}. The @option{-force_cpusubtype_ALL} option can be used to override this. The Darwin tools vary in their behavior when presented with an ISA -mismatch. The assembler, @file{as}, will only permit instructions to +mismatch. The assembler, @file{as}, only permits instructions to be used that are valid for the subtype of the file it is generating, so you cannot put 64-bit instructions in a @samp{ppc750} object file. -The linker for shared libraries, @file{/usr/bin/libtool}, will fail -and print an error if asked to create a shared library with a less +The linker for shared libraries, @file{/usr/bin/libtool}, fails +and prints an error if asked to create a shared library with a less restrictive subtype than its input files (for instance, trying to put a @samp{ppc970} object file in a @samp{ppc7400} library). The linker -for executables, @command{ld}, will quietly give the executable the most +for executables, @command{ld}, quietly gives the executable the most restrictive subtype of any of its input files. @table @gcctabopt @@ -11871,8 +11891,8 @@ Includes of subframework headers can only appear in a header of a framework that contains the subframework, or in a sibling subframework header. Two subframeworks are siblings if they occur in the same framework. A subframework should not have the same name as a -framework, a warning will be issued if this is violated. Currently a -subframework cannot have subframeworks, in the future, the mechanism +framework; a warning is issued if this is violated. Currently a +subframework cannot have subframeworks; in the future, the mechanism may be extended to support this. The standard frameworks can be found in @file{/System/Library/Frameworks} and @file{/Library/Frameworks}. An example include looks like @@ -11964,12 +11984,12 @@ See man ld(1) for more information. @item -bundle_loader @var{executable} @opindex bundle_loader -This option specifies the @var{executable} that will be loading the build +This option specifies the @var{executable} that will load the build output file being linked. See man ld(1) for more information. @item -dynamiclib @opindex dynamiclib -When passed this option, GCC will produce a dynamic library instead of +When passed this option, GCC produces a dynamic library instead of an executable when linking, using the Darwin @file{libtool} command. @item -force_cpusubtype_ALL @@ -12114,10 +12134,10 @@ These @samp{-m} options are defined for the DEC Alpha implementations: @opindex msoft-float Use (do not use) the hardware floating-point instructions for floating-point operations. When @option{-msoft-float} is specified, -functions in @file{libgcc.a} will be used to perform floating-point +functions in @file{libgcc.a} are used to perform floating-point operations. Unless they are replaced by routines that emulate the floating-point operations, or compiled in such a way as to call such -emulations routines, these routines will issue floating-point +emulations routines, these routines issue floating-point operations. If you are compiling for an Alpha without floating-point operations, you must ensure that the library is built so as not to call them. @@ -12255,13 +12275,13 @@ generated assembly file. @opindex mbuild-constants Normally GCC examines a 32- or 64-bit integer constant to see if it can construct it from smaller constants in two or three -instructions. If it cannot, it will output the constant as a literal and -generate code to load it from the data segment at run time. +instructions. If it cannot, it outputs the constant as a literal and +generates code to load it from the data segment at run time. Use this option to require GCC to construct @emph{all} integer constants using code, even if it takes more instructions (the maximum is six). -You would typically use this option to build a shared library dynamic +You typically use this option to build a shared library dynamic loader. Itself a shared library, it must relocate itself in memory before it can find the variables and constants in its own data segment. @@ -12284,7 +12304,7 @@ before it can find the variables and constants in its own data segment. Indicate whether GCC should generate code to use the optional BWX, CIX, FIX and MAX instruction sets. The default is to use the instruction sets supported by the CPU type specified via @option{-mcpu=} option or that -of the CPU on which GCC was built if none was specified. +of the CPU on which GCC was built if none is specified. @item -mfloat-vax @itemx -mfloat-ieee @@ -12343,9 +12363,9 @@ The default is @option{-mlarge-text}. Set the instruction set and instruction scheduling parameters for machine type @var{cpu_type}. You can specify either the @samp{EV} style name or the corresponding chip number. GCC supports scheduling -parameters for the EV4, EV5 and EV6 family of processors and will -choose the default values for the instruction set from the processor -you specify. If you do not specify a processor type, GCC will default +parameters for the EV4, EV5 and EV6 family of processors and +chooses the default values for the instruction set from the processor +you specify. If you do not specify a processor type, GCC defaults to the processor on which the compiler was built. Supported values for @var{cpu_type} are @@ -12429,7 +12449,7 @@ These options are defined specifically for the FR30 port. @item -msmall-model @opindex msmall-model Use the small address space model. This can produce smaller code, but -it does assume that all symbolic values and addresses will fit into a +it does assume that all symbolic values and addresses fit into a 20-bit range. @item -mno-lsim @@ -12865,7 +12885,7 @@ Generate code for the specified architecture. The choices for 1.1, and @samp{2.0} for PA 2.0 processors. Refer to @file{/usr/lib/sched.models} on an HP-UX system to determine the proper architecture option for your machine. Code compiled for lower numbered -architectures will run on higher numbered architectures, but not the +architectures runs on higher numbered architectures, but not the other way around. @item -mpa-risc-1-0 @@ -12912,7 +12932,7 @@ Such code is suitable for level 0 PA systems and kernels. Generate code that assumes calls never cross space boundaries. This allows GCC to emit code that performs faster indirect calls. -This option will not work in the presence of shared libraries or nested +This option does not work in the presence of shared libraries or nested functions. @item -mfixed-range=@var{register-range} @@ -13019,7 +13039,7 @@ Distances are measured from the beginning of functions when using the and @option{-mno-portable-runtime} options together under HP-UX with the SOM linker. -It is normally not desirable to use this option as it will degrade +It is normally not desirable to use this option as it degrades performance. However, it may be useful in large applications, particularly when partial linking is used to build the application. @@ -14406,8 +14426,8 @@ runtime library for whatever I/O functions are needed. @item -memregs=@var{number} @opindex memregs= -Specifies the number of memory-based pseudo-registers GCC will use -during code generation. These pseudo-registers will be used like real +Specifies the number of memory-based pseudo-registers GCC uses +during code generation. These pseudo-registers are used like real registers, so there is a tradeoff between GCC's ability to fit the code into available registers, and the performance penalty of using memory instead of registers. Note that all modules in a program must @@ -14449,21 +14469,21 @@ The addressability of a particular object can be set with the @item -mmodel=medium @opindex mmodel=medium Assume objects may be anywhere in the 32-bit address space (the compiler -will generate @code{seth/add3} instructions to load their addresses), and +generates @code{seth/add3} instructions to load their addresses), and assume all subroutines are reachable with the @code{bl} instruction. @item -mmodel=large @opindex mmodel=large Assume objects may be anywhere in the 32-bit address space (the compiler -will generate @code{seth/add3} instructions to load their addresses), and +generates @code{seth/add3} instructions to load their addresses), and assume subroutines may not be reachable with the @code{bl} instruction -(the compiler will generate the much slower @code{seth/add3/jl} +(the compiler generates the much slower @code{seth/add3/jl} instruction sequence). @item -msdata=none @opindex msdata=none -Disable use of the small data area. Variables will be put into -one of @samp{.data}, @samp{bss}, or @samp{.rodata} (unless the +Disable use of the small data area. Variables are put into +one of @samp{.data}, @samp{.bss}, or @samp{.rodata} (unless the @code{section} attribute has been specified). This is the default. @@ -14492,7 +14512,7 @@ for this option to have any effect. All modules should be compiled with the same @option{-G @var{num}} value. Compiling with different values of @var{num} may or may not work; if it -doesn't the linker will give an error message---incorrect code will not be +doesn't the linker gives an error message---incorrect code is not generated. @item -mdebug @@ -14515,9 +14535,8 @@ or 2. @item -mbranch-cost=@var{number} @opindex mbranch-cost=@var{number} -@var{number} can only be 1 or 2. If it is 1 then branches will be -preferred over conditional code, if it is 2, then the opposite will -apply. +@var{number} can only be 1 or 2. If it is 1 then branches are +preferred over conditional code, if it is 2, then the opposite applies. @item -mflush-trap=@var{number} @opindex mflush-trap=@var{number} @@ -14532,7 +14551,7 @@ Specifies that the cache cannot be flushed by using a trap. @opindex mflush-func=@var{name} Specifies the name of the operating system function to call to flush the cache. The default is @emph{_flush_cache}, but a function call -will only be used if a trap is not available. +is only used if a trap is not available. @item -mno-flush-func @opindex mno-flush-func @@ -14820,10 +14839,10 @@ compiled with the Unix compiler. Also, you must provide function prototypes for all functions that take variable numbers of arguments (including @code{printf}); -otherwise incorrect code will be generated for calls to those +otherwise incorrect code is generated for calls to those functions. -In addition, seriously incorrect code will result if you call a +In addition, seriously incorrect code results if you call a function with too many arguments. (Normally, extra arguments are harmlessly ignored.) @@ -14845,8 +14864,8 @@ boundary (@option{-malign-int}) or a 16-bit boundary (@option{-mno-align-int}). Aligning variables on 32-bit boundaries produces code that runs somewhat faster on processors with 32-bit busses at the expense of more memory. -@strong{Warning:} if you use the @option{-malign-int} switch, GCC will -align structures containing the above types differently than +@strong{Warning:} if you use the @option{-malign-int} switch, GCC +aligns structures containing the above types differently than most published application binary interface specifications for the m68k. @item -mpcrel @@ -14861,7 +14880,7 @@ not presently supported with @option{-mpcrel}, though this could be supported fo @itemx -mstrict-align @opindex mno-strict-align @opindex mstrict-align -Do not (do) assume that unaligned memory references will be handled by +Do not (do) assume that unaligned memory references are handled by the system. @item -msep-data @@ -14884,10 +14903,10 @@ Generate code that doesn't assume ID based shared libraries are being used. This is the default. @item -mshared-library-id=n -Specified the identification number of the ID based shared library being -compiled. Specifying a value of 0 will generate more compact code, specifying -other values will force the allocation of that number to the current -library but is no more space or time efficient than omitting this option. +Specifies the identification number of the ID-based shared library being +compiled. Specifying a value of 0 generates more compact code; specifying +other values forces the allocation of that number to the current +library, but is no more space- or time-efficient than omitting this option. @item -mxgot @itemx -mno-xgot @@ -15027,7 +15046,7 @@ registers. @item -mbased=@var{n} @opindex mbased= -Variables of size @var{n} bytes or smaller will be placed in the +Variables of size @var{n} bytes or smaller are placed in the @code{.based} section by default. Based variables use the @code{$tp} register as a base register, and there is a 128-byte limit to the @code{.based} section. @@ -15040,7 +15059,7 @@ test-and-set (@code{tas}). @item -mc=@var{name} @opindex mc= -Selects which section constant data will be placed in. @var{name} may +Selects which section constant data is placed in. @var{name} may be @code{tiny}, @code{near}, or @code{far}. @item -mclip @@ -15158,7 +15177,7 @@ this option, functions default to the @code{.near} section. @item -mtiny=@var{n} @opindex mtiny= -Variables that are @var{n} bytes or smaller will be allocated to the +Variables that are @var{n} bytes or smaller are allocated to the @code{.tiny} section. These variables use the @code{$gp} base register. The default for this option is 4, but note that there's a 65536-byte limit to the @code{.tiny} section. @@ -15280,7 +15299,7 @@ configurations. @item -march=@var{arch} @opindex march -Generate code that will run on @var{arch}, which can be the name of a +Generate code that runs on @var{arch}, which can be the name of a generic MIPS ISA, or the name of a particular processor. The ISA names are: @samp{mips1}, @samp{mips2}, @samp{mips3}, @samp{mips4}, @@ -15334,11 +15353,11 @@ GCC defines two macros based on the value of this option. The first is @samp{_MIPS_ARCH}, which gives the name of target architecture, as a string. The second has the form @samp{_MIPS_ARCH_@var{foo}}, where @var{foo} is the capitalized value of @samp{_MIPS_ARCH}@. -For example, @option{-march=r2000} will set @samp{_MIPS_ARCH} -to @samp{"r2000"} and define the macro @samp{_MIPS_ARCH_R2000}. +For example, @option{-march=r2000} sets @samp{_MIPS_ARCH} +to @samp{"r2000"} and defines the macro @samp{_MIPS_ARCH_R2000}. Note that the @samp{_MIPS_ARCH} macro uses the processor names given -above. In other words, it will have the full prefix and will not +above. In other words, it has the full prefix and does not abbreviate @samp{000} as @samp{k}. In the case of @samp{from-abi}, the macro names the resolved architecture (either @samp{"mips1"} or @samp{"mips3"}). It names the default architecture when no @@ -15351,10 +15370,10 @@ the way instructions are scheduled, and the perceived cost of arithmetic operations. The list of @var{arch} values is the same as for @option{-march}. -When this option is not used, GCC will optimize for the processor +When this option is not used, GCC optimizes for the processor specified by @option{-march}. By using @option{-march} and -@option{-mtune} together, it is possible to generate code that will -run on a family of processors, but optimize the code for one +@option{-mtune} together, it is possible to generate code that +runs on a family of processors, but optimize the code for one particular member of that family. @option{-mtune} defines the macros @samp{_MIPS_TUNE} and @@ -15398,7 +15417,7 @@ Equivalent to @option{-march=mips64r2}. @opindex mips16 @opindex mno-mips16 Generate (do not generate) MIPS16 code. If GCC is targetting a -MIPS32 or MIPS64 architecture, it will make use of the MIPS16e ASE@. +MIPS32 or MIPS64 architecture, it makes use of the MIPS16e ASE@. MIPS16 code generation can also be controlled on a per-function basis by means of @code{mips16} and @code{nomips16} attributes. @@ -15478,7 +15497,7 @@ functions. This mode is selected by @option{-mno-shared}. @option{-mno-shared} depends on binutils 2.16 or higher and generates objects that can only be linked by the GNU linker. However, the option does not affect the ABI of the final executable; it only affects the ABI -of relocatable objects. Using @option{-mno-shared} will generally make +of relocatable objects. Using @option{-mno-shared} generally makes executables both smaller and quicker. @option{-mshared} is the default. @@ -15504,8 +15523,8 @@ Lift (do not lift) the usual restrictions on the size of the global offset table. GCC normally uses a single instruction to load values from the GOT@. -While this is relatively efficient, it will only work if the GOT -is smaller than about 64k. Anything larger will cause the linker +While this is relatively efficient, it only works if the GOT +is smaller than about 64k. Anything larger causes the linker to report an error such as: @cindex relocation truncated to fit (MIPS) @@ -15514,8 +15533,8 @@ relocation truncated to fit: R_MIPS_GOT16 foobar @end smallexample If this happens, you should recompile your code with @option{-mxgot}. -It should then work with very large GOTs, although it will also be -less efficient, since it will take three instructions to fetch the +This works with very large GOTs, although the code is also +less efficient, since it takes three instructions to fetch the value of a global symbol. Note that some linkers can create multiple GOTs. If you have such a @@ -15566,7 +15585,7 @@ operations. This is the default. @opindex mno-llsc Use (do not use) @samp{ll}, @samp{sc}, and @samp{sync} instructions to implement atomic memory built-in functions. When neither option is -specified, GCC will use the instructions if the target architecture +specified, GCC uses the instructions if the target architecture supports them. @option{-mllsc} is useful if the runtime environment can emulate the @@ -15680,8 +15699,8 @@ more room for the main program. @itemx -mno-extern-sdata @opindex mextern-sdata @opindex mno-extern-sdata -Assume (do not assume) that externally-defined data will be in -a small data section if that data is within the @option{-G} limit. +Assume (do not assume) that externally-defined data is in +a small data section if the size of that data is within the @option{-G} limit. @option{-mextern-sdata} is the default for all configurations. If you compile a module @var{Mod} with @option{-mextern-sdata} @option{-G @@ -15713,8 +15732,8 @@ configurations. @option{-mno-gpopt} is useful for cases where the @code{$gp} register might not hold the value of @code{_gp}. For example, if the code is part of a library that might be used in a boot monitor, programs that -call boot monitor routines will pass an unknown value in @code{$gp}. -(In such situations, the boot monitor itself would usually be compiled +call boot monitor routines pass an unknown value in @code{$gp}. +(In such situations, the boot monitor itself is usually compiled with @option{-G0}.) @option{-mno-gpopt} implies @option{-mno-local-sdata} and @@ -15922,7 +15941,7 @@ instructions. These errata are handled by the assembler, not by GCC itself. @opindex mfix-vr4130 Work around the VR4130 @code{mflo}/@code{mfhi} errata. The workarounds are implemented by the assembler rather than by GCC, -although GCC will avoid using @code{mflo} and @code{mfhi} if the +although GCC avoids using @code{mflo} and @code{mfhi} if the VR4130 @code{macc}, @code{macchi}, @code{dmacc} and @code{dmacchi} instructions are available instead. @@ -15941,7 +15960,7 @@ side-effects of speculation on R10K processors. In common with many processors, the R10K tries to predict the outcome of a conditional branch and speculatively executes instructions from the ``taken'' branch. It later aborts these instructions if the -predicted outcome was wrong. However, on the R10K, even aborted +predicted outcome is wrong. However, on the R10K, even aborted instructions can have side effects. This problem only affects kernel stores and, depending on the system, @@ -15949,14 +15968,14 @@ kernel loads. As an example, a speculatively-executed store may load the target memory into cache and mark the cache line as dirty, even if the store itself is later aborted. If a DMA operation writes to the same area of memory before the ``dirty'' line is flushed, the cached -data will overwrite the DMA-ed data. See the R10K processor manual +data overwrites the DMA-ed data. See the R10K processor manual for a full description, including other potential problems. One workaround is to insert cache barrier instructions before every memory access that might be speculatively executed and that might have side effects even if aborted. @option{-mr10k-cache-barrier=@var{setting}} controls GCC's implementation of this workaround. It assumes that -aborted accesses to any byte in the following regions will not have +aborted accesses to any byte in the following regions does not have side effects: @enumerate @@ -16027,14 +16046,15 @@ default for the selected architecture. By default, Branch Likely instructions may be generated if they are supported by the selected architecture. An exception is for the MIPS32 and MIPS64 architectures and processors that implement those architectures; for those, Branch -Likely instructions will not be generated by default because the MIPS32 +Likely instructions are not be generated by default because the MIPS32 and MIPS64 architectures specifically deprecate their use. @item -mfp-exceptions @itemx -mno-fp-exceptions @opindex mfp-exceptions -Specifies whether FP exceptions are enabled. This affects how we schedule -FP instructions for some processors. The default is that FP exceptions are +Specifies whether FP exceptions are enabled. This affects how +FP instructions are scheduled for some processors. +The default is that FP exceptions are enabled. For instance, on the SB-1, if FP exceptions are disabled, and we are emitting @@ -16046,7 +16066,7 @@ FP pipe. @opindex mvr4130-align The VR4130 pipeline is two-way superscalar, but can only issue two instructions together if the first one is 8-byte aligned. When this -option is enabled, GCC will align pairs of instructions that it +option is enabled, GCC aligns pairs of instructions that it thinks should execute in parallel. This option only has an effect when optimizing for the VR4130. @@ -16058,7 +16078,7 @@ It is enabled by default at optimization level @option{-O3}. @opindex msynci Enable (disable) generation of @code{synci} instructions on architectures that support it. The @code{synci} instructions (if -enabled) will be generated when @code{__builtin___clear_cache()} is +enabled) are generated when @code{__builtin___clear_cache()} is compiled. This option defaults to @code{-mno-synci}, but the default can be @@ -16066,7 +16086,7 @@ overridden by configuring with @code{--with-synci}. When compiling code for single processor systems, it is generally safe to use @code{synci}. However, on many multi-core (SMP) systems, it -will not invalidate the instruction caches on all cores and may lead +does not invalidate the instruction caches on all cores and may lead to undefined behavior. @item -mrelax-pic-calls @@ -16236,8 +16256,8 @@ type. The CPU type must be one of @samp{mn10300}, @samp{am33}, @opindex mreturn-pointer-on-d0 When generating a function that returns a pointer, return the pointer in both @code{a0} and @code{d0}. Otherwise, the pointer is returned -only in a0, and attempts to call such functions without a prototype -would result in errors. Note that this option is on by default; use +only in @code{a0}, and attempts to call such functions without a prototype +result in errors. Note that this option is on by default; use @option{-mno-return-pointer-on-d0} to disable it. @item -mno-crt0 @@ -16390,9 +16410,9 @@ parameters for array element type @var{ae_type}. Supported values for @var{ae_type} are @samp{ANY}, @samp{MUL}, and @samp{MAC}. @option{-mae=ANY} selects a completely generic AE type. Code -generated with this option will run on any of the other AE types. The -code will not be as efficient as it would be if compiled for a specific -AE type, and some types of operation (e.g., multiplication) will not +generated with this option runs on any of the other AE types. The +code is not as efficient as it would be if compiled for a specific +AE type, and some types of operation (e.g., multiplication) do not work properly on all types of AE. @option{-mae=MUL} selects a MUL AE type. This is the most useful AE type @@ -16405,7 +16425,7 @@ since the DSP AE does not provide hardware support for byte load/stores. @item -msymbol-as-address Enable the compiler to directly use a symbol name as an address in a load/store instruction, without first loading it into a -register. Typically, the use of this option will generate larger +register. Typically, the use of this option generates larger programs, which run faster than when the option isn't used. However, the results vary from program to program, so it is left as a user option, rather than being permanently enabled. @@ -16416,10 +16436,10 @@ warnings can be generated, for example, when compiling code that performs byte-level memory operations on the MAC AE type. The MAC AE has no hardware support for byte-level memory operations, so all byte load/stores must be synthesized from word load/store operations. This is -inefficient and a warning will be generated indicating to the programmer -that they should rewrite the code to avoid byte operations, or to target -an AE type that has the necessary hardware support. This option enables -the warning to be turned off. +inefficient and a warning is generated to indicate +that you should rewrite the code to avoid byte operations, or to target +an AE type that has the necessary hardware support. This option disables +these warnings. @end table @@ -16576,8 +16596,8 @@ and to treat GPRs as 64-bit, doubleword quantities. GCC defaults to @option{-mno-powerpc64}. If you specify both @option{-mno-power} and @option{-mno-powerpc}, GCC -will use only the instructions in the common subset of both -architectures plus some special AIX common-mode calls, and will not use +uses only the instructions in the common subset of both +architectures plus some special AIX common-mode calls, and does not use the MQ register. Specifying both @option{-mpower} and @option{-mpowerpc} permits GCC to use any instruction from either architecture and to allow use of the MQ register; specify this for the Motorola MPC601. @@ -16616,9 +16636,9 @@ Supported values for @var{cpu_type} are @samp{401}, @samp{403}, @samp{rios1}, @samp{rios2}, @samp{rsc}, and @samp{rs64}. @option{-mcpu=common} selects a completely generic processor. Code -generated under this option will run on any POWER or PowerPC processor. -GCC will use only the instructions in the common subset of both -architectures, and will not use the MQ register. GCC assumes a generic +generated under this option runs on any POWER or PowerPC processor. +GCC uses only the instructions in the common subset of both +architectures, and does not use the MQ register. GCC assumes a generic processor model for scheduling purposes. @option{-mcpu=power}, @option{-mcpu=power2}, @option{-mcpu=powerpc}, and @@ -16628,7 +16648,7 @@ types, with an appropriate, generic processor model assumed for scheduling purposes. The other options specify a specific processor. Code generated under -those options will run best on that processor, and may not run at all on +those options runs best on that processor, and may not run at all on others. The @option{-mcpu} options automatically enable or disable the @@ -16639,7 +16659,7 @@ following options: -mpowerpc-gpopt -mpowerpc-gfxopt -msingle-float -mdouble-float @gol -msimple-fpu -mstring -mmulhw -mdlmzb -mmfpgpr -mvsx} -The particular options set for any particular CPU will vary between +The particular options set for any particular CPU varies between compiler versions, depending on what setting seems to produce optimal code for that CPU; it doesn't necessarily reflect the actual hardware's capabilities. If you wish to set an individual option to a particular @@ -16656,9 +16676,9 @@ environment. @opindex mtune Set the instruction scheduling parameters for machine type @var{cpu_type}, but do not set the architecture type, register usage, or -choice of mnemonics, as @option{-mcpu=@var{cpu_type}} would. The same +choice of mnemonics, as @option{-mcpu=@var{cpu_type}} does. The same values for @var{cpu_type} are used for @option{-mtune} as for -@option{-mcpu}. If both are specified, the code generated will use the +@option{-mcpu}. If both are specified, the code generated uses the architecture, registers, and mnemonics set by @option{-mcpu}, but the scheduling parameters set by @option{-mtune}. @@ -16794,9 +16814,9 @@ pointer to 64 bits, and generates code for PowerPC64, as for @opindex mminimal-toc Modify generation of the TOC (Table Of Contents), which is created for every executable file. The @option{-mfull-toc} option is selected by -default. In that case, GCC will allocate at least one TOC entry for +default. In that case, GCC allocates at least one TOC entry for each unique non-automatic variable reference in your program. GCC -will also place floating-point constants in the TOC@. However, only +also places floating-point constants in the TOC@. However, only 16,384 entries are available in the TOC@. If you receive a linker error message that saying you have overflowed @@ -16812,9 +16832,9 @@ slower and larger code at the expense of conserving TOC space. If you still run out of space in the TOC even when you specify both of these options, specify @option{-mminimal-toc} instead. This option causes GCC to make only one TOC entry for every file. When you specify this -option, GCC will produce code that is slower and larger but which +option, GCC produces code that is slower and larger but which uses extremely little TOC space. You may wish to use this option -only on files that contain less frequently executed code. +only on files that contain less frequently-executed code. @item -maix64 @itemx -maix32 @@ -16998,7 +17018,7 @@ size. @opindex mno-strict-align @opindex mstrict-align On System V.4 and embedded PowerPC systems do not (do) assume that -unaligned memory references will be handled by the system. +unaligned memory references are handled by the system. @item -mrelocatable @itemx -mno-relocatable @@ -17097,7 +17117,7 @@ Any dependence for which the latency is greater than or equal to @item -minsert-sched-nops=@var{scheme} @opindex minsert-sched-nops -This option controls which NOP insertion scheme will be used during +This option controls which NOP insertion scheme is used during the second scheduling pass. The argument @var{scheme} takes one of the following values: @@ -17204,10 +17224,10 @@ On System V.4 and embedded PowerPC systems assume that all calls to variable argument functions are properly prototyped. Otherwise, the compiler must insert an instruction before every non prototyped call to set or clear bit 6 of the condition code register (@var{CR}) to -indicate whether floating-point values were passed in the floating-point +indicate whether floating-point values are passed in the floating-point registers in case the function takes variable arguments. With @option{-mprototype}, only calls to prototyped variable argument functions -will set or clear the bit. +set or clear the bit. @item -msim @opindex msim @@ -17257,7 +17277,7 @@ environment, and the @option{-msdata} option can use both @code{r2} and @code{r13} to point to two separate small data areas. Selecting @option{-mno-eabi} means that the stack is aligned to a 16-byte boundary, do not call an initialization function from @code{main}, and the -@option{-msdata} option will only use @code{r13} to point to a single +@option{-msdata} option only uses @code{r13} to point to a single small data area. The @option{-meabi} option is on by default if you configured GCC using one of the @samp{powerpc*-*-eabi*} options. @@ -17337,7 +17357,7 @@ names in the assembly language output using symbolic forms. By default assume that all calls are far away so that a longer more expensive calling sequence is required. This is required for calls further than 32 megabytes (33,554,432 bytes) from the current location. -A short call will be generated if the compiler knows +A short call is generated if the compiler knows the call cannot be that far away. This setting can be overridden by the @code{shortcall} function attribute, or by @code{#pragma longcall(0)}. @@ -17348,12 +17368,12 @@ generate slower code. As of this writing, the AIX linker can do this, as can the GNU linker for PowerPC/64. It is planned to add this feature to the GNU linker for 32-bit PowerPC systems as well. -On Darwin/PPC systems, @code{#pragma longcall} will generate @code{jbsr +On Darwin/PPC systems, @code{#pragma longcall} generates @code{jbsr callee, L42}, plus a @dfn{branch island} (glue code). The two target addresses represent the callee and the branch island. The -Darwin/PPC linker will prefer the first address and generate a @code{bl -callee} if the PPC @code{bl} instruction will reach the callee directly; -otherwise, the linker will generate @code{bl L42} to call the branch +Darwin/PPC linker prefers the first address and generates a @code{bl +callee} if the PPC @code{bl} instruction reaches the callee directly; +otherwise, the linker generates @code{bl L42} to call the branch island. The branch island is appended to the body of the calling function; it computes the full 32-bit address of the callee and jumps to it. @@ -17362,7 +17382,7 @@ On Mach-O (Darwin) systems, this option directs the compiler emit to the glue for every direct call, and the Darwin linker decides whether to use or discard it. -In the future, we may cause GCC to ignore all longcall specifications +In the future, GCC may ignore all longcall specifications when the linker is known to generate glue. @item -mtls-markers @@ -17383,7 +17403,7 @@ This option sets flags for both the preprocessor and linker. @item -mrecip @itemx -mno-recip @opindex mrecip -This option will enable GCC to use the reciprocal estimate and +This option enables use of the reciprocal estimate and reciprocal square root estimate instructions with additional Newton-Raphson steps to increase precision instead of doing a divide or square root and divide for floating-point arguments. You should use @@ -17411,7 +17431,7 @@ be preceded by a @code{!} to invert the option: @code{rsqrtf}: enable the single-precision reciprocal square root approximation instructions; @code{rsqrtd}: enable the double-precision reciprocal square root approximation instructions; -So for example, @option{-mrecip=all,!rsqrtd} would enable the +So, for example, @option{-mrecip=all,!rsqrtd} enables all of the reciprocal estimate instructions, except for the @code{FRSQRTE}, @code{XSRSQRTEDP}, and @code{XVRSQRTEDP} instructions which handle the double-precision reciprocal square root calculations. @@ -17433,7 +17453,7 @@ Specifies the ABI type to use for vectorizing intrinsics using an external library. The only type supported at present is @code{mass}, which specifies to use IBM's Mathematical Acceleration Subsystem (MASS) libraries for vectorizing intrinsics using external libraries. -GCC will currently emit calls to @code{acosd2}, @code{acosf4}, +GCC currently emits calls to @code{acosd2}, @code{acosf4}, @code{acoshd2}, @code{acoshf4}, @code{asind2}, @code{asinf4}, @code{asinhd2}, @code{asinhf4}, @code{atan2d2}, @code{atan2f4}, @code{atand2}, @code{atanf4}, @code{atanhd2}, @code{atanhf4}, @@ -17448,8 +17468,8 @@ GCC will currently emit calls to @code{acosd2}, @code{acosf4}, @code{sinhf4}, @code{sqrtd2}, @code{sqrtf4}, @code{tand2}, @code{tanf4}, @code{tanhd2}, and @code{tanhf4} when generating code for power7. Both @option{-ftree-vectorize} and -@option{-funsafe-math-optimizations} have to be enabled. The MASS -libraries will have to be specified at link time. +@option{-funsafe-math-optimizations} must also be enabled. The MASS +libraries must be specified at link time. @item -mfriz @itemx -mno-friz @@ -17468,8 +17488,8 @@ Generate (do not generate) code to load up the static chain register systems where a function pointer points to a 3-word descriptor giving the function address, TOC value to be loaded in register @var{r2}, and static chain value to be loaded in register @var{r11}. The -@option{-mpointers-to-nested-functions} is on by default. You will -not be able to call through pointers to nested functions or pointers +@option{-mpointers-to-nested-functions} is on by default. You cannot +call through pointers to nested functions or pointers to functions compiled in other languages that use the static chain if you use the @option{-mno-pointers-to-nested-functions}. @@ -17508,9 +17528,9 @@ Enables (@option{-fpu}) or disables (@option{-nofpu}) the use of RX floating-point hardware. The default is enabled for the @var{RX600} series and disabled for the @var{RX200} series. -Floating-point instructions will only be generated for 32-bit floating-point -values however, so if the @option{-m64bit-doubles} option is in -use then the FPU hardware will not be used for doubles. +Floating-point instructions are only generated for 32-bit floating-point +values, however, so the FPU hardware is not used for doubles if the +@option{-m64bit-doubles} option is used. @emph{Note} If the @option{-fpu} option is enabled then @option{-funsafe-math-optimizations} is also enabled automatically. @@ -17546,9 +17566,8 @@ limited and it is up to the programmer to ensure that the area does not overflow. Also when the small data area is used one of the RX's registers (usually @code{r13}) is reserved for use pointing to this area, so it is no longer available for use by the compiler. This -could result in slower and/or larger code if variables which once -could have been held in the reserved register are now pushed onto the -stack. +could result in slower and/or larger code if variables are pushed onto +the stack instead of being held in this register. Note, common variables (variables that have not been initialized) and constants are not placed into the small data area as they are assigned @@ -17594,14 +17613,14 @@ or 4 means that constants of any size are allowed. @item -mrelax @opindex mrelax Enable linker relaxation. Linker relaxation is a process whereby the -linker will attempt to reduce the size of a program by finding shorter +linker attempts to reduce the size of a program by finding shorter versions of various instructions. Disabled by default. @item -mint-register=@var{N} @opindex mint-register Specify the number of registers to reserve for fast interrupt handler functions. The value @var{N} can be between 0 and 4. A value of 1 -means that register @code{r13} will be reserved for the exclusive use +means that register @code{r13} is reserved for the exclusive use of fast interrupt handlers. A value of 2 reserves @code{r13} and @code{r12}. A value of 3 reserves @code{r13}, @code{r12} and @code{r11}, and a value of 4 reserves @code{r13} through @code{r10}. @@ -17620,7 +17639,7 @@ makes the interrupt handlers faster. @opindex mpid @opindex mno-pid Enables the generation of position independent data. When enabled any -access to constant data will done via an offset from a base address +access to constant data is done via an offset from a base address held in a register. This allows the location of constant data to be determined at run time without requiring the executable to be relocated, which is a benefit to embedded applications with tight @@ -17649,7 +17668,7 @@ via the @option{-mno-pid} command-line option. @emph{Note:} The generic GCC command-line option @option{-ffixed-@var{reg}} has special significance to the RX port when used with the @code{interrupt} function attribute. This attribute indicates a -function intended to process fast interrupts. GCC will will ensure +function intended to process fast interrupts. GCC ensures that it only uses the registers @code{r10}, @code{r11}, @code{r12} and/or @code{r13} and only provided that the normal use of the corresponding registers have been restricted via the @@ -17669,7 +17688,7 @@ These are the @samp{-m} options defined for the S/390 and zSeries architecture. @opindex msoft-float Use (do not use) the hardware floating-point instructions and registers for floating-point operations. When @option{-msoft-float} is specified, -functions in @file{libgcc.a} will be used to perform floating-point +functions in @file{libgcc.a} are used to perform floating-point operations. When @option{-mhard-float} is specified, the compiler generates IEEE floating-point instructions. This is the default. @@ -17679,7 +17698,7 @@ generates IEEE floating-point instructions. This is the default. @opindex mno-hard-dfp Use (do not use) the hardware decimal-floating-point instructions for decimal-floating-point operations. When @option{-mno-hard-dfp} is -specified, functions in @file{libgcc.a} will be used to perform +specified, functions in @file{libgcc.a} are used to perform decimal-floating-point operations. When @option{-mhard-dfp} is specified, the compiler generates decimal-floating-point hardware instructions. This is the default for @option{-march=z9-ec} or higher. @@ -17792,7 +17811,7 @@ The default is to not print debug information. @item -march=@var{cpu-type} @opindex march -Generate code that will run on @var{cpu-type}, which is the name of a system +Generate code that runs on @var{cpu-type}, which is the name of a system representing a certain processor type. Possible values for @var{cpu-type} are @samp{g5}, @samp{g6}, @samp{z900}, @samp{z990}, @samp{z9-109}, @samp{z9-ec} and @samp{z10}. @@ -17998,7 +18017,7 @@ Compile code for the processor in little-endian mode. @item -mdalign @opindex mdalign Align doubles at 64-bit boundaries. Note that this changes the calling -conventions, and thus some functions from the standard C library will +conventions, and thus some functions from the standard C library do not work unless you recompile it first with @option{-mdalign}. @item -mrelax @@ -18056,10 +18075,10 @@ This option has no effect if @option{-musermode} is in effect and the selected code generation option (e.g. @option{-m4}) does not allow the use of the @code{icbi} instruction. If the selected code generation option does not allow the use of the @code{icbi} -instruction, and @option{-musermode} is not in effect, the inlined code will -manipulate the instruction cache address array directly with an associative -write. This not only requires privileged mode, but it will also -fail if the cache line had been mapped via the TLB and has become unmapped. +instruction, and @option{-musermode} is not in effect, the inlined code +manipulates the instruction cache address array directly with an associative +write. This not only requires privileged mode at run time, but it also +fails if the cache line had been mapped via the TLB and has become unmapped. @item -misize @opindex misize @@ -18161,7 +18180,7 @@ in that case. @item inv20u @itemx inv20l Variants of the @samp{inv:minlat} strategy. In the case -that the inverse calculation was not separated from the multiply, they speed +that the inverse calculation is not separated from the multiply, they speed up division where the dividend fits into 20 bits (plus sign where applicable) by inserting a test to skip a number of operations in this case; this test slows down the case of larger dividends. @samp{inv20u} assumes the case of a such @@ -18245,7 +18264,7 @@ of symbol loads. The default is @option{-mno-invalid-symbols}. @item -mbranch-cost=@var{num} @opindex mbranch-cost=@var{num} Assume @var{num} to be the cost for a branch instruction. Higher numbers -will make the compiler try to generate more branch-free code if possible. +make the compiler try to generate more branch-free code if possible. If not specified the value is selected depending on the processor type that is being compiled for. @@ -18288,7 +18307,7 @@ code into a shared object. @option{-mimpure-text} suppresses the ``relocations remain against allocatable but non-writable sections'' linker error message. -However, the necessary relocations will trigger copy-on-write, and the +However, the necessary relocations trigger copy-on-write, and the shared object is not actually shared across processes. Instead of using @option{-mimpure-text}, you should compile all source code with @option{-fpic} or @option{-fPIC}. @@ -18336,7 +18355,7 @@ software with this option. With @option{-mflat}, the compiler does not generate save/restore instructions and uses a ``flat'' or single register window model. This model is compatible with the regular register window model. The local registers and the input -registers (0--5) are still treated as ``call-saved'' registers and will be +registers (0--5) are still treated as ``call-saved'' registers and are saved on the stack as needed. With @option{-mno-flat} (the default), the compiler generates save/restore @@ -18408,7 +18427,7 @@ should have 8-byte alignment. This enables the use of pairs of assignment, in place of twice as many @code{ld} and @code{st} pairs. However, the use of this changed alignment directly violates the SPARC ABI@. Thus, it's intended only for use on targets where the developer -acknowledges that their resulting code will not be directly in line with +acknowledges that their resulting code is not directly in line with the rules of the ABI@. @item -mcpu=@var{cpu_type} @@ -18495,7 +18514,7 @@ additionally optimizes it for Sun UltraSPARC T4 chips. @opindex mtune Set the instruction scheduling parameters for machine type @var{cpu_type}, but do not set the instruction set or register set that the -option @option{-mcpu=@var{cpu_type}} would. +option @option{-mcpu=@var{cpu_type}} does. The same values for @option{-mcpu=@var{cpu_type}} can be used for @option{-mtune=@var{cpu_type}}, but the only useful values are those @@ -18660,9 +18679,9 @@ These @samp{-m} options are supported on the SPU: @opindex merror-reloc The loader for SPU does not handle dynamic relocations. By default, GCC -will give an error when it generates code that requires a dynamic +gives an error when it generates code that requires a dynamic relocation. @option{-mno-error-reloc} disables the error, -@option{-mwarn-reloc} will generate a warning instead. +@option{-mwarn-reloc} generates a warning instead. @item -msafe-dma @itemx -munsafe-dma @@ -18681,9 +18700,9 @@ the DMA instructions as potentially affecting all memory. @item -mbranch-hints @opindex mbranch-hints -By default, GCC will generate a branch hint instruction to avoid -pipeline stalls for always taken or probably taken branches. A hint -will not be generated closer than 8 instructions away from its branch. +By default, GCC generates a branch hint instruction to avoid +pipeline stalls for always-taken or probably-taken branches. A hint +is not generated closer than 8 instructions away from its branch. There is little reason to disable them, except for debugging purposes, or to make an object a little bit smaller. @@ -18701,7 +18720,7 @@ a full 32-bit address. By default, GCC links against startup code that assumes the SPU-style main function interface (which has an unconventional parameter list). -With @option{-mstdmain}, GCC will link your program against startup +With @option{-mstdmain}, GCC links your program against startup code that assumes a C99-style interface to @code{main}, including a local copy of @code{argv} strings. @@ -18748,36 +18767,36 @@ This option controls the version of libgcc that the compiler links to an executable and selects whether atomic updates to the software-managed cache of PPU-side variables are used. If you use atomic updates, changes to a PPU variable from SPU code using the @code{__ea} named address space -qualifier will not interfere with changes to other PPU variables residing +qualifier do not interfere with changes to other PPU variables residing in the same cache line from PPU code. If you do not use atomic updates, -such interference may occur; however, writing back cache lines will be +such interference may occur; however, writing back cache lines is more efficient. The default behavior is to use atomic updates. @item -mdual-nops @itemx -mdual-nops=@var{n} @opindex mdual-nops -By default, GCC will insert nops to increase dual issue when it expects +By default, GCC inserts nops to increase dual issue when it expects it to increase performance. @var{n} can be a value from 0 to 10. A -smaller @var{n} will insert fewer nops. 10 is the default, 0 is the +smaller @var{n} inserts fewer nops. 10 is the default, 0 is the same as @option{-mno-dual-nops}. Disabled with @option{-Os}. @item -mhint-max-nops=@var{n} @opindex mhint-max-nops Maximum number of nops to insert for a branch hint. A branch hint must -be at least 8 instructions away from the branch it is effecting. GCC -will insert up to @var{n} nops to enforce this, otherwise it will not +be at least 8 instructions away from the branch it is affecting. GCC +inserts up to @var{n} nops to enforce this, otherwise it does not generate the branch hint. @item -mhint-max-distance=@var{n} @opindex mhint-max-distance The encoding of the branch hint instruction limits the hint to be within -256 instructions of the branch it is effecting. By default, GCC makes +256 instructions of the branch it is affecting. By default, GCC makes sure it is within 125. @item -msafe-hints @opindex msafe-hints Work around a hardware bug that causes the SPU to stall indefinitely. -By default, GCC will insert the @code{hbrp} instruction to make sure +By default, GCC inserts the @code{hbrp} instruction to make sure this stall won't happen. @end table @@ -18869,8 +18888,8 @@ These @samp{-m} options are defined for V850 implementations: @opindex mlong-calls @opindex mno-long-calls Treat all calls as being far away (near). If calls are assumed to be -far away, the compiler will always load the functions address up into a -register, and call indirect through the pointer. +far away, the compiler always loads the function's address into a +register, and calls indirect through the pointer. @item -mno-ep @itemx -mep @@ -18925,28 +18944,28 @@ table. @item -mapp-regs @opindex mapp-regs -This option will cause r2 and r5 to be used in the code generated by +This option causes r2 and r5 to be used in the code generated by the compiler. This setting is the default. @item -mno-app-regs @opindex mno-app-regs -This option will cause r2 and r5 to be treated as fixed registers. +This option causes r2 and r5 to be treated as fixed registers. @item -mv850e2v3 @opindex mv850e2v3 Specify that the target processor is the V850E2V3. The preprocessor -constants @samp{__v850e2v3__} will be defined if +constant @samp{__v850e2v3__} is defined if this option is used. @item -mv850e2 @opindex mv850e2 Specify that the target processor is the V850E2. The preprocessor -constants @samp{__v850e2__} will be defined if this option is used. +constant @samp{__v850e2__} is defined if this option is used. @item -mv850e1 @opindex mv850e1 Specify that the target processor is the V850E1. The preprocessor -constants @samp{__v850e1__} and @samp{__v850e__} will be defined if +constants @samp{__v850e1__} and @samp{__v850e__} are defined if this option is used. @item -mv850es @@ -18957,21 +18976,21 @@ the @option{-mv850e1} option. @item -mv850e @opindex mv850e Specify that the target processor is the V850E@. The preprocessor -constant @samp{__v850e__} will be defined if this option is used. +constant @samp{__v850e__} is defined if this option is used. If neither @option{-mv850} nor @option{-mv850e} nor @option{-mv850e1} nor @option{-mv850e2} nor @option{-mv850e2v3} -are defined then a default target processor will be chosen and the -relevant @samp{__v850*__} preprocessor constant will be defined. +are defined then a default target processor is chosen and the +relevant @samp{__v850*__} preprocessor constant is defined. The preprocessor constants @samp{__v850} and @samp{__v851__} are always defined, regardless of which processor variant is the target. @item -mdisable-callt @opindex mdisable-callt -This option will suppress generation of the CALLT instruction for the +This option suppresses generation of the @code{CALLT} instruction for the v850e, v850e1, v850e2 and v850e2v3 flavors of the v850 architecture. The default is -@option{-mno-disable-callt} which allows the CALLT instruction to be used. +@option{-mno-disable-callt} which allows the @code{CALLT} instruction to be used. @end table @@ -18990,8 +19009,8 @@ ranges. @item -mgnu @opindex mgnu -Do output those jump instructions, on the assumption that you -will assemble with the GNU assembler. +Do output those jump instructions, on the assumption that the +GNU assembler is being used. @item -mg @opindex mg @@ -19157,11 +19176,11 @@ automatically align instructions to reduce branch penalties at the expense of some code density. The assembler attempts to widen density instructions to align branch targets and the instructions following call instructions. If there are not enough preceding safe density -instructions to align a target, no widening will be performed. The +instructions to align a target, no widening is performed. The default is @option{-mtarget-align}. These options do not affect the treatment of auto-aligned instructions like @code{LOOP}, which the -assembler will always align, either by widening density instructions or -by inserting no-op instructions. +assembler always aligns, either by widening density instructions or +by inserting NOP instructions. @item -mlongcalls @itemx -mno-longcalls @@ -19176,10 +19195,10 @@ instruction into an @code{L32R} followed by a @code{CALLX} instruction. The default is @option{-mno-longcalls}. This option should be used in programs where the call target can potentially be out of range. This option is implemented in the assembler, not the compiler, so the -assembly code generated by GCC will still show direct call +assembly code generated by GCC still shows direct call instructions---look at the disassembled object code to see the actual -instructions. Note that the assembler will use an indirect call for -every cross-file call, not just those that really will be out of range. +instructions. Note that the assembler uses an indirect call for +every cross-file call, not just those that really are out of range. @end table @node zSeries Options @@ -19198,7 +19217,7 @@ These machine-independent options control the interface conventions used in code generation. Most of them have both positive and negative forms; the negative form -of @option{-ffoo} would be @option{-fno-foo}. In the table below, only +of @option{-ffoo} is @option{-fno-foo}. In the table below, only one of the forms is listed---the one that is not the default. You can figure out the other form by either removing @samp{no-} or adding it. @@ -19227,11 +19246,11 @@ front end, as required by the Java language specification. @item -fexceptions @opindex fexceptions Enable exception handling. Generates extra code needed to propagate -exceptions. For some targets, this implies GCC will generate frame +exceptions. For some targets, this implies GCC generates frame unwind information for all functions, which can produce significant data size overhead, although it does not affect execution. If you do not -specify this option, GCC will enable it by default for languages like -C++ that normally require exception handling, and disable it for +specify this option, GCC enables it by default for languages like +C++ that normally require exception handling, and disables it for languages like C that do not normally require it. However, you may need to enable this option when compiling C code that needs to interoperate properly with exception handlers written in C++. You may also wish to @@ -19249,10 +19268,10 @@ arbitrary signal handlers such as @code{SIGALRM}. @item -funwind-tables @opindex funwind-tables -Similar to @option{-fexceptions}, except that it will just generate any needed -static data, but will not affect the generated code in any other way. -You will normally not enable this option; instead, a language processor -that needs this handling would enable it on your behalf. +Similar to @option{-fexceptions}, except that it just generates any needed +static data, but does not affect the generated code in any other way. +You normally do not need to enable this option; instead, a language processor +that needs this handling enables it on your behalf. @item -fasynchronous-unwind-tables @opindex fasynchronous-unwind-tables @@ -19301,7 +19320,7 @@ Use it to conform to a non-default application binary interface. @opindex fshort-enums Allocate to an @code{enum} type only as many bytes as it needs for the declared range of possible values. Specifically, the @code{enum} type -will be equivalent to the smallest integer type that has enough room. +is equivalent to the smallest integer type that has enough room. @strong{Warning:} the @option{-fshort-enums} switch causes GCC to generate code that is not binary compatible with code generated without that switch. @@ -19340,7 +19359,7 @@ uninitialized global variables in the data section of the object file, rather than generating them as common blocks. This has the effect that if the same variable is declared (without @code{extern}) in two different compilations, -you will get a multiple-definition error when you link them. +you get a multiple-definition error when you link them. In this case, you must compile with @option{-fcommon} instead. Compiling with @option{-fno-common} is useful on targets for which it provides better performance, or if you wish to verify that the @@ -19372,7 +19391,7 @@ files. @item -frecord-gcc-switches @opindex frecord-gcc-switches -This switch causes the command line that was used to invoke the +This switch causes the command line used to invoke the compiler to be recorded into the object file that is being created. This switch is only implemented on some targets and the exact format of the recording is target and binary file format dependent, but it @@ -19425,7 +19444,7 @@ are defined to 2. @opindex fPIE These options are similar to @option{-fpic} and @option{-fPIC}, but generated position independent code can be only linked into executables. -Usually these options are used when @option{-pie} GCC option will be +Usually these options are used when @option{-pie} GCC option is used during linking. @option{-fpie} and @option{-fPIE} both define the macros @@ -19459,11 +19478,11 @@ three-way choice. Treat the register named @var{reg} as an allocable register that is clobbered by function calls. It may be allocated for temporaries or variables that do not live across a call. Functions compiled this way -will not save and restore the register @var{reg}. +do not save and restore the register @var{reg}. -It is an error to used this flag with the frame pointer or stack pointer. +It is an error to use this flag with the frame pointer or stack pointer. Use of this flag for other registers that have fixed pervasive roles in -the machine's execution model will produce disastrous results. +the machine's execution model produces disastrous results. This flag does not have a negative form, because it specifies a three-way choice. @@ -19472,14 +19491,14 @@ three-way choice. @opindex fcall-saved Treat the register named @var{reg} as an allocable register saved by functions. It may be allocated even for temporaries or variables that -live across a call. Functions compiled this way will save and restore +live across a call. Functions compiled this way save and restore the register @var{reg} if they use it. -It is an error to used this flag with the frame pointer or stack pointer. +It is an error to use this flag with the frame pointer or stack pointer. Use of this flag for other registers that have fixed pervasive roles in -the machine's execution model will produce disastrous results. +the machine's execution model produces disastrous results. -A different sort of disaster will result from the use of this flag for +A different sort of disaster results from the use of this flag for a register in which function values may be returned. This flag does not have a negative form, because it specifies a @@ -19491,7 +19510,7 @@ Without a value specified, pack all structure members together without holes. When a value is specified (which must be a small power of two), pack structure members according to this value, representing the maximum alignment (that is, objects with default alignment requirements larger than -this will be output potentially unaligned at the next fitting location. +this are output potentially unaligned at the next fitting location. @strong{Warning:} the @option{-fpack-struct} switch causes GCC to generate code that is not binary compatible with code generated without that switch. @@ -19502,7 +19521,7 @@ Use it to conform to a non-default application binary interface. @opindex finstrument-functions Generate instrumentation calls for entry and exit to functions. Just after function entry and just before function exit, the following -profiling functions will be called with the address of the current +profiling functions are called with the address of the current function and its call site. (On some platforms, @code{__builtin_return_address} does not work beyond the current function, so the call site information may not be available to the @@ -19519,18 +19538,18 @@ The first argument is the address of the start of the current function, which may be looked up exactly in the symbol table. This instrumentation is also done for functions expanded inline in other -functions. The profiling calls will indicate where, conceptually, the +functions. The profiling calls indicate where, conceptually, the inline function is entered and exited. This means that addressable versions of such functions must be available. If all your uses of a function are expanded inline, this may mean an additional expansion of code size. If you use @samp{extern inline} in your C code, an addressable version of such functions must be provided. (This is -normally the case anyways, but if you get lucky and the optimizer always +normally the case anyway, but if you get lucky and the optimizer always expands the functions inline, you might have gotten away without providing static copies.) A function may be given the attribute @code{no_instrument_function}, in -which case this instrumentation will not be done. This can be used, for +which case this instrumentation is not done. This can be used, for example, for the profiling functions listed above, high-priority interrupt routines, and any functions from which the profiling functions cannot safely be called (perhaps signal handlers, if the profiling @@ -19553,7 +19572,7 @@ For example: @end smallexample @noindent -will exclude any inline function defined in files whose pathnames +excludes any inline function defined in files whose pathnames contain @code{/bits/stl} or @code{include/sys}. If, for some reason, you want to include letter @code{','} in one of @@ -19596,7 +19615,7 @@ target support in the compiler but comes with the following drawbacks: @enumerate @item -Modified allocation strategy for large objects: they will always be +Modified allocation strategy for large objects: they are always allocated dynamically if their size exceeds a fixed threshold. @item @@ -19619,8 +19638,8 @@ Note that old-style stack checking is also the fallback method for @opindex fstack-limit-symbol @opindex fno-stack-limit Generate code to ensure that the stack does not grow beyond a certain value, -either the value of a register or the address of a symbol. If the stack -would grow beyond the value, a signal is raised. For most targets, +either the value of a register or the address of a symbol. If a larger +stack is required, a signal is raised at run time. For most targets, the signal is raised before the stack overruns the boundary, so it is possible to catch the signal without taking special precautions. @@ -19672,7 +19691,7 @@ The default without @option{-fpic} is @code{initial-exec}; with @item -fvisibility=@var{default|internal|hidden|protected} @opindex fvisibility Set the default ELF image symbol visibility to the specified option---all -symbols will be marked with this unless overridden within the code. +symbols are marked with this unless overridden within the code. Using this feature can very substantially improve linking and load times of shared object libraries, produce more optimized code, provide near-perfect API export and prevent symbol clashes. @@ -19682,7 +19701,7 @@ you distribute. Despite the nomenclature, @code{default} always means public; i.e., available to be linked against from outside the shared object. @code{protected} and @code{internal} are pretty useless in real-world -usage so the only other commonly used option will be @code{hidden}. +usage so the only other commonly used option is @code{hidden}. The default if @option{-fvisibility} isn't specified is @code{default}, i.e., make every symbol public---this causes the same behavior as previous versions of @@ -19723,15 +19742,15 @@ before including any such headers. @samp{extern} declarations are not affected by @option{-fvisibility}, so a lot of code can be recompiled with @option{-fvisibility=hidden} with no modifications. However, this means that calls to @code{extern} -functions with no explicit visibility will use the PLT, so it is more +functions with no explicit visibility use the PLT, so it is more effective to use @code{__attribute ((visibility))} and/or @code{#pragma GCC visibility} to tell the compiler which @code{extern} declarations should be treated as hidden. Note that @option{-fvisibility} does affect C++ vague linkage -entities. This means that, for instance, an exception class that will +entities. This means that, for instance, an exception class that is be thrown between DSOs must be explicitly marked with default -visibility so that the @samp{type_info} nodes will be unified between +visibility so that the @samp{type_info} nodes are unified between the DSOs. An overview of these techniques, their benefits and how to use them @@ -19749,9 +19768,9 @@ declare all peripheral bit-fields as @code{unsigned short} (assuming short is 16 bits on these targets) to force GCC to use 16-bit accesses instead of, perhaps, a more efficient 32-bit access. -If this option is disabled, the compiler will use the most efficient +If this option is disabled, the compiler uses the most efficient instruction. In the previous example, that might be a 32-bit load -instruction, even though that will access bytes that do not contain +instruction, even though that accesses bytes that do not contain any portion of the bit-field, or memory-mapped registers unrelated to the one being updated. @@ -19816,7 +19835,7 @@ Kingdom encoded in UTF-8. The @env{LC_CTYPE} environment variable specifies character classification. GCC uses it to determine the character boundaries in a string; this is needed for some multibyte encodings that contain quote -and escape characters that would otherwise be interpreted as a string +and escape characters that are otherwise interpreted as a string end or escape. The @env{LC_MESSAGES} environment variable specifies the language to @@ -19849,8 +19868,8 @@ names of the subprograms executed by the compiler. No slash is added when this prefix is combined with the name of a subprogram, but you can specify a prefix that ends with a slash if you wish. -If @env{GCC_EXEC_PREFIX} is not set, GCC will attempt to figure out -an appropriate prefix to use based on the pathname it was invoked with. +If @env{GCC_EXEC_PREFIX} is not set, GCC attempts to figure out +an appropriate prefix to use based on the pathname it is invoked with. If GCC cannot find the subprogram using the specified prefix, it tries looking in the usual places for the subprogram. @@ -19870,10 +19889,10 @@ directories to search for header files. For each of the standard directories whose name normally begins with @samp{/usr/local/lib/gcc} (more precisely, with the value of @env{GCC_INCLUDE_DIR}), GCC tries replacing that beginning with the specified prefix to produce an -alternate directory name. Thus, with @option{-Bfoo/}, GCC will search -@file{foo/bar} where it would normally search @file{/usr/local/lib/bar}. -These alternate directories are searched first; the standard directories -come next. If a standard directory begins with the configured +alternate directory name. Thus, with @option{-Bfoo/}, GCC searches +@file{foo/bar} just before it searches the standard directory +@file{/usr/local/lib/bar}. +If a standard directory begins with the configured @var{prefix} then the value of @var{prefix} is replaced by @env{GCC_EXEC_PREFIX} when looking for header files. @@ -19913,12 +19932,12 @@ Recognize EUCJP characters. @end table If @env{LANG} is not defined, or if it has some other value, then the -compiler will use mblen and mbtowc as defined by the default locale to +compiler uses @code{mblen} and @code{mbtowc} as defined by the default locale to recognize and translate multibyte characters. @end table @noindent -Some additional environments variables affect the behavior of the +Some additional environment variables affect the behavior of the preprocessor. @include cppenv.texi @@ -19933,17 +19952,16 @@ preprocessor. Often large projects have many header files that are included in every source file. The time the compiler takes to process these header files over and over again can account for nearly all of the time required to -build the project. To make builds faster, GCC allows users to -@dfn{precompile} a header file; then, if builds can use the precompiled -header file they will be much faster. +build the project. To make builds faster, GCC allows you to +@dfn{precompile} a header file. To create a precompiled header file, simply compile it as you would any other file, if necessary using the @option{-x} option to make the driver -treat it as a C or C++ header file. You will probably want to use a +treat it as a C or C++ header file. You may want to use a tool like @command{make} to keep the precompiled header up-to-date when the headers it contains change. -A precompiled header file will be searched for when @code{#include} is +A precompiled header file is searched for when @code{#include} is seen in the compilation. As it searches for the included file (@pxref{Search Path,,Search Path,cpp,The C Preprocessor}) the compiler looks for a precompiled header in each directory just before it @@ -19953,8 +19971,8 @@ the precompiled header file can't be used, it is ignored. For instance, if you have @code{#include "all.h"}, and you have @file{all.h.gch} in the same directory as @file{all.h}, then the -precompiled header file will be used if possible, and the original -header will be used otherwise. +precompiled header file is used if possible, and the original +header is used otherwise. Alternatively, you might decide to put the precompiled header file in a directory and use @option{-I} to ensure that directory is searched @@ -19968,17 +19986,17 @@ precompiled headers, good for projects not designed with precompiled header files in mind, is to simply take most of the header files used by a project, include them from another header file, precompile that header file, and @option{-include} the precompiled header. If the header files -have guards against multiple inclusion, they will be skipped because +have guards against multiple inclusion, they are skipped because they've already been included (in the precompiled header). If you need to precompile the same header file for different languages, targets, or compiler options, you can instead make a @emph{directory} named like @file{all.h.gch}, and put each precompiled header in the directory, perhaps using @option{-o}. It doesn't matter -what you call the files in the directory, every precompiled header in -the directory will be considered. The first precompiled header -encountered in the directory that is valid for this compilation will -be used; they're searched in no particular order. +what you call the files in the directory; every precompiled header in +the directory is considered. The first precompiled header +encountered in the directory that is valid for this compilation is +used; they're searched in no particular order. There are many other possibilities, limited only by your imagination, good sense, and the constraints of your build system. @@ -20045,14 +20063,14 @@ precompiled header. The following are known to be safe: @end itemize -For all of these except the last, the compiler will automatically -ignore the precompiled header if the conditions aren't met. If you +For all of these except the last, the compiler automatically +ignores the precompiled header if the conditions aren't met. If you find an option combination that doesn't work and doesn't cause the precompiled header to be ignored, please consider filing a bug report, see @ref{Bugs}. If you do use differing options when generating and using the -precompiled header, the actual behavior will be a mixture of the +precompiled header, the actual behavior is a mixture of the behavior for the options. For instance, if you use @option{-g} to generate the precompiled header but not when using it, you may or may not get debugging information for routines in the precompiled header. diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index c4eb355e253..bca84a72ce5 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -4736,6 +4736,10 @@ Other shift and rotate instructions, analogous to the Vector shift and rotate instructions that take vectors as operand 2 instead of a scalar type. +@cindex @code{bswap@var{m}2} instruction pattern +@item @samp{bswap@var{m}2} +Reverse the order of bytes of operand 1 and store the result in operand 0. + @cindex @code{neg@var{m}2} instruction pattern @cindex @code{ssneg@var{m}2} instruction pattern @cindex @code{usneg@var{m}2} instruction pattern diff --git a/gcc/dse.c b/gcc/dse.c index d6c8de7fad8..19d938301bb 100644 --- a/gcc/dse.c +++ b/gcc/dse.c @@ -1,5 +1,5 @@ /* RTL dead store elimination. - Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Richard Sandiford <rsandifor@codesourcery.com> @@ -1499,11 +1499,7 @@ record_store (rtx body, bb_info_t bb_info) } else { - rtx base_term = find_base_term (XEXP (mem, 0)); - if (!base_term - || (GET_CODE (base_term) == ADDRESS - && GET_MODE (base_term) == Pmode - && XEXP (base_term, 0) == stack_pointer_rtx)) + if (may_be_sp_based_p (XEXP (mem, 0))) insn_info->stack_pointer_based = true; insn_info->contains_cselib_groups = true; diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index ca88fc56b10..1240ddb5637 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -14572,7 +14572,7 @@ reference_to_unused (tree * tp, int * walk_subtrees, else if (TREE_CODE (*tp) == VAR_DECL) { struct varpool_node *node = varpool_get_node (*tp); - if (!node || !node->needed) + if (!node || !node->analyzed) return *tp; } else if (TREE_CODE (*tp) == FUNCTION_DECL @@ -17057,7 +17057,7 @@ premark_types_used_by_global_vars_helper (void **slot, /* Ask cgraph if the global variable really is to be emitted. If yes, then we'll keep the DIE of ENTRY->TYPE. */ struct varpool_node *node = varpool_get_node (entry->var_decl); - if (node && node->needed) + if (node && node->analyzed) { die->die_perennial_p = 1; /* Keep the parent DIEs as well. */ @@ -18369,6 +18369,7 @@ gen_producer_string (void) case OPT__output_pch_: case OPT_fdiagnostics_show_location_: case OPT_fdiagnostics_show_option: + case OPT_fdiagnostics_show_caret: case OPT_fverbose_asm: case OPT____: case OPT__sysroot_: diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 8d7d4417d59..9da585c35a7 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -970,6 +970,22 @@ void set_reg_attrs_from_value (rtx reg, rtx x) { int offset; + bool can_be_reg_pointer = true; + + /* Don't call mark_reg_pointer for incompatible pointer sign + extension. */ + while (GET_CODE (x) == SIGN_EXTEND + || GET_CODE (x) == ZERO_EXTEND + || GET_CODE (x) == TRUNCATE + || (GET_CODE (x) == SUBREG && subreg_lowpart_p (x))) + { +#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) + if ((GET_CODE (x) == SIGN_EXTEND && POINTERS_EXTEND_UNSIGNED) + || (GET_CODE (x) != SIGN_EXTEND && ! POINTERS_EXTEND_UNSIGNED)) + can_be_reg_pointer = false; +#endif + x = XEXP (x, 0); + } /* Hard registers can be reused for multiple purposes within the same function, so setting REG_ATTRS, REG_POINTER and REG_POINTER_ALIGN @@ -983,14 +999,14 @@ set_reg_attrs_from_value (rtx reg, rtx x) if (MEM_OFFSET_KNOWN_P (x)) REG_ATTRS (reg) = get_reg_attrs (MEM_EXPR (x), MEM_OFFSET (x) + offset); - if (MEM_POINTER (x)) + if (can_be_reg_pointer && MEM_POINTER (x)) mark_reg_pointer (reg, 0); } else if (REG_P (x)) { if (REG_ATTRS (x)) update_reg_offset (reg, x, offset); - if (REG_POINTER (x)) + if (can_be_reg_pointer && REG_POINTER (x)) mark_reg_pointer (reg, REGNO_POINTER_ALIGN (REGNO (x))); } } diff --git a/gcc/except.c b/gcc/except.c index e3a9ef07422..254dd8c32ae 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -1344,6 +1344,28 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch) e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU); e->count = bb->count; e->probability = REG_BR_PROB_BASE; + if (current_loops) + { + struct loop *loop = bb->next_bb->loop_father; + /* If we created a pre-header block, add the new block to the + outer loop, otherwise to the loop itself. */ + if (bb->next_bb == loop->header) + add_bb_to_loop (bb, loop_outer (loop)); + else + add_bb_to_loop (bb, loop); + /* ??? For multiple dispatches we will end up with edges + from the loop tree root into this loop, making it a + multiple-entry loop. Discard all affected loops. */ + if (num_dispatch > 1) + { + for (loop = bb->loop_father; + loop_outer (loop); loop = loop_outer (loop)) + { + loop->header = NULL; + loop->latch = NULL; + } + } + } disp_index++; } @@ -1364,6 +1386,24 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch) e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU); e->count = bb->count; e->probability = REG_BR_PROB_BASE; + if (current_loops) + { + struct loop *loop = bb->next_bb->loop_father; + /* If we created a pre-header block, add the new block to the + outer loop, otherwise to the loop itself. */ + if (bb->next_bb == loop->header) + add_bb_to_loop (bb, loop_outer (loop)); + else + add_bb_to_loop (bb, loop); + } + } + else + { + /* We are not wiring up edges here, but as the dispatcher call + is at function begin simply associate the block with the + outermost (non-)loop. */ + if (current_loops) + add_bb_to_loop (bb, current_loops->tree_root); } } @@ -2774,8 +2814,6 @@ output_ttype (tree type, int tt_format, int tt_format_size) value = const0_rtx; else { - struct varpool_node *node; - /* FIXME lto. pass_ipa_free_lang_data changes all types to runtime types so TYPE should already be a runtime type reference. When pass_ipa_free_lang data is made a default @@ -2794,12 +2832,7 @@ output_ttype (tree type, int tt_format, int tt_format_size) { type = TREE_OPERAND (type, 0); if (TREE_CODE (type) == VAR_DECL) - { - node = varpool_node (type); - if (node) - varpool_mark_needed_node (node); - is_public = TREE_PUBLIC (type); - } + is_public = TREE_PUBLIC (type); } else gcc_assert (TREE_CODE (type) == INTEGER_CST); diff --git a/gcc/expr.c b/gcc/expr.c index 548a407d55e..479dacf7f7a 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -6778,6 +6778,43 @@ array_ref_low_bound (tree exp) return build_int_cst (TREE_TYPE (TREE_OPERAND (exp, 1)), 0); } +/* Returns true if REF is an array reference to an array at the end of + a structure. If this is the case, the array may be allocated larger + than its upper bound implies. */ + +bool +array_at_struct_end_p (tree ref) +{ + if (TREE_CODE (ref) != ARRAY_REF + && TREE_CODE (ref) != ARRAY_RANGE_REF) + return false; + + while (handled_component_p (ref)) + { + /* If the reference chain contains a component reference to a + non-union type and there follows another field the reference + is not at the end of a structure. */ + if (TREE_CODE (ref) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE) + { + tree nextf = DECL_CHAIN (TREE_OPERAND (ref, 1)); + while (nextf && TREE_CODE (nextf) != FIELD_DECL) + nextf = DECL_CHAIN (nextf); + if (nextf) + return false; + } + + ref = TREE_OPERAND (ref, 0); + } + + /* If the reference is based on a declared entity, the size of the array + is constrained by its given domain. */ + if (DECL_P (ref)) + return false; + + return true; +} + /* Return a tree representing the upper bound of the array mentioned in EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ @@ -9015,8 +9052,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, && stmt_is_replaceable_p (SSA_NAME_DEF_STMT (exp))) g = SSA_NAME_DEF_STMT (exp); if (g) - return expand_expr_real (gimple_assign_rhs_to_tree (g), target, tmode, - modifier, NULL); + { + rtx r = expand_expr_real (gimple_assign_rhs_to_tree (g), target, + tmode, modifier, NULL); + if (REG_P (r) && !REG_EXPR (r)) + set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (exp), r); + return r; + } ssa_name = exp; decl_rtl = get_rtx_for_ssa_name (ssa_name); @@ -9598,6 +9640,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode1, &unsignedp, &volatilep, true); rtx orig_op0, memloc; + bool mem_attrs_from_type = false; /* If we got back the original object, something is wrong. Perhaps we are evaluating an expression too early. In any event, don't @@ -9703,6 +9746,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, memloc = assign_temp (nt, 1, 1, 1); emit_move_insn (memloc, op0); op0 = memloc; + mem_attrs_from_type = true; } if (offset) @@ -9875,7 +9919,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, emit_move_insn (new_rtx, op0); op0 = copy_rtx (new_rtx); PUT_MODE (op0, BLKmode); - set_mem_attributes (op0, exp, 1); } return op0; @@ -9896,7 +9939,14 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, if (op0 == orig_op0) op0 = copy_rtx (op0); - set_mem_attributes (op0, exp, 0); + /* If op0 is a temporary because of forcing to memory, pass only the + type to set_mem_attributes so that the original expression is never + marked as ADDRESSABLE through MEM_EXPR of the temporary. */ + if (mem_attrs_from_type) + set_mem_attributes (op0, type, 0); + else + set_mem_attributes (op0, exp, 0); + if (REG_P (XEXP (op0, 0))) mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0)); diff --git a/gcc/fold-const.c b/gcc/fold-const.c index df0c05c6e02..41081ff919c 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -2562,6 +2562,14 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) case IMAGPART_EXPR: return OP_SAME (0); + case TARGET_MEM_REF: + /* Require equal extra operands and then fall thru to MEM_REF + handling of the two common operands. */ + if (!OP_SAME_WITH_NULL (2) + || !OP_SAME_WITH_NULL (3) + || !OP_SAME_WITH_NULL (4)) + return 0; + /* Fallthru. */ case MEM_REF: /* Require equal access sizes, and similar pointer types. We can have incomplete types for array references of @@ -7820,7 +7828,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) && inter_prec >= inside_prec && (inter_float || inter_vec || inter_unsignedp == inside_unsignedp) - && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type)) && ! final_ptr && (! final_vec || inter_prec == inside_prec)) @@ -7857,7 +7865,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) == (final_unsignedp && final_prec > inter_prec)) && ! (inside_ptr && inter_prec != final_prec) && ! (final_ptr && inside_prec != inter_prec) - && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type))) return fold_build1_loc (loc, code, type, TREE_OPERAND (op0, 0)); } @@ -9685,6 +9693,48 @@ fold_addr_of_array_ref_difference (location_t loc, tree type, return NULL_TREE; } +/* If the real or vector real constant CST of type TYPE has an exact + inverse, return it, else return NULL. */ + +static tree +exact_inverse (tree type, tree cst) +{ + REAL_VALUE_TYPE r; + tree unit_type, *elts; + enum machine_mode mode; + unsigned vec_nelts, i; + + switch (TREE_CODE (cst)) + { + case REAL_CST: + r = TREE_REAL_CST (cst); + + if (exact_real_inverse (TYPE_MODE (type), &r)) + return build_real (type, r); + + return NULL_TREE; + + case VECTOR_CST: + vec_nelts = VECTOR_CST_NELTS (cst); + elts = XALLOCAVEC (tree, vec_nelts); + unit_type = TREE_TYPE (type); + mode = TYPE_MODE (unit_type); + + for (i = 0; i < vec_nelts; i++) + { + r = TREE_REAL_CST (VECTOR_CST_ELT (cst, i)); + if (!exact_real_inverse (mode, &r)) + return NULL_TREE; + elts[i] = build_real (unit_type, r); + } + + return build_vector (type, elts); + + default: + return NULL_TREE; + } +} + /* Fold a binary expression of code CODE and type TYPE with operands OP0 and OP1. LOC is the location of the resulting expression. Return the folded expression if folding is successful. Otherwise, @@ -11726,23 +11776,24 @@ fold_binary_loc (location_t loc, so only do this if -freciprocal-math. We can actually always safely do it if ARG1 is a power of two, but it's hard to tell if it is or not in a portable manner. */ - if (TREE_CODE (arg1) == REAL_CST) + if (optimize + && (TREE_CODE (arg1) == REAL_CST + || (TREE_CODE (arg1) == COMPLEX_CST + && COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg1))) + || (TREE_CODE (arg1) == VECTOR_CST + && VECTOR_FLOAT_TYPE_P (TREE_TYPE (arg1))))) { if (flag_reciprocal_math - && 0 != (tem = const_binop (code, build_real (type, dconst1), - arg1))) + && 0 != (tem = const_binop (code, build_one_cst (type), arg1))) return fold_build2_loc (loc, MULT_EXPR, type, arg0, tem); - /* Find the reciprocal if optimizing and the result is exact. */ - if (optimize) + /* Find the reciprocal if optimizing and the result is exact. + TODO: Complex reciprocal not implemented. */ + if (TREE_CODE (arg1) != COMPLEX_CST) { - REAL_VALUE_TYPE r; - r = TREE_REAL_CST (arg1); - if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r)) - { - tem = build_real (type, r); - return fold_build2_loc (loc, MULT_EXPR, type, - fold_convert_loc (loc, type, arg0), tem); - } + tree inverse = exact_inverse (TREE_TYPE (arg0), arg1); + + if (inverse) + return fold_build2_loc (loc, MULT_EXPR, type, arg0, inverse); } } /* Convert A/B/C to A/(B*C). */ @@ -14340,7 +14391,8 @@ fold_checksum_tree (const_tree expr, struct md5_ctx *ctx, htab_t ht) fold_checksum_tree (TREE_IMAGPART (expr), ctx, ht); break; case VECTOR_CST: - fold_checksum_tree (TREE_VECTOR_CST_ELTS (expr), ctx, ht); + for (i = 0; i < (int) VECTOR_CST_NELTS (expr); ++i) + fold_checksum_tree (VECTOR_CST_ELT (expr, i), ctx, ht); break; default: break; diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 02c43558aa3..cfe1192b6ef 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,44 @@ +2012-04-18 Steven Bosscher <steven@gcc.gnu.org> + + * trans-decl.c (gfc_trans_entry_master_switch): Build SWITCH_EXPR + with NULL_TREE type instead of void_type_node. + * trans-io.c (io_result): Likewise. + * trans-stmt.c (gfc_trans_integer_select, + gfc_trans_character_select): Likewise. + +2012-04-16 Tobias Burnus <burnus@net-b.de> + + PR fortran/52864 + * expr.c (gfc_check_vardef_context): Fix assignment check for + pointer components. + +2012-04-16 Janus Weil <janus@gcc.gnu.org> + + PR fortran/52968 + * class.c (gfc_build_class_symbol): Make sure the 'f2k_derived' + namespace is present. + +2012-04-15 Janus Weil <janus@gcc.gnu.org> + + PR fortran/51082 + * trans-expr.c (gfc_conv_expr_reference): Check if the expression is a + simple function call (or a more involved PPC reference). + +2012-04-15 Tobias Burnus <burnus@net-b.de> + + PR fortran/52916 + PR fortran/40973 + * gfortran.h (symbol_attribute): Add public_used. + * interface.c (check_sym_interfaces, check_uop_interfaces, + gfc_check_interfaces): Set it. + * resolve.c (resolve_typebound_procedure): Ditto. + * trans-decl.c (build_function_decl): Use it. + +2012-04-11 Tobias Burnus <burnus@net-b.de> + + PR fortran/52729 + * resolve.c (resolve_symbol): Fix searching for parent NS decl. + 2012-04-08 Tobias Burnus <burnus@net-b.de> PR fortran/52751 diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c index a27513646c9..c71aa4a7c48 100644 --- a/gcc/fortran/class.c +++ b/gcc/fortran/class.c @@ -541,8 +541,7 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr, fclass->refs++; fclass->ts.type = BT_UNKNOWN; fclass->attr.abstract = ts->u.derived->attr.abstract; - if (ts->u.derived->f2k_derived) - fclass->f2k_derived = gfc_get_namespace (NULL, 0); + fclass->f2k_derived = gfc_get_namespace (NULL, 0); if (gfc_add_flavor (&fclass->attr, FL_DERIVED, NULL, &gfc_current_locus) == FAILURE) return FAILURE; @@ -579,8 +578,6 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr, c->attr.access = ACCESS_PRIVATE; c->attr.pointer = 1; } - else if (!fclass->f2k_derived) - fclass->f2k_derived = gfc_get_namespace (NULL, 0); /* Since the extension field is 8 bit wide, we can only have up to 255 extension levels. */ diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index e6a9c885f02..d9614413e67 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -4645,9 +4645,11 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj, return FAILURE; } - /* INTENT(IN) dummy argument. Check this, unless the object itself is - the component of sub-component of a pointer. Obviously, - procedure pointers are of no interest here. */ + /* INTENT(IN) dummy argument. Check this, unless the object itself is the + component of sub-component of a pointer; we need to distinguish + assignment to a pointer component from pointer-assignment to a pointer + component. Note that (normal) assignment to procedure pointers is not + possible. */ check_intentin = true; ptr_component = (sym->ts.type == BT_CLASS && CLASS_DATA (sym)) ? CLASS_DATA (sym)->attr.class_pointer : sym->attr.pointer; @@ -4656,7 +4658,11 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj, if (ptr_component && ref->type == REF_COMPONENT) check_intentin = false; if (ref->type == REF_COMPONENT && ref->u.c.component->attr.pointer) - ptr_component = true; + { + ptr_component = true; + if (!pointer) + check_intentin = false; + } } if (check_intentin && sym->attr.intent == INTENT_IN) { diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 8e83cb4cbd5..25bdfa5ca3c 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -726,6 +726,10 @@ typedef struct unsigned sequence:1, elemental:1, pure:1, recursive:1; unsigned unmaskable:1, masked:1, contained:1, mod_proc:1, abstract:1; + /* Set if a (public) symbol [e.g. generic name] exposes this symbol, + which is relevant for private module procedures. */ + unsigned public_used:1; + /* This is set if a contained procedure could be declared pure. This is used for certain optimizations that require the result or arguments cannot alias. Note that this is zero for PURE procedures. */ diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 298ae23d260..2f1d24e6e33 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -1390,6 +1390,9 @@ check_sym_interfaces (gfc_symbol *sym) for (p = sym->generic; p; p = p->next) { + if (sym->attr.access != ACCESS_PRIVATE) + p->sym->attr.public_used = 1; + if (p->sym->attr.mod_proc && (p->sym->attr.if_source != IFSRC_DECL || p->sym->attr.procedure)) @@ -1415,11 +1418,16 @@ check_uop_interfaces (gfc_user_op *uop) char interface_name[100]; gfc_user_op *uop2; gfc_namespace *ns; + gfc_interface *p; sprintf (interface_name, "operator interface '%s'", uop->name); if (check_interface0 (uop->op, interface_name)) return; + if (uop->access != ACCESS_PRIVATE) + for (p = uop->op; p; p = p->next) + p->sym->attr.public_used = 1; + for (ns = gfc_current_ns; ns; ns = ns->parent) { uop2 = gfc_find_uop (uop->name, ns); @@ -1489,6 +1497,7 @@ void gfc_check_interfaces (gfc_namespace *ns) { gfc_namespace *old_ns, *ns2; + gfc_interface *p; char interface_name[100]; int i; @@ -1513,6 +1522,10 @@ gfc_check_interfaces (gfc_namespace *ns) if (check_interface0 (ns->op[i], interface_name)) continue; + for (p = ns->op[i]; p; p = p->next) + p->sym->attr.public_used = 1; + + if (ns->op[i]) gfc_check_operator_interface (ns->op[i]->sym, (gfc_intrinsic_op) i, ns->op[i]->where); diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index b63a0c69e6a..57da577dfaa 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -11304,6 +11304,7 @@ resolve_typebound_procedure (gfc_symtree* stree) gcc_assert (stree->n.tb->u.specific); proc = stree->n.tb->u.specific->n.sym; where = stree->n.tb->where; + proc->attr.public_used = 1; /* Default access should already be resolved from the parser. */ gcc_assert (stree->n.tb->access != ACCESS_UNKNOWN); @@ -12246,7 +12247,10 @@ resolve_symbol (gfc_symbol *sym) symbol_attribute class_attr; gfc_array_spec *as; - if (sym->attr.flavor == FL_UNKNOWN) + if (sym->attr.flavor == FL_UNKNOWN + || (sym->attr.flavor == FL_PROCEDURE && !sym->attr.intrinsic + && !sym->attr.generic && !sym->attr.external + && sym->attr.if_source == IFSRC_UNKNOWN)) { /* If we find that a flavorless symbol is an interface in one of the @@ -12270,9 +12274,10 @@ resolve_symbol (gfc_symbol *sym) /* Otherwise give it a flavor according to such attributes as it has. */ - if (sym->attr.external == 0 && sym->attr.intrinsic == 0) + if (sym->attr.flavor == FL_UNKNOWN && sym->attr.external == 0 + && sym->attr.intrinsic == 0) sym->attr.flavor = FL_VARIABLE; - else + else if (sym->attr.flavor == FL_UNKNOWN) { sym->attr.flavor = FL_PROCEDURE; if (sym->attr.dimension) diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index aec96aa75a2..d6c090e8606 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -1844,7 +1844,8 @@ build_function_decl (gfc_symbol * sym, bool global) if (!current_function_decl && !sym->attr.entry_master && !sym->attr.is_main_program - && (sym->attr.access != ACCESS_PRIVATE || sym->binding_label)) + && (sym->attr.access != ACCESS_PRIVATE || sym->binding_label + || sym->attr.public_used)) TREE_PUBLIC (fndecl) = 1; attributes = add_attributes_to_decl (attr, NULL_TREE); @@ -4748,7 +4749,8 @@ gfc_trans_entry_master_switch (gfc_entry_list * el) tmp = gfc_finish_block (&block); /* The first argument selects the entry point. */ val = DECL_ARGUMENTS (current_function_decl); - tmp = build3_v (SWITCH_EXPR, val, tmp, NULL_TREE); + tmp = fold_build3_loc (input_location, SWITCH_EXPR, NULL_TREE, + val, tmp, NULL_TREE); return tmp; } diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 036b55bdf96..cd48d5a67af 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -5650,7 +5650,7 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr) && ((expr->value.function.esym && expr->value.function.esym->result->attr.pointer && !expr->value.function.esym->result->attr.dimension) - || (!expr->value.function.esym + || (!expr->value.function.esym && !expr->ref && expr->symtree->n.sym->attr.pointer && !expr->symtree->n.sym->attr.dimension))) { diff --git a/gcc/fortran/trans-io.c b/gcc/fortran/trans-io.c index 12dfcf82333..8218f85a98d 100644 --- a/gcc/fortran/trans-io.c +++ b/gcc/fortran/trans-io.c @@ -882,7 +882,8 @@ io_result (stmtblock_t * block, tree var, gfc_st_label * err_label, rc, build_int_cst (TREE_TYPE (rc), IOPARM_common_libreturn_mask)); - tmp = build3_v (SWITCH_EXPR, rc, tmp, NULL_TREE); + tmp = fold_build3_loc (input_location, SWITCH_EXPR, NULL_TREE, + rc, tmp, NULL_TREE); gfc_add_expr_to_block (block, tmp); } diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index bb3a89084e0..12a1390e2aa 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -1918,7 +1918,8 @@ gfc_trans_integer_select (gfc_code * code) } tmp = gfc_finish_block (&body); - tmp = build3_v (SWITCH_EXPR, se.expr, tmp, NULL_TREE); + tmp = fold_build3_loc (input_location, SWITCH_EXPR, NULL_TREE, + se.expr, tmp, NULL_TREE); gfc_add_expr_to_block (&block, tmp); tmp = build1_v (LABEL_EXPR, end_label); @@ -2203,7 +2204,8 @@ gfc_trans_character_select (gfc_code *code) gfc_add_block_to_block (&block, &expr1se.post); tmp = gfc_finish_block (&body); - tmp = build3_v (SWITCH_EXPR, case_num, tmp, NULL_TREE); + tmp = fold_build3_loc (input_location, SWITCH_EXPR, NULL_TREE, + case_num, tmp, NULL_TREE); gfc_add_expr_to_block (&block, tmp); tmp = build1_v (LABEL_EXPR, end_label); @@ -2349,7 +2351,8 @@ gfc_trans_character_select (gfc_code *code) gfc_add_block_to_block (&block, &expr1se.post); tmp = gfc_finish_block (&body); - tmp = build3_v (SWITCH_EXPR, case_num, tmp, NULL_TREE); + tmp = fold_build3_loc (input_location, SWITCH_EXPR, NULL_TREE, + case_num, tmp, NULL_TREE); gfc_add_expr_to_block (&block, tmp); tmp = build1_v (LABEL_EXPR, end_label); diff --git a/gcc/fwprop.c b/gcc/fwprop.c index 4fab5b06072..c3530372c12 100644 --- a/gcc/fwprop.c +++ b/gcc/fwprop.c @@ -664,7 +664,12 @@ propagate_rtx (rtx x, enum machine_mode mode, rtx old_rtx, rtx new_rtx, return NULL_RTX; flags = 0; - if (REG_P (new_rtx) || CONSTANT_P (new_rtx)) + if (REG_P (new_rtx) + || CONSTANT_P (new_rtx) + || (GET_CODE (new_rtx) == SUBREG + && REG_P (SUBREG_REG (new_rtx)) + && (GET_MODE_SIZE (mode) + <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (new_rtx)))))) flags |= PR_CAN_APPEAR; if (!for_each_rtx (&new_rtx, varying_mem_p, NULL)) flags |= PR_HANDLE_MEM; diff --git a/gcc/genemit.c b/gcc/genemit.c index 173e4d30ab2..91025e24d88 100644 --- a/gcc/genemit.c +++ b/gcc/genemit.c @@ -160,9 +160,6 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used) gen_rtx_scratch (x, subroutine_type); return; - case ADDRESS: - fatal ("ADDRESS expression code used in named instruction pattern"); - case PC: printf ("pc_rtx"); return; diff --git a/gcc/gengtype.c b/gcc/gengtype.c index 9cf20772afd..b8876679f73 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -2296,6 +2296,8 @@ struct walk_type_data const char *reorder_fn; bool needs_cast_p; bool fn_wants_lvalue; + bool in_record_p; + int loopcounter; }; /* Print a mangled name representing T to OF. */ @@ -2597,7 +2599,7 @@ walk_type (type_p t, struct walk_type_data *d) } else { - int loopcounter = d->counter++; + int loopcounter = d->loopcounter; const char *oldval = d->val; const char *oldprevval3 = d->prev_val[3]; char *newval; @@ -2607,7 +2609,10 @@ walk_type (type_p t, struct walk_type_data *d) oprintf (d->of, "%*ssize_t i%d;\n", d->indent, "", loopcounter); oprintf (d->of, "%*sfor (i%d = 0; i%d != (size_t)(", d->indent, "", loopcounter, loopcounter); - output_escaped_param (d, length, "length"); + if (!d->in_record_p) + output_escaped_param (d, length, "length"); + else + oprintf (d->of, "l%d", loopcounter); oprintf (d->of, "); i%d++) {\n", loopcounter); d->indent += 2; d->val = newval = xasprintf ("%s[i%d]", oldval, loopcounter); @@ -2629,7 +2634,7 @@ walk_type (type_p t, struct walk_type_data *d) case TYPE_ARRAY: { - int loopcounter = d->counter++; + int loopcounter; const char *oldval = d->val; char *newval; @@ -2638,6 +2643,11 @@ walk_type (type_p t, struct walk_type_data *d) if (t->u.a.p->kind == TYPE_SCALAR) break; + if (length) + loopcounter = d->loopcounter; + else + loopcounter = d->counter++; + /* When walking an array, compute the length and store it in a local variable before walking the array elements, instead of recomputing the length expression each time through the loop. @@ -2648,13 +2658,16 @@ walk_type (type_p t, struct walk_type_data *d) oprintf (d->of, "%*s{\n", d->indent, ""); d->indent += 2; oprintf (d->of, "%*ssize_t i%d;\n", d->indent, "", loopcounter); - oprintf (d->of, "%*ssize_t l%d = (size_t)(", - d->indent, "", loopcounter); - if (length) - output_escaped_param (d, length, "length"); - else - oprintf (d->of, "%s", t->u.a.len); - oprintf (d->of, ");\n"); + if (!d->in_record_p || !length) + { + oprintf (d->of, "%*ssize_t l%d = (size_t)(", + d->indent, "", loopcounter); + if (length) + output_escaped_param (d, length, "length"); + else + oprintf (d->of, "%s", t->u.a.len); + oprintf (d->of, ");\n"); + } oprintf (d->of, "%*sfor (i%d = 0; i%d != l%d; i%d++) {\n", d->indent, "", @@ -2683,6 +2696,9 @@ walk_type (type_p t, struct walk_type_data *d) const int union_p = t->kind == TYPE_UNION; int seen_default_p = 0; options_p o; + int lengths_seen = 0; + int endcounter; + bool any_length_seen = false; if (!t->u.s.line.file) error_at_line (d->line, "incomplete structure `%s'", t->u.s.tag); @@ -2718,6 +2734,45 @@ walk_type (type_p t, struct walk_type_data *d) d->indent += 2; oprintf (d->of, "%*s{\n", d->indent, ""); } + + for (f = t->u.s.fields; f; f = f->next) + { + options_p oo; + int skip_p = 0; + const char *fieldlength = NULL; + + d->reorder_fn = NULL; + for (oo = f->opt; oo; oo = oo->next) + if (strcmp (oo->name, "skip") == 0) + skip_p = 1; + else if (strcmp (oo->name, "length") == 0 + && oo->kind == OPTION_STRING) + fieldlength = oo->info.string; + + if (skip_p) + continue; + if (fieldlength) + { + lengths_seen++; + d->counter++; + if (!union_p) + { + if (!any_length_seen) + { + oprintf (d->of, "%*s{\n", d->indent, ""); + d->indent += 2; + } + any_length_seen = true; + + oprintf (d->of, "%*ssize_t l%d = (size_t)(", + d->indent, "", d->counter - 1); + output_escaped_param (d, fieldlength, "length"); + oprintf (d->of, ");\n"); + } + } + } + endcounter = d->counter; + for (f = t->u.s.fields; f; f = f->next) { options_p oo; @@ -2726,6 +2781,7 @@ walk_type (type_p t, struct walk_type_data *d) int skip_p = 0; int default_p = 0; int use_param_p = 0; + const char *fieldlength = NULL; char *newval; d->reorder_fn = NULL; @@ -2746,6 +2802,9 @@ walk_type (type_p t, struct walk_type_data *d) else if (strncmp (oo->name, "use_param", 9) == 0 && (oo->name[9] == '\0' || ISDIGIT (oo->name[9]))) use_param_p = 1; + else if (strcmp (oo->name, "length") == 0 + && oo->kind == OPTION_STRING) + fieldlength = oo->info.string; if (skip_p) continue; @@ -2779,16 +2838,24 @@ walk_type (type_p t, struct walk_type_data *d) "field `%s' is missing `tag' or `default' option", f->name); + if (fieldlength) + { + d->loopcounter = endcounter - lengths_seen--; + } + d->line = &f->line; d->val = newval = xasprintf ("%s%s%s", oldval, dot, f->name); d->opt = f->opt; d->used_length = false; + d->in_record_p = !union_p; if (union_p && use_param_p && d->param == NULL) oprintf (d->of, "%*sgcc_unreachable ();\n", d->indent, ""); else walk_type (f->type, d); + d->in_record_p = false; + free (newval); if (union_p) @@ -2813,6 +2880,11 @@ walk_type (type_p t, struct walk_type_data *d) oprintf (d->of, "%*s}\n", d->indent, ""); d->indent -= 2; } + if (any_length_seen) + { + d->indent -= 2; + oprintf (d->of, "%*s}\n", d->indent, ""); + } } break; @@ -4981,6 +5053,7 @@ main (int argc, char **argv) POS_HERE (do_scalar_typedef ("double_int", &pos)); POS_HERE (do_scalar_typedef ("uint64_t", &pos)); POS_HERE (do_scalar_typedef ("uint8", &pos)); + POS_HERE (do_scalar_typedef ("uintptr_t", &pos)); POS_HERE (do_scalar_typedef ("jword", &pos)); POS_HERE (do_scalar_typedef ("JCF_u2", &pos)); POS_HERE (do_scalar_typedef ("void", &pos)); diff --git a/gcc/genmodes.c b/gcc/genmodes.c index 8b6f5bce96b..84517b9f3dc 100644 --- a/gcc/genmodes.c +++ b/gcc/genmodes.c @@ -1,5 +1,5 @@ /* Generate the machine mode enumeration and associated tables. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -427,7 +427,6 @@ make_complex_modes (enum mode_class cl, { struct mode_data *m; struct mode_data *c; - char buf[8]; enum mode_class cclass = complex_class (cl); if (cclass == MODE_RANDOM) @@ -435,43 +434,42 @@ make_complex_modes (enum mode_class cl, for (m = modes[cl]; m; m = m->next) { + char *p, *buf; + size_t m_len; + /* Skip BImode. FIXME: BImode probably shouldn't be MODE_INT. */ if (m->precision == 1) continue; - if (strlen (m->name) >= sizeof buf) - { - error ("%s:%d:mode name \"%s\" is too long", - m->file, m->line, m->name); - continue; - } + m_len = strlen (m->name); + /* The leading "1 +" is in case we prepend a "C" below. */ + buf = (char *) xmalloc (1 + m_len + 1); /* Float complex modes are named SCmode, etc. Int complex modes are named CSImode, etc. This inconsistency should be eliminated. */ + p = 0; if (cl == MODE_FLOAT) { - char *p, *q = 0; - strncpy (buf, m->name, sizeof buf); + memcpy (buf, m->name, m_len + 1); p = strchr (buf, 'F'); - if (p == 0) - q = strchr (buf, 'D'); - if (p == 0 && q == 0) + if (p == 0 && strchr (buf, 'D') == 0) { error ("%s:%d: float mode \"%s\" has no 'F' or 'D'", m->file, m->line, m->name); + free (buf); continue; } - - if (p != 0) - *p = 'C'; - else - snprintf (buf, sizeof buf, "C%s", m->name); } + if (p != 0) + *p = 'C'; else - snprintf (buf, sizeof buf, "C%s", m->name); + { + buf[0] = 'C'; + memcpy (buf + 1, m->name, m_len + 1); + } - c = new_mode (cclass, xstrdup (buf), file, line); + c = new_mode (cclass, buf, file, line); c->component = m; } } diff --git a/gcc/genoutput.c b/gcc/genoutput.c index bc41b7bc7f5..bae2381c9aa 100644 --- a/gcc/genoutput.c +++ b/gcc/genoutput.c @@ -510,10 +510,6 @@ scan_operands (struct data *d, rtx part, int this_address_p, scan_operands (d, XVECEXP (part, 2, i), 0, 0); return; - case ADDRESS: - scan_operands (d, XEXP (part, 0), 1, 0); - return; - case STRICT_LOW_PART: scan_operands (d, XEXP (part, 0), 0, 1); return; diff --git a/gcc/genpeep.c b/gcc/genpeep.c index ac08d80d556..a6f1033eada 100644 --- a/gcc/genpeep.c +++ b/gcc/genpeep.c @@ -231,10 +231,6 @@ match_rtx (rtx x, struct link *path, int fail_label) } return; - case ADDRESS: - match_rtx (XEXP (x, 0), path, fail_label); - return; - default: break; } diff --git a/gcc/genrecog.c b/gcc/genrecog.c index 0d8be8f7607..9ce5106db2f 100644 --- a/gcc/genrecog.c +++ b/gcc/genrecog.c @@ -687,7 +687,6 @@ add_to_sequence (rtx pattern, struct decision_head *last, sub = this_decision = new_decision (pos, last); place = &this_decision->tests; - restart: mode = GET_MODE (pattern); code = GET_CODE (pattern); @@ -854,10 +853,6 @@ add_to_sequence (rtx pattern, struct decision_head *last, test->u.dup = XINT (pattern, 0); goto fini; - case ADDRESS: - pattern = XEXP (pattern, 0); - goto restart; - default: break; } diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 0ea5d56543f..49505ee9494 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -70,6 +70,7 @@ can_refer_decl_in_current_unit_p (tree decl) flags incorrectly. Those variables should never be finalized. */ gcc_checking_assert (!(vnode = varpool_get_node (decl)) + || vnode->alias || !vnode->finalized); return false; } @@ -3087,7 +3088,7 @@ gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo) offset += token * size; fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), DECL_INITIAL (v), offset, size); - if (!fn) + if (!fn || integer_zerop (fn)) return NULL_TREE; gcc_assert (TREE_CODE (fn) == ADDR_EXPR || TREE_CODE (fn) == FDESC_EXPR); diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index f6deba17938..4a1ae0bfa9a 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -240,15 +240,17 @@ gimple_check_call_args (gimple stmt, tree fndecl) i < nargs; i++, p = DECL_CHAIN (p)) { + tree arg; /* We cannot distinguish a varargs function from the case of excess parameters, still deferring the inlining decision to the callee is possible. */ if (!p) break; + arg = gimple_call_arg (stmt, i); if (p == error_mark_node - || gimple_call_arg (stmt, i) == error_mark_node - || !fold_convertible_p (DECL_ARG_TYPE (p), - gimple_call_arg (stmt, i))) + || arg == error_mark_node + || (!types_compatible_p (DECL_ARG_TYPE (p), TREE_TYPE (arg)) + && !fold_convertible_p (DECL_ARG_TYPE (p), arg))) return false; } } @@ -256,15 +258,17 @@ gimple_check_call_args (gimple stmt, tree fndecl) { for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p)) { + tree arg; /* If this is a varargs function defer inlining decision to callee. */ if (!p) break; + arg = gimple_call_arg (stmt, i); if (TREE_VALUE (p) == error_mark_node - || gimple_call_arg (stmt, i) == error_mark_node + || arg == error_mark_node || TREE_CODE (TREE_VALUE (p)) == VOID_TYPE - || !fold_convertible_p (TREE_VALUE (p), - gimple_call_arg (stmt, i))) + || (!types_compatible_p (TREE_VALUE (p), TREE_TYPE (arg)) + && !fold_convertible_p (TREE_VALUE (p), arg))) return false; } } diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 43e3518a05d..cef61180c38 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1003,7 +1003,7 @@ unshare_body (tree fndecl) if (cgn) for (cgn = cgn->nested; cgn; cgn = cgn->next_nested) - unshare_body (cgn->decl); + unshare_body (cgn->symbol.decl); } /* Callback for walk_tree to unmark the visited trees rooted at *TP. @@ -1046,7 +1046,7 @@ unvisit_body (tree fndecl) if (cgn) for (cgn = cgn->nested; cgn; cgn = cgn->next_nested) - unvisit_body (cgn->decl); + unvisit_body (cgn->symbol.decl); } /* Unconditionally make an unshared copy of EXPR. This is used when using @@ -1575,6 +1575,9 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) tree switch_expr = *expr_p; gimple_seq switch_body_seq = NULL; enum gimplify_status ret; + tree index_type = TREE_TYPE (switch_expr); + if (index_type == NULL_TREE) + index_type = TREE_TYPE (SWITCH_COND (switch_expr)); ret = gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL, is_gimple_val, fb_rvalue); @@ -1585,6 +1588,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) { VEC (tree,heap) *labels; VEC (tree,heap) *saved_labels; + tree min_value, max_value; tree default_case = NULL_TREE; size_t i, len; gimple gimple_switch; @@ -1593,7 +1597,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) be bothered to null out the body too. */ gcc_assert (!SWITCH_LABELS (switch_expr)); - /* save old labels, get new ones from body, then restore the old + /* Save old labels, get new ones from body, then restore the old labels. Save all the things from the switch body to append after. */ saved_labels = gimplify_ctxp->case_labels; gimplify_ctxp->case_labels = VEC_alloc (tree, heap, 8); @@ -1603,18 +1607,82 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) gimplify_ctxp->case_labels = saved_labels; i = 0; + min_value = TYPE_MIN_VALUE (index_type); + max_value = TYPE_MAX_VALUE (index_type); while (i < VEC_length (tree, labels)) { tree elt = VEC_index (tree, labels, i); tree low = CASE_LOW (elt); + tree high = CASE_HIGH (elt); bool remove_element = FALSE; + if (low) { - /* Discard empty ranges. */ - tree high = CASE_HIGH (elt); - if (high && tree_int_cst_lt (high, low)) - remove_element = TRUE; + gcc_checking_assert (TREE_CODE (low) == INTEGER_CST); + gcc_checking_assert (!high || TREE_CODE (high) == INTEGER_CST); + + /* This is a non-default case label, i.e. it has a value. + + See if the case label is reachable within the range of + the index type. Remove out-of-range case values. Turn + case ranges into a canonical form (high > low strictly) + and convert the case label values to the index type. + + NB: The type of gimple_switch_index() may be the promoted + type, but the case labels retain the original type. */ + + if (high) + { + /* This is a case range. Discard empty ranges. + If the bounds or the range are equal, turn this + into a simple (one-value) case. */ + int cmp = tree_int_cst_compare (high, low); + if (cmp < 0) + remove_element = TRUE; + else if (cmp == 0) + high = NULL_TREE; + } + + if (! high) + { + /* If the simple case value is unreachable, ignore it. */ + if ((TREE_CODE (min_value) == INTEGER_CST + && tree_int_cst_compare (low, min_value) < 0) + || (TREE_CODE (max_value) == INTEGER_CST + && tree_int_cst_compare (low, max_value) > 0)) + remove_element = TRUE; + else + low = fold_convert (index_type, low); + } + else + { + /* If the entire case range is unreachable, ignore it. */ + if ((TREE_CODE (min_value) == INTEGER_CST + && tree_int_cst_compare (high, min_value) < 0) + || (TREE_CODE (max_value) == INTEGER_CST + && tree_int_cst_compare (low, max_value) > 0)) + remove_element = TRUE; + else + { + /* If the lower bound is less than the index type's + minimum value, truncate the range bounds. */ + if (TREE_CODE (min_value) == INTEGER_CST + && tree_int_cst_compare (low, min_value) < 0) + low = min_value; + low = fold_convert (index_type, low); + + /* If the upper bound is greater than the index type's + maximum value, truncate the range bounds. */ + if (TREE_CODE (max_value) == INTEGER_CST + && tree_int_cst_compare (high, max_value) > 0) + high = max_value; + high = fold_convert (index_type, high); + } + } + + CASE_LOW (elt) = low; + CASE_HIGH (elt) = high; } else { @@ -1636,25 +1704,20 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) if (!default_case) { - tree type = TREE_TYPE (switch_expr); - /* If the switch has no default label, add one, so that we jump around the switch body. If the labels already cover the whole - range of type, add the default label pointing to one of the - existing labels. */ - if (type == void_type_node) - type = TREE_TYPE (SWITCH_COND (switch_expr)); + range of the switch index_type, add the default label pointing + to one of the existing labels. */ if (len - && INTEGRAL_TYPE_P (type) - && TYPE_MIN_VALUE (type) - && TYPE_MAX_VALUE (type) + && TYPE_MIN_VALUE (index_type) + && TYPE_MAX_VALUE (index_type) && tree_int_cst_equal (CASE_LOW (VEC_index (tree, labels, 0)), - TYPE_MIN_VALUE (type))) + TYPE_MIN_VALUE (index_type))) { tree low, high = CASE_HIGH (VEC_index (tree, labels, len - 1)); if (!high) high = CASE_LOW (VEC_index (tree, labels, len - 1)); - if (tree_int_cst_equal (high, TYPE_MAX_VALUE (type))) + if (tree_int_cst_equal (high, TYPE_MAX_VALUE (index_type))) { for (i = 1; i < len; i++) { diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index f779e9b89cf..efbb8b11ac4 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,14 @@ +2012-04-20 Ian Lance Taylor <iant@google.com> + + * lang.opt: Add -fgo-check-divide-zero and + -fgo-check-divide-overflow. + * gccgo.texi (Invoking gccgo): Document new options. + +2012-04-18 Steven Bosscher <steven@gcc.gnu.org> + + * go-gcc.cc (Gcc_backend::switch_statement): Build SWITCH_EXPR + with NULL_TREE type instead of void_type_node. + 2012-03-09 Ian Lance Taylor <iant@google.com> * go-gcc.cc (Gcc_backend::assignment_statement): Convert the rhs diff --git a/gcc/go/gccgo.texi b/gcc/go/gccgo.texi index 13b56fc7345..5d0efb44fdb 100644 --- a/gcc/go/gccgo.texi +++ b/gcc/go/gccgo.texi @@ -12,7 +12,7 @@ @include gcc-common.texi @c Copyright years for this manual. -@set copyrights-go 2010 +@set copyrights-go 2010, 2011, 2012 @copying @c man begin COPYRIGHT @@ -174,6 +174,31 @@ By default @command{gccgo} will warn about functions which have one or more return parameters but lack an explicit @code{return} statement. This warning may be disabled using @option{-fno-require-return-statement}. + +@item -fgo-check-divide-zero +@cindex @option{-fgo-check-divide-zero} +@cindex @option{-fno-go-check-divide-zero} +Add explicit checks for division by zero. In Go a division (or +modulos) by zero causes a panic. On Unix systems this is detected in +the runtime by catching the @code{SIGFPE} signal. Some processors, +such as PowerPC, do not generate a SIGFPE on division by zero. Some +runtimes do not generate a signal that can be caught. On those +systems, this option may be used. Or the checks may be removed via +@option{-fno-go-check-divide-zero}. This option is currently on by +default, but in the future may be off by default on systems that do +not require it. + +@item -fgo-check-divide-overflow +@cindex @option{-fgo-check-divide-overflow} +@cindex @option{-fno-go-check-divide-overflow} +Add explicit checks for division overflow. For example, division +overflow occurs when computing @code{INT_MIN / -1}. In Go this should +be wrapped, to produce @code{INT_MIN}. Some processors, such as x86, +generate a trap on division overflow. On those systems, this option +may be used. Or the checks may be removed via +@option{-fno-go-check-divide-overflow}. This option is currently on +by default, but in the future may be off by default on systems that do +not require it. @end table @c man end diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 96c171835c4..08950b8e1d9 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -1087,7 +1087,7 @@ Gcc_backend::switch_statement( if (tv == error_mark_node) return this->error_statement(); tree t = build3_loc(switch_location.gcc_location(), SWITCH_EXPR, - void_type_node, tv, stmt_list, NULL_TREE); + NULL_TREE, tv, stmt_list, NULL_TREE); return this->make_statement(t); } diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index baff0c9a5d9..cb94e4f8dd9 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -2403,8 +2403,7 @@ class Const_expression : public Expression do_numeric_constant_value(Numeric_constant* nc) const; bool - do_string_constant_value(std::string* val) const - { return this->constant_->const_value()->expr()->string_constant_value(val); } + do_string_constant_value(std::string* val) const; Type* do_type(); @@ -2514,6 +2513,21 @@ Const_expression::do_numeric_constant_value(Numeric_constant* nc) const return r; } +bool +Const_expression::do_string_constant_value(std::string* val) const +{ + if (this->seen_) + return false; + + Expression* e = this->constant_->const_value()->expr(); + + this->seen_ = true; + bool ok = e->string_constant_value(val); + this->seen_ = false; + + return ok; +} + // Return the type of the const reference. Type* @@ -5633,6 +5647,7 @@ Binary_expression::do_get_tree(Translate_context* context) enum tree_code code; bool use_left_type = true; bool is_shift_op = false; + bool is_idiv_op = false; switch (this->op_) { case OPERATOR_EQEQ: @@ -5675,11 +5690,15 @@ Binary_expression::do_get_tree(Translate_context* context) if (t->float_type() != NULL || t->complex_type() != NULL) code = RDIV_EXPR; else - code = TRUNC_DIV_EXPR; + { + code = TRUNC_DIV_EXPR; + is_idiv_op = true; + } } break; case OPERATOR_MOD: code = TRUNC_MOD_EXPR; + is_idiv_op = true; break; case OPERATOR_LSHIFT: code = LSHIFT_EXPR; @@ -5700,6 +5719,7 @@ Binary_expression::do_get_tree(Translate_context* context) go_unreachable(); } + location_t gccloc = this->location().gcc_location(); tree type = use_left_type ? TREE_TYPE(left) : TREE_TYPE(right); if (this->left_->type()->is_string_type()) @@ -5727,28 +5747,27 @@ Binary_expression::do_get_tree(Translate_context* context) } tree eval_saved = NULL_TREE; - if (is_shift_op) + if (is_shift_op + || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow))) { // Make sure the values are evaluated. - if (!DECL_P(left) && TREE_SIDE_EFFECTS(left)) + if (!DECL_P(left)) { left = save_expr(left); eval_saved = left; } - if (!DECL_P(right) && TREE_SIDE_EFFECTS(right)) + if (!DECL_P(right)) { right = save_expr(right); if (eval_saved == NULL_TREE) eval_saved = right; else - eval_saved = fold_build2_loc(this->location().gcc_location(), - COMPOUND_EXPR, + eval_saved = fold_build2_loc(gccloc, COMPOUND_EXPR, void_type_node, eval_saved, right); } } - tree ret = fold_build2_loc(this->location().gcc_location(), - code, + tree ret = fold_build2_loc(gccloc, code, compute_type != NULL_TREE ? compute_type : type, left, right); @@ -5766,39 +5785,116 @@ Binary_expression::do_get_tree(Translate_context* context) tree compare = fold_build2(LT_EXPR, boolean_type_node, right, build_int_cst_type(TREE_TYPE(right), bits)); - tree overflow_result = fold_convert_loc(this->location().gcc_location(), - TREE_TYPE(left), + tree overflow_result = fold_convert_loc(gccloc, TREE_TYPE(left), integer_zero_node); if (this->op_ == OPERATOR_RSHIFT && !this->left_->type()->integer_type()->is_unsigned()) { tree neg = - fold_build2_loc(this->location().gcc_location(), LT_EXPR, - boolean_type_node, left, - fold_convert_loc(this->location().gcc_location(), - TREE_TYPE(left), + fold_build2_loc(gccloc, LT_EXPR, boolean_type_node, + left, + fold_convert_loc(gccloc, TREE_TYPE(left), integer_zero_node)); tree neg_one = - fold_build2_loc(this->location().gcc_location(), - MINUS_EXPR, TREE_TYPE(left), - fold_convert_loc(this->location().gcc_location(), - TREE_TYPE(left), + fold_build2_loc(gccloc, MINUS_EXPR, TREE_TYPE(left), + fold_convert_loc(gccloc, TREE_TYPE(left), integer_zero_node), - fold_convert_loc(this->location().gcc_location(), - TREE_TYPE(left), + fold_convert_loc(gccloc, TREE_TYPE(left), integer_one_node)); overflow_result = - fold_build3_loc(this->location().gcc_location(), COND_EXPR, - TREE_TYPE(left), neg, neg_one, - overflow_result); + fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left), + neg, neg_one, overflow_result); + } + + ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left), + compare, ret, overflow_result); + + if (eval_saved != NULL_TREE) + ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret), + eval_saved, ret); + } + + // Add checks for division by zero and division overflow as needed. + if (is_idiv_op) + { + if (go_check_divide_zero) + { + // right == 0 + tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node, + right, + fold_convert_loc(gccloc, + TREE_TYPE(right), + integer_zero_node)); + + // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO), 0 + int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO; + tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret), + Gogo::runtime_error(errcode, + this->location()), + fold_convert_loc(gccloc, TREE_TYPE(ret), + integer_zero_node)); + + // right == 0 ? (__go_runtime_error(...), 0) : ret + ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), + check, panic, ret); } - ret = fold_build3_loc(this->location().gcc_location(), COND_EXPR, - TREE_TYPE(left), compare, ret, overflow_result); + if (go_check_divide_overflow) + { + // right == -1 + // FIXME: It would be nice to say that this test is expected + // to return false. + tree m1 = integer_minus_one_node; + tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node, + right, + fold_convert_loc(gccloc, + TREE_TYPE(right), + m1)); + + tree overflow; + if (TYPE_UNSIGNED(TREE_TYPE(ret))) + { + // An unsigned -1 is the largest possible number, so + // dividing is always 1 or 0. + tree cmp = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node, + left, right); + if (this->op_ == OPERATOR_DIV) + overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), + cmp, + fold_convert_loc(gccloc, + TREE_TYPE(ret), + integer_one_node), + fold_convert_loc(gccloc, + TREE_TYPE(ret), + integer_zero_node)); + else + overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), + cmp, + fold_convert_loc(gccloc, + TREE_TYPE(ret), + integer_zero_node), + left); + } + else + { + // Computing left / -1 is the same as computing - left, + // which does not overflow since Go sets -fwrapv. + if (this->op_ == OPERATOR_DIV) + overflow = fold_build1_loc(gccloc, NEGATE_EXPR, TREE_TYPE(left), + left); + else + overflow = integer_zero_node; + } + overflow = fold_convert_loc(gccloc, TREE_TYPE(ret), overflow); + + // right == -1 ? - left : ret + ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), + check, overflow, ret); + } if (eval_saved != NULL_TREE) - ret = fold_build2_loc(this->location().gcc_location(), COMPOUND_EXPR, - TREE_TYPE(ret), eval_saved, ret); + ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret), + eval_saved, ret); } return ret; diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index fa229320c96..762f9fc9b81 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -495,7 +495,6 @@ Gogo::write_initialization_function(tree fndecl, tree init_stmt_list) gimplify_function_tree(fndecl); cgraph_add_new_function(fndecl, false); - cgraph_mark_needed_node(cgraph_get_node(fndecl)); current_function_decl = NULL_TREE; pop_cfun(); diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 6c77c3bd9e9..9c5f8cb4a6b 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -2791,6 +2791,9 @@ static const int RUNTIME_ERROR_MAKE_MAP_OUT_OF_BOUNDS = 8; // Channel capacity out of bounds in make: negative or overflow. static const int RUNTIME_ERROR_MAKE_CHAN_OUT_OF_BOUNDS = 9; +// Division by zero. +static const int RUNTIME_ERROR_DIVISION_BY_ZERO = 10; + // This is used by some of the langhooks. extern Gogo* go_get_gogo(); diff --git a/gcc/go/lang.opt b/gcc/go/lang.opt index 96c8d739f85..c14df9c6107 100644 --- a/gcc/go/lang.opt +++ b/gcc/go/lang.opt @@ -1,6 +1,6 @@ ; lang.opt -- Options for the gcc Go front end. -; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. +; Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc. ; ; This file is part of GCC. ; @@ -37,6 +37,14 @@ Wall Go ; Documented in c.opt +fgo-check-divide-zero +Go Var(go_check_divide_zero) Init(1) +Add explicit checks for division by zero + +fgo-check-divide-overflow +Go Var(go_check_divide_overflow) Init(1) +Add explicit checks for division overflow in INT_MIN / -1 + fgo-dump- Go Joined RejectNegative -fgo-dump-<type> Dump Go frontend internal information diff --git a/gcc/godump.c b/gcc/godump.c index a42e641d181..ab1edc620f9 100644 --- a/gcc/godump.c +++ b/gcc/godump.c @@ -1024,12 +1024,25 @@ go_output_typedef (struct godump_container *container, tree decl) fprintf (go_dump_file, "type _%s ", IDENTIFIER_POINTER (DECL_NAME (decl))); go_output_type (container); + + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))) + { + HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl)); + + if (size > 0) + fprintf (go_dump_file, + "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC, + IDENTIFIER_POINTER (DECL_NAME (decl)), + size); + } + pointer_set_insert (container->decls_seen, decl); } else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))) { void **slot; const char *type; + HOST_WIDE_INT size; type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl)))); /* If type defined already, skip. */ @@ -1047,6 +1060,13 @@ go_output_typedef (struct godump_container *container, tree decl) fprintf (go_dump_file, "type _%s ", IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl)))); go_output_type (container); + + size = int_size_in_bytes (TREE_TYPE (decl)); + if (size > 0) + fprintf (go_dump_file, + "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC, + IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))), + size); } else return; diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c index d9bcf278307..4a2ca40ba13 100644 --- a/gcc/graphite-sese-to-poly.c +++ b/gcc/graphite-sese-to-poly.c @@ -1092,7 +1092,7 @@ build_loop_iteration_domains (scop_p scop, struct loop *loop, scan_tree_for_params (SCOP_REGION (scop), nb_iters, ub_expr, one); mpz_clear (one); - if (max_stmt_executions (loop, true, &nit)) + if (max_stmt_executions (loop, &nit)) add_upper_bounds_from_estimated_nit (scop, nit, dim, ub_expr); /* loop_i <= expr_nb_iters */ diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index 09c6af22d43..569cd2bace4 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -3946,88 +3946,106 @@ static void prune_ready_list (state_t temp_state, bool first_cycle_insn_p, bool shadows_only_p, bool modulo_epilogue_p) { - int i; + int i, pass; bool sched_group_found = false; + int min_cost_group = 1; - restart: for (i = 0; i < ready.n_ready; i++) { rtx insn = ready_element (&ready, i); - int cost = 0; - const char *reason = "resource conflict"; - - if (DEBUG_INSN_P (insn)) - continue; - - if (SCHED_GROUP_P (insn) && !sched_group_found) + if (SCHED_GROUP_P (insn)) { sched_group_found = true; - if (i > 0) - goto restart; + break; } + } - if (sched_group_found && !SCHED_GROUP_P (insn)) - { - cost = 1; - reason = "not in sched group"; - } - else if (modulo_epilogue_p && INSN_EXACT_TICK (insn) == INVALID_TICK) - { - cost = max_insn_queue_index; - reason = "not an epilogue insn"; - } - else if (shadows_only_p && !SHADOW_P (insn)) - { - cost = 1; - reason = "not a shadow"; - } - else if (recog_memoized (insn) < 0) - { - if (!first_cycle_insn_p - && (GET_CODE (PATTERN (insn)) == ASM_INPUT - || asm_noperands (PATTERN (insn)) >= 0)) - cost = 1; - reason = "asm"; - } - else if (sched_pressure_p) - cost = 0; - else + /* Make two passes if there's a SCHED_GROUP_P insn; make sure to handle + such an insn first and note its cost, then schedule all other insns + for one cycle later. */ + for (pass = sched_group_found ? 0 : 1; pass < 2; ) + { + int n = ready.n_ready; + for (i = 0; i < n; i++) { - int delay_cost = 0; + rtx insn = ready_element (&ready, i); + int cost = 0; + const char *reason = "resource conflict"; - if (delay_htab) + if (DEBUG_INSN_P (insn)) + continue; + + if (sched_group_found && !SCHED_GROUP_P (insn)) { - struct delay_pair *delay_entry; - delay_entry - = (struct delay_pair *)htab_find_with_hash (delay_htab, insn, - htab_hash_pointer (insn)); - while (delay_entry && delay_cost == 0) + if (pass == 0) + continue; + cost = min_cost_group; + reason = "not in sched group"; + } + else if (modulo_epilogue_p + && INSN_EXACT_TICK (insn) == INVALID_TICK) + { + cost = max_insn_queue_index; + reason = "not an epilogue insn"; + } + else if (shadows_only_p && !SHADOW_P (insn)) + { + cost = 1; + reason = "not a shadow"; + } + else if (recog_memoized (insn) < 0) + { + if (!first_cycle_insn_p + && (GET_CODE (PATTERN (insn)) == ASM_INPUT + || asm_noperands (PATTERN (insn)) >= 0)) + cost = 1; + reason = "asm"; + } + else if (sched_pressure_p) + cost = 0; + else + { + int delay_cost = 0; + + if (delay_htab) { - delay_cost = estimate_shadow_tick (delay_entry); - if (delay_cost > max_insn_queue_index) - delay_cost = max_insn_queue_index; - delay_entry = delay_entry->next_same_i1; + struct delay_pair *delay_entry; + delay_entry + = (struct delay_pair *)htab_find_with_hash (delay_htab, insn, + htab_hash_pointer (insn)); + while (delay_entry && delay_cost == 0) + { + delay_cost = estimate_shadow_tick (delay_entry); + if (delay_cost > max_insn_queue_index) + delay_cost = max_insn_queue_index; + delay_entry = delay_entry->next_same_i1; + } } - } - memcpy (temp_state, curr_state, dfa_state_size); - cost = state_transition (temp_state, insn); - if (cost < 0) - cost = 0; - else if (cost == 0) - cost = 1; - if (cost < delay_cost) + memcpy (temp_state, curr_state, dfa_state_size); + cost = state_transition (temp_state, insn); + if (cost < 0) + cost = 0; + else if (cost == 0) + cost = 1; + if (cost < delay_cost) + { + cost = delay_cost; + reason = "shadow tick"; + } + } + if (cost >= 1) { - cost = delay_cost; - reason = "shadow tick"; + if (SCHED_GROUP_P (insn) && cost > min_cost_group) + min_cost_group = cost; + ready_remove (&ready, i); + queue_insn (insn, cost, reason); + if (i + 1 < n) + break; } } - if (cost >= 1) - { - ready_remove (&ready, i); - queue_insn (insn, cost, reason); - goto restart; - } + if (i == n) + pass++; } } diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index e4e13abe0aa..79e27380283 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -3927,6 +3927,11 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge) edge else_succ; int then_prob, else_prob; + /* We do not want to speculate (empty) loop latches. */ + if (current_loops + && else_bb->loop_father->latch == else_bb) + return FALSE; + /* If we are partitioning hot/cold basic blocks, we don't want to mess up unconditional or indirect jumps that cross between hot and cold sections. diff --git a/gcc/input.c b/gcc/input.c index 4077f9e5dbd..bf5fe481fdf 100644 --- a/gcc/input.c +++ b/gcc/input.c @@ -50,6 +50,65 @@ expand_location (source_location loc) return xloc; } +/* Reads one line from file into a static buffer. */ +static const char * +read_line (FILE *file) +{ + static char *string; + static size_t string_len; + size_t pos = 0; + char *ptr; + + if (!string_len) + { + string_len = 200; + string = XNEWVEC (char, string_len); + } + + while ((ptr = fgets (string + pos, string_len - pos, file))) + { + size_t len = strlen (string + pos); + + if (string[pos + len - 1] == '\n') + { + string[pos + len - 1] = 0; + return string; + } + pos += len; + ptr = XNEWVEC (char, string_len * 2); + if (ptr) + { + memcpy (ptr, string, pos); + string = ptr; + string_len += 2; + } + else + pos = 0; + } + + return pos ? string : NULL; +} + +/* Return the physical source line that corresponds to xloc in a + buffer that is statically allocated. The newline is replaced by + the null character. */ + +const char * +location_get_source_line(expanded_location xloc) +{ + const char *buffer; + int lines = 1; + FILE *stream = xloc.file ? fopen (xloc.file, "r") : NULL; + if (!stream) + return NULL; + + while ((buffer = read_line (stream)) && lines < xloc.line) + lines++; + + fclose (stream); + return buffer; +} + #define ONE_K 1024 #define ONE_M (ONE_K * ONE_K) diff --git a/gcc/input.h b/gcc/input.h index f2f351311fc..4b152228fc4 100644 --- a/gcc/input.h +++ b/gcc/input.h @@ -38,6 +38,7 @@ extern char builtins_location_check[(BUILTINS_LOCATION < RESERVED_LOCATION_COUNT) ? 1 : -1]; extern expanded_location expand_location (source_location); +extern const char * location_get_source_line(expanded_location xloc); /* Historically GCC used location_t, while cpp used source_location. This could be removed but it hardly seems worth the effort. */ diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index bb008c03878..4826c582c83 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -247,11 +247,11 @@ ipa_lat_is_single_const (struct ipcp_lattice *lat) static inline bool edge_within_scc (struct cgraph_edge *cs) { - struct ipa_dfs_info *caller_dfs = (struct ipa_dfs_info *) cs->caller->aux; + struct ipa_dfs_info *caller_dfs = (struct ipa_dfs_info *) cs->caller->symbol.aux; struct ipa_dfs_info *callee_dfs; struct cgraph_node *callee = cgraph_function_node (cs->callee, NULL); - callee_dfs = (struct ipa_dfs_info *) callee->aux; + callee_dfs = (struct ipa_dfs_info *) callee->symbol.aux; return (caller_dfs && callee_dfs && caller_dfs->scc_no == callee_dfs->scc_no); @@ -450,7 +450,7 @@ ipcp_cloning_candidate_p (struct cgraph_node *node) return false; } - if (!optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->decl))) + if (!optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->symbol.decl))) { if (dump_file) fprintf (dump_file, "Not considering %s for cloning; " @@ -1192,7 +1192,7 @@ devirtualization_time_bonus (struct cgraph_node *node, else if (isummary->size <= MAX_INLINE_INSNS_AUTO / 2) res += 15; else if (isummary->size <= MAX_INLINE_INSNS_AUTO - || DECL_DECLARED_INLINE_P (callee->decl)) + || DECL_DECLARED_INLINE_P (callee->symbol.decl)) res += 7; } @@ -1209,7 +1209,7 @@ good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit, { if (time_benefit == 0 || !flag_ipa_cp_clone - || !optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->decl))) + || !optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->symbol.decl))) return false; gcc_assert (size_cost > 0); @@ -1532,14 +1532,14 @@ propagate_constants_topo (struct topo_info *topo) if (!cgraph_function_with_gimple_body_p (node)) continue; - node_dfs_info = (struct ipa_dfs_info *) node->aux; + node_dfs_info = (struct ipa_dfs_info *) node->symbol.aux; /* First, iteratively propagate within the strongly connected component until all lattices stabilize. */ v = node_dfs_info->next_cycle; while (v) { push_node_to_stack (topo, v); - v = ((struct ipa_dfs_info *) v->aux)->next_cycle; + v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle; } v = node; @@ -1568,7 +1568,7 @@ propagate_constants_topo (struct topo_info *topo) if (!edge_within_scc (cs)) propagate_constants_accross_call (cs); - v = ((struct ipa_dfs_info *) v->aux)->next_cycle; + v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle; } } } @@ -2384,20 +2384,20 @@ static void identify_dead_nodes (struct cgraph_node *node) { struct cgraph_node *v; - for (v = node; v ; v = ((struct ipa_dfs_info *) v->aux)->next_cycle) + for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle) if (cgraph_will_be_removed_from_program_if_no_direct_calls (v) && !cgraph_for_node_and_aliases (v, has_undead_caller_from_outside_scc_p, NULL, true)) IPA_NODE_REF (v)->node_dead = 1; - for (v = node; v ; v = ((struct ipa_dfs_info *) v->aux)->next_cycle) + for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle) if (!IPA_NODE_REF (v)->node_dead) spread_undeadness (v); if (dump_file && (dump_flags & TDF_DETAILS)) { - for (v = node; v ; v = ((struct ipa_dfs_info *) v->aux)->next_cycle) + for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle) if (IPA_NODE_REF (v)->node_dead) fprintf (dump_file, " Marking node as dead: %s/%i.\n", cgraph_node_name (v), v->uid); @@ -2424,7 +2424,7 @@ ipcp_decision_stage (struct topo_info *topo) { struct cgraph_node *v; iterate = false; - for (v = node; v ; v = ((struct ipa_dfs_info *) v->aux)->next_cycle) + for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle) if (cgraph_function_with_gimple_body_p (v) && ipcp_versionable_function_p (v)) iterate |= decide_whether_version_node (v); @@ -2494,9 +2494,8 @@ ipcp_generate_summary (void) FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) { - /* Unreachable nodes should have been eliminated before ipcp. */ - gcc_assert (node->needed || node->reachable); - node->local.versionable = tree_versionable_function_p (node->decl); + node->local.versionable + = tree_versionable_function_p (node->symbol.decl); ipa_analyze_node (node); } } @@ -2543,7 +2542,7 @@ struct ipa_opt_pass_d pass_ipa_cp = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_cgraph | + TODO_dump_symtab | TODO_remove_functions | TODO_ggc_collect /* todo_flags_finish */ }, ipcp_generate_summary, /* generate_summary */ diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index 4026f4ed50f..dd01d33740f 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -1186,7 +1186,7 @@ dump_inline_summary (FILE * f, struct cgraph_node *node) int i; fprintf (f, "Inline summary for %s/%i", cgraph_node_name (node), node->uid); - if (DECL_DISREGARD_INLINE_LIMITS (node->decl)) + if (DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl)) fprintf (f, " always_inline"); if (s->inlinable) fprintf (f, " inlinable"); @@ -1226,8 +1226,8 @@ dump_inline_summaries (FILE *f) { struct cgraph_node *node; - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed && !node->global.inlined_to) + FOR_EACH_DEFINED_FUNCTION (node) + if (!node->global.inlined_to) dump_inline_summary (f, node); } @@ -1583,7 +1583,7 @@ compute_bb_predicates (struct cgraph_node *node, struct ipa_node_params *parms_info, struct inline_summary *summary) { - struct function *my_function = DECL_STRUCT_FUNCTION (node->decl); + struct function *my_function = DECL_STRUCT_FUNCTION (node->symbol.decl); bool done = false; basic_block bb; @@ -1871,7 +1871,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) <0,2>. */ basic_block bb; gimple_stmt_iterator bsi; - struct function *my_function = DECL_STRUCT_FUNCTION (node->decl); + struct function *my_function = DECL_STRUCT_FUNCTION (node->symbol.decl); int freq; struct inline_summary *info = inline_summary (node); struct predicate bb_predicate; @@ -1906,7 +1906,7 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early) compute_bb_predicates (node, parms_info, info); FOR_EACH_BB_FN (bb, my_function) { - freq = compute_call_stmt_bb_frequency (node->decl, bb); + freq = compute_call_stmt_bb_frequency (node->symbol.decl, bb); /* TODO: Obviously predicates can be propagated down across CFG. */ if (parms_info) @@ -2096,8 +2096,8 @@ compute_inline_parameters (struct cgraph_node *node, bool early) } /* Even is_gimple_min_invariant rely on current_function_decl. */ - current_function_decl = node->decl; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + current_function_decl = node->symbol.decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); /* Estimate the stack size for the function if we're optimizing. */ self_stack_size = optimize ? estimated_stack_frame_size (node) : 0; @@ -2106,10 +2106,10 @@ compute_inline_parameters (struct cgraph_node *node, bool early) info->stack_frame_offset = 0; /* Can this function be inlined at all? */ - info->inlinable = tree_inlinable_function_p (node->decl); + info->inlinable = tree_inlinable_function_p (node->symbol.decl); /* Type attributes can use parameter indices to describe them. */ - if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl))) + if (TYPE_ATTRIBUTES (TREE_TYPE (node->symbol.decl))) node->local.can_change_signature = false; else { @@ -2121,7 +2121,7 @@ compute_inline_parameters (struct cgraph_node *node, bool early) /* Functions calling builtin_apply can not change signature. */ for (e = node->callees; e; e = e->next_callee) { - tree cdecl = e->callee->decl; + tree cdecl = e->callee->symbol.decl; if (DECL_BUILT_IN (cdecl) && DECL_BUILT_IN_CLASS (cdecl) == BUILT_IN_NORMAL && (DECL_FUNCTION_CODE (cdecl) == BUILT_IN_APPLY_ARGS @@ -2879,13 +2879,13 @@ do_estimate_growth (struct cgraph_node *node) d.growth = d.growth < info->size ? info->size : d.growth; else { - if (!DECL_EXTERNAL (node->decl) + if (!DECL_EXTERNAL (node->symbol.decl) && cgraph_will_be_removed_from_program_if_no_direct_calls (node)) d.growth -= info->size; /* COMDAT functions are very often not shared across multiple units since they come from various template instantiations. Take this into account. */ - else if (DECL_COMDAT (node->decl) + else if (DECL_COMDAT (node->symbol.decl) && cgraph_can_remove_if_no_direct_calls_p (node)) d.growth -= (info->size * (100 - PARAM_VALUE (PARAM_COMDAT_SHARING_PROBABILITY)) @@ -2923,8 +2923,8 @@ inline_indirect_intraprocedural_analysis (struct cgraph_node *node) static void inline_analyze_function (struct cgraph_node *node) { - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - current_function_decl = node->decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); + current_function_decl = node->symbol.decl; if (dump_file) fprintf (dump_file, "\nAnalyzing function: %s/%u\n", diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c index 32d8c167be1..c6cbd015c33 100644 --- a/gcc/ipa-inline-transform.c +++ b/gcc/ipa-inline-transform.c @@ -88,16 +88,16 @@ can_remove_node_now_p_1 (struct cgraph_node *node) /* FIXME: When address is taken of DECL_EXTERNAL function we still can remove its offline copy, but we would need to keep unanalyzed node in the callgraph so references can point to it. */ - return (!node->address_taken - && !ipa_ref_has_aliases_p (&node->ref_list) + return (!node->symbol.address_taken + && !ipa_ref_has_aliases_p (&node->symbol.ref_list) && cgraph_can_remove_if_no_direct_calls_p (node) /* Inlining might enable more devirtualizing, so we want to remove those only after all devirtualizable virtual calls are processed. Lacking may edges in callgraph we just preserve them post inlining. */ - && (!DECL_VIRTUAL_P (node->decl) - || (!DECL_COMDAT (node->decl) - && !DECL_EXTERNAL (node->decl))) + && (!DECL_VIRTUAL_P (node->symbol.decl) + || (!DECL_COMDAT (node->symbol.decl) + && !DECL_EXTERNAL (node->symbol.decl))) /* During early inlining some unanalyzed cgraph nodes might be in the callgraph and they might reffer the function in question. */ && !cgraph_new_nodes); @@ -116,10 +116,10 @@ can_remove_node_now_p (struct cgraph_node *node, struct cgraph_edge *e) /* When we see same comdat group, we need to be sure that all items can be removed. */ - if (!node->same_comdat_group) + if (!node->symbol.same_comdat_group) return true; - for (next = node->same_comdat_group; - next != node; next = next->same_comdat_group) + for (next = cgraph (node->symbol.same_comdat_group); + next != node; next = cgraph (next->symbol.same_comdat_group)) if ((next->callers && next->callers != e) || !can_remove_node_now_p_1 (next)) return false; @@ -157,20 +157,20 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, For now we keep the ohter functions in the group in program until cgraph_remove_unreachable_functions gets rid of them. */ gcc_assert (!e->callee->global.inlined_to); - if (e->callee->analyzed && !DECL_EXTERNAL (e->callee->decl)) + if (e->callee->analyzed && !DECL_EXTERNAL (e->callee->symbol.decl)) { if (overall_size) *overall_size -= inline_summary (e->callee)->size; nfunctions_inlined++; } duplicate = false; - e->callee->local.externally_visible = false; + e->callee->symbol.externally_visible = false; update_noncloned_frequencies (e->callee, e->frequency); } else { struct cgraph_node *n; - n = cgraph_clone_node (e->callee, e->callee->decl, + n = cgraph_clone_node (e->callee, e->callee->symbol.decl, e->count, e->frequency, update_original, NULL, true); cgraph_redirect_edge_callee (e, n); @@ -211,7 +211,7 @@ inline_call (struct cgraph_edge *e, bool update_original, gcc_assert (!callee->global.inlined_to); e->inline_failed = CIF_OK; - DECL_POSSIBLY_INLINED (callee->decl) = true; + DECL_POSSIBLY_INLINED (callee->symbol.decl) = true; to = e->caller; if (to->global.inlined_to) @@ -273,13 +273,13 @@ save_inline_function_body (struct cgraph_node *node) fprintf (dump_file, "\nSaving body of %s for later reuse\n", cgraph_node_name (node)); - gcc_assert (node == cgraph_get_node (node->decl)); + gcc_assert (node == cgraph_get_node (node->symbol.decl)); /* first_clone will be turned into real function. */ first_clone = node->clones; - first_clone->decl = copy_node (node->decl); - cgraph_insert_node_to_hashtable (first_clone); - gcc_assert (first_clone == cgraph_get_node (first_clone->decl)); + first_clone->symbol.decl = copy_node (node->symbol.decl); + symtab_insert_node_to_hashtable ((symtab_node) first_clone); + gcc_assert (first_clone == cgraph_get_node (first_clone->symbol.decl)); /* Now reshape the clone tree, so all other clones descends from first_clone. */ @@ -307,8 +307,8 @@ save_inline_function_body (struct cgraph_node *node) if (first_clone->clones) for (n = first_clone->clones; n != first_clone;) { - gcc_assert (n->decl == node->decl); - n->decl = first_clone->decl; + gcc_assert (n->symbol.decl == node->symbol.decl); + n->symbol.decl = first_clone->symbol.decl; if (n->clones) n = n->clones; else if (n->next_sibling_clone) @@ -323,15 +323,15 @@ save_inline_function_body (struct cgraph_node *node) } /* Copy the OLD_VERSION_NODE function tree to the new version. */ - tree_function_versioning (node->decl, first_clone->decl, NULL, true, NULL, - false, NULL, NULL); + tree_function_versioning (node->symbol.decl, first_clone->symbol.decl, + NULL, true, NULL, false, NULL, NULL); /* The function will be short lived and removed after we inline all the clones, but make it internal so we won't confuse ourself. */ - DECL_EXTERNAL (first_clone->decl) = 0; - DECL_COMDAT_GROUP (first_clone->decl) = NULL_TREE; - TREE_PUBLIC (first_clone->decl) = 0; - DECL_COMDAT (first_clone->decl) = 0; + DECL_EXTERNAL (first_clone->symbol.decl) = 0; + DECL_COMDAT_GROUP (first_clone->symbol.decl) = NULL_TREE; + TREE_PUBLIC (first_clone->symbol.decl) = 0; + DECL_COMDAT (first_clone->symbol.decl) = 0; VEC_free (ipa_opt_pass, heap, first_clone->ipa_transforms_to_apply); first_clone->ipa_transforms_to_apply = NULL; diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index d7ccf684f64..451bd617603 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -240,18 +240,18 @@ can_inline_edge_p (struct cgraph_edge *e, bool report) enum availability avail; struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, &avail); - tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (e->caller->decl); + tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (e->caller->symbol.decl); tree callee_tree - = callee ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee->decl) : NULL; - struct function *caller_cfun = DECL_STRUCT_FUNCTION (e->caller->decl); + = callee ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee->symbol.decl) : NULL; + struct function *caller_cfun = DECL_STRUCT_FUNCTION (e->caller->symbol.decl); struct function *callee_cfun - = callee ? DECL_STRUCT_FUNCTION (callee->decl) : NULL; + = callee ? DECL_STRUCT_FUNCTION (callee->symbol.decl) : NULL; if (!caller_cfun && e->caller->clone_of) - caller_cfun = DECL_STRUCT_FUNCTION (e->caller->clone_of->decl); + caller_cfun = DECL_STRUCT_FUNCTION (e->caller->clone_of->symbol.decl); if (!callee_cfun && callee && callee->clone_of) - callee_cfun = DECL_STRUCT_FUNCTION (callee->clone_of->decl); + callee_cfun = DECL_STRUCT_FUNCTION (callee->clone_of->symbol.decl); gcc_assert (e->inline_failed); @@ -276,18 +276,18 @@ can_inline_edge_p (struct cgraph_edge *e, bool report) inlinable = false; } /* Don't inline if the functions have different EH personalities. */ - else if (DECL_FUNCTION_PERSONALITY (e->caller->decl) - && DECL_FUNCTION_PERSONALITY (callee->decl) - && (DECL_FUNCTION_PERSONALITY (e->caller->decl) - != DECL_FUNCTION_PERSONALITY (callee->decl))) + else if (DECL_FUNCTION_PERSONALITY (e->caller->symbol.decl) + && DECL_FUNCTION_PERSONALITY (callee->symbol.decl) + && (DECL_FUNCTION_PERSONALITY (e->caller->symbol.decl) + != DECL_FUNCTION_PERSONALITY (callee->symbol.decl))) { e->inline_failed = CIF_EH_PERSONALITY; inlinable = false; } /* TM pure functions should not be inlined into non-TM_pure functions. */ - else if (is_tm_pure (callee->decl) - && !is_tm_pure (e->caller->decl)) + else if (is_tm_pure (callee->symbol.decl) + && !is_tm_pure (e->caller->symbol.decl)) { e->inline_failed = CIF_UNSPECIFIED; inlinable = false; @@ -303,19 +303,19 @@ can_inline_edge_p (struct cgraph_edge *e, bool report) inlinable = false; } /* Check compatibility of target optimization options. */ - else if (!targetm.target_option.can_inline_p (e->caller->decl, - callee->decl)) + else if (!targetm.target_option.can_inline_p (e->caller->symbol.decl, + callee->symbol.decl)) { e->inline_failed = CIF_TARGET_OPTION_MISMATCH; inlinable = false; } /* Check if caller growth allows the inlining. */ - else if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl) + else if (!DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl) && !lookup_attribute ("flatten", DECL_ATTRIBUTES (e->caller->global.inlined_to - ? e->caller->global.inlined_to->decl - : e->caller->decl)) + ? e->caller->global.inlined_to->symbol.decl + : e->caller->symbol.decl)) && !caller_growth_limits (e)) inlinable = false; /* Don't inline a function with a higher optimization level than the @@ -336,7 +336,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report) if (((caller_opt->x_optimize > callee_opt->x_optimize) || (caller_opt->x_optimize_size != callee_opt->x_optimize_size)) /* gcc.dg/pr43564.c. Look at forced inline even in -O0. */ - && !DECL_DISREGARD_INLINE_LIMITS (e->callee->decl)) + && !DECL_DISREGARD_INLINE_LIMITS (e->callee->symbol.decl)) { e->inline_failed = CIF_OPTIMIZATION_MISMATCH; inlinable = false; @@ -359,7 +359,7 @@ can_early_inline_edge_p (struct cgraph_edge *e) /* Early inliner might get called at WPA stage when IPA pass adds new function. In this case we can not really do any of early inlining because function bodies are missing. */ - if (!gimple_has_body_p (callee->decl)) + if (!gimple_has_body_p (callee->symbol.decl)) { e->inline_failed = CIF_BODY_NOT_AVAILABLE; return false; @@ -368,8 +368,8 @@ can_early_inline_edge_p (struct cgraph_edge *e) (i.e. the callgraph is cyclic and we did not process the callee by early inliner, yet). We don't have CIF code for this case; later we will re-do the decision in the real inliner. */ - if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (e->caller->decl)) - || !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (callee->decl))) + if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (e->caller->symbol.decl)) + || !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (callee->symbol.decl))) { if (dump_file) fprintf (dump_file, " edge not inlinable: not in SSA form\n"); @@ -389,7 +389,7 @@ leaf_node_p (struct cgraph_node *n) { struct cgraph_edge *e; for (e = n->callees; e; e = e->next_callee) - if (!is_inexpensive_builtin (e->callee->decl)) + if (!is_inexpensive_builtin (e->callee->symbol.decl)) return false; return true; } @@ -403,9 +403,9 @@ want_early_inline_function_p (struct cgraph_edge *e) bool want_inline = true; struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL); - if (DECL_DISREGARD_INLINE_LIMITS (callee->decl)) + if (DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl)) ; - else if (!DECL_DECLARED_INLINE_P (callee->decl) + else if (!DECL_DECLARED_INLINE_P (callee->symbol.decl) && !flag_inline_small_functions) { e->inline_failed = CIF_FUNCTION_NOT_INLINE_CANDIDATE; @@ -462,9 +462,9 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) bool want_inline = true; struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL); - if (DECL_DISREGARD_INLINE_LIMITS (callee->decl)) + if (DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl)) ; - else if (!DECL_DECLARED_INLINE_P (callee->decl) + else if (!DECL_DECLARED_INLINE_P (callee->symbol.decl) && !flag_inline_small_functions) { e->inline_failed = CIF_FUNCTION_NOT_INLINE_CANDIDATE; @@ -476,7 +476,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) if (growth <= 0) ; - else if (DECL_DECLARED_INLINE_P (callee->decl) + else if (DECL_DECLARED_INLINE_P (callee->symbol.decl) && growth >= MAX_INLINE_INSNS_SINGLE) { e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT; @@ -514,17 +514,17 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) Consequently we ask cgraph_can_remove_if_no_direct_calls_p instead of cgraph_will_be_removed_from_program_if_no_direct_calls */ - && !DECL_EXTERNAL (callee->decl) + && !DECL_EXTERNAL (callee->symbol.decl) && cgraph_can_remove_if_no_direct_calls_p (callee) && estimate_growth (callee) <= 0) ; - else if (!DECL_DECLARED_INLINE_P (callee->decl) + else if (!DECL_DECLARED_INLINE_P (callee->symbol.decl) && !flag_inline_functions) { e->inline_failed = CIF_NOT_DECLARED_INLINED; want_inline = false; } - else if (!DECL_DECLARED_INLINE_P (callee->decl) + else if (!DECL_DECLARED_INLINE_P (callee->symbol.decl) && growth >= MAX_INLINE_INSNS_AUTO) { e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT; @@ -564,7 +564,7 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge, int caller_freq = CGRAPH_FREQ_BASE; int max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO); - if (DECL_DECLARED_INLINE_P (edge->caller->decl)) + if (DECL_DECLARED_INLINE_P (edge->caller->symbol.decl)) max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH); if (!cgraph_maybe_hot_edge_p (edge)) @@ -690,7 +690,7 @@ want_inline_function_called_once_p (struct cgraph_node *node) return false; /* External functions are not really in the unit, so inlining them when called once would just increase the program size. */ - if (DECL_EXTERNAL (function->decl)) + if (DECL_EXTERNAL (function->symbol.decl)) return false; /* Offline body must be optimized out. */ if (!cgraph_will_be_removed_from_program_if_no_direct_calls (function)) @@ -745,7 +745,7 @@ edge_badness (struct cgraph_edge *edge, bool dump) NULL); struct inline_summary *callee_info = inline_summary (callee); - if (DECL_DISREGARD_INLINE_LIMITS (callee->decl)) + if (DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl)) return INT_MIN; growth = estimate_edge_growth (edge); @@ -957,9 +957,10 @@ reset_edge_caches (struct cgraph_node *node) for (edge = where->callers; edge; edge = edge->next_caller) if (edge->inline_failed) reset_edge_growth_cache (edge); - for (i = 0; ipa_ref_list_refering_iterate (&where->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (&where->symbol.ref_list, + i, ref); i++) if (ref->use == IPA_REF_ALIAS) - reset_edge_caches (ipa_ref_refering_node (ref)); + reset_edge_caches (ipa_ref_referring_node (ref)); if (!e) return; @@ -1008,10 +1009,11 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node, if (!bitmap_set_bit (updated_nodes, node->uid)) return; - for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, + i, ref); i++) if (ref->use == IPA_REF_ALIAS) { - struct cgraph_node *alias = ipa_ref_refering_node (ref); + struct cgraph_node *alias = ipa_ref_referring_node (ref); update_caller_keys (heap, alias, updated_nodes, check_inlinablity_for); } @@ -1178,7 +1180,7 @@ recursive_inlining (struct cgraph_edge *edge, if (node->global.inlined_to) node = node->global.inlined_to; - if (DECL_DECLARED_INLINE_P (node->decl)) + if (DECL_DECLARED_INLINE_P (node->symbol.decl)) limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE); /* Make sure that function is small enough to be considered for inlining. */ @@ -1213,8 +1215,8 @@ recursive_inlining (struct cgraph_edge *edge, depth = 1; for (cnode = curr->caller; cnode->global.inlined_to; cnode = cnode->callers->caller) - if (node->decl - == cgraph_function_or_thunk_node (curr->callee, NULL)->decl) + if (node->symbol.decl + == cgraph_function_or_thunk_node (curr->callee, NULL)->symbol.decl) depth++; if (!want_inline_self_recursive_call_p (curr, node, false, depth)) @@ -1234,7 +1236,7 @@ recursive_inlining (struct cgraph_edge *edge, if (!master_clone) { /* We need original clone to copy around. */ - master_clone = cgraph_clone_node (node, node->decl, + master_clone = cgraph_clone_node (node, node->symbol.decl, node->count, CGRAPH_FREQ_BASE, false, NULL, true); for (e = master_clone->callees; e; e = e->next_callee) @@ -1265,10 +1267,10 @@ recursive_inlining (struct cgraph_edge *edge, /* Remove master clone we used for inlining. We rely that clones inlined into master clone gets queued just before master clone so we don't need recursion. */ - for (node = cgraph_nodes; node != master_clone; + for (node = cgraph_first_function (); node != master_clone; node = next) { - next = node->next; + next = cgraph_next_function (node); if (node->global.inlined_to == master_clone) cgraph_remove_node (node); } @@ -1349,7 +1351,7 @@ inline_small_functions (void) { struct inline_summary *info = inline_summary (node); - if (!DECL_EXTERNAL (node->decl)) + if (!DECL_EXTERNAL (node->symbol.decl)) initial_size += info->size; } @@ -1451,7 +1453,7 @@ inline_small_functions (void) } if (overall_size + growth > max_size - && !DECL_DISREGARD_INLINE_LIMITS (callee->decl)) + && !DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl)) { edge->inline_failed = CIF_INLINE_UNIT_GROWTH_LIMIT; report_inline_failed_reason (edge); @@ -1497,7 +1499,7 @@ inline_small_functions (void) where = edge->caller; while (where->global.inlined_to) { - if (where->decl == callee->decl) + if (where->symbol.decl == callee->symbol.decl) outer_node = where, depth++; where = where->callers->caller; } @@ -1506,7 +1508,7 @@ inline_small_functions (void) true, depth)) { edge->inline_failed - = (DECL_DISREGARD_INLINE_LIMITS (edge->callee->decl) + = (DECL_DISREGARD_INLINE_LIMITS (edge->callee->symbol.decl) ? CIF_RECURSIVE_INLINING : CIF_UNSPECIFIED); continue; } @@ -1593,9 +1595,9 @@ flatten_function (struct cgraph_node *node, bool early) struct cgraph_edge *e; /* We shouldn't be called recursively when we are being processed. */ - gcc_assert (node->aux == NULL); + gcc_assert (node->symbol.aux == NULL); - node->aux = (void *) node; + node->symbol.aux = (void *) node; for (e = node->callees; e; e = e->next_callee) { @@ -1603,7 +1605,7 @@ flatten_function (struct cgraph_node *node, bool early) struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL); /* We've hit cycle? It is time to give up. */ - if (callee->aux) + if (callee->symbol.aux) { if (dump_file) fprintf (dump_file, @@ -1637,8 +1639,8 @@ flatten_function (struct cgraph_node *node, bool early) continue; } - if (gimple_in_ssa_p (DECL_STRUCT_FUNCTION (node->decl)) - != gimple_in_ssa_p (DECL_STRUCT_FUNCTION (callee->decl))) + if (gimple_in_ssa_p (DECL_STRUCT_FUNCTION (node->symbol.decl)) + != gimple_in_ssa_p (DECL_STRUCT_FUNCTION (callee->symbol.decl))) { if (dump_file) fprintf (dump_file, "Not inlining: SSA form does not match.\n"); @@ -1654,13 +1656,13 @@ flatten_function (struct cgraph_node *node, bool early) orig_callee = callee; inline_call (e, true, NULL, NULL); if (e->callee != orig_callee) - orig_callee->aux = (void *) node; + orig_callee->symbol.aux = (void *) node; flatten_function (e->callee, early); if (e->callee != orig_callee) - orig_callee->aux = NULL; + orig_callee->symbol.aux = NULL; } - node->aux = NULL; + node->symbol.aux = NULL; } /* Decide on the inlining. We do so in the topological order to avoid @@ -1683,8 +1685,8 @@ ipa_inline (void) nnodes = ipa_reverse_postorder (order); - for (node = cgraph_nodes; node; node = node->next) - node->aux = 0; + FOR_EACH_FUNCTION (node) + node->symbol.aux = 0; if (dump_file) fprintf (dump_file, "\nFlattening functions:\n"); @@ -1701,7 +1703,7 @@ ipa_inline (void) try to flatten itself turning it into a self-recursive function. */ if (lookup_attribute ("flatten", - DECL_ATTRIBUTES (node->decl)) != NULL) + DECL_ATTRIBUTES (node->symbol.decl)) != NULL) { if (dump_file) fprintf (dump_file, @@ -1740,7 +1742,7 @@ ipa_inline (void) to be hot. */ for (cold = 0; cold <= 1; cold ++) { - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { if (want_inline_function_called_once_p (node) && (cold @@ -1798,7 +1800,7 @@ inline_always_inline_functions (struct cgraph_node *node) for (e = node->callees; e; e = e->next_callee) { struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL); - if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl)) + if (!DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl)) continue; if (cgraph_edge_recursive_p (e)) @@ -1841,7 +1843,7 @@ early_inline_small_functions (struct cgraph_node *node) continue; /* Do not consider functions not declared inline. */ - if (!DECL_DECLARED_INLINE_P (callee->decl) + if (!DECL_DECLARED_INLINE_P (callee->symbol.decl) && !flag_inline_small_functions && !flag_inline_functions) continue; @@ -1917,10 +1919,10 @@ early_inliner (void) cycles of edges to be always inlined in the callgraph. We might want to be smarter and just avoid this type of inlining. */ - || DECL_DISREGARD_INLINE_LIMITS (node->decl)) + || DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl)) ; else if (lookup_attribute ("flatten", - DECL_ATTRIBUTES (node->decl)) != NULL) + DECL_ATTRIBUTES (node->symbol.decl)) != NULL) { /* When the function is marked to be flattened, recursively inline all calls in it. */ @@ -1951,9 +1953,9 @@ early_inliner (void) = estimate_num_insns (edge->call_stmt, &eni_size_weights); es->call_stmt_time = estimate_num_insns (edge->call_stmt, &eni_time_weights); - if (edge->callee->decl + if (edge->callee->symbol.decl && !gimple_check_call_matching_types (edge->call_stmt, - edge->callee->decl)) + edge->callee->symbol.decl)) edge->call_stmt_cannot_inline_p = true; } timevar_pop (TV_INTEGRATION); @@ -2023,7 +2025,7 @@ struct ipa_opt_pass_d pass_ipa_inline = 0, /* properties_provided */ 0, /* properties_destroyed */ TODO_remove_functions, /* todo_flags_finish */ - TODO_dump_cgraph + TODO_dump_symtab | TODO_remove_functions | TODO_ggc_collect /* todo_flags_finish */ }, inline_generate_summary, /* generate_summary */ diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h index a2c6cac0147..824a6c50350 100644 --- a/gcc/ipa-inline.h +++ b/gcc/ipa-inline.h @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see Conditions that are interesting for function body are collected into CONDS vector. They are of simple for function_param OP VAL, where VAL is - IPA invariant. The conditions are then refered by predicates. */ + IPA invariant. The conditions are then referred by predicates. */ typedef struct GTY(()) condition { diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 3856793b054..97a6a5cb0cf 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -91,7 +91,7 @@ ipa_populate_param_decls (struct cgraph_node *node, tree parm; int param_num; - fndecl = node->decl; + fndecl = node->symbol.decl; fnargs = DECL_ARGUMENTS (fndecl); param_num = 0; for (parm = fnargs; parm; parm = DECL_CHAIN (parm)) @@ -129,7 +129,7 @@ ipa_initialize_node_params (struct cgraph_node *node) { int param_count; - param_count = count_formal_params (node->decl); + param_count = count_formal_params (node->symbol.decl); if (param_count) { VEC_safe_grow_cleared (ipa_param_descriptor_t, heap, @@ -260,7 +260,7 @@ ipa_print_all_jump_functions (FILE *f) struct cgraph_node *node; fprintf (f, "\nJump functions:\n"); - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) { ipa_print_node_jump_functions (f, node); } @@ -1590,7 +1590,7 @@ static void ipa_analyze_params_uses (struct cgraph_node *node, struct param_analysis_info *parms_ainfo) { - tree decl = node->decl; + tree decl = node->symbol.decl; basic_block bb; struct function *func; gimple_stmt_iterator gsi; @@ -1606,7 +1606,7 @@ ipa_analyze_params_uses (struct cgraph_node *node, /* For SSA regs see if parameter is used. For non-SSA we compute the flag during modification analysis. */ if (is_gimple_reg (parm) - && gimple_default_def (DECL_STRUCT_FUNCTION (node->decl), parm)) + && gimple_default_def (DECL_STRUCT_FUNCTION (node->symbol.decl), parm)) ipa_set_param_used (info, i, true); } @@ -1650,8 +1650,8 @@ ipa_analyze_node (struct cgraph_node *node) ipa_check_create_node_params (); ipa_check_create_edge_args (); info = IPA_NODE_REF (node); - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - current_function_decl = node->decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); + current_function_decl = node->symbol.decl; ipa_initialize_node_params (node); param_count = ipa_get_param_count (info); @@ -1906,7 +1906,7 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs, if (new_direct_edge->call_stmt) new_direct_edge->call_stmt_cannot_inline_p = !gimple_check_call_matching_types (new_direct_edge->call_stmt, - new_direct_edge->callee->decl); + new_direct_edge->callee->symbol.decl); if (new_edges) { VEC_safe_push (cgraph_edge_p, heap, *new_edges, @@ -2209,7 +2209,7 @@ ipa_print_all_params (FILE * f) struct cgraph_node *node; fprintf (f, "\nFunction parameters:\n"); - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) ipa_print_node_params (f, node); } @@ -2427,7 +2427,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt, len = VEC_length (ipa_parm_adjustment_t, adjustments); vargs = VEC_alloc (tree, heap, len); - callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl; + callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->symbol.decl; gsi = gsi_for_stmt (stmt); for (i = 0; i < len; i++) @@ -3087,7 +3087,7 @@ ipa_update_after_lto_read (void) ipa_check_create_node_params (); ipa_check_create_edge_args (); - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) if (node->analyzed) ipa_initialize_node_params (node); } diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index e8b21f9fc6b..29b4c177b28 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -724,7 +724,7 @@ check_stmt (gimple_stmt_iterator *gsip, funct_state local, bool ipa) static funct_state analyze_function (struct cgraph_node *fn, bool ipa) { - tree decl = fn->decl; + tree decl = fn->symbol.decl; tree old_decl = current_function_decl; funct_state l; basic_block this_block; @@ -736,7 +736,7 @@ analyze_function (struct cgraph_node *fn, bool ipa) l->looping = false; l->can_throw = false; state_from_flags (&l->state_previously_known, &l->looping_previously_known, - flags_from_decl_or_type (fn->decl), + flags_from_decl_or_type (fn->symbol.decl), cgraph_node_cannot_return (fn)); if (fn->thunk.thunk_p || fn->alias) @@ -924,7 +924,7 @@ generate_summary (void) by default, but the info can be used at LTO with -fwhole-program or when function got cloned and the clone is AVAILABLE. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) set_function_state (node, analyze_function (node, true)); @@ -1037,7 +1037,7 @@ pure_const_read_summary (void) fs->can_throw = bp_unpack_value (&bp, 1); if (dump_file) { - int flags = flags_from_decl_or_type (node->decl); + int flags = flags_from_decl_or_type (node->symbol.decl); fprintf (dump_file, "Read info for %s/%i ", cgraph_node_name (node), node->uid); @@ -1215,11 +1215,11 @@ propagate_pure_const (void) } } else if (special_builtin_state (&edge_state, &edge_looping, - y->decl)) + y->symbol.decl)) ; else state_from_flags (&edge_state, &edge_looping, - flags_from_decl_or_type (y->decl), + flags_from_decl_or_type (y->symbol.decl), cgraph_edge_cannot_lead_to_return (e)); /* Merge the results with what we already know. */ @@ -1258,7 +1258,7 @@ propagate_pure_const (void) break; /* And finally all loads and stores. */ - for (i = 0; ipa_ref_list_reference_iterate (&w->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_reference_iterate (&w->symbol.ref_list, i, ref); i++) { enum pure_const_state_e ref_state = IPA_CONST; bool ref_looping = false; @@ -1266,7 +1266,7 @@ propagate_pure_const (void) { case IPA_REF_LOAD: /* readonly reads are safe. */ - if (TREE_READONLY (ipa_ref_varpool_node (ref)->decl)) + if (TREE_READONLY (ipa_ref_varpool_node (ref)->symbol.decl)) break; if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " nonreadonly global var read\n"); @@ -1290,7 +1290,7 @@ propagate_pure_const (void) if (pure_const_state == IPA_NEITHER) break; } - w_info = (struct ipa_dfs_info *) w->aux; + w_info = (struct ipa_dfs_info *) w->symbol.aux; w = w_info->next_cycle; } if (dump_file && (dump_flags & TDF_DETAILS)) @@ -1325,9 +1325,9 @@ propagate_pure_const (void) switch (this_state) { case IPA_CONST: - if (!TREE_READONLY (w->decl)) + if (!TREE_READONLY (w->symbol.decl)) { - warn_function_const (w->decl, !this_looping); + warn_function_const (w->symbol.decl, !this_looping); if (dump_file) fprintf (dump_file, "Function found to be %sconst: %s\n", this_looping ? "looping " : "", @@ -1337,9 +1337,9 @@ propagate_pure_const (void) break; case IPA_PURE: - if (!DECL_PURE_P (w->decl)) + if (!DECL_PURE_P (w->symbol.decl)) { - warn_function_pure (w->decl, !this_looping); + warn_function_pure (w->symbol.decl, !this_looping); if (dump_file) fprintf (dump_file, "Function found to be %spure: %s\n", this_looping ? "looping " : "", @@ -1351,7 +1351,7 @@ propagate_pure_const (void) default: break; } - w_info = (struct ipa_dfs_info *) w->aux; + w_info = (struct ipa_dfs_info *) w->symbol.aux; w = w_info->next_cycle; } } @@ -1418,17 +1418,17 @@ propagate_nothrow (void) if (can_throw) break; - if (y_l->can_throw && !TREE_NOTHROW (w->decl) + if (y_l->can_throw && !TREE_NOTHROW (w->symbol.decl) && e->can_throw_external) can_throw = true; } - else if (e->can_throw_external && !TREE_NOTHROW (y->decl)) + else if (e->can_throw_external && !TREE_NOTHROW (y->symbol.decl)) can_throw = true; } for (ie = node->indirect_calls; ie; ie = ie->next_callee) if (ie->can_throw_external) can_throw = true; - w_info = (struct ipa_dfs_info *) w->aux; + w_info = (struct ipa_dfs_info *) w->symbol.aux; w = w_info->next_cycle; } @@ -1438,16 +1438,16 @@ propagate_nothrow (void) while (w) { funct_state w_l = get_function_state (w); - if (!can_throw && !TREE_NOTHROW (w->decl)) + if (!can_throw && !TREE_NOTHROW (w->symbol.decl)) { cgraph_set_nothrow_flag (w, true); if (dump_file) fprintf (dump_file, "Function found to be nothrow: %s\n", cgraph_node_name (w)); } - else if (can_throw && !TREE_NOTHROW (w->decl)) + else if (can_throw && !TREE_NOTHROW (w->symbol.decl)) w_l->can_throw = true; - w_info = (struct ipa_dfs_info *) w->aux; + w_info = (struct ipa_dfs_info *) w->symbol.aux; w = w_info->next_cycle; } } @@ -1475,7 +1475,7 @@ propagate (void) propagate_pure_const (); /* Cleanup. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) if (has_function_state (node)) free (get_function_state (node)); VEC_free (funct_state, heap, funct_state_vec); diff --git a/gcc/ipa-ref-inline.h b/gcc/ipa-ref-inline.h index 6ca9ba08f30..636af145789 100644 --- a/gcc/ipa-ref-inline.h +++ b/gcc/ipa-ref-inline.h @@ -19,61 +19,51 @@ 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/>. */ -/* Return callgraph node REF is refering. */ +/* Return callgraph node REF is referring. */ static inline struct cgraph_node * ipa_ref_node (struct ipa_ref *ref) { - gcc_assert (ref->refered_type == IPA_REF_CGRAPH); - return ref->refered.cgraph_node; + return cgraph (ref->referred); } -/* Return varpool node REF is refering. */ +/* Return varpool node REF is referring. */ static inline struct varpool_node * ipa_ref_varpool_node (struct ipa_ref *ref) { - gcc_assert (ref->refered_type == IPA_REF_VARPOOL); - return ref->refered.varpool_node; + return varpool (ref->referred); } /* Return cgraph node REF is in. */ static inline struct cgraph_node * -ipa_ref_refering_node (struct ipa_ref *ref) +ipa_ref_referring_node (struct ipa_ref *ref) { - gcc_assert (ref->refering_type == IPA_REF_CGRAPH); - return ref->refering.cgraph_node; + return cgraph (ref->referring); } /* Return varpool node REF is in. */ static inline struct varpool_node * -ipa_ref_refering_varpool_node (struct ipa_ref *ref) +ipa_ref_referring_varpool_node (struct ipa_ref *ref) { - gcc_assert (ref->refering_type == IPA_REF_VARPOOL); - return ref->refering.varpool_node; + return varpool (ref->referring); } /* Return reference list REF is in. */ static inline struct ipa_ref_list * -ipa_ref_refering_ref_list (struct ipa_ref *ref) +ipa_ref_referring_ref_list (struct ipa_ref *ref) { - if (ref->refering_type == IPA_REF_CGRAPH) - return &ipa_ref_refering_node (ref)->ref_list; - else - return &ipa_ref_refering_varpool_node (ref)->ref_list; + return &ref->referring->symbol.ref_list; } /* Return reference list REF is in. */ static inline struct ipa_ref_list * -ipa_ref_refered_ref_list (struct ipa_ref *ref) +ipa_ref_referred_ref_list (struct ipa_ref *ref) { - if (ref->refered_type == IPA_REF_CGRAPH) - return &ipa_ref_node (ref)->ref_list; - else - return &ipa_ref_varpool_node (ref)->ref_list; + return &ref->referred->symbol.ref_list; } /* Return first reference in LIST or NULL if empty. */ @@ -86,14 +76,14 @@ ipa_ref_list_first_reference (struct ipa_ref_list *list) return VEC_index (ipa_ref_t, list->references, 0); } -/* Return first refering ref in LIST or NULL if empty. */ +/* Return first referring ref in LIST or NULL if empty. */ static inline struct ipa_ref * -ipa_ref_list_first_refering (struct ipa_ref_list *list) +ipa_ref_list_first_referring (struct ipa_ref_list *list) { - if (!VEC_length (ipa_ref_ptr, list->refering)) + if (!VEC_length (ipa_ref_ptr, list->referring)) return NULL; - return VEC_index (ipa_ref_ptr, list->refering, 0); + return VEC_index (ipa_ref_ptr, list->referring, 0); } /* Clear reference list. */ @@ -101,7 +91,7 @@ ipa_ref_list_first_refering (struct ipa_ref_list *list) static inline void ipa_empty_ref_list (struct ipa_ref_list *list) { - list->refering = NULL; + list->referring = NULL; list->references = NULL; } @@ -115,5 +105,5 @@ ipa_ref_list_nreferences (struct ipa_ref_list *list) #define ipa_ref_list_reference_iterate(L,I,P) \ VEC_iterate(ipa_ref_t, (L)->references, (I), (P)) -#define ipa_ref_list_refering_iterate(L,I,P) \ - VEC_iterate(ipa_ref_ptr, (L)->refering, (I), (P)) +#define ipa_ref_list_referring_iterate(L,I,P) \ + VEC_iterate(ipa_ref_ptr, (L)->referring, (I), (P)) diff --git a/gcc/ipa-ref.c b/gcc/ipa-ref.c index 8520bca33ac..7926eb6a7d6 100644 --- a/gcc/ipa-ref.c +++ b/gcc/ipa-ref.c @@ -1,5 +1,5 @@ /* Interprocedural reference lists. - Copyright (C) 2010 + Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Jan Hubicka @@ -34,54 +34,28 @@ static const char *ipa_ref_use_name[] = {"read","write","addr","alias"}; of the use and STMT the statement (if it exists). */ struct ipa_ref * -ipa_record_reference (struct cgraph_node *refering_node, - struct varpool_node *refering_varpool_node, - struct cgraph_node *refered_node, - struct varpool_node *refered_varpool_node, +ipa_record_reference (symtab_node referring_node, + symtab_node referred_node, enum ipa_ref_use use_type, gimple stmt) { struct ipa_ref *ref; struct ipa_ref_list *list, *list2; VEC(ipa_ref_t,gc) *old_references; - gcc_assert ((!refering_node) ^ (!refering_varpool_node)); - gcc_assert ((!refered_node) ^ (!refered_varpool_node)); - gcc_assert (!stmt || refering_node); - gcc_assert (use_type != IPA_REF_ALIAS || !stmt); - list = (refering_node ? &refering_node->ref_list - : &refering_varpool_node->ref_list); + gcc_checking_assert (!stmt || symtab_function_p (referring_node)); + gcc_checking_assert (use_type != IPA_REF_ALIAS || !stmt); + + list = &referring_node->symbol.ref_list; old_references = list->references; VEC_safe_grow (ipa_ref_t, gc, list->references, VEC_length (ipa_ref_t, list->references) + 1); ref = VEC_last (ipa_ref_t, list->references); - list2 = (refered_node ? &refered_node->ref_list - : &refered_varpool_node->ref_list); - VEC_safe_push (ipa_ref_ptr, heap, list2->refering, ref); - ref->refered_index = VEC_length (ipa_ref_ptr, list2->refering) - 1; - if (refering_node) - { - ref->refering.cgraph_node = refering_node; - ref->refering_type = IPA_REF_CGRAPH; - } - else - { - ref->refering.varpool_node = refering_varpool_node; - ref->refering_type = IPA_REF_VARPOOL; - gcc_assert (use_type == IPA_REF_ADDR || use_type == IPA_REF_ALIAS); - } - if (refered_node) - { - ref->refered.cgraph_node = refered_node; - ref->refered_type = IPA_REF_CGRAPH; - gcc_assert (use_type == IPA_REF_ADDR || use_type == IPA_REF_ALIAS); - } - else - { - varpool_mark_needed_node (refered_varpool_node); - ref->refered.varpool_node = refered_varpool_node; - ref->refered_type = IPA_REF_VARPOOL; - } + list2 = &referred_node->symbol.ref_list; + VEC_safe_push (ipa_ref_ptr, heap, list2->referring, ref); + ref->referred_index = VEC_length (ipa_ref_ptr, list2->referring) - 1; + ref->referring = referring_node; + ref->referred = referred_node; ref->stmt = stmt; ref->use = use_type; @@ -91,8 +65,8 @@ ipa_record_reference (struct cgraph_node *refering_node, int i; for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++) VEC_replace (ipa_ref_ptr, - ipa_ref_refered_ref_list (ref)->refering, - ref->refered_index, ref); + ipa_ref_referred_ref_list (ref)->referring, + ref->referred_index, ref); } return ref; } @@ -102,30 +76,30 @@ ipa_record_reference (struct cgraph_node *refering_node, void ipa_remove_reference (struct ipa_ref *ref) { - struct ipa_ref_list *list = ipa_ref_refered_ref_list (ref); - struct ipa_ref_list *list2 = ipa_ref_refering_ref_list (ref); + struct ipa_ref_list *list = ipa_ref_referred_ref_list (ref); + struct ipa_ref_list *list2 = ipa_ref_referring_ref_list (ref); VEC(ipa_ref_t,gc) *old_references = list2->references; struct ipa_ref *last; - gcc_assert (VEC_index (ipa_ref_ptr, list->refering, ref->refered_index) == ref); - last = VEC_last (ipa_ref_ptr, list->refering); + gcc_assert (VEC_index (ipa_ref_ptr, list->referring, ref->referred_index) == ref); + last = VEC_last (ipa_ref_ptr, list->referring); if (ref != last) { - VEC_replace (ipa_ref_ptr, list->refering, - ref->refered_index, - VEC_last (ipa_ref_ptr, list->refering)); - VEC_index (ipa_ref_ptr, list->refering, - ref->refered_index)->refered_index = ref->refered_index; + VEC_replace (ipa_ref_ptr, list->referring, + ref->referred_index, + VEC_last (ipa_ref_ptr, list->referring)); + VEC_index (ipa_ref_ptr, list->referring, + ref->referred_index)->referred_index = ref->referred_index; } - VEC_pop (ipa_ref_ptr, list->refering); + VEC_pop (ipa_ref_ptr, list->referring); last = VEC_last (ipa_ref_t, list2->references); if (ref != last) { *ref = *last; VEC_replace (ipa_ref_ptr, - ipa_ref_refered_ref_list (ref)->refering, - ref->refered_index, ref); + ipa_ref_referred_ref_list (ref)->referring, + ref->referred_index, ref); } VEC_pop (ipa_ref_t, list2->references); gcc_assert (list2->references == old_references); @@ -145,12 +119,12 @@ ipa_remove_all_references (struct ipa_ref_list *list) /* Remove all references in ref list LIST. */ void -ipa_remove_all_refering (struct ipa_ref_list *list) +ipa_remove_all_referring (struct ipa_ref_list *list) { - while (VEC_length (ipa_ref_ptr, list->refering)) - ipa_remove_reference (VEC_last (ipa_ref_ptr, list->refering)); - VEC_free (ipa_ref_ptr, heap, list->refering); - list->refering = NULL; + while (VEC_length (ipa_ref_ptr, list->referring)) + ipa_remove_reference (VEC_last (ipa_ref_ptr, list->referring)); + VEC_free (ipa_ref_ptr, heap, list->referring); + list->referring = NULL; } /* Dump references in LIST to FILE. */ @@ -162,38 +136,27 @@ ipa_dump_references (FILE * file, struct ipa_ref_list *list) int i; for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++) { - if (ref->refered_type == IPA_REF_CGRAPH) - { - fprintf (file, " fn:%s/%i (%s)", cgraph_node_name (ipa_ref_node (ref)), - ipa_ref_node (ref)->uid, - ipa_ref_use_name [ref->use]); - } - else - fprintf (file, " var:%s (%s)", - varpool_node_name (ipa_ref_varpool_node (ref)), - ipa_ref_use_name [ref->use]); + fprintf (file, "%s/%i (%s)", + symtab_node_asm_name (ref->referred), + ref->referred->symbol.order, + ipa_ref_use_name [ref->use]); } fprintf (file, "\n"); } -/* Dump refering in LIST to FILE. */ +/* Dump referring in LIST to FILE. */ void -ipa_dump_refering (FILE * file, struct ipa_ref_list *list) +ipa_dump_referring (FILE * file, struct ipa_ref_list *list) { struct ipa_ref *ref; int i; - for (i = 0; ipa_ref_list_refering_iterate (list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (list, i, ref); i++) { - if (ref->refering_type == IPA_REF_CGRAPH) - fprintf (file, " fn:%s/%i (%s)", - cgraph_node_name (ipa_ref_refering_node (ref)), - ipa_ref_refering_node (ref)->uid, - ipa_ref_use_name [ref->use]); - else - fprintf (file, " var:%s (%s)", - varpool_node_name (ipa_ref_refering_varpool_node (ref)), - ipa_ref_use_name [ref->use]); + fprintf (file, "%s/%i (%s)", + symtab_node_asm_name (ref->referring), + ref->referring->symbol.order, + ipa_ref_use_name [ref->use]); } fprintf (file, "\n"); } @@ -201,46 +164,37 @@ ipa_dump_refering (FILE * file, struct ipa_ref_list *list) /* Clone all references from SRC to DEST_NODE or DEST_VARPOOL_NODE. */ void -ipa_clone_references (struct cgraph_node *dest_node, - struct varpool_node *dest_varpool_node, +ipa_clone_references (symtab_node dest_node, struct ipa_ref_list *src) { struct ipa_ref *ref; int i; for (i = 0; ipa_ref_list_reference_iterate (src, i, ref); i++) - ipa_record_reference (dest_node, dest_varpool_node, - ref->refered_type == IPA_REF_CGRAPH - ? ipa_ref_node (ref) : NULL, - ref->refered_type == IPA_REF_VARPOOL - ? ipa_ref_varpool_node (ref) : NULL, + ipa_record_reference (dest_node, + ref->referred, ref->use, ref->stmt); } -/* Clone all refering from SRC to DEST_NODE or DEST_VARPOOL_NODE. */ +/* Clone all referring from SRC to DEST_NODE or DEST_VARPOOL_NODE. */ void -ipa_clone_refering (struct cgraph_node *dest_node, - struct varpool_node *dest_varpool_node, +ipa_clone_referring (symtab_node dest_node, struct ipa_ref_list *src) { struct ipa_ref *ref; int i; - for (i = 0; ipa_ref_list_refering_iterate (src, i, ref); i++) - ipa_record_reference ( - ref->refering_type == IPA_REF_CGRAPH - ? ipa_ref_refering_node (ref) : NULL, - ref->refering_type == IPA_REF_VARPOOL - ? ipa_ref_refering_varpool_node (ref) : NULL, - dest_node, dest_varpool_node, + for (i = 0; ipa_ref_list_referring_iterate (src, i, ref); i++) + ipa_record_reference (ref->referring, + dest_node, ref->use, ref->stmt); } -/* Return true when execution of REF can load to return from +/* Return true when execution of REF can lead to return from function. */ bool ipa_ref_cannot_lead_to_return (struct ipa_ref *ref) { - return cgraph_node_cannot_return (ipa_ref_refering_node (ref)); + return cgraph_node_cannot_return (ipa_ref_referring_node (ref)); } /* Return true if list contains an alias. */ @@ -249,7 +203,7 @@ ipa_ref_has_aliases_p (struct ipa_ref_list *ref_list) { struct ipa_ref *ref; int i; - for (i = 0; ipa_ref_list_refering_iterate (ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (ref_list, i, ref); i++) if (ref->use == IPA_REF_ALIAS) return true; return false; diff --git a/gcc/ipa-ref.h b/gcc/ipa-ref.h index 2fdb6ba4158..96750ba50f6 100644 --- a/gcc/ipa-ref.h +++ b/gcc/ipa-ref.h @@ -21,6 +21,10 @@ along with GCC; see the file COPYING3. If not see struct cgraph_node; struct varpool_node; +union symtab_node_def; +typedef union symtab_node_def *symtab_node; +typedef const union symtab_node_def *const_symtab_node; + /* How the reference is done. */ enum GTY(()) ipa_ref_use @@ -31,30 +35,13 @@ enum GTY(()) ipa_ref_use IPA_REF_ALIAS }; -/* Type of refering or refered type. */ -enum GTY(()) ipa_ref_type -{ - IPA_REF_CGRAPH, - IPA_REF_VARPOOL -}; - -/* We can have references spanning both callgraph and varpool, - so all pointers needs to be of both types. */ -union GTY(()) ipa_ref_ptr_u -{ - struct cgraph_node * GTY((tag ("IPA_REF_CGRAPH"))) cgraph_node; - struct varpool_node * GTY((tag ("IPA_REF_VARPOOL"))) varpool_node; -}; - /* Record of reference in callgraph or varpool. */ struct GTY(()) ipa_ref { - union ipa_ref_ptr_u GTY ((desc ("%1.refering_type"))) refering; - union ipa_ref_ptr_u GTY ((desc ("%1.refered_type"))) refered; + symtab_node referring; + symtab_node referred; gimple stmt; - unsigned int refered_index; - ENUM_BITFIELD (ipa_ref_type) refering_type:1; - ENUM_BITFIELD (ipa_ref_type) refered_type:1; + unsigned int referred_index; ENUM_BITFIELD (ipa_ref_use) use:2; }; @@ -73,21 +60,19 @@ struct GTY(()) ipa_ref_list VEC(ipa_ref_t,gc) *references; /* Refering is vector of pointers to references. It must not live in GGC space or GGC will try to mark middle of references vectors. */ - VEC(ipa_ref_ptr,heap) * GTY((skip)) refering; + VEC(ipa_ref_ptr,heap) * GTY((skip)) referring; }; -struct ipa_ref * ipa_record_reference (struct cgraph_node *, - struct varpool_node *, - struct cgraph_node *, - struct varpool_node *, +struct ipa_ref * ipa_record_reference (symtab_node, + symtab_node, enum ipa_ref_use, gimple); void ipa_remove_reference (struct ipa_ref *); void ipa_remove_all_references (struct ipa_ref_list *); -void ipa_remove_all_refering (struct ipa_ref_list *); +void ipa_remove_all_referring (struct ipa_ref_list *); void ipa_dump_references (FILE *, struct ipa_ref_list *); -void ipa_dump_refering (FILE *, struct ipa_ref_list *); -void ipa_clone_references (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *); -void ipa_clone_refering (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *); +void ipa_dump_referring (FILE *, struct ipa_ref_list *); +void ipa_clone_references (symtab_node, struct ipa_ref_list *); +void ipa_clone_referring (symtab_node, struct ipa_ref_list *); bool ipa_ref_cannot_lead_to_return (struct ipa_ref *); bool ipa_ref_has_aliases_p (struct ipa_ref_list *); diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c index 7b45c653675..41957345bb0 100644 --- a/gcc/ipa-reference.c +++ b/gcc/ipa-reference.c @@ -200,7 +200,7 @@ ipa_reference_get_not_read_global (struct cgraph_node *fn) info = get_reference_optimization_summary (cgraph_function_node (fn, NULL)); if (info) return info->statics_not_read; - else if (flags_from_decl_or_type (fn->decl) & ECF_LEAF) + else if (flags_from_decl_or_type (fn->symbol.decl) & ECF_LEAF) return all_module_statics; else return NULL; @@ -219,7 +219,7 @@ ipa_reference_get_not_written_global (struct cgraph_node *fn) info = get_reference_optimization_summary (fn); if (info) return info->statics_not_written; - else if (flags_from_decl_or_type (fn->decl) & ECF_LEAF) + else if (flags_from_decl_or_type (fn->symbol.decl) & ECF_LEAF) return all_module_statics; else return NULL; @@ -310,9 +310,9 @@ propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x /* Only look into nodes we can propagate something. */ if (avail > AVAIL_OVERWRITABLE || (avail == AVAIL_OVERWRITABLE - && (flags_from_decl_or_type (y->decl) & ECF_LEAF))) + && (flags_from_decl_or_type (y->symbol.decl) & ECF_LEAF))) { - int flags = flags_from_decl_or_type (y->decl); + int flags = flags_from_decl_or_type (y->symbol.decl); if (get_reference_vars_info (y)) { ipa_reference_vars_info_t y_info @@ -433,12 +433,12 @@ analyze_function (struct cgraph_node *fn) tree var; local = init_function_info (fn); - for (i = 0; ipa_ref_list_reference_iterate (&fn->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_reference_iterate (&fn->symbol.ref_list, i, ref); i++) { - if (ref->refered_type != IPA_REF_VARPOOL) + if (!symtab_variable_p (ref->referred)) continue; - var = ipa_ref_varpool_node (ref)->decl; - if (ipa_ref_varpool_node (ref)->externally_visible + var = ipa_ref_varpool_node (ref)->symbol.decl; + if (ipa_ref_varpool_node (ref)->symbol.externally_visible || !ipa_ref_varpool_node (ref)->analyzed || !is_proper_for_analysis (var)) continue; @@ -530,9 +530,8 @@ generate_summary (void) bm_temp = BITMAP_ALLOC (&local_info_obstack); /* Process all of the functions next. */ - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed) - analyze_function (node); + FOR_EACH_DEFINED_FUNCTION (node) + analyze_function (node); if (dump_file) EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi) @@ -544,7 +543,7 @@ generate_summary (void) BITMAP_FREE(bm_temp); if (dump_file) - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) { ipa_reference_local_vars_info_t l; @@ -554,7 +553,7 @@ generate_summary (void) l = &get_reference_vars_info (node)->local; fprintf (dump_file, "\nFunction name:%s/%i:", - cgraph_node_name (node), node->uid); + cgraph_node_asm_name (node), node->symbol.order); fprintf (dump_file, "\n locals read: "); if (l->statics_read) EXECUTE_IF_SET_IN_BITMAP (l->statics_read, @@ -580,7 +579,7 @@ static void read_write_all_from_decl (struct cgraph_node *node, bool * read_all, bool * write_all) { - tree decl = node->decl; + tree decl = node->symbol.decl; int flags = flags_from_decl_or_type (decl); if ((flags & ECF_LEAF) && cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) @@ -593,7 +592,7 @@ read_write_all_from_decl (struct cgraph_node *node, bool * read_all, *read_all = true; if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " %s/%i -> read all\n", - cgraph_node_name (node), node->uid); + cgraph_node_asm_name (node), node->symbol.order); } else { @@ -603,7 +602,7 @@ read_write_all_from_decl (struct cgraph_node *node, bool * read_all, *write_all = true; if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " %s/%i -> read all, write all\n", - cgraph_node_name (node), node->uid); + cgraph_node_asm_name (node), node->symbol.order); } } @@ -654,7 +653,7 @@ propagate (void) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Starting cycle with %s/%i\n", - cgraph_node_name (node), node->uid); + cgraph_node_asm_name (node), node->symbol.order); node_l = &node_info->local; node_g = &node_info->global; @@ -692,13 +691,13 @@ propagate (void) /* If any node in a cycle is read_all or write_all they all are. */ - w_info = (struct ipa_dfs_info *) node->aux; + w_info = (struct ipa_dfs_info *) node->symbol.aux; w = w_info->next_cycle; while (w && (!read_all || !write_all)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Visiting %s/%i\n", - cgraph_node_name (w), w->uid); + cgraph_node_asm_name (w), w->symbol.order); /* When function is overwritable, we can not assume anything. */ if (cgraph_function_body_availability (w) <= AVAIL_OVERWRITABLE) read_write_all_from_decl (w, &read_all, &write_all); @@ -727,7 +726,7 @@ propagate (void) } } - w_info = (struct ipa_dfs_info *) w->aux; + w_info = (struct ipa_dfs_info *) w->symbol.aux; w = w_info->next_cycle; } @@ -751,14 +750,14 @@ propagate (void) } propagate_bits (node_g, node); - w_info = (struct ipa_dfs_info *) node->aux; + w_info = (struct ipa_dfs_info *) node->symbol.aux; w = w_info->next_cycle; while (w && (!read_all || !write_all)) { ipa_reference_vars_info_t w_ri = get_reference_vars_info (w); ipa_reference_local_vars_info_t w_l = &w_ri->local; - int flags = flags_from_decl_or_type (w->decl); + int flags = flags_from_decl_or_type (w->symbol.decl); /* These global bitmaps are initialized from the local info of all of the nodes in the region. However there is no @@ -773,13 +772,13 @@ propagate (void) bitmap_ior_into (node_g->statics_written, w_l->statics_written); propagate_bits (node_g, w); - w_info = (struct ipa_dfs_info *) w->aux; + w_info = (struct ipa_dfs_info *) w->symbol.aux; w = w_info->next_cycle; } /* All nodes within a cycle have the same global info bitmaps. */ node_info->global = *node_g; - w_info = (struct ipa_dfs_info *) node->aux; + w_info = (struct ipa_dfs_info *) node->symbol.aux; w = w_info->next_cycle; while (w) { @@ -788,7 +787,7 @@ propagate (void) w_ri->global = *node_g; - w_info = (struct ipa_dfs_info *) w->aux; + w_info = (struct ipa_dfs_info *) w->symbol.aux; w = w_info->next_cycle; } } @@ -812,7 +811,7 @@ propagate (void) node_l = &node_info->local; fprintf (dump_file, "\nFunction name:%s/%i:", - cgraph_node_name (node), node->uid); + cgraph_node_asm_name (node), node->symbol.order); fprintf (dump_file, "\n locals read: "); if (node_l->statics_read) EXECUTE_IF_SET_IN_BITMAP (node_l->statics_read, @@ -830,7 +829,7 @@ propagate (void) get_static_name (index)); } - w_info = (struct ipa_dfs_info *) node->aux; + w_info = (struct ipa_dfs_info *) node->symbol.aux; w = w_info->next_cycle; while (w) { @@ -838,7 +837,7 @@ propagate (void) get_reference_vars_info (w); ipa_reference_local_vars_info_t w_l = &w_ri->local; fprintf (dump_file, "\n next cycle: %s/%i ", - cgraph_node_name (w), w->uid); + cgraph_node_asm_name (w), w->symbol.order); fprintf (dump_file, "\n locals read: "); if (w_l->statics_read) EXECUTE_IF_SET_IN_BITMAP (w_l->statics_read, @@ -857,7 +856,7 @@ propagate (void) get_static_name (index)); } - w_info = (struct ipa_dfs_info *) w->aux; + w_info = (struct ipa_dfs_info *) w->symbol.aux; w = w_info->next_cycle; } fprintf (dump_file, "\n globals read: "); @@ -884,18 +883,18 @@ propagate (void) } /* Cleanup. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { ipa_reference_vars_info_t node_info; ipa_reference_global_vars_info_t node_g; ipa_reference_optimization_summary_t opt; - if (!node->analyzed || node->alias) + if (node->alias) continue; node_info = get_reference_vars_info (node); if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE - || (flags_from_decl_or_type (node->decl) & ECF_LEAF)) + || (flags_from_decl_or_type (node->symbol.decl) & ECF_LEAF)) { node_g = &node_info->global; @@ -968,7 +967,7 @@ write_node_summary_p (struct cgraph_node *node, In future we might also want to include summaries of functions references by initializers of constant variables references in current unit. */ if (!reachable_from_this_partition_p (node, set) - && !referenced_from_this_partition_p (&node->ref_list, set, vset)) + && !referenced_from_this_partition_p (&node->symbol.ref_list, set, vset)) return false; /* See if the info has non-empty intersections with vars we want to encode. */ @@ -1035,12 +1034,12 @@ ipa_reference_write_optimization_summary (cgraph_node_set set, for (i = 0; i < lto_varpool_encoder_size (varpool_encoder); i++) { struct varpool_node *vnode = lto_varpool_encoder_deref (varpool_encoder, i); - if (!vnode->externally_visible + if (!vnode->symbol.externally_visible && vnode->analyzed - && bitmap_bit_p (all_module_statics, DECL_UID (vnode->decl)) - && referenced_from_this_partition_p (&vnode->ref_list, set, vset)) + && bitmap_bit_p (all_module_statics, DECL_UID (vnode->symbol.decl)) + && referenced_from_this_partition_p (&vnode->symbol.ref_list, set, vset)) { - tree decl = vnode->decl; + tree decl = vnode->symbol.decl; bitmap_set_bit (ltrans_statics, DECL_UID (decl)); splay_tree_insert (reference_vars_to_consider, DECL_UID (decl), (splay_tree_value)decl); @@ -1149,7 +1148,7 @@ ipa_reference_read_optimization_summary (void) if (dump_file) fprintf (dump_file, "\nFunction name:%s/%i:\n static not read:", - cgraph_node_name (node), node->uid); + cgraph_node_asm_name (node), node->symbol.order); /* Set the statics not read. */ v_count = streamer_read_hwi (ib); diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index 9dddf393fa7..1997f62538b 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -1203,16 +1203,16 @@ split_function (struct split_point *split_point) /* For usual cloning it is enough to clear builtin only when signature changes. For partial inlining we however can not expect the part of builtin implementation to have same semantic as the whole. */ - if (DECL_BUILT_IN (node->decl)) + if (DECL_BUILT_IN (node->symbol.decl)) { - DECL_BUILT_IN_CLASS (node->decl) = NOT_BUILT_IN; - DECL_FUNCTION_CODE (node->decl) = (enum built_in_function) 0; + DECL_BUILT_IN_CLASS (node->symbol.decl) = NOT_BUILT_IN; + DECL_FUNCTION_CODE (node->symbol.decl) = (enum built_in_function) 0; } cgraph_node_remove_callees (cur_node); if (!split_part_return_p) - TREE_THIS_VOLATILE (node->decl) = 1; + TREE_THIS_VOLATILE (node->symbol.decl) = 1; if (dump_file) - dump_function_to_file (node->decl, dump_file, dump_flags); + dump_function_to_file (node->symbol.decl, dump_file, dump_flags); /* Create the basic block we place call into. It is the entry basic block split after last label. */ @@ -1237,7 +1237,7 @@ split_function (struct split_point *split_point) false, GSI_CONTINUE_LINKING); VEC_replace (tree, args_to_pass, i, arg); } - call = gimple_build_call_vec (node->decl, args_to_pass); + call = gimple_build_call_vec (node->symbol.decl, args_to_pass); gimple_set_block (call, DECL_INITIAL (current_function_decl)); /* We avoid address being taken on any variable used by split part, @@ -1423,7 +1423,7 @@ execute_split_functions (void) fprintf (dump_file, "Not splitting: not inlinable.\n"); return 0; } - if (DECL_DISREGARD_INLINE_LIMITS (node->decl)) + if (DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl)) { if (dump_file) fprintf (dump_file, "Not splitting: disregarding inline limits.\n"); @@ -1455,8 +1455,8 @@ execute_split_functions (void) called once. It is possible that the caller is called more then once and then inlining would still benefit. */ if ((!node->callers || !node->callers->next_caller) - && !node->address_taken - && (!flag_lto || !node->local.externally_visible)) + && !node->symbol.address_taken + && (!flag_lto || !node->symbol.externally_visible)) { if (dump_file) fprintf (dump_file, "Not splitting: not called directly " diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c index 0a462ef25b5..e22977a0707 100644 --- a/gcc/ipa-utils.c +++ b/gcc/ipa-utils.c @@ -86,7 +86,7 @@ searchc (struct searchc_env* env, struct cgraph_node *v, bool (*ignore_edge) (struct cgraph_edge *)) { struct cgraph_edge *edge; - struct ipa_dfs_info *v_info = (struct ipa_dfs_info *) v->aux; + struct ipa_dfs_info *v_info = (struct ipa_dfs_info *) v->symbol.aux; /* mark node as old */ v_info->new_node = false; @@ -107,11 +107,11 @@ searchc (struct searchc_env* env, struct cgraph_node *v, if (!w || (ignore_edge && ignore_edge (edge))) continue; - if (w->aux + if (w->symbol.aux && (avail > AVAIL_OVERWRITABLE || (env->allow_overwritable && avail == AVAIL_OVERWRITABLE))) { - w_info = (struct ipa_dfs_info *) w->aux; + w_info = (struct ipa_dfs_info *) w->symbol.aux; if (w_info->new_node) { searchc (env, w, ignore_edge); @@ -136,7 +136,7 @@ searchc (struct searchc_env* env, struct cgraph_node *v, struct ipa_dfs_info *x_info; do { x = env->stack[--(env->stack_size)]; - x_info = (struct ipa_dfs_info *) x->aux; + x_info = (struct ipa_dfs_info *) x->symbol.aux; x_info->on_stack = false; x_info->scc_no = v_info->dfn_number; @@ -178,7 +178,7 @@ ipa_reduced_postorder (struct cgraph_node **order, env.reduce = reduce; env.allow_overwritable = allow_overwritable; - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { enum availability avail = cgraph_function_body_availability (node); @@ -187,20 +187,20 @@ ipa_reduced_postorder (struct cgraph_node **order, && (avail == AVAIL_OVERWRITABLE))) { /* Reuse the info if it is already there. */ - struct ipa_dfs_info *info = (struct ipa_dfs_info *) node->aux; + struct ipa_dfs_info *info = (struct ipa_dfs_info *) node->symbol.aux; if (!info) info = XCNEW (struct ipa_dfs_info); info->new_node = true; info->on_stack = false; info->next_cycle = NULL; - node->aux = info; + node->symbol.aux = info; splay_tree_insert (env.nodes_marked_new, (splay_tree_key)node->uid, (splay_tree_value)node); } else - node->aux = NULL; + node->symbol.aux = NULL; } result = splay_tree_min (env.nodes_marked_new); while (result) @@ -222,13 +222,13 @@ void ipa_free_postorder_info (void) { struct cgraph_node *node; - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { /* Get rid of the aux information. */ - if (node->aux) + if (node->symbol.aux) { - free (node->aux); - node->aux = NULL; + free (node->symbol.aux); + node->symbol.aux = NULL; } } } @@ -261,13 +261,13 @@ ipa_reverse_postorder (struct cgraph_node **order) output algorithm. Ignore the fact that some functions won't need to be output and put them into order as well, so we get dependencies right through inline functions. */ - for (node = cgraph_nodes; node; node = node->next) - node->aux = NULL; + FOR_EACH_FUNCTION (node) + node->symbol.aux = NULL; for (pass = 0; pass < 2; pass++) - for (node = cgraph_nodes; node; node = node->next) - if (!node->aux + FOR_EACH_FUNCTION (node) + if (!node->symbol.aux && (pass - || (!node->address_taken + || (!node->symbol.address_taken && !node->global.inlined_to && !node->alias && !node->thunk.thunk_p && !cgraph_only_called_directly_p (node)))) @@ -276,7 +276,7 @@ ipa_reverse_postorder (struct cgraph_node **order) stack[stack_size].node = node; stack[stack_size].edge = node->callers; stack[stack_size].ref = 0; - node->aux = (void *)(size_t)1; + node->symbol.aux = (void *)(size_t)1; while (stack_size >= 0) { while (true) @@ -290,35 +290,35 @@ ipa_reverse_postorder (struct cgraph_node **order) /* Break possible cycles involving always-inline functions by ignoring edges from always-inline functions to non-always-inline functions. */ - if (DECL_DISREGARD_INLINE_LIMITS (edge->caller->decl) + if (DECL_DISREGARD_INLINE_LIMITS (edge->caller->symbol.decl) && !DECL_DISREGARD_INLINE_LIMITS - (cgraph_function_node (edge->callee, NULL)->decl)) + (cgraph_function_node (edge->callee, NULL)->symbol.decl)) node2 = NULL; } - for (;ipa_ref_list_refering_iterate (&stack[stack_size].node->ref_list, + for (;ipa_ref_list_referring_iterate (&stack[stack_size].node->symbol.ref_list, stack[stack_size].ref, ref) && !node2; stack[stack_size].ref++) { if (ref->use == IPA_REF_ALIAS) - node2 = ipa_ref_refering_node (ref); + node2 = ipa_ref_referring_node (ref); } if (!node2) break; - if (!node2->aux) + if (!node2->symbol.aux) { stack[++stack_size].node = node2; stack[stack_size].edge = node2->callers; stack[stack_size].ref = 0; - node2->aux = (void *)(size_t)1; + node2->symbol.aux = (void *)(size_t)1; } } order[order_pos++] = stack[stack_size--].node; } } free (stack); - for (node = cgraph_nodes; node; node = node->next) - node->aux = NULL; + FOR_EACH_FUNCTION (node) + node->symbol.aux = NULL; return order_pos; } diff --git a/gcc/ipa.c b/gcc/ipa.c index 88dd9072c0c..34b58e857d7 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -60,13 +60,13 @@ static void enqueue_cgraph_node (struct cgraph_node *node, struct cgraph_node **first) { /* Node is still in queue; do nothing. */ - if (node->aux && node->aux != (void *) 2) + if (node->symbol.aux && node->symbol.aux != (void *) 2) return; /* Node was already processed as unreachable, re-enqueue only if it became reachable now. */ - if (node->aux == (void *)2 && !node->reachable) + if (node->symbol.aux == (void *)2 && !node->reachable) return; - node->aux = *first; + node->symbol.aux = *first; *first = node; } @@ -75,7 +75,7 @@ enqueue_cgraph_node (struct cgraph_node *node, struct cgraph_node **first) static void enqueue_varpool_node (struct varpool_node *node, struct varpool_node **first) { - node->aux = *first; + node->symbol.aux = *first; *first = node; } @@ -91,12 +91,13 @@ process_references (struct ipa_ref_list *list, struct ipa_ref *ref; for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++) { - if (ref->refered_type == IPA_REF_CGRAPH) + if (symtab_function_p (ref->referred)) { struct cgraph_node *node = ipa_ref_node (ref); if (!node->reachable && node->analyzed - && (!DECL_EXTERNAL (node->decl) + && (!DECL_EXTERNAL (node->symbol.decl) + || node->alias || before_inlining_p)) node->reachable = true; enqueue_cgraph_node (node, first); @@ -106,7 +107,7 @@ process_references (struct ipa_ref_list *list, struct varpool_node *node = ipa_ref_varpool_node (ref); if (!node->needed) { - varpool_mark_needed_node (node); + node->needed = true; enqueue_varpool_node (node, first_varpool); } } @@ -121,12 +122,12 @@ cgraph_non_local_node_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED { /* FIXME: Aliases can be local, but i386 gets thunks wrong then. */ return !(cgraph_only_called_directly_or_aliased_p (node) - && !ipa_ref_has_aliases_p (&node->ref_list) + && !ipa_ref_has_aliases_p (&node->symbol.ref_list) && node->analyzed - && !DECL_EXTERNAL (node->decl) - && !node->local.externally_visible - && !node->reachable_from_other_partition - && !node->in_other_partition); + && !DECL_EXTERNAL (node->symbol.decl) + && !node->symbol.externally_visible + && !node->symbol.used_from_other_partition + && !node->symbol.in_other_partition); } /* Return true when function can be marked local. */ @@ -154,7 +155,8 @@ has_addr_references_p (struct cgraph_node *node, int i; struct ipa_ref *ref; - for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, + i, ref); i++) if (ref->use == IPA_REF_ADDR) return true; return false; @@ -175,28 +177,27 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) bool changed = false; #ifdef ENABLE_CHECKING - verify_cgraph (); + verify_symtab (); #endif if (file) fprintf (file, "\nReclaiming functions:"); #ifdef ENABLE_CHECKING - for (node = cgraph_nodes; node; node = node->next) - gcc_assert (!node->aux); - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - gcc_assert (!vnode->aux); + FOR_EACH_FUNCTION (node) + gcc_assert (!node->symbol.aux); + FOR_EACH_VARIABLE (vnode) + gcc_assert (!vnode->symbol.aux); #endif - varpool_reset_queue (); /* Mark functions whose bodies are obviously needed. This is mostly when they can be referenced externally. Inline clones are special since their declarations are shared with master clone and thus cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) if (node->analyzed && !node->global.inlined_to && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node) /* Keep around virtual functions for possible devirtualization. */ || (before_inlining_p - && DECL_VIRTUAL_P (node->decl) - && (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))))) + && DECL_VIRTUAL_P (node->symbol.decl) + && (DECL_COMDAT (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl))))) { gcc_assert (!node->global.inlined_to); enqueue_cgraph_node (node, &first); @@ -204,20 +205,17 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) } else { - gcc_assert (!node->aux); + gcc_assert (!node->symbol.aux); node->reachable = false; } /* Mark variables that are obviously needed. */ - for (vnode = varpool_nodes; vnode; vnode = vnode->next) + FOR_EACH_VARIABLE (vnode) { - vnode->next_needed = NULL; - vnode->prev_needed = NULL; - if ((vnode->analyzed || vnode->force_output) + if ((vnode->analyzed || vnode->symbol.force_output) && !varpool_can_remove_if_no_refs (vnode)) { - vnode->needed = false; - varpool_mark_needed_node (vnode); + vnode->needed = true; enqueue_varpool_node (vnode, &first_varpool); } else @@ -238,9 +236,9 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) { struct cgraph_edge *e; node = first; - first = (struct cgraph_node *) first->aux; + first = (struct cgraph_node *) first->symbol.aux; if (!node->reachable) - node->aux = (void *)2; + node->symbol.aux = (void *)2; /* If we found this node reachable, first mark on the callees reachable too, unless they are direct calls to extern inline functions @@ -252,24 +250,26 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) if (!e->callee->reachable && node->analyzed && (!e->inline_failed - || !DECL_EXTERNAL (e->callee->decl) + || !DECL_EXTERNAL (e->callee->symbol.decl) + || node->alias || before_inlining_p)) e->callee->reachable = true; enqueue_cgraph_node (e->callee, &first); } - process_references (&node->ref_list, &first, &first_varpool, before_inlining_p); + process_references (&node->symbol.ref_list, &first, + &first_varpool, before_inlining_p); } /* If any function in a comdat group is reachable, force all other functions in the same comdat group to be also reachable. */ - if (node->same_comdat_group + if (node->symbol.same_comdat_group && node->reachable && !node->global.inlined_to) { - for (next = node->same_comdat_group; + for (next = cgraph (node->symbol.same_comdat_group); next != node; - next = next->same_comdat_group) + next = cgraph (next->symbol.same_comdat_group)) if (!next->reachable) { next->reachable = true; @@ -281,12 +281,12 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) function is clone of real clone, we must keep it around in order to make materialize_clones produce function body with the changes applied. */ - while (node->clone_of && !node->clone_of->aux - && !gimple_has_body_p (node->decl)) + while (node->clone_of && !node->clone_of->symbol.aux + && !gimple_has_body_p (node->symbol.decl)) { - bool noninline = node->clone_of->decl != node->decl; + bool noninline = node->clone_of->symbol.decl != node->symbol.decl; node = node->clone_of; - if (noninline && !node->reachable && !node->aux) + if (noninline && !node->reachable && !node->symbol.aux) { enqueue_cgraph_node (node, &first); break; @@ -296,21 +296,22 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) if (first_varpool != (struct varpool_node *) (void *) 1) { vnode = first_varpool; - first_varpool = (struct varpool_node *)first_varpool->aux; - vnode->aux = NULL; - process_references (&vnode->ref_list, &first, &first_varpool, before_inlining_p); + first_varpool = (struct varpool_node *)first_varpool->symbol.aux; + vnode->symbol.aux = NULL; + process_references (&vnode->symbol.ref_list, &first, + &first_varpool, before_inlining_p); /* If any function in a comdat group is reachable, force all other functions in the same comdat group to be also reachable. */ - if (vnode->same_comdat_group) + if (vnode->symbol.same_comdat_group) { struct varpool_node *next; - for (next = vnode->same_comdat_group; + for (next = varpool (vnode->symbol.same_comdat_group); next != vnode; - next = next->same_comdat_group) + next = varpool (next->symbol.same_comdat_group)) if (!next->needed) { - varpool_mark_needed_node (next); + next->needed = true; enqueue_varpool_node (next, &first_varpool); } } @@ -326,16 +327,16 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) Also we need to care functions that are unreachable but we need to keep them around for later clonning. In this case we also turn them to unanalyzed nodes, but keep the body around. */ - for (node = cgraph_nodes; node; node = next) + for (node = cgraph_first_function (); node; node = next) { - next = node->next; - if (node->aux && !node->reachable) + next = cgraph_next_function (node); + if (node->symbol.aux && !node->reachable) { cgraph_node_remove_callees (node); - ipa_remove_all_references (&node->ref_list); + ipa_remove_all_references (&node->symbol.ref_list); node->analyzed = false; } - if (!node->aux) + if (!node->symbol.aux) { struct cgraph_edge *e; bool found = false; @@ -349,13 +350,14 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) for (e = node->callers; e && !found; e = e->next_caller) if (e->caller->reachable) found = true; - for (i = 0; (ipa_ref_list_refering_iterate (&node->ref_list, i, ref) + for (i = 0; (ipa_ref_list_referring_iterate (&node->symbol.ref_list, + i, ref) && !found); i++) - if (ref->refering_type == IPA_REF_CGRAPH - && ipa_ref_refering_node (ref)->reachable) + if (symtab_function_p (ref->referring) + && ipa_ref_referring_node (ref)->reachable) found = true; - else if (ref->refering_type == IPA_REF_VARPOOL - && ipa_ref_refering_varpool_node (ref)->needed) + else if (symtab_variable_p (ref->referring) + && ipa_ref_referring_varpool_node (ref)->needed) found = true; /* If so, we need to keep node in the callgraph. */ @@ -369,7 +371,7 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) Otherwise we can just remove the body but keep the clone. */ for (clone = node->clones; clone; clone = clone->next_sibling_clone) - if (clone->aux) + if (clone->symbol.aux) break; if (!clone) { @@ -381,17 +383,17 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) if (node->next_sibling_clone) node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone; if (node->clone_of) - node->former_clone_of = node->clone_of->decl; + node->former_clone_of = node->clone_of->symbol.decl; node->clone_of = NULL; node->next_sibling_clone = NULL; node->prev_sibling_clone = NULL; } else - gcc_assert (!clone->in_other_partition); + gcc_assert (!clone->symbol.in_other_partition); node->analyzed = false; changed = true; cgraph_node_remove_callees (node); - ipa_remove_all_references (&node->ref_list); + ipa_remove_all_references (&node->symbol.ref_list); } } else @@ -401,7 +403,7 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) } } } - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) { /* Inline clones might be kept around so their materializing allows further cloning. If the function the clone is inlined into is removed, we need @@ -413,7 +415,7 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) node->global.inlined_to = NULL; update_inlined_to_pointer (node, node); } - node->aux = NULL; + node->symbol.aux = NULL; } if (file) @@ -421,9 +423,9 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) if (file) fprintf (file, "Reclaiming variables:"); - for (vnode = varpool_nodes; vnode; vnode = vnext) + for (vnode = varpool_first_variable (); vnode; vnode = vnext) { - vnext = vnode->next; + vnext = varpool_next_variable (vnode); if (!vnode->needed) { if (file) @@ -437,15 +439,15 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) if (file) fprintf (file, "\nClearing address taken flags:"); - for (node = cgraph_nodes; node; node = node->next) - if (node->address_taken - && !node->reachable_from_other_partition) + FOR_EACH_DEFINED_FUNCTION (node) + if (node->symbol.address_taken + && !node->symbol.used_from_other_partition) { if (!cgraph_for_node_and_aliases (node, has_addr_references_p, NULL, true)) { if (file) fprintf (file, " %s", cgraph_node_name (node)); - node->address_taken = false; + node->symbol.address_taken = false; changed = true; if (cgraph_local_node_p (node)) { @@ -463,7 +465,7 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) return changed; #ifdef ENABLE_CHECKING - verify_cgraph (); + verify_symtab (); #endif /* Reclaim alias pairs for functions that have disappeared from the @@ -488,15 +490,17 @@ ipa_discover_readonly_nonaddressable_vars (void) struct varpool_node *vnode; if (dump_file) fprintf (dump_file, "Clearing variable flags:"); - for (vnode = varpool_nodes; vnode; vnode = vnode->next) + FOR_EACH_VARIABLE (vnode) if (vnode->finalized && varpool_all_refs_explicit_p (vnode) - && (TREE_ADDRESSABLE (vnode->decl) || !TREE_READONLY (vnode->decl))) + && (TREE_ADDRESSABLE (vnode->symbol.decl) + || !TREE_READONLY (vnode->symbol.decl))) { bool written = false; bool address_taken = false; int i; struct ipa_ref *ref; - for (i = 0; ipa_ref_list_refering_iterate (&vnode->ref_list, i, ref) + for (i = 0; ipa_ref_list_referring_iterate (&vnode->symbol.ref_list, + i, ref) && (!written || !address_taken); i++) switch (ref->use) { @@ -509,21 +513,21 @@ ipa_discover_readonly_nonaddressable_vars (void) written = true; break; } - if (TREE_ADDRESSABLE (vnode->decl) && !address_taken) + if (TREE_ADDRESSABLE (vnode->symbol.decl) && !address_taken) { if (dump_file) fprintf (dump_file, " %s (addressable)", varpool_node_name (vnode)); - TREE_ADDRESSABLE (vnode->decl) = 0; + TREE_ADDRESSABLE (vnode->symbol.decl) = 0; } - if (!TREE_READONLY (vnode->decl) && !address_taken && !written + if (!TREE_READONLY (vnode->symbol.decl) && !address_taken && !written /* Making variable in explicit section readonly can cause section type conflict. See e.g. gcc.c-torture/compile/pr23237.c */ - && DECL_SECTION_NAME (vnode->decl) == NULL) + && DECL_SECTION_NAME (vnode->symbol.decl) == NULL) { if (dump_file) fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode)); - TREE_READONLY (vnode->decl) = 1; + TREE_READONLY (vnode->symbol.decl) = 1; } } if (dump_file) @@ -536,14 +540,15 @@ cgraph_address_taken_from_non_vtable_p (struct cgraph_node *node) { int i; struct ipa_ref *ref; - for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, + i, ref); i++) if (ref->use == IPA_REF_ADDR) { struct varpool_node *node; - if (ref->refering_type == IPA_REF_CGRAPH) + if (symtab_function_p (ref->referring)) return true; - node = ipa_ref_refering_varpool_node (ref); - if (!DECL_VIRTUAL_P (node->decl)) + node = ipa_ref_referring_varpool_node (ref); + if (!DECL_VIRTUAL_P (node->symbol.decl)) return true; } return false; @@ -562,20 +567,20 @@ bool cgraph_comdat_can_be_unshared_p (struct cgraph_node *node) { if ((cgraph_address_taken_from_non_vtable_p (node) - && !DECL_VIRTUAL_P (node->decl)) + && !DECL_VIRTUAL_P (node->symbol.decl)) || !node->analyzed) return false; - if (node->same_comdat_group) + if (node->symbol.same_comdat_group) { struct cgraph_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) + for (next = cgraph (node->symbol.same_comdat_group); + next != node; next = cgraph (next->symbol.same_comdat_group)) if (cgraph_address_taken_from_non_vtable_p (next) - && !DECL_VIRTUAL_P (next->decl)) + && !DECL_VIRTUAL_P (next->symbol.decl)) return false; } return true; @@ -589,8 +594,9 @@ cgraph_externally_visible_p (struct cgraph_node *node, { if (!node->local.finalized) return false; - if (!DECL_COMDAT (node->decl) - && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))) + if (!DECL_COMDAT (node->symbol.decl) + && (!TREE_PUBLIC (node->symbol.decl) + || DECL_EXTERNAL (node->symbol.decl))) return false; /* Do not even try to be smart about aliased nodes. Until we properly @@ -603,34 +609,36 @@ cgraph_externally_visible_p (struct cgraph_node *node, 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)) + if (DECL_BUILT_IN (node->symbol.decl)) return true; /* If linker counts on us, we must preserve the function. */ if (cgraph_used_from_object_file_p (node)) return true; - if (DECL_PRESERVE_P (node->decl)) + if (DECL_PRESERVE_P (node->symbol.decl)) return true; - if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl))) + if (lookup_attribute ("externally_visible", + DECL_ATTRIBUTES (node->symbol.decl))) return true; if (TARGET_DLLIMPORT_DECL_ATTRIBUTES - && lookup_attribute ("dllexport", DECL_ATTRIBUTES (node->decl))) + && lookup_attribute ("dllexport", + DECL_ATTRIBUTES (node->symbol.decl))) return true; - if (node->resolution == LDPR_PREVAILING_DEF_IRONLY) + if (node->symbol.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) + && DECL_COMDAT (node->symbol.decl) && cgraph_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) + && (DECL_VISIBILITY (node->symbol.decl) == VISIBILITY_HIDDEN + || DECL_VISIBILITY (node->symbol.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->analyzed) @@ -638,7 +646,7 @@ cgraph_externally_visible_p (struct cgraph_node *node, else if (!whole_program) return true; - if (MAIN_NAME_P (DECL_NAME (node->decl))) + if (MAIN_NAME_P (DECL_NAME (node->symbol.decl))) return true; return false; @@ -649,7 +657,13 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool varpool_externally_visible_p (struct varpool_node *vnode, bool aliased) { - if (!DECL_COMDAT (vnode->decl) && !TREE_PUBLIC (vnode->decl)) + /* Do not touch weakrefs; while they are not externally visible, + dropping their DECL_EXTERNAL flags confuse most + of code handling them. */ + if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl)) + return true; + + if (!DECL_COMDAT (vnode->symbol.decl) && !TREE_PUBLIC (vnode->symbol.decl)) return false; /* Do not even try to be smart about aliased nodes. Until we properly @@ -661,16 +675,16 @@ varpool_externally_visible_p (struct varpool_node *vnode, bool aliased) if (varpool_used_from_object_file_p (vnode)) return true; - if (DECL_HARD_REGISTER (vnode->decl)) + if (DECL_HARD_REGISTER (vnode->symbol.decl)) return true; - if (DECL_PRESERVE_P (vnode->decl)) + if (DECL_PRESERVE_P (vnode->symbol.decl)) return true; if (lookup_attribute ("externally_visible", - DECL_ATTRIBUTES (vnode->decl))) + DECL_ATTRIBUTES (vnode->symbol.decl))) return true; if (TARGET_DLLIMPORT_DECL_ATTRIBUTES && lookup_attribute ("dllexport", - DECL_ATTRIBUTES (vnode->decl))) + DECL_ATTRIBUTES (vnode->symbol.decl))) return true; /* See if we have linker information about symbol not being used or @@ -681,7 +695,7 @@ varpool_externally_visible_p (struct varpool_node *vnode, bool aliased) This is needed for i.e. references from asm statements. */ if (varpool_used_from_object_file_p (vnode)) return true; - if (vnode->resolution == LDPR_PREVAILING_DEF_IRONLY) + if (vnode->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY) return false; /* As a special case, the COMDAT virutal tables can be unshared. @@ -690,14 +704,14 @@ varpool_externally_visible_p (struct varpool_node *vnode, bool aliased) is faster for dynamic linking. Also this match logic hidding vtables from LTO symbol tables. */ if ((in_lto_p || flag_whole_program) - && !vnode->force_output - && DECL_COMDAT (vnode->decl) && DECL_VIRTUAL_P (vnode->decl)) + && !vnode->symbol.force_output + && DECL_COMDAT (vnode->symbol.decl) && DECL_VIRTUAL_P (vnode->symbol.decl)) return false; /* When doing link time optimizations, hidden symbols become local. */ if (in_lto_p - && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN - || DECL_VISIBILITY (vnode->decl) == VISIBILITY_INTERNAL) + && (DECL_VISIBILITY (vnode->symbol.decl) == VISIBILITY_HIDDEN + || DECL_VISIBILITY (vnode->symbol.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. */ && vnode->finalized) @@ -712,7 +726,7 @@ varpool_externally_visible_p (struct varpool_node *vnode, bool aliased) 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 (vnode->decl) || DECL_WEAK (vnode->decl)) + if (DECL_COMDAT (vnode->symbol.decl) || DECL_WEAK (vnode->symbol.decl)) return true; return false; } @@ -720,13 +734,13 @@ varpool_externally_visible_p (struct varpool_node *vnode, bool aliased) /* Dissolve the same_comdat_group list in which NODE resides. */ static void -dissolve_same_comdat_group_list (struct cgraph_node *node) +dissolve_same_comdat_group_list (symtab_node node) { - struct cgraph_node *n = node, *next; + symtab_node n = node, next; do { - next = n->same_comdat_group; - n->same_comdat_group = NULL; + next = n->symbol.same_comdat_group; + n->symbol.same_comdat_group = NULL; n = next; } while (n != node); @@ -762,22 +776,20 @@ function_and_variable_visibility (bool whole_program) IDENTIFIER_POINTER (p->target)); if ((node = cgraph_node_for_asm (p->target)) != NULL - && !DECL_EXTERNAL (node->decl)) + && !DECL_EXTERNAL (node->symbol.decl)) { if (!node->analyzed) continue; - cgraph_mark_needed_node (node); - gcc_assert (node->needed); + cgraph_mark_force_output_node (node); pointer_set_insert (aliased_nodes, node); if (dump_file) fprintf (dump_file, " node %s/%i", cgraph_node_name (node), node->uid); } else if ((vnode = varpool_node_for_asm (p->target)) != NULL - && !DECL_EXTERNAL (vnode->decl)) + && !DECL_EXTERNAL (vnode->symbol.decl)) { - varpool_mark_needed_node (vnode); - gcc_assert (vnode->needed); + vnode->symbol.force_output = 1; pointer_set_insert (aliased_vnodes, vnode); if (dump_file) fprintf (dump_file, " varpool node %s", @@ -787,76 +799,79 @@ function_and_variable_visibility (bool whole_program) fprintf (dump_file, "\n"); } - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) { - int flags = flags_from_decl_or_type (node->decl); + int flags = flags_from_decl_or_type (node->symbol.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; + DECL_STATIC_CONSTRUCTOR (node->symbol.decl) = 0; + DECL_STATIC_DESTRUCTOR (node->symbol.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 (node->needed - && (DECL_EXTERNAL (node->decl) || !node->analyzed)) - node->needed = 0; + if (node->symbol.force_output + && (DECL_EXTERNAL (node->symbol.decl) || !node->analyzed)) + node->symbol.force_output = 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 neccesary 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; + if (DECL_COMDAT (node->symbol.decl) && !TREE_PUBLIC (node->symbol.decl)) + DECL_COMDAT (node->symbol.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, and simplifies later passes. */ - if (node->same_comdat_group && DECL_EXTERNAL (node->decl)) + if (node->symbol.same_comdat_group && DECL_EXTERNAL (node->symbol.decl)) { #ifdef ENABLE_CHECKING - struct cgraph_node *n; + symtab_node n; - for (n = node->same_comdat_group; - n != node; - n = n->same_comdat_group) + for (n = node->symbol.same_comdat_group; + n != (symtab_node)node; + n = n->symbol.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)); + gcc_assert (DECL_EXTERNAL (n->symbol.decl)); #endif - dissolve_same_comdat_group_list (node); + dissolve_same_comdat_group_list ((symtab_node) node); } - gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl)) - || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)); + gcc_assert ((!DECL_WEAK (node->symbol.decl) + && !DECL_COMDAT (node->symbol.decl)) + || TREE_PUBLIC (node->symbol.decl) + || DECL_EXTERNAL (node->symbol.decl)); if (cgraph_externally_visible_p (node, whole_program, pointer_set_contains (aliased_nodes, node))) { gcc_assert (!node->global.inlined_to); - node->local.externally_visible = true; + node->symbol.externally_visible = true; } else - node->local.externally_visible = false; - if (!node->local.externally_visible && node->analyzed - && !DECL_EXTERNAL (node->decl)) + node->symbol.externally_visible = false; + if (!node->symbol.externally_visible && node->analyzed + && !DECL_EXTERNAL (node->symbol.decl)) { - gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl)); - cgraph_make_decl_local (node->decl); - node->resolution = LDPR_PREVAILING_DEF_IRONLY; - if (node->same_comdat_group) + gcc_assert (whole_program || in_lto_p + || !TREE_PUBLIC (node->symbol.decl)); + cgraph_make_decl_local (node->symbol.decl); + node->symbol.resolution = LDPR_PREVAILING_DEF_IRONLY; + if (node->symbol.same_comdat_group) /* 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. */ - dissolve_same_comdat_group_list (node); + dissolve_same_comdat_group_list ((symtab_node) node); } if (node->thunk.thunk_p - && TREE_PUBLIC (node->decl)) + && TREE_PUBLIC (node->symbol.decl)) { struct cgraph_node *decl_node = node; @@ -864,25 +879,26 @@ function_and_variable_visibility (bool whole_program) /* 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)) + if (DECL_ONE_ONLY (decl_node->symbol.decl)) { - gcc_checking_assert (DECL_COMDAT (node->decl) - == DECL_COMDAT (decl_node->decl)); - gcc_checking_assert (DECL_COMDAT_GROUP (node->decl) - == DECL_COMDAT_GROUP (decl_node->decl)); - gcc_checking_assert (node->same_comdat_group); + gcc_checking_assert (DECL_COMDAT (node->symbol.decl) + == DECL_COMDAT (decl_node->symbol.decl)); + gcc_checking_assert (DECL_COMDAT_GROUP (node->symbol.decl) + == DECL_COMDAT_GROUP (decl_node->symbol.decl)); + gcc_checking_assert (node->symbol.same_comdat_group); } - if (DECL_EXTERNAL (decl_node->decl)) - DECL_EXTERNAL (node->decl) = 1; + if (DECL_EXTERNAL (decl_node->symbol.decl)) + DECL_EXTERNAL (node->symbol.decl) = 1; } } - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) node->local.local = cgraph_local_node_p (node); - for (vnode = varpool_nodes; vnode; vnode = vnode->next) + FOR_EACH_VARIABLE (vnode) { /* weak flag makes no sense on local variables. */ - gcc_assert (!DECL_WEAK (vnode->decl) - || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl)); + gcc_assert (!DECL_WEAK (vnode->symbol.decl) + || TREE_PUBLIC (vnode->symbol.decl) + || DECL_EXTERNAL (vnode->symbol.decl)); /* In several cases declarations can not be common: - when declaration has initializer @@ -896,34 +912,36 @@ function_and_variable_visibility (bool whole_program) 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 + if (DECL_COMMON (vnode->symbol.decl) + && (!(TREE_PUBLIC (vnode->symbol.decl) + || DECL_EXTERNAL (vnode->symbol.decl)) + || (DECL_INITIAL (vnode->symbol.decl) + && DECL_INITIAL (vnode->symbol.decl) != error_mark_node) + || DECL_WEAK (vnode->symbol.decl) + || DECL_SECTION_NAME (vnode->symbol.decl) != NULL || ! (ADDR_SPACE_GENERIC_P - (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl)))))) - DECL_COMMON (vnode->decl) = 0; + (TYPE_ADDR_SPACE (TREE_TYPE (vnode->symbol.decl)))))) + DECL_COMMON (vnode->symbol.decl) = 0; } - for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) + FOR_EACH_DEFINED_VARIABLE (vnode) { if (!vnode->finalized) continue; - if (vnode->needed - && varpool_externally_visible_p - (vnode, - pointer_set_contains (aliased_vnodes, vnode))) - vnode->externally_visible = true; + if (varpool_externally_visible_p + (vnode, + pointer_set_contains (aliased_vnodes, vnode))) + vnode->symbol.externally_visible = true; else - vnode->externally_visible = false; - if (!vnode->externally_visible) + vnode->symbol.externally_visible = false; + if (!vnode->symbol.externally_visible) { - gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl)); - cgraph_make_decl_local (vnode->decl); - vnode->resolution = LDPR_PREVAILING_DEF_IRONLY; + gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->symbol.decl)); + cgraph_make_decl_local (vnode->symbol.decl); + if (vnode->symbol.same_comdat_group) + dissolve_same_comdat_group_list ((symtab_node) vnode); + vnode->symbol.resolution = LDPR_PREVAILING_DEF_IRONLY; } - gcc_assert (TREE_STATIC (vnode->decl)); + gcc_assert (TREE_STATIC (vnode->symbol.decl)); } pointer_set_destroy (aliased_nodes); pointer_set_destroy (aliased_vnodes); @@ -931,18 +949,18 @@ function_and_variable_visibility (bool whole_program) if (dump_file) { fprintf (dump_file, "\nMarking local functions:"); - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) if (node->local.local) fprintf (dump_file, " %s", cgraph_node_name (node)); fprintf (dump_file, "\n\n"); fprintf (dump_file, "\nMarking externally visible functions:"); - for (node = cgraph_nodes; node; node = node->next) - if (node->local.externally_visible) + FOR_EACH_DEFINED_FUNCTION (node) + if (node->symbol.externally_visible) fprintf (dump_file, " %s", cgraph_node_name (node)); fprintf (dump_file, "\n\n"); fprintf (dump_file, "\nMarking externally visible variables:"); - for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) - if (vnode->externally_visible) + FOR_EACH_DEFINED_VARIABLE (vnode) + if (vnode->symbol.externally_visible) fprintf (dump_file, " %s", varpool_node_name (vnode)); fprintf (dump_file, "\n\n"); } @@ -974,7 +992,7 @@ struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_remove_functions | TODO_dump_cgraph + TODO_remove_functions | TODO_dump_symtab | TODO_ggc_collect /* todo_flags_finish */ } }; @@ -993,25 +1011,13 @@ static unsigned int whole_program_function_and_variable_visibility (void) { struct cgraph_node *node; - struct varpool_node *vnode; function_and_variable_visibility (flag_whole_program); - for (node = cgraph_nodes; node; node = node->next) - if ((node->local.externally_visible && !DECL_COMDAT (node->decl)) + FOR_EACH_DEFINED_FUNCTION (node) + if ((node->symbol.externally_visible && !DECL_COMDAT (node->symbol.decl)) && node->local.finalized) - cgraph_mark_needed_node (node); - for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) - if (vnode->externally_visible && !DECL_COMDAT (vnode->decl)) - varpool_mark_needed_node (vnode); - if (dump_file) - { - fprintf (dump_file, "\nNeeded variables:"); - for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) - if (vnode->needed) - fprintf (dump_file, " %s", varpool_node_name (vnode)); - fprintf (dump_file, "\n\n"); - } + cgraph_mark_reachable_node (node); if (optimize) ipa_discover_readonly_nonaddressable_vars (); return 0; @@ -1032,7 +1038,7 @@ struct ipa_opt_pass_d pass_ipa_whole_program_visibility = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_remove_functions | TODO_dump_cgraph + TODO_remove_functions | TODO_dump_symtab | TODO_ggc_collect /* todo_flags_finish */ }, NULL, /* generate_summary */ @@ -1064,13 +1070,13 @@ ipa_profile (void) if (order[i]->local.local && cgraph_propagate_frequency (order[i])) { for (e = order[i]->callees; e; e = e->next_callee) - if (e->callee->local.local && !e->callee->aux) + if (e->callee->local.local && !e->callee->symbol.aux) { something_changed = true; - e->callee->aux = (void *)1; + e->callee->symbol.aux = (void *)1; } } - order[i]->aux = NULL; + order[i]->symbol.aux = NULL; } while (something_changed) @@ -1078,16 +1084,16 @@ ipa_profile (void) something_changed = false; for (i = order_pos - 1; i >= 0; i--) { - if (order[i]->aux && cgraph_propagate_frequency (order[i])) + if (order[i]->symbol.aux && cgraph_propagate_frequency (order[i])) { for (e = order[i]->callees; e; e = e->next_callee) - if (e->callee->local.local && !e->callee->aux) + if (e->callee->local.local && !e->callee->symbol.aux) { something_changed = true; - e->callee->aux = (void *)1; + e->callee->symbol.aux = (void *)1; } } - order[i]->aux = NULL; + order[i]->symbol.aux = NULL; } } free (order); @@ -1232,12 +1238,12 @@ static VEC(tree, heap) *static_dtors; static void record_cdtor_fn (struct cgraph_node *node) { - if (DECL_STATIC_CONSTRUCTOR (node->decl)) - VEC_safe_push (tree, heap, static_ctors, node->decl); - if (DECL_STATIC_DESTRUCTOR (node->decl)) - VEC_safe_push (tree, heap, static_dtors, node->decl); - node = cgraph_get_node (node->decl); - DECL_DISREGARD_INLINE_LIMITS (node->decl) = 1; + if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl)) + VEC_safe_push (tree, heap, static_ctors, node->symbol.decl); + if (DECL_STATIC_DESTRUCTOR (node->symbol.decl)) + VEC_safe_push (tree, heap, static_dtors, node->symbol.decl); + node = cgraph_get_node (node->symbol.decl); + DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl) = 1; } /* Define global constructors/destructor functions for the CDTORS, of @@ -1390,10 +1396,9 @@ static unsigned int ipa_cdtor_merge (void) { struct cgraph_node *node; - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed - && (DECL_STATIC_CONSTRUCTOR (node->decl) - || DECL_STATIC_DESTRUCTOR (node->decl))) + FOR_EACH_DEFINED_FUNCTION (node) + if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl) + || DECL_STATIC_DESTRUCTOR (node->symbol.decl)) record_cdtor_fn (node); build_cdtor_fns (); VEC_free (tree, heap, static_ctors); diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c index 34e6ef9346b..1199763aeb3 100644 --- a/gcc/ira-costs.c +++ b/gcc/ira-costs.c @@ -1650,6 +1650,8 @@ find_costs_and_classes (FILE *dump_file) COSTS (total_allocno_costs, parent_a_num)->mem_cost += add_cost; + if (i >= first_moveable_pseudo && i < last_moveable_pseudo) + COSTS (total_allocno_costs, parent_a_num)->mem_cost = 0; } a_costs = COSTS (costs, a_num)->cost; for (k = cost_classes_ptr->num - 1; k >= 0; k--) @@ -1667,7 +1669,9 @@ find_costs_and_classes (FILE *dump_file) i_mem_cost += add_cost; } } - if (equiv_savings < 0) + if (i >= first_moveable_pseudo && i < last_moveable_pseudo) + i_mem_cost = 0; + else if (equiv_savings < 0) i_mem_cost = -equiv_savings; else if (equiv_savings > 0) { diff --git a/gcc/ira-emit.c b/gcc/ira-emit.c index 3dcd3241cfc..4523a8d41d9 100644 --- a/gcc/ira-emit.c +++ b/gcc/ira-emit.c @@ -330,8 +330,8 @@ add_to_edge_list (edge e, move_t move, bool head_p) /* Create and return new pseudo-register with the same attributes as ORIGINAL_REG. */ -static rtx -create_new_reg (rtx original_reg) +rtx +ira_create_new_reg (rtx original_reg) { rtx new_reg; @@ -625,7 +625,7 @@ change_loop (ira_loop_tree_node_t node) fprintf (ira_dump_file, " %i vs parent %i:", ALLOCNO_HARD_REGNO (allocno), ALLOCNO_HARD_REGNO (parent_allocno)); - set_allocno_reg (allocno, create_new_reg (original_reg)); + set_allocno_reg (allocno, ira_create_new_reg (original_reg)); } } } @@ -646,7 +646,7 @@ change_loop (ira_loop_tree_node_t node) if (! used_p) continue; bitmap_set_bit (renamed_regno_bitmap, regno); - set_allocno_reg (allocno, create_new_reg (allocno_emit_reg (allocno))); + set_allocno_reg (allocno, ira_create_new_reg (allocno_emit_reg (allocno))); } } @@ -852,7 +852,7 @@ modify_move_list (move_t list) ALLOCNO_ASSIGNED_P (new_allocno) = true; ALLOCNO_HARD_REGNO (new_allocno) = -1; ALLOCNO_EMIT_DATA (new_allocno)->reg - = create_new_reg (allocno_emit_reg (set_move->to)); + = ira_create_new_reg (allocno_emit_reg (set_move->to)); /* Make it possibly conflicting with all earlier created allocnos. Cases where temporary allocnos diff --git a/gcc/ira-int.h b/gcc/ira-int.h index 9faabb5d703..5db2ccc268c 100644 --- a/gcc/ira-int.h +++ b/gcc/ira-int.h @@ -1138,8 +1138,13 @@ static inline bool ira_allocno_object_iter_cond (ira_allocno_object_iterator *i, ira_allocno_t a, ira_object_t *o) { - *o = ALLOCNO_OBJECT (a, i->n); - return i->n++ < ALLOCNO_NUM_OBJECTS (a); + int n = i->n++; + if (n < ALLOCNO_NUM_OBJECTS (a)) + { + *o = ALLOCNO_OBJECT (a, n); + return true; + } + return false; } /* Loop over all objects associated with allocno A. In each @@ -1416,3 +1421,6 @@ ira_allocate_and_set_or_copy_costs (int **vec, enum reg_class aclass, reg_costs[i] = val; } } + +extern rtx ira_create_new_reg (rtx); +extern int first_moveable_pseudo, last_moveable_pseudo; diff --git a/gcc/ira.c b/gcc/ira.c index 41a2928d0c9..3b598e65064 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -384,7 +384,7 @@ along with GCC; see the file COPYING3. If not see #include "ggc.h" #include "ira-int.h" #include "dce.h" - +#include "dbgcnt.h" struct target_ira default_target_ira; struct target_ira_int default_target_ira_int; @@ -3512,7 +3512,521 @@ build_insn_chain (void) if (dump_file) print_insn_chains (dump_file); } + +/* Examine the rtx found in *LOC, which is read or written to as determined + by TYPE. Return false if we find a reason why an insn containing this + rtx should not be moved (such as accesses to non-constant memory), true + otherwise. */ +static bool +rtx_moveable_p (rtx *loc, enum op_type type) +{ + const char *fmt; + rtx x = *loc; + enum rtx_code code = GET_CODE (x); + int i, j; + + code = GET_CODE (x); + switch (code) + { + case CONST: + case CONST_INT: + case CONST_DOUBLE: + case CONST_FIXED: + case CONST_VECTOR: + case SYMBOL_REF: + case LABEL_REF: + return true; + + case PC: + return type == OP_IN; + + case CC0: + return false; + + case REG: + if (x == frame_pointer_rtx) + return true; + if (HARD_REGISTER_P (x)) + return false; + + return true; + + case MEM: + if (type == OP_IN && MEM_READONLY_P (x)) + return rtx_moveable_p (&XEXP (x, 0), OP_IN); + return false; + + case SET: + return (rtx_moveable_p (&SET_SRC (x), OP_IN) + && rtx_moveable_p (&SET_DEST (x), OP_OUT)); + + case STRICT_LOW_PART: + return rtx_moveable_p (&XEXP (x, 0), OP_OUT); + + case ZERO_EXTRACT: + case SIGN_EXTRACT: + return (rtx_moveable_p (&XEXP (x, 0), type) + && rtx_moveable_p (&XEXP (x, 1), OP_IN) + && rtx_moveable_p (&XEXP (x, 2), OP_IN)); + + case CLOBBER: + return rtx_moveable_p (&SET_DEST (x), OP_OUT); + + default: + break; + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (!rtx_moveable_p (&XEXP (x, i), type)) + return false; + } + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + { + if (!rtx_moveable_p (&XVECEXP (x, i, j), type)) + return false; + } + } + return true; +} + +/* A wrapper around dominated_by_p, which uses the information in UID_LUID + to give dominance relationships between two insns I1 and I2. */ +static bool +insn_dominated_by_p (rtx i1, rtx i2, int *uid_luid) +{ + basic_block bb1 = BLOCK_FOR_INSN (i1); + basic_block bb2 = BLOCK_FOR_INSN (i2); + + if (bb1 == bb2) + return uid_luid[INSN_UID (i2)] < uid_luid[INSN_UID (i1)]; + return dominated_by_p (CDI_DOMINATORS, bb1, bb2); +} + +/* Record the range of register numbers added by find_moveable_pseudos. */ +int first_moveable_pseudo, last_moveable_pseudo; + +/* These two vectors hold data for every register added by + find_movable_pseudos, with index 0 holding data for the + first_moveable_pseudo. */ +/* The original home register. */ +static VEC (rtx, heap) *pseudo_replaced_reg; +/* The move instruction we added to move the value to its original home + register. */ +static VEC (rtx, heap) *pseudo_move_insn; + +/* Look for instances where we have an instruction that is known to increase + register pressure, and whose result is not used immediately. If it is + possible to move the instruction downwards to just before its first use, + split its lifetime into two ranges. We create a new pseudo to compute the + value, and emit a move instruction just before the first use. If, after + register allocation, the new pseudo remains unallocated, the function + move_unallocated_pseudos then deletes the move instruction and places + the computation just before the first use. + + Such a move is safe and profitable if all the input registers remain live + and unchanged between the original computation and its first use. In such + a situation, the computation is known to increase register pressure, and + moving it is known to at least not worsen it. + + We restrict moves to only those cases where a register remains unallocated, + in order to avoid interfering too much with the instruction schedule. As + an exception, we may move insns which only modify their input register + (typically induction variables), as this increases the freedom for our + intended transformation, and does not limit the second instruction + scheduler pass. */ + +static void +find_moveable_pseudos (void) +{ + unsigned i; + int max_regs = max_reg_num (); + int max_uid = get_max_uid (); + basic_block bb; + int *uid_luid = XNEWVEC (int, max_uid); + rtx *closest_uses = XNEWVEC (rtx, max_regs); + /* A set of registers which are live but not modified throughout a block. */ + bitmap_head *bb_transp_live = XNEWVEC (bitmap_head, last_basic_block); + /* A set of registers which only exist in a given basic block. */ + bitmap_head *bb_local = XNEWVEC (bitmap_head, last_basic_block); + /* A set of registers which are set once, in an instruction that can be + moved freely downwards, but are otherwise transparent to a block. */ + bitmap_head *bb_moveable_reg_sets = XNEWVEC (bitmap_head, last_basic_block); + bitmap_head live, used, set, interesting, unusable_as_input; + bitmap_iterator bi; + bitmap_initialize (&interesting, 0); + + first_moveable_pseudo = max_regs; + VEC_free (rtx, heap, pseudo_move_insn); + VEC_free (rtx, heap, pseudo_replaced_reg); + VEC_safe_grow (rtx, heap, pseudo_move_insn, max_regs); + VEC_safe_grow (rtx, heap, pseudo_replaced_reg, max_regs); + + df_analyze (); + calculate_dominance_info (CDI_DOMINATORS); + + i = 0; + bitmap_initialize (&live, 0); + bitmap_initialize (&used, 0); + bitmap_initialize (&set, 0); + bitmap_initialize (&unusable_as_input, 0); + FOR_EACH_BB (bb) + { + rtx insn; + bitmap transp = bb_transp_live + bb->index; + bitmap moveable = bb_moveable_reg_sets + bb->index; + bitmap local = bb_local + bb->index; + + bitmap_initialize (local, 0); + bitmap_initialize (transp, 0); + bitmap_initialize (moveable, 0); + bitmap_copy (&live, df_get_live_out (bb)); + bitmap_and_into (&live, df_get_live_in (bb)); + bitmap_copy (transp, &live); + bitmap_clear (moveable); + bitmap_clear (&live); + bitmap_clear (&used); + bitmap_clear (&set); + FOR_BB_INSNS (bb, insn) + if (NONDEBUG_INSN_P (insn)) + { + df_ref *u_rec, *d_rec; + + uid_luid[INSN_UID (insn)] = i++; + + u_rec = DF_INSN_USES (insn); + d_rec = DF_INSN_DEFS (insn); + if (d_rec[0] != NULL && d_rec[1] == NULL + && u_rec[0] != NULL && u_rec[1] == NULL + && DF_REF_REGNO (*u_rec) == DF_REF_REGNO (*d_rec) + && !bitmap_bit_p (&set, DF_REF_REGNO (*u_rec)) + && rtx_moveable_p (&PATTERN (insn), OP_IN)) + { + unsigned regno = DF_REF_REGNO (*u_rec); + bitmap_set_bit (moveable, regno); + bitmap_set_bit (&set, regno); + bitmap_set_bit (&used, regno); + bitmap_clear_bit (transp, regno); + continue; + } + while (*u_rec) + { + unsigned regno = DF_REF_REGNO (*u_rec); + bitmap_set_bit (&used, regno); + if (bitmap_clear_bit (moveable, regno)) + bitmap_clear_bit (transp, regno); + u_rec++; + } + + while (*d_rec) + { + unsigned regno = DF_REF_REGNO (*d_rec); + bitmap_set_bit (&set, regno); + bitmap_clear_bit (transp, regno); + bitmap_clear_bit (moveable, regno); + d_rec++; + } + } + } + + bitmap_clear (&live); + bitmap_clear (&used); + bitmap_clear (&set); + + FOR_EACH_BB (bb) + { + bitmap local = bb_local + bb->index; + rtx insn; + + FOR_BB_INSNS (bb, insn) + if (NONDEBUG_INSN_P (insn)) + { + rtx def_insn, closest_use, note; + df_ref *def_rec, def, use; + unsigned regno; + bool all_dominated, all_local; + enum machine_mode mode; + + def_rec = DF_INSN_DEFS (insn); + /* There must be exactly one def in this insn. */ + def = *def_rec; + if (!def || def_rec[1] || !single_set (insn)) + continue; + /* This must be the only definition of the reg. We also limit + which modes we deal with so that we can assume we can generate + move instructions. */ + regno = DF_REF_REGNO (def); + mode = GET_MODE (DF_REF_REG (def)); + if (DF_REG_DEF_COUNT (regno) != 1 + || !DF_REF_INSN_INFO (def) + || HARD_REGISTER_NUM_P (regno) + || (!INTEGRAL_MODE_P (mode) && !FLOAT_MODE_P (mode))) + continue; + def_insn = DF_REF_INSN (def); + + for (note = REG_NOTES (def_insn); note; note = XEXP (note, 1)) + if (REG_NOTE_KIND (note) == REG_EQUIV && MEM_P (XEXP (note, 0))) + break; + + if (note) + { + if (dump_file) + fprintf (dump_file, "Ignoring reg %d, has equiv memory\n", + regno); + bitmap_set_bit (&unusable_as_input, regno); + continue; + } + + use = DF_REG_USE_CHAIN (regno); + all_dominated = true; + all_local = true; + closest_use = NULL_RTX; + for (; use; use = DF_REF_NEXT_REG (use)) + { + rtx insn; + if (!DF_REF_INSN_INFO (use)) + { + all_dominated = false; + all_local = false; + break; + } + insn = DF_REF_INSN (use); + if (DEBUG_INSN_P (insn)) + continue; + if (BLOCK_FOR_INSN (insn) != BLOCK_FOR_INSN (def_insn)) + all_local = false; + if (!insn_dominated_by_p (insn, def_insn, uid_luid)) + all_dominated = false; + if (closest_use != insn && closest_use != const0_rtx) + { + if (closest_use == NULL_RTX) + closest_use = insn; + else if (insn_dominated_by_p (closest_use, insn, uid_luid)) + closest_use = insn; + else if (!insn_dominated_by_p (insn, closest_use, uid_luid)) + closest_use = const0_rtx; + } + } + if (!all_dominated) + { + if (dump_file) + fprintf (dump_file, "Reg %d not all uses dominated by set\n", + regno); + continue; + } + if (all_local) + bitmap_set_bit (local, regno); + if (closest_use == const0_rtx || closest_use == NULL + || next_nonnote_nondebug_insn (def_insn) == closest_use) + { + if (dump_file) + fprintf (dump_file, "Reg %d uninteresting%s\n", regno, + closest_use == const0_rtx || closest_use == NULL + ? " (no unique first use)" : ""); + continue; + } +#ifdef HAVE_cc0 + if (reg_referenced_p (cc0_rtx, PATTERN (closest_use))) + { + if (dump_file) + fprintf (dump_file, "Reg %d: closest user uses cc0\n", + regno); + continue; + } +#endif + bitmap_set_bit (&interesting, regno); + closest_uses[regno] = closest_use; + + if (dump_file && (all_local || all_dominated)) + { + fprintf (dump_file, "Reg %u:", regno); + if (all_local) + fprintf (dump_file, " local to bb %d", bb->index); + if (all_dominated) + fprintf (dump_file, " def dominates all uses"); + if (closest_use != const0_rtx) + fprintf (dump_file, " has unique first use"); + fputs ("\n", dump_file); + } + } + } + + EXECUTE_IF_SET_IN_BITMAP (&interesting, 0, i, bi) + { + df_ref def = DF_REG_DEF_CHAIN (i); + rtx def_insn = DF_REF_INSN (def); + basic_block def_block = BLOCK_FOR_INSN (def_insn); + bitmap def_bb_local = bb_local + def_block->index; + bitmap def_bb_moveable = bb_moveable_reg_sets + def_block->index; + bitmap def_bb_transp = bb_transp_live + def_block->index; + bool local_to_bb_p = bitmap_bit_p (def_bb_local, i); + rtx use_insn = closest_uses[i]; + df_ref *def_insn_use_rec = DF_INSN_USES (def_insn); + bool all_ok = true; + bool all_transp = true; + + if (!REG_P (DF_REF_REG (def))) + continue; + + if (!local_to_bb_p) + { + if (dump_file) + fprintf (dump_file, "Reg %u not local to one basic block\n", + i); + continue; + } + if (reg_equiv_init (i) != NULL_RTX) + { + if (dump_file) + fprintf (dump_file, "Ignoring reg %u with equiv init insn\n", + i); + continue; + } + if (!rtx_moveable_p (&PATTERN (def_insn), OP_IN)) + { + if (dump_file) + fprintf (dump_file, "Found def insn %d for %d to be not moveable\n", + INSN_UID (def_insn), i); + continue; + } + if (dump_file) + fprintf (dump_file, "Examining insn %d, def for %d\n", + INSN_UID (def_insn), i); + while (*def_insn_use_rec != NULL) + { + df_ref use = *def_insn_use_rec; + unsigned regno = DF_REF_REGNO (use); + if (bitmap_bit_p (&unusable_as_input, regno)) + { + all_ok = false; + if (dump_file) + fprintf (dump_file, " found unusable input reg %u.\n", regno); + break; + } + if (!bitmap_bit_p (def_bb_transp, regno)) + { + if (bitmap_bit_p (def_bb_moveable, regno) + && !control_flow_insn_p (use_insn) +#ifdef HAVE_cc0 + && !sets_cc0_p (use_insn) +#endif + ) + { + if (modified_between_p (DF_REF_REG (use), def_insn, use_insn)) + { + rtx x = NEXT_INSN (def_insn); + while (!modified_in_p (DF_REF_REG (use), x)) + { + gcc_assert (x != use_insn); + x = NEXT_INSN (x); + } + if (dump_file) + fprintf (dump_file, " input reg %u modified but insn %d moveable\n", + regno, INSN_UID (x)); + emit_insn_after (PATTERN (x), use_insn); + set_insn_deleted (x); + } + else + { + if (dump_file) + fprintf (dump_file, " input reg %u modified between def and use\n", + regno); + all_transp = false; + } + } + else + all_transp = false; + } + + def_insn_use_rec++; + } + if (!all_ok) + continue; + if (!dbg_cnt (ira_move)) + break; + if (dump_file) + fprintf (dump_file, " all ok%s\n", all_transp ? " and transp" : ""); + + if (all_transp) + { + rtx def_reg = DF_REF_REG (def); + rtx newreg = ira_create_new_reg (def_reg); + if (validate_change (def_insn, DF_REF_LOC (def), newreg, 0)) + { + unsigned nregno = REGNO (newreg); + rtx move = emit_insn_before (gen_move_insn (def_reg, newreg), + use_insn); + nregno -= max_regs; + VEC_replace (rtx, pseudo_move_insn, nregno, move); + VEC_replace (rtx, pseudo_replaced_reg, nregno, def_reg); + } + } + } + + FOR_EACH_BB (bb) + { + bitmap_clear (bb_local + bb->index); + bitmap_clear (bb_transp_live + bb->index); + bitmap_clear (bb_moveable_reg_sets + bb->index); + } + bitmap_clear (&interesting); + bitmap_clear (&unusable_as_input); + free (uid_luid); + free (closest_uses); + free (bb_local); + free (bb_transp_live); + free (bb_moveable_reg_sets); + + last_moveable_pseudo = max_reg_num (); + + fix_reg_equiv_init(); + regstat_free_n_sets_and_refs (); + regstat_free_ri (); + regstat_init_n_sets_and_refs (); + regstat_compute_ri (); + free_dominance_info (CDI_DOMINATORS); +} +/* Perform the second half of the transformation started in + find_moveable_pseudos. We look for instances where the newly introduced + pseudo remains unallocated, and remove it by moving the definition to + just before its use, replacing the move instruction generated by + find_moveable_pseudos. */ +static void +move_unallocated_pseudos (void) +{ + int i; + for (i = first_moveable_pseudo; i < last_moveable_pseudo; i++) + if (reg_renumber[i] < 0) + { + df_ref def = DF_REG_DEF_CHAIN (i); + int idx = i - first_moveable_pseudo; + rtx other_reg = VEC_index (rtx, pseudo_replaced_reg, idx); + rtx def_insn = DF_REF_INSN (def); + rtx move_insn = VEC_index (rtx, pseudo_move_insn, idx); + rtx set; + rtx newinsn = emit_insn_after (PATTERN (def_insn), move_insn); + int success; + + if (dump_file) + fprintf (dump_file, "moving def of %d (insn %d now) ", + REGNO (other_reg), INSN_UID (def_insn)); + + set = single_set (newinsn); + success = validate_change (newinsn, &SET_DEST (set), other_reg, 0); + gcc_assert (success); + if (dump_file) + fprintf (dump_file, " %d) rather than keep unallocated replacement %d\n", + INSN_UID (newinsn), i); + delete_insn (move_insn); + delete_insn (def_insn); + SET_REG_N_REFS (i, 0); + } +} /* All natural loops. */ @@ -3606,6 +4120,8 @@ ira (FILE *f) } } + find_moveable_pseudos (); + max_regno_before_ira = allocated_reg_info_size = max_reg_num (); ira_setup_eliminable_regset (); @@ -3716,6 +4232,7 @@ ira (FILE *f) max_regno * sizeof (struct ira_spilled_reg_stack_slot)); } allocate_initial_values (reg_equivs); + move_unallocated_pseudos (); } static void @@ -3814,7 +4331,7 @@ struct rtl_opt_pass pass_ira = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0, /* todo_flags_finish */ } }; @@ -3840,6 +4357,6 @@ struct rtl_opt_pass pass_reload = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */ + TODO_ggc_collect /* todo_flags_finish */ } }; diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 3e6cb4d9dc9..532a6bf26ee 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,39 @@ +2012-04-22 Jan Hubicka <jh@suse.cz> + + * class.c (build_utf8_ref): Do not mark varpool node as needed. + +2012-04-20 Jan Hubicka <jh@suse.cz> + + * class.c (make_local_function_alias): Do not mark symbol referenced. + +2012-04-11 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * jcf-dump.c (print_constant): Cast JPOOL_USHORT2, JPOOL_USHORT1 + results to long to match formats. + +2012-04-11 Andrew Haley <aph@redhat.com> + + * jcf-reader.c (jcf_parse_bootstrap_methods): Add + ATTRIBUTE_UNUSED. + +2012-04-11 Andrew Haley <aph@redhat.com> + + * jcf.h (bootstrap_method): New. + (BootstrapMethods): New. + (JCF): Add BootstrapMethods. + (enum cpool_tag): Add MethodHandle, MethodType, and InvokeDynamic. + * jcf-reader.c (jcf_parse_bootstrap_methods): New. + (jcf_parse_constant_pool): Handlers for MethodHandle, MethodType, + and InvokeDynamic. + (jcf_parse_bootstrap_methods): New. + * javaop.def (invokedynamic): New opcode. + * jcf-parse.c (get_constant): An unknown constant type should not + be an internal error, but a fatal one. Make it so. + * jcf-dump.c (HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE): New. + (HANDLE_END_BOOTSTRAP_METHODS): New. + (print_constant): Handlers for MethodHandle, MethodType, and + InvokeDynamic. + 2012-04-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> * class.c (emit_register_classes_in_jcr_section): Set DECL_USER_ALIGN. diff --git a/gcc/java/class.c b/gcc/java/class.c index 3c34abad7fe..33a39998034 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -1001,7 +1001,6 @@ build_utf8_ref (tree name) DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (ctype); pushdecl (decl); rest_of_decl_compilation (decl, global_bindings_p (), 0); - varpool_mark_needed_node (varpool_node (decl)); ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl); IDENTIFIER_UTF8_REF (name) = ref; return ref; @@ -1407,7 +1406,6 @@ make_local_function_alias (tree method) DECL_INITIAL (alias) = error_mark_node; TREE_ADDRESSABLE (alias) = 1; TREE_USED (alias) = 1; - TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; if (!flag_syntax_only) assemble_alias (alias, DECL_ASSEMBLER_NAME (method)); return alias; diff --git a/gcc/java/javaop.def b/gcc/java/javaop.def index 653c77f72b8..6fe986d5d2d 100644 --- a/gcc/java/javaop.def +++ b/gcc/java/javaop.def @@ -292,6 +292,7 @@ JAVAOP (invokevirtual, 182, INVOKE, VIRTUAL,0) JAVAOP (invokespecial, 183, INVOKE, SPECIAL, 0) JAVAOP (invokestatic, 184, INVOKE, STATIC, 0) JAVAOP (invokeinterface,185, INVOKE, INTERFACE, 1) +JAVAOP (invokedynamic, 186, INVOKE, DYNAMIC, 1) JAVAOP (new, 187, OBJECT, PTR, NEW) JAVAOP (newarray, 188, ARRAY, NUM, NEW) JAVAOP (anewarray, 189, ARRAY, PTR, NEW) diff --git a/gcc/java/jcf-dump.c b/gcc/java/jcf-dump.c index 0c5878cc579..67233d11c0e 100644 --- a/gcc/java/jcf-dump.c +++ b/gcc/java/jcf-dump.c @@ -430,6 +430,23 @@ utf8_equal_string (JCF *jcf, int index, const char * value) print_element_value (out, jcf, 1); \ } +#define HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE() \ +{ \ + COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ + fputc ('\n', out); jcf_parse_bootstrap_methods (jcf, attribute_length); \ +} + +#define HANDLE_END_BOOTSTRAP_METHODS(NUM_METHODS) \ + { \ + int i; \ + for (i = 0; i < NUM_METHODS; i++) \ + { \ + bootstrap_method *m = &jcf->bootstrap_methods.methods[i]; \ + fprintf (out, " %d: ", i); \ + print_constant (out, jcf, m->method_ref, 1); \ + fprintf (out, "\n"); \ + } \ + } #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \ { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \ @@ -898,6 +915,55 @@ print_constant (FILE *out, JCF *jcf, int index, int verbosity) fputc ('\"', out); } break; + case CONSTANT_MethodHandle: + { + int kind = JPOOL_USHORT1 (jcf, index); + if (verbosity > 0) + fprintf (out, "MethodHandle kind: %d=", kind); + switch(kind) { + case 1: + case 2: + case 3: + case 4: + if (verbosity > 0) + fprintf (out, "Fieldref: %ld=", (long) JPOOL_USHORT2 (jcf, index)); + print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0); + case 5: + case 6: + case 7: + case 8: + if (verbosity > 0) + fprintf (out, "Methodref: %ld=", (long) JPOOL_USHORT2 (jcf, index)); + print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0); + break; + case 9: + if (verbosity > 0) + fprintf (out, "InterfaceMethodref: %ld=", + (long) JPOOL_USHORT2 (jcf, index)); + print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0); + break; + } + break; + } + case CONSTANT_MethodType: + if (verbosity > 0) + fprintf (out, "MethodType %ld: ", (long) JPOOL_USHORT1 (jcf, index)); + print_signature (out, jcf, JPOOL_USHORT1 (jcf, index), 0); + break; + case CONSTANT_InvokeDynamic: + { + uint16 name_and_type = JPOOL_USHORT2 (jcf, index); + if (verbosity > 0) + fprintf (out, "InvokeDynamic: "); + fprintf (out, "bootstrap_method: %ld ", + (long) JPOOL_USHORT1 (jcf, index)); + if (verbosity == 2) + fprintf (out, " name_and_type: %d=<", name_and_type); + print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType); + if (verbosity == 2) + fputc ('>', out); + break; + } default: fprintf (out, "(Unknown constant type %d)", kind); } diff --git a/gcc/java/jcf-io.c b/gcc/java/jcf-io.c index 0dc761534c6..c50ec49ccc5 100644 --- a/gcc/java/jcf-io.c +++ b/gcc/java/jcf-io.c @@ -518,6 +518,26 @@ verify_constant_pool (JCF *jcf) case CONSTANT_Utf8: case CONSTANT_Unicode: break; + case CONSTANT_MethodHandle: + n = JPOOL_USHORT1 (jcf, i); + if (n < 1 || n > 9) + return i; + n = JPOOL_USHORT2 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf)) + return i; + break; + case CONSTANT_MethodType: + n = JPOOL_USHORT1 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) + return i; + break; + case CONSTANT_InvokeDynamic: + n = JPOOL_USHORT2 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType) + return i; + break; default: return i; } diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c index 04c04f575cf..c799676074e 100644 --- a/gcc/java/jcf-parse.c +++ b/gcc/java/jcf-parse.c @@ -1113,8 +1113,8 @@ get_constant (JCF *jcf, int index) jcf->cpool.data[index].t = value; return value; bad: - internal_error ("bad value constant type %d, index %d", - JPOOL_TAG (jcf, index), index); + fatal_error ("bad value constant type %d, index %d", + JPOOL_TAG (jcf, index), index); } tree diff --git a/gcc/java/jcf-reader.c b/gcc/java/jcf-reader.c index 315bd411a52..8978de2c196 100644 --- a/gcc/java/jcf-reader.c +++ b/gcc/java/jcf-reader.c @@ -36,6 +36,7 @@ static int jcf_parse_fields (JCF *); static int jcf_parse_one_method (JCF *, int); static int jcf_parse_methods (JCF *); static int jcf_parse_final_attributes (JCF *); +static int jcf_parse_bootstrap_methods (JCF *, int) ATTRIBUTE_UNUSED; #ifdef NEED_PEEK_ATTRIBUTE static int peek_attribute (JCF *, int, const char *, int); #endif @@ -293,6 +294,15 @@ get_attribute (JCF *jcf, int index, } else #endif + if (MATCH_ATTRIBUTE ("BootstrapMethods")) + { +#ifdef HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE + HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE(); +#else + JCF_SKIP (jcf, attribute_length); +#endif + } + else { #ifdef PROCESS_OTHER_ATTRIBUTE PROCESS_OTHER_ATTRIBUTE(jcf, attribute_name, attribute_length); @@ -382,6 +392,17 @@ jcf_parse_constant_pool (JCF* jcf) JCF_SKIP (jcf, n); #endif break; + case CONSTANT_MethodHandle: + jcf->cpool.data[i].w = JCF_readu (jcf); + jcf->cpool.data[i].w |= JCF_readu2 (jcf) << 16; + break; + case CONSTANT_MethodType: + jcf->cpool.data[i].w = JCF_readu2 (jcf); + break; + case CONSTANT_InvokeDynamic: + jcf->cpool.data[i].w = JCF_readu2 (jcf); + jcf->cpool.data[i].w |= JCF_readu2 (jcf) << 16; + break; default: return i; } @@ -521,3 +542,39 @@ jcf_parse_final_attributes (JCF *jcf) return 0; } +/* Read and handle the "BootstrapMethods" attribute. + + Return 0 if OK. +*/ +static int +jcf_parse_bootstrap_methods (JCF* jcf, int attribute_length ATTRIBUTE_UNUSED) +{ + int i; + uint16 num_methods = JCF_readu2 (jcf); + jcf->bootstrap_methods.count = num_methods; + jcf->bootstrap_methods.methods + = (bootstrap_method *) ggc_alloc_atomic (num_methods + * sizeof (bootstrap_method)); +#ifdef HANDLE_START_BOOTSTRAP_METHODS + HANDLE_START_BOOTSTRAP_METHODS (jcf, num_methods); +#endif + + for (i = 0; i < num_methods; i++) + { + unsigned j; + bootstrap_method *m = &jcf->bootstrap_methods.methods[i]; + m->method_ref = JCF_readu2 (jcf); + m->num_arguments = JCF_readu2 (jcf); + m->bootstrap_arguments + = (unsigned *) ggc_alloc_atomic (m->num_arguments + * sizeof (unsigned)); + for (j = 0; j < m->num_arguments; j++) + m->bootstrap_arguments[j] = JCF_readu2 (jcf); + } + +#ifdef HANDLE_END_BOOTSTRAP_METHODS + HANDLE_END_BOOTSTRAP_METHODS (num_methods); +#endif + + return 0; +} diff --git a/gcc/java/jcf.h b/gcc/java/jcf.h index b066b2967c3..40b4ae2d278 100644 --- a/gcc/java/jcf.h +++ b/gcc/java/jcf.h @@ -88,6 +88,17 @@ typedef struct GTY(()) CPool { desc ("cpool_entry_is_tree (%1.tags%a)"))) data; } CPool; +typedef struct GTY(()) bootstrap_method { + unsigned method_ref; + unsigned num_arguments; + unsigned* GTY((length ("%h.num_arguments"))) bootstrap_arguments; +} bootstrap_method; + +typedef struct GTY(()) BootstrapMethods { + unsigned count; + bootstrap_method* GTY((length ("%h.count"))) methods; +} BootstrapMethods; + struct ZipDirectory; /* JCF encapsulates the state of reading a Java Class File. */ @@ -109,6 +120,7 @@ typedef struct GTY(()) JCF { JCF_u2 this_class; JCF_u2 super_class; CPool cpool; + BootstrapMethods bootstrap_methods; } JCF; /*typedef JCF* JCF_FILE;*/ @@ -245,6 +257,10 @@ enum cpool_tag CONSTANT_NameAndType = 12, CONSTANT_Utf8 = 1, CONSTANT_Unicode = 2, + CONSTANT_MethodHandle = 15, + CONSTANT_MethodType = 16, + CONSTANT_InvokeDynamic = 18, + CONSTANT_None = 0 }; diff --git a/gcc/jump.c b/gcc/jump.c index 52cbbca43db..4c4b00118f4 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -1764,7 +1764,7 @@ rtx_renumbered_equal_p (const_rtx x, const_rtx y) if (GET_MODE (x) != GET_MODE (y)) return 0; - /* MEMs refering to different address space are not equivalent. */ + /* MEMs referring to different address space are not equivalent. */ if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) return 0; diff --git a/gcc/loop-iv.c b/gcc/loop-iv.c index 83d25015976..382d4ce1591 100644 --- a/gcc/loop-iv.c +++ b/gcc/loop-iv.c @@ -2190,8 +2190,8 @@ canonicalize_iv_subregs (struct rtx_iv *iv0, struct rtx_iv *iv1, return true; } -/* Tries to estimate the maximum number of iterations in LOOP, and store the - result in DESC. This function is called from iv_number_of_iterations with +/* Tries to estimate the maximum number of iterations in LOOP, and return the + result. This function is called from iv_number_of_iterations with a number of fields in DESC already filled in. OLD_NITER is the original expression for the number of iterations, before we tried to simplify it. */ @@ -2207,10 +2207,7 @@ determine_max_iter (struct loop *loop, struct niter_desc *desc, rtx old_niter) { nmax = INTVAL (XEXP (niter, 0)); if (!(nmax & (nmax + 1))) - { - desc->niter_max = nmax; - return nmax; - } + return nmax; } get_mode_bounds (desc->mode, desc->signed_p, desc->mode, &mmin, &mmax); @@ -2219,10 +2216,7 @@ determine_max_iter (struct loop *loop, struct niter_desc *desc, rtx old_niter) if (GET_CODE (niter) == UDIV) { if (!CONST_INT_P (XEXP (niter, 1))) - { - desc->niter_max = nmax; - return nmax; - } + return nmax; inc = INTVAL (XEXP (niter, 1)); niter = XEXP (niter, 0); } @@ -2241,7 +2235,6 @@ determine_max_iter (struct loop *loop, struct niter_desc *desc, rtx old_niter) if (dump_file) fprintf (dump_file, ";; improved upper bound by one.\n"); } - desc->niter_max = nmax / inc; return nmax / inc; } @@ -2259,7 +2252,7 @@ iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition, enum rtx_code cond; enum machine_mode mode, comp_mode; rtx mmin, mmax, mode_mmin, mode_mmax; - unsigned HOST_WIDEST_INT s, size, d, inv; + unsigned HOST_WIDEST_INT s, size, d, inv, max; HOST_WIDEST_INT up, down, inc, step_val; int was_sharp = false; rtx old_niter; @@ -2279,6 +2272,9 @@ iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition, desc->const_iter = false; desc->niter_expr = NULL_RTX; desc->niter_max = 0; + if (loop->any_upper_bound + && double_int_fits_in_uhwi_p (loop->nb_iterations_upper_bound)) + desc->niter_max = loop->nb_iterations_upper_bound.low; cond = GET_CODE (condition); gcc_assert (COMPARISON_P (condition)); @@ -2547,7 +2543,10 @@ iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition, down = INTVAL (CONST_INT_P (iv0.base) ? iv0.base : mode_mmin); - desc->niter_max = (up - down) / inc + 1; + max = (up - down) / inc + 1; + if (!desc->niter_max + || max < desc->niter_max) + desc->niter_max = max; if (iv0.step == const0_rtx) { @@ -2762,8 +2761,10 @@ iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition, } else { - if (!desc->niter_max) - desc->niter_max = determine_max_iter (loop, desc, old_niter); + max = determine_max_iter (loop, desc, old_niter); + if (!desc->niter_max + || max < desc->niter_max) + desc->niter_max = max; /* simplify_using_initial_values does a copy propagation on the registers in the expression for the number of iterations. This prolongs life diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c index 5a658d85bcb..f251f5dbacd 100644 --- a/gcc/loop-unroll.c +++ b/gcc/loop-unroll.c @@ -857,7 +857,9 @@ decide_unroll_runtime_iterations (struct loop *loop, int flags) } /* If we have profile feedback, check whether the loop rolls. */ - if (loop->header->count && expected_loop_iterations (loop) < 2 * nunroll) + if ((loop->header->count + && expected_loop_iterations (loop) < 2 * nunroll) + || desc->niter_max < 2 * nunroll) { if (dump_file) fprintf (dump_file, ";; Not unrolling loop, doesn't roll\n"); @@ -1400,8 +1402,9 @@ decide_unroll_stupid (struct loop *loop, int flags) } /* If we have profile feedback, check whether the loop rolls. */ - if (loop->header->count - && expected_loop_iterations (loop) < 2 * nunroll) + if ((loop->header->count + && expected_loop_iterations (loop) < 2 * nunroll) + || desc->niter_max < 2 * nunroll) { if (dump_file) fprintf (dump_file, ";; Not unrolling loop, doesn't roll\n"); diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index f57028d07fb..25634899047 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -290,7 +290,7 @@ lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge, streamer_write_hwi_stream (ob->main_stream, edge->count); bp = bitpack_create (ob->main_stream); - uid = (!gimple_has_body_p (edge->caller->decl) + uid = (!gimple_has_body_p (edge->caller->symbol.decl) ? edge->lto_stmt_uid : gimple_uid (edge->call_stmt)); bp_pack_enum (&bp, cgraph_inline_failed_enum, CIF_N_REASONS, edge->inline_failed); @@ -326,18 +326,18 @@ referenced_from_other_partition_p (struct ipa_ref_list *list, cgraph_node_set se { int i; struct ipa_ref *ref; - for (i = 0; ipa_ref_list_refering_iterate (list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (list, i, ref); i++) { - if (ref->refering_type == IPA_REF_CGRAPH) + if (symtab_function_p (ref->referring)) { - if (ipa_ref_refering_node (ref)->in_other_partition - || !cgraph_node_in_set_p (ipa_ref_refering_node (ref), set)) + if (ipa_ref_referring_node (ref)->symbol.in_other_partition + || !cgraph_node_in_set_p (ipa_ref_referring_node (ref), set)) return true; } else { - if (ipa_ref_refering_varpool_node (ref)->in_other_partition - || !varpool_node_in_set_p (ipa_ref_refering_varpool_node (ref), + if (ipa_ref_referring_varpool_node (ref)->symbol.in_other_partition + || !varpool_node_in_set_p (ipa_ref_referring_varpool_node (ref), vset)) return true; } @@ -356,7 +356,7 @@ reachable_from_other_partition_p (struct cgraph_node *node, cgraph_node_set set) if (node->global.inlined_to) return false; for (e = node->callers; e; e = e->next_caller) - if (e->caller->in_other_partition + if (e->caller->symbol.in_other_partition || !cgraph_node_in_set_p (e->caller, set)) return true; return false; @@ -370,16 +370,16 @@ referenced_from_this_partition_p (struct ipa_ref_list *list, cgraph_node_set set { int i; struct ipa_ref *ref; - for (i = 0; ipa_ref_list_refering_iterate (list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (list, i, ref); i++) { - if (ref->refering_type == IPA_REF_CGRAPH) + if (symtab_function_p (ref->referring)) { - if (cgraph_node_in_set_p (ipa_ref_refering_node (ref), set)) + if (cgraph_node_in_set_p (ipa_ref_referring_node (ref), set)) return true; } else { - if (varpool_node_in_set_p (ipa_ref_refering_varpool_node (ref), + if (varpool_node_in_set_p (ipa_ref_referring_varpool_node (ref), vset)) return true; } @@ -428,7 +428,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, streamer_write_enum (ob->main_stream, LTO_cgraph_tags, LTO_cgraph_last_tag, tag); - streamer_write_hwi_stream (ob->main_stream, node->order); + streamer_write_hwi_stream (ob->main_stream, node->symbol.order); /* In WPA mode, we only output part of the call-graph. Also, we fake cgraph node attributes. There are two cases that we care. @@ -469,7 +469,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, streamer_write_hwi_stream (ob->main_stream, ref); - lto_output_fn_decl_index (ob->decl_state, ob->main_stream, node->decl); + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, node->symbol.decl); streamer_write_hwi_stream (ob->main_stream, node->count); streamer_write_hwi_stream (ob->main_stream, node->count_materialization_scale); @@ -486,9 +486,10 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, streamer_write_hwi_stream (ob->main_stream, ref); } - if (node->same_comdat_group && !boundary_p) + if (node->symbol.same_comdat_group && !boundary_p) { - ref = lto_cgraph_encoder_lookup (encoder, node->same_comdat_group); + ref = lto_cgraph_encoder_lookup (encoder, + cgraph (node->symbol.same_comdat_group)); gcc_assert (ref != LCC_NOT_FOUND); } else @@ -497,19 +498,20 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, bp = bitpack_create (ob->main_stream); bp_pack_value (&bp, node->local.local, 1); - bp_pack_value (&bp, node->local.externally_visible, 1); + bp_pack_value (&bp, node->symbol.externally_visible, 1); bp_pack_value (&bp, node->local.finalized, 1); bp_pack_value (&bp, node->local.versionable, 1); bp_pack_value (&bp, node->local.can_change_signature, 1); bp_pack_value (&bp, node->local.redefined_extern_inline, 1); - bp_pack_value (&bp, node->needed, 1); - bp_pack_value (&bp, node->address_taken, 1); + bp_pack_value (&bp, node->symbol.force_output, 1); + bp_pack_value (&bp, node->symbol.address_taken, 1); bp_pack_value (&bp, node->abstract_and_needed, 1); bp_pack_value (&bp, tag == LTO_cgraph_analyzed_node - && !DECL_EXTERNAL (node->decl) - && !DECL_COMDAT (node->decl) + && !DECL_EXTERNAL (node->symbol.decl) + && !DECL_COMDAT (node->symbol.decl) && (reachable_from_other_partition_p (node, set) - || referenced_from_other_partition_p (&node->ref_list, set, vset)), 1); + || referenced_from_other_partition_p (&node->symbol.ref_list, + set, vset)), 1); bp_pack_value (&bp, node->lowered, 1); bp_pack_value (&bp, in_other_partition, 1); /* Real aliases in a boundary become non-aliases. However we still stream @@ -518,14 +520,14 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, defined in other unit, we may use the info on aliases to resolve symbol1 != symbol2 type tests that we can do only for locally defined objects otherwise. */ - bp_pack_value (&bp, node->alias && (!boundary_p || DECL_EXTERNAL (node->decl)), 1); + bp_pack_value (&bp, node->alias && (!boundary_p || DECL_EXTERNAL (node->symbol.decl)), 1); bp_pack_value (&bp, node->frequency, 2); bp_pack_value (&bp, node->only_called_at_startup, 1); bp_pack_value (&bp, node->only_called_at_exit, 1); bp_pack_value (&bp, node->tm_clone, 1); bp_pack_value (&bp, node->thunk.thunk_p && !boundary_p, 1); bp_pack_enum (&bp, ld_plugin_symbol_resolution, - LDPR_NUM_KNOWN, node->resolution); + LDPR_NUM_KNOWN, node->symbol.resolution); streamer_write_bitpack (&bp); if (node->thunk.thunk_p && !boundary_p) @@ -538,7 +540,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, streamer_write_uhwi_stream (ob->main_stream, node->thunk.virtual_value); } if ((node->alias || node->thunk.thunk_p) - && (!boundary_p || (node->alias && DECL_EXTERNAL (node->decl)))) + && (!boundary_p || (node->alias && DECL_EXTERNAL (node->symbol.decl)))) { streamer_write_hwi_in_range (ob->main_stream, 0, 1, node->thunk.alias != NULL); @@ -560,21 +562,20 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node struct bitpack_d bp; int ref; - streamer_write_hwi_stream (ob->main_stream, node->order); - lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->decl); + streamer_write_hwi_stream (ob->main_stream, node->symbol.order); + lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->symbol.decl); bp = bitpack_create (ob->main_stream); - bp_pack_value (&bp, node->externally_visible, 1); - bp_pack_value (&bp, node->force_output, 1); + bp_pack_value (&bp, node->symbol.externally_visible, 1); + bp_pack_value (&bp, node->symbol.force_output, 1); bp_pack_value (&bp, node->finalized, 1); bp_pack_value (&bp, node->alias, 1); bp_pack_value (&bp, node->alias_of != NULL, 1); gcc_assert (node->finalized || !node->analyzed); - gcc_assert (node->needed); /* Constant pool initializers can be de-unified into individual ltrans units. FIXME: Alternatively at -Os we may want to avoid generating for them the local labels and share them across LTRANS partitions. */ - if (DECL_IN_CONSTANT_POOL (node->decl) - && !DECL_COMDAT (node->decl)) + if (DECL_IN_CONSTANT_POOL (node->symbol.decl) + && !DECL_COMDAT (node->symbol.decl)) { bp_pack_value (&bp, 0, 1); /* used_from_other_parition. */ bp_pack_value (&bp, 0, 1); /* in_other_partition. */ @@ -582,23 +583,24 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node else { bp_pack_value (&bp, node->analyzed - && referenced_from_other_partition_p (&node->ref_list, + && referenced_from_other_partition_p (&node->symbol.ref_list, set, vset), 1); bp_pack_value (&bp, boundary_p, 1); /* in_other_partition. */ } streamer_write_bitpack (&bp); if (node->alias_of) lto_output_var_decl_index (ob->decl_state, ob->main_stream, node->alias_of); - if (node->same_comdat_group && !boundary_p) + if (node->symbol.same_comdat_group && !boundary_p) { - ref = lto_varpool_encoder_lookup (varpool_encoder, node->same_comdat_group); + ref = lto_varpool_encoder_lookup (varpool_encoder, + varpool (node->symbol.same_comdat_group)); gcc_assert (ref != LCC_NOT_FOUND); } else ref = LCC_NOT_FOUND; streamer_write_hwi_stream (ob->main_stream, ref); streamer_write_enum (ob->main_stream, ld_plugin_symbol_resolution, - LDPR_NUM_KNOWN, node->resolution); + LDPR_NUM_KNOWN, node->symbol.resolution); } /* Output the varpool NODE to OB. @@ -611,10 +613,10 @@ lto_output_ref (struct lto_simple_output_block *ob, struct ipa_ref *ref, { struct bitpack_d bp; bp = bitpack_create (ob->main_stream); - bp_pack_value (&bp, ref->refered_type, 1); + bp_pack_value (&bp, symtab_function_p (ref->referred), 1); bp_pack_value (&bp, ref->use, 2); streamer_write_bitpack (&bp); - if (ref->refered_type == IPA_REF_CGRAPH) + if (symtab_function_p (ref->referred)) { int nref = lto_cgraph_encoder_lookup (encoder, ipa_ref_node (ref)); gcc_assert (nref != LCC_NOT_FOUND); @@ -671,7 +673,7 @@ add_references (lto_cgraph_encoder_t encoder, int i; struct ipa_ref *ref; for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++) - if (ref->refered_type == IPA_REF_CGRAPH) + if (symtab_function_p (ref->referred)) add_node_to (encoder, ipa_ref_node (ref), false); else { @@ -719,13 +721,14 @@ output_refs (cgraph_node_set set, varpool_node_set vset, { struct cgraph_node *node = csi_node (csi); - count = ipa_ref_list_nreferences (&node->ref_list); + count = ipa_ref_list_nreferences (&node->symbol.ref_list); if (count) { streamer_write_uhwi_stream (ob->main_stream, count); streamer_write_uhwi_stream (ob->main_stream, lto_cgraph_encoder_lookup (encoder, node)); - for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, + i, ref); i++) lto_output_ref (ob, ref, encoder, varpool_encoder); } } @@ -736,14 +739,15 @@ output_refs (cgraph_node_set set, varpool_node_set vset, { struct varpool_node *node = vsi_node (vsi); - count = ipa_ref_list_nreferences (&node->ref_list); + count = ipa_ref_list_nreferences (&node->symbol.ref_list); if (count) { streamer_write_uhwi_stream (ob->main_stream, count); streamer_write_uhwi_stream (ob->main_stream, lto_varpool_encoder_lookup (varpool_encoder, node)); - for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, + i, ref); i++) lto_output_ref (ob, ref, encoder, varpool_encoder); } } @@ -775,7 +779,7 @@ compute_ltrans_boundary (struct lto_out_decl_state *state, { node = csi_node (csi); add_node_to (encoder, node, true); - add_references (encoder, varpool_encoder, &node->ref_list); + add_references (encoder, varpool_encoder, &node->symbol.ref_list); } for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi)) { @@ -783,7 +787,7 @@ compute_ltrans_boundary (struct lto_out_decl_state *state, gcc_assert (!vnode->alias || vnode->alias_of); lto_varpool_encoder_encode (varpool_encoder, vnode); lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode); - add_references (encoder, varpool_encoder, &vnode->ref_list); + add_references (encoder, varpool_encoder, &vnode->symbol.ref_list); } /* Pickle in also the initializer of all referenced readonly variables to help folding. Constant pool variables are not shared, so we must @@ -791,16 +795,16 @@ compute_ltrans_boundary (struct lto_out_decl_state *state, for (i = 0; i < lto_varpool_encoder_size (varpool_encoder); i++) { struct varpool_node *vnode = lto_varpool_encoder_deref (varpool_encoder, i); - if (DECL_INITIAL (vnode->decl) + if (DECL_INITIAL (vnode->symbol.decl) && !lto_varpool_encoder_encode_initializer_p (varpool_encoder, vnode) - && const_value_known_p (vnode->decl)) + && const_value_known_p (vnode->symbol.decl)) { lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode); - add_references (encoder, varpool_encoder, &vnode->ref_list); + add_references (encoder, varpool_encoder, &vnode->symbol.ref_list); } else if (vnode->alias || vnode->alias_of) - add_references (encoder, varpool_encoder, &vnode->ref_list); + add_references (encoder, varpool_encoder, &vnode->symbol.ref_list); } /* Go over all the nodes again to include callees that are not in @@ -897,23 +901,23 @@ input_overwrite_node (struct lto_file_decl_data *file_data, enum LTO_cgraph_tags tag, struct bitpack_d *bp) { - node->aux = (void *) tag; - node->local.lto_file_data = file_data; + node->symbol.aux = (void *) tag; + node->symbol.lto_file_data = file_data; node->local.local = bp_unpack_value (bp, 1); - node->local.externally_visible = bp_unpack_value (bp, 1); + node->symbol.externally_visible = bp_unpack_value (bp, 1); node->local.finalized = bp_unpack_value (bp, 1); node->local.versionable = bp_unpack_value (bp, 1); node->local.can_change_signature = bp_unpack_value (bp, 1); node->local.redefined_extern_inline = bp_unpack_value (bp, 1); - node->needed = bp_unpack_value (bp, 1); - node->address_taken = bp_unpack_value (bp, 1); + node->symbol.force_output = bp_unpack_value (bp, 1); + node->symbol.address_taken = bp_unpack_value (bp, 1); node->abstract_and_needed = bp_unpack_value (bp, 1); - node->reachable_from_other_partition = bp_unpack_value (bp, 1); + node->symbol.used_from_other_partition = bp_unpack_value (bp, 1); node->lowered = bp_unpack_value (bp, 1); node->analyzed = tag == LTO_cgraph_analyzed_node; - node->in_other_partition = bp_unpack_value (bp, 1); - if (node->in_other_partition + node->symbol.in_other_partition = bp_unpack_value (bp, 1); + if (node->symbol.in_other_partition /* Avoid updating decl when we are seeing just inline clone. When inlining function that has functions already inlined into it, we produce clones of inline clones. @@ -922,10 +926,10 @@ input_overwrite_node (struct lto_file_decl_data *file_data, we might end up streaming inline clone from other partition to support clone we are interested in. */ && (!node->clone_of - || node->clone_of->decl != node->decl)) + || node->clone_of->symbol.decl != node->symbol.decl)) { - DECL_EXTERNAL (node->decl) = 1; - TREE_STATIC (node->decl) = 0; + DECL_EXTERNAL (node->symbol.decl) = 1; + TREE_STATIC (node->symbol.decl) = 0; } node->alias = bp_unpack_value (bp, 1); node->frequency = (enum node_frequency)bp_unpack_value (bp, 2); @@ -933,7 +937,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, node->only_called_at_exit = bp_unpack_value (bp, 1); node->tm_clone = bp_unpack_value (bp, 1); node->thunk.thunk_p = bp_unpack_value (bp, 1); - node->resolution = bp_unpack_enum (bp, ld_plugin_symbol_resolution, + node->symbol.resolution = bp_unpack_enum (bp, ld_plugin_symbol_resolution, LDPR_NUM_KNOWN); } @@ -992,9 +996,9 @@ input_node (struct lto_file_decl_data *file_data, else node = cgraph_get_create_node (fn_decl); - node->order = order; - if (order >= cgraph_order) - cgraph_order = order + 1; + node->symbol.order = order; + if (order >= symtab_order) + symtab_order = order + 1; node->count = streamer_read_hwi (ib); node->count_materialization_scale = streamer_read_hwi (ib); @@ -1008,7 +1012,7 @@ input_node (struct lto_file_decl_data *file_data, have already been read will have their tag stored in the 'aux' field. Since built-in functions can be referenced in multiple functions, they are expected to be read more than once. */ - if (node->aux && !DECL_BUILT_IN (node->decl)) + if (node->symbol.aux && !DECL_BUILT_IN (node->symbol.decl)) internal_error ("bytecode stream: found multiple instances of cgraph " "node %d", node->uid); @@ -1019,7 +1023,7 @@ input_node (struct lto_file_decl_data *file_data, node->global.inlined_to = (cgraph_node_ptr) (intptr_t) ref; /* Store a reference for now, and fix up later to be a pointer. */ - node->same_comdat_group = (cgraph_node_ptr) (intptr_t) ref2; + node->symbol.same_comdat_group = (symtab_node) (intptr_t) ref2; if (node->thunk.thunk_p) { @@ -1063,27 +1067,25 @@ input_varpool_node (struct lto_file_decl_data *file_data, decl_index = streamer_read_uhwi (ib); var_decl = lto_file_decl_data_get_var_decl (file_data, decl_index); node = varpool_node (var_decl); - node->order = order; - if (order >= cgraph_order) - cgraph_order = order + 1; - node->lto_file_data = file_data; + node->symbol.order = order; + if (order >= symtab_order) + symtab_order = order + 1; + node->symbol.lto_file_data = file_data; bp = streamer_read_bitpack (ib); - node->externally_visible = bp_unpack_value (&bp, 1); - node->force_output = bp_unpack_value (&bp, 1); + node->symbol.externally_visible = bp_unpack_value (&bp, 1); + node->symbol.force_output = bp_unpack_value (&bp, 1); node->finalized = bp_unpack_value (&bp, 1); node->alias = bp_unpack_value (&bp, 1); non_null_aliasof = bp_unpack_value (&bp, 1); - node->analyzed = node->finalized; - node->used_from_other_partition = bp_unpack_value (&bp, 1); - node->in_other_partition = bp_unpack_value (&bp, 1); - if (node->in_other_partition) + node->symbol.used_from_other_partition = bp_unpack_value (&bp, 1); + node->symbol.in_other_partition = bp_unpack_value (&bp, 1); + node->analyzed = (node->finalized && (!node->alias || !node->symbol.in_other_partition)); + if (node->symbol.in_other_partition) { - DECL_EXTERNAL (node->decl) = 1; - TREE_STATIC (node->decl) = 0; + DECL_EXTERNAL (node->symbol.decl) = 1; + TREE_STATIC (node->symbol.decl) = 0; } - if (node->finalized) - varpool_mark_needed_node (node); if (non_null_aliasof) { decl_index = streamer_read_uhwi (ib); @@ -1091,9 +1093,9 @@ input_varpool_node (struct lto_file_decl_data *file_data, } ref = streamer_read_hwi (ib); /* Store a reference for now, and fix up later to be a pointer. */ - node->same_comdat_group = (struct varpool_node *) (intptr_t) ref; - node->resolution = streamer_read_enum (ib, ld_plugin_symbol_resolution, - LDPR_NUM_KNOWN); + node->symbol.same_comdat_group = (symtab_node) (intptr_t) ref; + node->symbol.resolution = streamer_read_enum (ib, ld_plugin_symbol_resolution, + LDPR_NUM_KNOWN); return node; } @@ -1103,27 +1105,26 @@ input_varpool_node (struct lto_file_decl_data *file_data, static void input_ref (struct lto_input_block *ib, - struct cgraph_node *refering_node, - struct varpool_node *refering_varpool_node, + symtab_node referring_node, VEC(cgraph_node_ptr, heap) *nodes, - VEC(varpool_node_ptr, heap) *varpool_nodes) + VEC(varpool_node_ptr, heap) *varpool_nodes_vec) { struct cgraph_node *node = NULL; struct varpool_node *varpool_node = NULL; struct bitpack_d bp; - enum ipa_ref_type type; + int type; enum ipa_ref_use use; bp = streamer_read_bitpack (ib); - type = (enum ipa_ref_type) bp_unpack_value (&bp, 1); + type = bp_unpack_value (&bp, 1); use = (enum ipa_ref_use) bp_unpack_value (&bp, 2); - if (type == IPA_REF_CGRAPH) + if (type) node = VEC_index (cgraph_node_ptr, nodes, streamer_read_hwi (ib)); else - varpool_node = VEC_index (varpool_node_ptr, varpool_nodes, + varpool_node = VEC_index (varpool_node_ptr, varpool_nodes_vec, streamer_read_hwi (ib)); - ipa_record_reference (refering_node, refering_varpool_node, - node, varpool_node, use, NULL); + ipa_record_reference (referring_node, + node ? (symtab_node) node : (symtab_node) varpool_node, use, NULL); } /* Read an edge from IB. NODES points to a vector of previously read nodes for @@ -1145,13 +1146,13 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes, int ecf_flags = 0; caller = VEC_index (cgraph_node_ptr, nodes, streamer_read_hwi (ib)); - if (caller == NULL || caller->decl == NULL_TREE) + if (caller == NULL || caller->symbol.decl == NULL_TREE) internal_error ("bytecode stream: no caller found while reading edge"); if (!indirect) { callee = VEC_index (cgraph_node_ptr, nodes, streamer_read_hwi (ib)); - if (callee == NULL || callee->decl == NULL_TREE) + if (callee == NULL || callee->symbol.decl == NULL_TREE) internal_error ("bytecode stream: no callee found while reading edge"); } else @@ -1205,7 +1206,7 @@ input_cgraph_1 (struct lto_file_decl_data *file_data, unsigned i; tag = streamer_read_enum (ib, LTO_cgraph_tags, LTO_cgraph_last_tag); - order_base = cgraph_order; + order_base = symtab_order; while (tag) { if (tag == LTO_cgraph_edge) @@ -1215,7 +1216,7 @@ input_cgraph_1 (struct lto_file_decl_data *file_data, else { node = input_node (file_data, ib, tag,nodes); - if (node == NULL || node->decl == NULL_TREE) + if (node == NULL || node->symbol.decl == NULL_TREE) internal_error ("bytecode stream: found empty cgraph node"); VEC_safe_push (cgraph_node_ptr, heap, nodes, node); lto_cgraph_encoder_encode (file_data->cgraph_node_encoder, node); @@ -1229,16 +1230,16 @@ input_cgraph_1 (struct lto_file_decl_data *file_data, /* AUX pointers should be all non-zero for nodes read from the stream. */ #ifdef ENABLE_CHECKING FOR_EACH_VEC_ELT (cgraph_node_ptr, nodes, i, node) - gcc_assert (node->aux); + gcc_assert (node->symbol.aux); #endif FOR_EACH_VEC_ELT (cgraph_node_ptr, nodes, i, node) { int ref = (int) (intptr_t) node->global.inlined_to; /* We share declaration of builtins, so we may read same node twice. */ - if (!node->aux) + if (!node->symbol.aux) continue; - node->aux = NULL; + node->symbol.aux = NULL; /* Fixup inlined_to from reference to pointer. */ if (ref != LCC_NOT_FOUND) @@ -1246,16 +1247,16 @@ input_cgraph_1 (struct lto_file_decl_data *file_data, else node->global.inlined_to = NULL; - ref = (int) (intptr_t) node->same_comdat_group; + ref = (int) (intptr_t) node->symbol.same_comdat_group; /* Fixup same_comdat_group from reference to pointer. */ if (ref != LCC_NOT_FOUND) - node->same_comdat_group = VEC_index (cgraph_node_ptr, nodes, ref); + node->symbol.same_comdat_group = (symtab_node)VEC_index (cgraph_node_ptr, nodes, ref); else - node->same_comdat_group = NULL; + node->symbol.same_comdat_group = NULL; } FOR_EACH_VEC_ELT (cgraph_node_ptr, nodes, i, node) - node->aux = (void *)1; + node->symbol.aux = (void *)1; return nodes; } @@ -1279,24 +1280,24 @@ input_varpool_1 (struct lto_file_decl_data *file_data, } #ifdef ENABLE_CHECKING FOR_EACH_VEC_ELT (varpool_node_ptr, varpool, i, node) - gcc_assert (!node->aux); + gcc_assert (!node->symbol.aux); #endif FOR_EACH_VEC_ELT (varpool_node_ptr, varpool, i, node) { - int ref = (int) (intptr_t) node->same_comdat_group; + int ref = (int) (intptr_t) node->symbol.same_comdat_group; /* We share declaration of builtins, so we may read same node twice. */ - if (node->aux) + if (node->symbol.aux) continue; - node->aux = (void *)1; + node->symbol.aux = (void *)1; /* Fixup same_comdat_group from reference to pointer. */ if (ref != LCC_NOT_FOUND) - node->same_comdat_group = VEC_index (varpool_node_ptr, varpool, ref); + node->symbol.same_comdat_group = (symtab_node)VEC_index (varpool_node_ptr, varpool, ref); else - node->same_comdat_group = NULL; + node->symbol.same_comdat_group = NULL; } FOR_EACH_VEC_ELT (varpool_node_ptr, varpool, i, node) - node->aux = NULL; + node->symbol.aux = NULL; return varpool; } @@ -1319,7 +1320,7 @@ input_refs (struct lto_input_block *ib, node = VEC_index (cgraph_node_ptr, nodes, idx); while (count) { - input_ref (ib, node, NULL, nodes, varpool); + input_ref (ib, (symtab_node) node, nodes, varpool); count--; } } @@ -1333,7 +1334,7 @@ input_refs (struct lto_input_block *ib, streamer_read_uhwi (ib)); while (count) { - input_ref (ib, NULL, node, nodes, varpool); + input_ref (ib, (symtab_node) node, nodes, varpool); count--; } } @@ -1417,16 +1418,16 @@ merge_profile_summaries (struct lto_file_decl_data **file_data_vec) /* Now compute count_materialization_scale of each node. During LTRANS we already have values of count_materialization_scale computed, so just update them. */ - for (node = cgraph_nodes; node; node = node->next) - if (node->local.lto_file_data - && node->local.lto_file_data->profile_info.runs) + FOR_EACH_FUNCTION (node) + if (node->symbol.lto_file_data + && node->symbol.lto_file_data->profile_info.runs) { int scale; scale = ((node->count_materialization_scale * max_runs - + node->local.lto_file_data->profile_info.runs / 2) - / node->local.lto_file_data->profile_info.runs); + + node->symbol.lto_file_data->profile_info.runs / 2) + / node->symbol.lto_file_data->profile_info.runs); node->count_materialization_scale = scale; if (scale < 0) fatal_error ("Profile information in %s corrupted", @@ -1453,6 +1454,8 @@ input_cgraph (void) unsigned int j = 0; struct cgraph_node *node; + cgraph_state = CGRAPH_STATE_IPA_SSA; + while ((file_data = file_data_vec[j++])) { const char *data; @@ -1496,15 +1499,15 @@ input_cgraph (void) /* Clear out the aux field that was used to store enough state to tell which nodes should be overwritten. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) { /* Some nodes may have been created by cgraph_node. This happens when the callgraph contains nested functions. If the node for the parent function was never emitted to the gimple file, cgraph_node will create a node for it when setting the context of the nested function. */ - if (node->local.lto_file_data) - node->aux = NULL; + if (node->symbol.lto_file_data) + node->symbol.aux = NULL; } } @@ -1564,7 +1567,7 @@ output_node_opt_summary (struct output_block *ob, int parm_num; tree parm; - for (parm_num = 0, parm = DECL_ARGUMENTS (node->decl); parm; + for (parm_num = 0, parm = DECL_ARGUMENTS (node->symbol.decl); parm; parm = DECL_CHAIN (parm), parm_num++) if (map->old_tree == parm) break; @@ -1666,7 +1669,7 @@ input_node_opt_summary (struct cgraph_node *node, struct ipa_replace_map *map = ggc_alloc_ipa_replace_map (); VEC_safe_push (ipa_replace_map_p, gc, node->clone.tree_map, map); - for (parm_num = 0, parm = DECL_ARGUMENTS (node->decl); parm_num; + for (parm_num = 0, parm = DECL_ARGUMENTS (node->symbol.decl); parm_num; parm = DECL_CHAIN (parm)) parm_num --; map->parm_num = streamer_read_uhwi (ib_main); diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index 44513f758ef..1f2bfb6adc8 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -1225,8 +1225,8 @@ lto_input_toplevel_asms (struct lto_file_decl_data *file_data, int order_base) { struct cgraph_asm_node *node = cgraph_add_asm_node (str); node->order = streamer_read_hwi (&ib) + order_base; - if (node->order >= cgraph_order) - cgraph_order = node->order + 1; + if (node->order >= symtab_order) + symtab_order = node->order + 1; } clear_line_info (data_in); diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index 054bb85be0b..89850f0c08a 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -784,7 +784,7 @@ output_function (struct cgraph_node *node) basic_block bb; struct output_block *ob; - function = node->decl; + function = node->symbol.decl; fn = DECL_STRUCT_FUNCTION (function); ob = create_output_block (LTO_section_function_body); @@ -904,11 +904,13 @@ output_alias_pair_p (alias_pair *p, symbol_alias_set_t *defined, { vnode = varpool_get_node (p->decl); return (vnode - && referenced_from_this_partition_p (&vnode->ref_list, set, vset)); + && referenced_from_this_partition_p (&vnode->symbol.ref_list, + set, vset)); } node = cgraph_get_node (p->decl); return (node - && (referenced_from_this_partition_p (&node->ref_list, set, vset) + && (referenced_from_this_partition_p (&node->symbol.ref_list, + set, vset) || reachable_from_this_partition_p (node, set))); } else @@ -1023,8 +1025,8 @@ lto_output_toplevel_asms (void) static void copy_function (struct cgraph_node *node) { - tree function = node->decl; - struct lto_file_decl_data *file_data = node->local.lto_file_data; + tree function = node->symbol.decl; + struct lto_file_decl_data *file_data = node->symbol.lto_file_data; struct lto_output_stream *output_stream = XCNEW (struct lto_output_stream); const char *data; size_t len; @@ -1051,7 +1053,7 @@ copy_function (struct cgraph_node *node) /* Copy decls. */ in_state = - lto_get_function_in_decl_state (node->local.lto_file_data, function); + lto_get_function_in_decl_state (node->symbol.lto_file_data, function); gcc_assert (in_state); for (i = 0; i < LTO_N_DECL_STREAMS; i++) @@ -1102,18 +1104,18 @@ lto_output (cgraph_node_set set, varpool_node_set vset) && !node->thunk.thunk_p) { #ifdef ENABLE_CHECKING - gcc_assert (!bitmap_bit_p (output, DECL_UID (node->decl))); - bitmap_set_bit (output, DECL_UID (node->decl)); + gcc_assert (!bitmap_bit_p (output, DECL_UID (node->symbol.decl))); + bitmap_set_bit (output, DECL_UID (node->symbol.decl)); #endif decl_state = lto_new_out_decl_state (); lto_push_out_decl_state (decl_state); - if (gimple_has_body_p (node->decl)) + if (gimple_has_body_p (node->symbol.decl)) output_function (node); else copy_function (node); gcc_assert (lto_get_out_decl_state () == decl_state); lto_pop_out_decl_state (); - lto_record_function_out_decl_state (node->decl, decl_state); + lto_record_function_out_decl_state (node->symbol.decl, decl_state); } } @@ -1417,64 +1419,64 @@ produce_symtab (struct output_block *ob, for (i = 0; i < lto_cgraph_encoder_size (encoder); i++) { node = lto_cgraph_encoder_deref (encoder, i); - if (DECL_EXTERNAL (node->decl)) + if (DECL_EXTERNAL (node->symbol.decl)) continue; - if (DECL_COMDAT (node->decl) + if (DECL_COMDAT (node->symbol.decl) && cgraph_comdat_can_be_unshared_p (node)) continue; if ((node->alias && !node->thunk.alias) || node->global.inlined_to) continue; - write_symbol (cache, &stream, node->decl, seen, false); + write_symbol (cache, &stream, node->symbol.decl, seen, false); } for (i = 0; i < lto_cgraph_encoder_size (encoder); i++) { node = lto_cgraph_encoder_deref (encoder, i); - if (!DECL_EXTERNAL (node->decl)) + if (!DECL_EXTERNAL (node->symbol.decl)) continue; /* We keep around unused extern inlines in order to be able to inline them indirectly or via vtables. Do not output them to symbol table: they end up being undefined and just consume space. */ - if (!node->address_taken && !node->callers) + if (!node->symbol.address_taken && !node->callers) continue; - if (DECL_COMDAT (node->decl) + if (DECL_COMDAT (node->symbol.decl) && cgraph_comdat_can_be_unshared_p (node)) continue; if ((node->alias && !node->thunk.alias) || node->global.inlined_to) continue; - write_symbol (cache, &stream, node->decl, seen, false); + write_symbol (cache, &stream, node->symbol.decl, seen, false); } /* Write all variables. */ for (i = 0; i < lto_varpool_encoder_size (varpool_encoder); i++) { vnode = lto_varpool_encoder_deref (varpool_encoder, i); - if (DECL_EXTERNAL (vnode->decl)) + if (DECL_EXTERNAL (vnode->symbol.decl)) continue; /* COMDAT virtual tables can be unshared. Do not declare them in the LTO symbol table to prevent linker from forcing them into the output. */ - if (DECL_COMDAT (vnode->decl) - && !vnode->force_output + if (DECL_COMDAT (vnode->symbol.decl) + && !vnode->symbol.force_output && vnode->finalized - && DECL_VIRTUAL_P (vnode->decl)) + && DECL_VIRTUAL_P (vnode->symbol.decl)) continue; if (vnode->alias && !vnode->alias_of) continue; - write_symbol (cache, &stream, vnode->decl, seen, false); + write_symbol (cache, &stream, vnode->symbol.decl, seen, false); } for (i = 0; i < lto_varpool_encoder_size (varpool_encoder); i++) { vnode = lto_varpool_encoder_deref (varpool_encoder, i); - if (!DECL_EXTERNAL (vnode->decl)) + if (!DECL_EXTERNAL (vnode->symbol.decl)) continue; - if (DECL_COMDAT (vnode->decl) - && !vnode->force_output + if (DECL_COMDAT (vnode->symbol.decl) + && !vnode->symbol.force_output && vnode->finalized - && DECL_VIRTUAL_P (vnode->decl)) + && DECL_VIRTUAL_P (vnode->symbol.decl)) continue; if (vnode->alias && !vnode->alias_of) continue; - write_symbol (cache, &stream, vnode->decl, seen, false); + write_symbol (cache, &stream, vnode->symbol.decl, seen, false); } /* Write all aliases. */ diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c index 68c6231760e..f1424447d0f 100644 --- a/gcc/lto-symtab.c +++ b/gcc/lto-symtab.c @@ -219,15 +219,15 @@ lto_cgraph_replace_node (struct cgraph_node *node, cgraph_node_name (prevailing_node), prevailing_node->uid, IDENTIFIER_POINTER ((*targetm.asm_out.mangle_assembler_name) - (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))))); + (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->symbol.decl))))); } /* Merge node flags. */ - if (node->needed) - cgraph_mark_needed_node (prevailing_node); + if (node->symbol.force_output) + cgraph_mark_force_output_node (prevailing_node); if (node->reachable) cgraph_mark_reachable_node (prevailing_node); - if (node->address_taken) + if (node->symbol.address_taken) { gcc_assert (!prevailing_node->global.inlined_to); cgraph_mark_address_taken_node (prevailing_node); @@ -235,8 +235,8 @@ lto_cgraph_replace_node (struct cgraph_node *node, /* Redirect all incoming edges. */ compatible_p - = types_compatible_p (TREE_TYPE (TREE_TYPE (prevailing_node->decl)), - TREE_TYPE (TREE_TYPE (node->decl))); + = types_compatible_p (TREE_TYPE (TREE_TYPE (prevailing_node->symbol.decl)), + TREE_TYPE (TREE_TYPE (node->symbol.decl))); for (e = node->callers; e; e = next) { next = e->next_caller; @@ -249,7 +249,7 @@ lto_cgraph_replace_node (struct cgraph_node *node, e->call_stmt_cannot_inline_p = 1; } /* Redirect incomming references. */ - ipa_clone_refering (prevailing_node, NULL, &node->ref_list); + ipa_clone_referring ((symtab_node)prevailing_node, &node->symbol.ref_list); /* Finally remove the replaced node. */ cgraph_remove_node (node); @@ -262,20 +262,14 @@ static void lto_varpool_replace_node (struct varpool_node *vnode, struct varpool_node *prevailing_node) { - /* Merge node flags. */ - if (vnode->needed) - { - gcc_assert (!vnode->analyzed || prevailing_node->analyzed); - varpool_mark_needed_node (prevailing_node); - } gcc_assert (!vnode->finalized || prevailing_node->finalized); gcc_assert (!vnode->analyzed || prevailing_node->analyzed); - ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list); + ipa_clone_referring ((symtab_node)prevailing_node, &vnode->symbol.ref_list); /* Be sure we can garbage collect the initializer. */ - if (DECL_INITIAL (vnode->decl)) - DECL_INITIAL (vnode->decl) = error_mark_node; + if (DECL_INITIAL (vnode->symbol.decl)) + DECL_INITIAL (vnode->symbol.decl) = error_mark_node; /* Finally remove the replaced node. */ varpool_remove_node (vnode); } @@ -693,9 +687,9 @@ lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED) First one would disable some whole program optimizations, while ther second would imply to many whole program assumptions. */ if (prevailing->node && !flag_ltrans && !prevailing->guessed) - prevailing->node->resolution = prevailing->resolution; + prevailing->node->symbol.resolution = prevailing->resolution; else if (prevailing->vnode && !flag_ltrans && !prevailing->guessed) - prevailing->vnode->resolution = prevailing->resolution; + prevailing->vnode->symbol.resolution = prevailing->resolution; return 1; } @@ -761,11 +755,11 @@ lto_symtab_merge_cgraph_nodes (void) lto_symtab_maybe_init_hash_table (); htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL); - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) if ((node->thunk.thunk_p || node->alias) && node->thunk.alias) node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias); - for (vnode = varpool_nodes; vnode; vnode = vnode->next) + FOR_EACH_VARIABLE (vnode) if (vnode->alias_of) vnode->alias_of = lto_symtab_prevailing_decl (vnode->alias_of); } diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index ef3bbfb6466..6b86475b27f 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,42 @@ +2012-04-20 Jan Hubicka <jh@suse.cz> + + * lto-partition.c (partition_cgraph_node_p): Use force_output. + +2012-04-18 Jan Hubicka <jh@suse.cz> + + * lto-partition.c (add_references_to_partition, lto_balanced_map): + Update for new ipa-ref API. + +2012-04-16 Jan Hubicka <jh@suse.cz> + + * lto.c (read_cgraph_and_symbols): Use FOR_EACH + walkers to walk cgraph and varpool. + (materialize_cgraph): Likewise. + * lto-partition.c (lto_1_to_1_map): Likewise. + (lto_balanced_map): Likewise. + (lto_promote_cross_file_statics): Likewise. + +2012-04-14 Jan Hubicka <jh@suse.cz> + + * lto.c: Update field referenced for new cgraph/varpool layout. + * lto-partition.c: Likewise. + +2012-04-11 Jan Hubicka <jh@suse.cz> + + * lto.c: Update copyright; remove params.h, ipa-inline.h + and ipa-utils.h inlines; inline lto-partition.h + (ltrans_partition_def, ltrans_partition, add_cgraph_node_to_partition, + add_varpool_node_to_partition, new_partition, free_ltrans_partitions, + add_references_to_partition, add_cgraph_node_to_partition_1, + add_cgraph_node_to_partition, add_varpool_node_to_partition, + undo_partition, partition_cgraph_node_p, partition_varpool_node_p, + lto_1_to_1_map, node_cmp, varpool_node_cmp, lto_balanced_map, + promote_var, promote_fn, lto_promote_cross_file_statics): move to... + * lto-partition.c: ... here; new file. + * lto-partition.h: New file. + * Make-lang.in (lto.o): Update dependencies. + (lto-partition.o): New. + 2012-04-05 Richard Guenther <rguenther@suse.de> * lto-lang.c (LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION): Remove diff --git a/gcc/lto/Make-lang.in b/gcc/lto/Make-lang.in index c48c8d2ebce..b02310992c2 100644 --- a/gcc/lto/Make-lang.in +++ b/gcc/lto/Make-lang.in @@ -23,7 +23,7 @@ # The name of the LTO compiler. LTO_EXE = lto1$(exeext) # The LTO-specific object files inclued in $(LTO_EXE). -LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-object.o attribs.o +LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-object.o attribs.o lto/lto-partition.o LTO_H = lto/lto.h $(HASHTAB_H) LINKER_PLUGIN_API_H = $(srcdir)/../include/plugin-api.h LTO_TREE_H = lto/lto-tree.h $(LINKER_PLUGIN_API_H) @@ -85,8 +85,13 @@ lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \ $(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_H) \ langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \ $(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \ - $(LTO_TAGS_H) $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h $(PARAMS_H) \ - ipa-inline.h $(IPA_UTILS_H) $(TREE_STREAMER_H) + $(LTO_TAGS_H) $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h \ + $(TREE_STREAMER_H) lto/lto-partition.h +lto/lto-partition.o: lto/lto-partition.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + toplev.h $(TREE_H) $(TM_H) \ + $(CGRAPH_H) $(TIMEVAR_H) \ + $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h $(PARAMS_H) \ + ipa-inline.h $(IPA_UTILS_H) lto/lto-partition.h lto/lto-object.o: lto/lto-object.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(DIAGNOSTIC_CORE_H) $(LTO_H) $(TM_H) $(LTO_STREAMER_H) \ ../include/simple-object.h diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c new file mode 100644 index 00000000000..e2aa595b502 --- /dev/null +++ b/gcc/lto/lto-partition.c @@ -0,0 +1,917 @@ +/* LTO partitioning logic routines. + Copyright 2009, 2010, 2011, 2012 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/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "toplev.h" +#include "tree.h" +#include "tm.h" +#include "cgraph.h" +#include "lto-streamer.h" +#include "timevar.h" +#include "params.h" +#include "ipa-inline.h" +#include "ipa-utils.h" +#include "lto-partition.h" + +VEC(ltrans_partition, heap) *ltrans_partitions; + +static void add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node); +static void add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode); + +/* Create new partition with name NAME. */ +static ltrans_partition +new_partition (const char *name) +{ + ltrans_partition part = XCNEW (struct ltrans_partition_def); + part->cgraph_set = cgraph_node_set_new (); + part->varpool_set = varpool_node_set_new (); + part->name = name; + part->insns = 0; + VEC_safe_push (ltrans_partition, heap, ltrans_partitions, part); + return part; +} + +/* Free memory used by ltrans datastructures. */ +void +free_ltrans_partitions (void) +{ + unsigned int idx; + ltrans_partition part; + for (idx = 0; VEC_iterate (ltrans_partition, ltrans_partitions, idx, part); idx++) + { + free_cgraph_node_set (part->cgraph_set); + free (part); + } + VEC_free (ltrans_partition, heap, ltrans_partitions); +} + +/* See all references that go to comdat objects and bring them into partition too. + Also see all aliases of the newly added entry and bring them, too. */ +static void +add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs) +{ + int i; + struct ipa_ref *ref; + for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++) + { + if (symtab_function_p (ref->referred) + && (DECL_COMDAT (cgraph_function_node (ipa_ref_node (ref), + NULL)->symbol.decl) + || (ref->use == IPA_REF_ALIAS + && lookup_attribute + ("weakref", DECL_ATTRIBUTES (ipa_ref_node (ref)->symbol.decl)))) + && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set)) + add_cgraph_node_to_partition (part, ipa_ref_node (ref)); + else + if (symtab_variable_p (ref->referred) + && (DECL_COMDAT (ipa_ref_varpool_node (ref)->symbol.decl) + || (ref->use == IPA_REF_ALIAS + && lookup_attribute + ("weakref", + DECL_ATTRIBUTES (ipa_ref_varpool_node (ref)->symbol.decl)))) + && !varpool_node_in_set_p (ipa_ref_varpool_node (ref), + part->varpool_set)) + add_varpool_node_to_partition (part, ipa_ref_varpool_node (ref)); + } + for (i = 0; ipa_ref_list_referring_iterate (refs, i, ref); i++) + { + if (symtab_function_p (ref->referring) + && ref->use == IPA_REF_ALIAS + && !cgraph_node_in_set_p (ipa_ref_referring_node (ref), + part->cgraph_set) + && !lookup_attribute ("weakref", + DECL_ATTRIBUTES + (ipa_ref_referring_node (ref)->symbol.decl))) + add_cgraph_node_to_partition (part, ipa_ref_referring_node (ref)); + else + if (symtab_variable_p (ref->referring) + && ref->use == IPA_REF_ALIAS + && !varpool_node_in_set_p (ipa_ref_referring_varpool_node (ref), + part->varpool_set) + && !lookup_attribute ("weakref", + DECL_ATTRIBUTES + (ipa_ref_referring_varpool_node (ref)->symbol.decl))) + add_varpool_node_to_partition (part, + ipa_ref_referring_varpool_node (ref)); + } +} + +/* Worker for add_cgraph_node_to_partition. */ + +static bool +add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data) +{ + ltrans_partition part = (ltrans_partition) data; + + /* non-COMDAT aliases of COMDAT functions needs to be output just once. */ + if (!DECL_COMDAT (node->symbol.decl) + && !node->global.inlined_to + && node->symbol.aux) + { + gcc_assert (node->thunk.thunk_p || node->alias); + return false; + } + + if (node->symbol.aux) + { + node->symbol.in_other_partition = 1; + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n", + cgraph_node_name (node), node->uid); + } + node->symbol.aux = (void *)((size_t)node->symbol.aux + 1); + cgraph_node_set_add (part->cgraph_set, node); + return false; +} + +/* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */ + +static void +add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node) +{ + struct cgraph_edge *e; + cgraph_node_set_iterator csi; + struct cgraph_node *n; + + /* If NODE is already there, we have nothing to do. */ + csi = cgraph_node_set_find (part->cgraph_set, node); + if (!csi_end_p (csi)) + return; + + cgraph_for_node_thunks_and_aliases (node, add_cgraph_node_to_partition_1, part, true); + + part->insns += inline_summary (node)->self_size; + + + cgraph_node_set_add (part->cgraph_set, node); + + for (e = node->callees; e; e = e->next_callee) + if ((!e->inline_failed + || DECL_COMDAT (cgraph_function_node (e->callee, NULL)->symbol.decl)) + && !cgraph_node_in_set_p (e->callee, part->cgraph_set)) + add_cgraph_node_to_partition (part, e->callee); + + /* The only way to assemble non-weakref alias is to add the aliased object into + the unit. */ + add_references_to_partition (part, &node->symbol.ref_list); + n = cgraph_function_node (node, NULL); + if (n != node + && !lookup_attribute ("weakref", + DECL_ATTRIBUTES (node->symbol.decl))) + add_cgraph_node_to_partition (part, n); + + if (node->symbol.same_comdat_group) + for (n = cgraph (node->symbol.same_comdat_group); + n != node; n = cgraph (n->symbol.same_comdat_group)) + add_cgraph_node_to_partition (part, n); +} + +/* Add VNODE to partition as well as comdat references partition PART. */ + +static void +add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode) +{ + varpool_node_set_iterator vsi; + struct varpool_node *v; + + /* If NODE is already there, we have nothing to do. */ + vsi = varpool_node_set_find (part->varpool_set, vnode); + if (!vsi_end_p (vsi)) + return; + + varpool_node_set_add (part->varpool_set, vnode); + + if (vnode->symbol.aux) + { + vnode->symbol.in_other_partition = 1; + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Varpool node %s now used in multiple partitions\n", + varpool_node_name (vnode)); + } + vnode->symbol.aux = (void *)((size_t)vnode->symbol.aux + 1); + + /* The only way to assemble non-weakref alias is to add the aliased object into + the unit. */ + v = varpool_variable_node (vnode, NULL); + if (v != vnode + && !lookup_attribute ("weakref", + DECL_ATTRIBUTES (vnode->symbol.decl))) + add_varpool_node_to_partition (part, v); + + add_references_to_partition (part, &vnode->symbol.ref_list); + + if (vnode->symbol.same_comdat_group + && !varpool_node_in_set_p (varpool (vnode->symbol.same_comdat_group), + part->varpool_set)) + add_varpool_node_to_partition (part, varpool (vnode->symbol.same_comdat_group)); +} + +/* Undo all additions until number of cgraph nodes in PARITION is N_CGRAPH_NODES + and number of varpool nodes is N_VARPOOL_NODES. */ + +static void +undo_partition (ltrans_partition partition, unsigned int n_cgraph_nodes, + unsigned int n_varpool_nodes) +{ + while (VEC_length (cgraph_node_ptr, partition->cgraph_set->nodes) > + n_cgraph_nodes) + { + struct cgraph_node *node = VEC_index (cgraph_node_ptr, + partition->cgraph_set->nodes, + n_cgraph_nodes); + partition->insns -= inline_summary (node)->self_size; + cgraph_node_set_remove (partition->cgraph_set, node); + node->symbol.aux = (void *)((size_t)node->symbol.aux - 1); + } + while (VEC_length (varpool_node_ptr, partition->varpool_set->nodes) > + n_varpool_nodes) + { + struct varpool_node *node = VEC_index (varpool_node_ptr, + partition->varpool_set->nodes, + n_varpool_nodes); + varpool_node_set_remove (partition->varpool_set, node); + node->symbol.aux = (void *)((size_t)node->symbol.aux - 1); + } +} + +/* Return true if NODE should be partitioned. + This means that partitioning algorithm should put NODE into one of partitions. + This apply to most functions with bodies. Functions that are not partitions + are put into every unit needing them. This is the case of i.e. COMDATs. */ + +static bool +partition_cgraph_node_p (struct cgraph_node *node) +{ + /* We will get proper partition based on function they are inlined to. */ + if (node->global.inlined_to) + return false; + /* Nodes without a body do not need partitioning. */ + if (!node->analyzed) + return false; + /* Extern inlines and comdat are always only in partitions they are needed. */ + if (DECL_EXTERNAL (node->symbol.decl) + || (DECL_COMDAT (node->symbol.decl) + && !node->symbol.force_output + && !cgraph_used_from_object_file_p (node))) + return false; + if (lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl))) + return false; + return true; +} + +/* Return true if VNODE should be partitioned. + This means that partitioning algorithm should put VNODE into one of partitions. */ + +static bool +partition_varpool_node_p (struct varpool_node *vnode) +{ + if (vnode->alias || !vnode->analyzed) + return false; + /* Constant pool and comdat are always only in partitions they are needed. */ + if (DECL_IN_CONSTANT_POOL (vnode->symbol.decl) + || (DECL_COMDAT (vnode->symbol.decl) + && !vnode->symbol.force_output + && !varpool_used_from_object_file_p (vnode))) + return false; + if (lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl))) + return false; + return true; +} + +/* Group cgrah nodes by input files. This is used mainly for testing + right now. */ + +void +lto_1_to_1_map (void) +{ + struct cgraph_node *node; + struct varpool_node *vnode; + struct lto_file_decl_data *file_data; + struct pointer_map_t *pmap; + ltrans_partition partition; + void **slot; + int npartitions = 0; + + timevar_push (TV_WHOPR_WPA); + + pmap = pointer_map_create (); + + FOR_EACH_DEFINED_FUNCTION (node) + { + if (!partition_cgraph_node_p (node) + || node->symbol.aux) + continue; + + file_data = node->symbol.lto_file_data; + + if (file_data) + { + slot = pointer_map_contains (pmap, file_data); + if (slot) + partition = (ltrans_partition) *slot; + else + { + partition = new_partition (file_data->file_name); + slot = pointer_map_insert (pmap, file_data); + *slot = partition; + npartitions++; + } + } + else if (!file_data + && VEC_length (ltrans_partition, ltrans_partitions)) + partition = VEC_index (ltrans_partition, ltrans_partitions, 0); + else + { + partition = new_partition (""); + slot = pointer_map_insert (pmap, NULL); + *slot = partition; + npartitions++; + } + + add_cgraph_node_to_partition (partition, node); + } + + FOR_EACH_VARIABLE (vnode) + { + if (!partition_varpool_node_p (vnode) + || vnode->symbol.aux) + continue; + file_data = vnode->symbol.lto_file_data; + slot = pointer_map_contains (pmap, file_data); + if (slot) + partition = (ltrans_partition) *slot; + else + { + partition = new_partition (file_data->file_name); + slot = pointer_map_insert (pmap, file_data); + *slot = partition; + npartitions++; + } + + add_varpool_node_to_partition (partition, vnode); + } + FOR_EACH_FUNCTION (node) + node->symbol.aux = NULL; + FOR_EACH_VARIABLE (vnode) + vnode->symbol.aux = NULL; + + /* If the cgraph is empty, create one cgraph node set so that there is still + an output file for any variables that need to be exported in a DSO. */ + if (!npartitions) + new_partition ("empty"); + + pointer_map_destroy (pmap); + + timevar_pop (TV_WHOPR_WPA); + + lto_stats.num_cgraph_partitions += VEC_length (ltrans_partition, + ltrans_partitions); +} + +/* Helper function for qsort; sort nodes by order. */ +static int +node_cmp (const void *pa, const void *pb) +{ + const struct cgraph_node *a = *(const struct cgraph_node * const *) pa; + const struct cgraph_node *b = *(const struct cgraph_node * const *) pb; + return b->symbol.order - a->symbol.order; +} + +/* Helper function for qsort; sort nodes by order. */ +static int +varpool_node_cmp (const void *pa, const void *pb) +{ + const struct varpool_node *a = *(const struct varpool_node * const *) pa; + const struct varpool_node *b = *(const struct varpool_node * const *) pb; + return b->symbol.order - a->symbol.order; +} + +/* Group cgraph nodes into equally-sized partitions. + + The partitioning algorithm is simple: nodes are taken in predefined order. + The order corresponds to the order we want functions to have in the final + output. In the future this will be given by function reordering pass, but + at the moment we use the topological order, which is a good approximation. + + The goal is to partition this linear order into intervals (partitions) so + that all the partitions have approximately the same size and the number of + callgraph or IPA reference edges crossing boundaries is minimal. + + This is a lot faster (O(n) in size of callgraph) than algorithms doing + priority-based graph clustering that are generally O(n^2) and, since + WHOPR is designed to make things go well across partitions, it leads + to good results. + + We compute the expected size of a partition as: + + max (total_size / lto_partitions, min_partition_size) + + We use dynamic expected size of partition so small programs are partitioned + into enough partitions to allow use of multiple CPUs, while large programs + are not partitioned too much. Creating too many partitions significantly + increases the streaming overhead. + + In the future, we would like to bound the maximal size of partitions so as + to prevent the LTRANS stage from consuming too much memory. At the moment, + however, the WPA stage is the most memory intensive for large benchmarks, + since too many types and declarations are read into memory. + + The function implements a simple greedy algorithm. Nodes are being added + to the current partition until after 3/4 of the expected partition size is + reached. Past this threshold, we keep track of boundary size (number of + edges going to other partitions) and continue adding functions until after + the current partition has grown to twice the expected partition size. Then + the process is undone to the point where the minimal ratio of boundary size + and in-partition calls was reached. */ + +void +lto_balanced_map (void) +{ + int n_nodes = 0; + int n_varpool_nodes = 0, varpool_pos = 0; + struct cgraph_node **postorder = + XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); + struct cgraph_node **order = XNEWVEC (struct cgraph_node *, cgraph_max_uid); + struct varpool_node **varpool_order = NULL; + int i, postorder_len; + struct cgraph_node *node; + int total_size = 0, best_total_size = 0; + int partition_size; + ltrans_partition partition; + unsigned int last_visited_cgraph_node = 0, last_visited_varpool_node = 0; + struct varpool_node *vnode; + int cost = 0, internal = 0; + int best_n_nodes = 0, best_n_varpool_nodes = 0, best_i = 0, best_cost = + INT_MAX, best_internal = 0; + int npartitions; + int current_order = -1; + + FOR_EACH_VARIABLE (vnode) + gcc_assert (!vnode->symbol.aux); + /* Until we have better ordering facility, use toplogical order. + Include only nodes we will partition and compute estimate of program + size. Note that since nodes that are not partitioned might be put into + multiple partitions, this is just an estimate of real size. This is why + we keep partition_size updated after every partition is finalized. */ + postorder_len = ipa_reverse_postorder (postorder); + + for (i = 0; i < postorder_len; i++) + { + node = postorder[i]; + if (partition_cgraph_node_p (node)) + { + order[n_nodes++] = node; + total_size += inline_summary (node)->size; + } + } + free (postorder); + + if (!flag_toplevel_reorder) + { + qsort (order, n_nodes, sizeof (struct cgraph_node *), node_cmp); + + FOR_EACH_VARIABLE (vnode) + if (partition_varpool_node_p (vnode)) + n_varpool_nodes++; + varpool_order = XNEWVEC (struct varpool_node *, n_varpool_nodes); + + n_varpool_nodes = 0; + FOR_EACH_VARIABLE (vnode) + if (partition_varpool_node_p (vnode)) + varpool_order[n_varpool_nodes++] = vnode; + qsort (varpool_order, n_varpool_nodes, sizeof (struct varpool_node *), + varpool_node_cmp); + } + + /* Compute partition size and create the first partition. */ + partition_size = total_size / PARAM_VALUE (PARAM_LTO_PARTITIONS); + if (partition_size < PARAM_VALUE (MIN_PARTITION_SIZE)) + partition_size = PARAM_VALUE (MIN_PARTITION_SIZE); + npartitions = 1; + partition = new_partition (""); + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Total unit size: %i, partition size: %i\n", + total_size, partition_size); + + for (i = 0; i < n_nodes; i++) + { + if (order[i]->symbol.aux) + continue; + + current_order = order[i]->symbol.order; + + if (!flag_toplevel_reorder) + while (varpool_pos < n_varpool_nodes + && varpool_order[varpool_pos]->symbol.order < current_order) + { + if (!varpool_order[varpool_pos]->symbol.aux) + add_varpool_node_to_partition (partition, varpool_order[varpool_pos]); + varpool_pos++; + } + + add_cgraph_node_to_partition (partition, order[i]); + total_size -= inline_summary (order[i])->size; + + + /* Once we added a new node to the partition, we also want to add + all referenced variables unless they was already added into some + earlier partition. + add_cgraph_node_to_partition adds possibly multiple nodes and + variables that are needed to satisfy needs of ORDER[i]. + We remember last visited cgraph and varpool node from last iteration + of outer loop that allows us to process every new addition. + + At the same time we compute size of the boundary into COST. Every + callgraph or IPA reference edge leaving the partition contributes into + COST. Every edge inside partition was earlier computed as one leaving + it and thus we need to subtract it from COST. */ + while (last_visited_cgraph_node < + VEC_length (cgraph_node_ptr, partition->cgraph_set->nodes) + || last_visited_varpool_node < VEC_length (varpool_node_ptr, + partition->varpool_set-> + nodes)) + { + struct ipa_ref_list *refs; + int j; + struct ipa_ref *ref; + bool cgraph_p = false; + + if (last_visited_cgraph_node < + VEC_length (cgraph_node_ptr, partition->cgraph_set->nodes)) + { + struct cgraph_edge *edge; + + cgraph_p = true; + node = VEC_index (cgraph_node_ptr, partition->cgraph_set->nodes, + last_visited_cgraph_node); + refs = &node->symbol.ref_list; + + last_visited_cgraph_node++; + + gcc_assert (node->analyzed); + + /* Compute boundary cost of callgraph edges. */ + for (edge = node->callees; edge; edge = edge->next_callee) + if (edge->callee->analyzed) + { + int edge_cost = edge->frequency; + cgraph_node_set_iterator csi; + + if (!edge_cost) + edge_cost = 1; + gcc_assert (edge_cost > 0); + csi = cgraph_node_set_find (partition->cgraph_set, edge->callee); + if (!csi_end_p (csi) + && csi.index < last_visited_cgraph_node - 1) + cost -= edge_cost, internal+= edge_cost; + else + cost += edge_cost; + } + for (edge = node->callers; edge; edge = edge->next_caller) + { + int edge_cost = edge->frequency; + cgraph_node_set_iterator csi; + + gcc_assert (edge->caller->analyzed); + if (!edge_cost) + edge_cost = 1; + gcc_assert (edge_cost > 0); + csi = cgraph_node_set_find (partition->cgraph_set, edge->caller); + if (!csi_end_p (csi) + && csi.index < last_visited_cgraph_node) + cost -= edge_cost; + else + cost += edge_cost; + } + } + else + { + refs = + &VEC_index (varpool_node_ptr, partition->varpool_set->nodes, + last_visited_varpool_node)->symbol.ref_list; + last_visited_varpool_node++; + } + + /* Compute boundary cost of IPA REF edges and at the same time look into + variables referenced from current partition and try to add them. */ + for (j = 0; ipa_ref_list_reference_iterate (refs, j, ref); j++) + if (symtab_variable_p (ref->referred)) + { + varpool_node_set_iterator vsi; + + vnode = ipa_ref_varpool_node (ref); + if (!vnode->finalized) + continue; + if (!vnode->symbol.aux && flag_toplevel_reorder + && partition_varpool_node_p (vnode)) + add_varpool_node_to_partition (partition, vnode); + vsi = varpool_node_set_find (partition->varpool_set, vnode); + if (!vsi_end_p (vsi) + && vsi.index < last_visited_varpool_node - !cgraph_p) + cost--, internal++; + else + cost++; + } + else + { + cgraph_node_set_iterator csi; + + node = ipa_ref_node (ref); + if (!node->analyzed) + continue; + csi = cgraph_node_set_find (partition->cgraph_set, node); + if (!csi_end_p (csi) + && csi.index < last_visited_cgraph_node - cgraph_p) + cost--, internal++; + else + cost++; + } + for (j = 0; ipa_ref_list_referring_iterate (refs, j, ref); j++) + if (symtab_variable_p (ref->referring)) + { + varpool_node_set_iterator vsi; + + vnode = ipa_ref_referring_varpool_node (ref); + gcc_assert (vnode->finalized); + if (!vnode->symbol.aux && flag_toplevel_reorder + && partition_varpool_node_p (vnode)) + add_varpool_node_to_partition (partition, vnode); + vsi = varpool_node_set_find (partition->varpool_set, vnode); + if (!vsi_end_p (vsi) + && vsi.index < last_visited_varpool_node) + cost--; + else + cost++; + } + else + { + cgraph_node_set_iterator csi; + + node = ipa_ref_referring_node (ref); + gcc_assert (node->analyzed); + csi = cgraph_node_set_find (partition->cgraph_set, node); + if (!csi_end_p (csi) + && csi.index < last_visited_cgraph_node) + cost--; + else + cost++; + } + } + + /* If the partition is large enough, start looking for smallest boundary cost. */ + if (partition->insns < partition_size * 3 / 4 + || best_cost == INT_MAX + || ((!cost + || (best_internal * (HOST_WIDE_INT) cost + > (internal * (HOST_WIDE_INT)best_cost))) + && partition->insns < partition_size * 5 / 4)) + { + best_cost = cost; + best_internal = internal; + best_i = i; + best_n_nodes = VEC_length (cgraph_node_ptr, + partition->cgraph_set->nodes); + best_n_varpool_nodes = VEC_length (varpool_node_ptr, + partition->varpool_set->nodes); + best_total_size = total_size; + } + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Step %i: added %s/%i, size %i, cost %i/%i best %i/%i, step %i\n", i, + cgraph_node_name (order[i]), order[i]->uid, partition->insns, cost, internal, + best_cost, best_internal, best_i); + /* Partition is too large, unwind into step when best cost was reached and + start new partition. */ + if (partition->insns > 2 * partition_size) + { + if (best_i != i) + { + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Unwinding %i insertions to step %i\n", + i - best_i, best_i); + undo_partition (partition, best_n_nodes, best_n_varpool_nodes); + } + i = best_i; + /* When we are finished, avoid creating empty partition. */ + while (i < n_nodes - 1 && order[i + 1]->symbol.aux) + i++; + if (i == n_nodes - 1) + break; + partition = new_partition (""); + last_visited_cgraph_node = 0; + last_visited_varpool_node = 0; + total_size = best_total_size; + cost = 0; + + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "New partition\n"); + best_n_nodes = 0; + best_n_varpool_nodes = 0; + best_cost = INT_MAX; + + /* Since the size of partitions is just approximate, update the size after + we finished current one. */ + if (npartitions < PARAM_VALUE (PARAM_LTO_PARTITIONS)) + partition_size = total_size + / (PARAM_VALUE (PARAM_LTO_PARTITIONS) - npartitions); + else + partition_size = INT_MAX; + + if (partition_size < PARAM_VALUE (MIN_PARTITION_SIZE)) + partition_size = PARAM_VALUE (MIN_PARTITION_SIZE); + npartitions ++; + } + } + + /* Varables that are not reachable from the code go into last partition. */ + if (flag_toplevel_reorder) + { + FOR_EACH_VARIABLE (vnode) + if (partition_varpool_node_p (vnode) && !vnode->symbol.aux) + add_varpool_node_to_partition (partition, vnode); + } + else + { + while (varpool_pos < n_varpool_nodes) + { + if (!varpool_order[varpool_pos]->symbol.aux) + add_varpool_node_to_partition (partition, varpool_order[varpool_pos]); + varpool_pos++; + } + free (varpool_order); + } + free (order); +} + +/* Promote variable VNODE to be static. */ + +static bool +promote_var (struct varpool_node *vnode) +{ + if (TREE_PUBLIC (vnode->symbol.decl) || DECL_EXTERNAL (vnode->symbol.decl)) + return false; + gcc_assert (flag_wpa); + TREE_PUBLIC (vnode->symbol.decl) = 1; + DECL_VISIBILITY (vnode->symbol.decl) = VISIBILITY_HIDDEN; + DECL_VISIBILITY_SPECIFIED (vnode->symbol.decl) = true; + if (cgraph_dump_file) + fprintf (cgraph_dump_file, + "Promoting var as hidden: %s\n", varpool_node_name (vnode)); + return true; +} + +/* Promote function NODE to be static. */ + +static bool +promote_fn (struct cgraph_node *node) +{ + gcc_assert (flag_wpa); + if (TREE_PUBLIC (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl)) + return false; + TREE_PUBLIC (node->symbol.decl) = 1; + DECL_VISIBILITY (node->symbol.decl) = VISIBILITY_HIDDEN; + DECL_VISIBILITY_SPECIFIED (node->symbol.decl) = true; + if (cgraph_dump_file) + fprintf (cgraph_dump_file, + "Promoting function as hidden: %s/%i\n", + cgraph_node_name (node), node->uid); + return true; +} + +/* Find out all static decls that need to be promoted to global because + of cross file sharing. This function must be run in the WPA mode after + all inlinees are added. */ + +void +lto_promote_cross_file_statics (void) +{ + struct varpool_node *vnode; + unsigned i, n_sets; + cgraph_node_set set; + varpool_node_set vset; + cgraph_node_set_iterator csi; + varpool_node_set_iterator vsi; + VEC(varpool_node_ptr, heap) *promoted_initializers = NULL; + struct pointer_set_t *inserted = pointer_set_create (); + + gcc_assert (flag_wpa); + + n_sets = VEC_length (ltrans_partition, ltrans_partitions); + for (i = 0; i < n_sets; i++) + { + ltrans_partition part + = VEC_index (ltrans_partition, ltrans_partitions, i); + set = part->cgraph_set; + vset = part->varpool_set; + + /* If node called or referred to from other partition, it needs to be + globalized. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + struct cgraph_node *node = csi_node (csi); + if (node->symbol.externally_visible) + continue; + if (node->global.inlined_to) + continue; + if ((!DECL_EXTERNAL (node->symbol.decl) + && !DECL_COMDAT (node->symbol.decl)) + && (referenced_from_other_partition_p (&node->symbol.ref_list, set, vset) + || reachable_from_other_partition_p (node, set))) + promote_fn (node); + } + for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi)) + { + vnode = vsi_node (vsi); + /* Constant pool references use internal labels and thus can not + be made global. It is sensible to keep those ltrans local to + allow better optimization. */ + if (!DECL_IN_CONSTANT_POOL (vnode->symbol.decl) + && !DECL_COMDAT (vnode->symbol.decl) + && !vnode->symbol.externally_visible && vnode->analyzed + && referenced_from_other_partition_p (&vnode->symbol.ref_list, + set, vset)) + promote_var (vnode); + } + + /* We export the initializer of a read-only var into each partition + referencing the var. Folding might take declarations from the + initializer and use them, so everything referenced from the + initializer can be accessed from this partition after folding. + + This means that we need to promote all variables and functions + referenced from all initializers of read-only vars referenced + from this partition that are not in this partition. This needs + to be done recursively. */ + FOR_EACH_VARIABLE (vnode) + if (const_value_known_p (vnode->symbol.decl) + && DECL_INITIAL (vnode->symbol.decl) + && !varpool_node_in_set_p (vnode, vset) + && referenced_from_this_partition_p (&vnode->symbol.ref_list, set, vset) + && !pointer_set_insert (inserted, vnode)) + VEC_safe_push (varpool_node_ptr, heap, promoted_initializers, vnode); + + while (!VEC_empty (varpool_node_ptr, promoted_initializers)) + { + int i; + struct ipa_ref *ref; + + vnode = VEC_pop (varpool_node_ptr, promoted_initializers); + for (i = 0; + ipa_ref_list_reference_iterate (&vnode->symbol.ref_list, i, ref); + i++) + { + if (symtab_function_p (ref->referred)) + { + struct cgraph_node *n = ipa_ref_node (ref); + gcc_assert (!n->global.inlined_to); + if (!n->symbol.externally_visible + && !cgraph_node_in_set_p (n, set)) + promote_fn (n); + } + else + { + struct varpool_node *v = ipa_ref_varpool_node (ref); + if (varpool_node_in_set_p (v, vset)) + continue; + + /* Constant pool references use internal labels and thus + cannot be made global. It is sensible to keep those + ltrans local to allow better optimization. */ + if (DECL_IN_CONSTANT_POOL (v->symbol.decl)) + { + if (!pointer_set_insert (inserted, vnode)) + VEC_safe_push (varpool_node_ptr, heap, + promoted_initializers, v); + } + else if (!v->symbol.externally_visible && v->analyzed) + { + if (promote_var (v) + && DECL_INITIAL (v->symbol.decl) + && const_value_known_p (v->symbol.decl) + && !pointer_set_insert (inserted, vnode)) + VEC_safe_push (varpool_node_ptr, heap, + promoted_initializers, v); + } + } + } + } + } + pointer_set_destroy (inserted); +} diff --git a/gcc/lto/lto-partition.h b/gcc/lto/lto-partition.h new file mode 100644 index 00000000000..2160274dda6 --- /dev/null +++ b/gcc/lto/lto-partition.h @@ -0,0 +1,40 @@ +/* LTO partitioning logic routines. + Copyright 2009, 2010, 2011, 2012 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/>. */ + + +/* Structure describing ltrans partitions. */ + +struct ltrans_partition_def +{ + cgraph_node_set cgraph_set; + varpool_node_set varpool_set; + const char * name; + int insns; +}; + +typedef struct ltrans_partition_def *ltrans_partition; +DEF_VEC_P(ltrans_partition); +DEF_VEC_ALLOC_P(ltrans_partition,heap); + +extern VEC(ltrans_partition, heap) *ltrans_partitions; + +void lto_1_to_1_map (void); +void lto_balanced_map (void); +void lto_promote_cross_file_statics (void); +void free_ltrans_partitions (void); diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 26b4065e0ab..fb374ff0c9f 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -1,5 +1,5 @@ /* Top-level LTO routines. - Copyright 2009, 2010, 2011 Free Software Foundation, Inc. + Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by CodeSourcery, Inc. This file is part of GCC. @@ -45,9 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "lto-streamer.h" #include "tree-streamer.h" #include "splay-tree.h" -#include "params.h" -#include "ipa-inline.h" -#include "ipa-utils.h" +#include "lto-partition.h" static GTY(()) tree first_personality_decl; @@ -210,7 +208,7 @@ lto_materialize_function (struct cgraph_node *node) const char *data, *name; size_t len; - decl = node->decl; + decl = node->symbol.decl; /* Read in functions with body (analyzed nodes) and also functions that are needed to produce virtual clones. */ if (cgraph_function_with_gimple_body_p (node) || has_analyzed_clone_p (node)) @@ -223,7 +221,7 @@ lto_materialize_function (struct cgraph_node *node) WPA mode, the body of the function is not needed. */ if (!flag_wpa) { - file_data = node->local.lto_file_data; + file_data = node->symbol.lto_file_data; name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); /* We may have renamed the declaration, e.g., a static function. */ @@ -1398,899 +1396,6 @@ free_section_data (struct lto_file_decl_data *file_data ATTRIBUTE_UNUSED, #endif } -/* Structure describing ltrans partitions. */ - -struct ltrans_partition_def -{ - cgraph_node_set cgraph_set; - varpool_node_set varpool_set; - const char * name; - int insns; -}; - -typedef struct ltrans_partition_def *ltrans_partition; -DEF_VEC_P(ltrans_partition); -DEF_VEC_ALLOC_P(ltrans_partition,heap); - -static VEC(ltrans_partition, heap) *ltrans_partitions; - -static void add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node); -static void add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode); - -/* Create new partition with name NAME. */ -static ltrans_partition -new_partition (const char *name) -{ - ltrans_partition part = XCNEW (struct ltrans_partition_def); - part->cgraph_set = cgraph_node_set_new (); - part->varpool_set = varpool_node_set_new (); - part->name = name; - part->insns = 0; - VEC_safe_push (ltrans_partition, heap, ltrans_partitions, part); - return part; -} - -/* Free memory used by ltrans datastructures. */ -static void -free_ltrans_partitions (void) -{ - unsigned int idx; - ltrans_partition part; - for (idx = 0; VEC_iterate (ltrans_partition, ltrans_partitions, idx, part); idx++) - { - free_cgraph_node_set (part->cgraph_set); - free (part); - } - VEC_free (ltrans_partition, heap, ltrans_partitions); -} - -/* See all references that go to comdat objects and bring them into partition too. - Also see all aliases of the newly added entry and bring them, too. */ -static void -add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs) -{ - int i; - struct ipa_ref *ref; - for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++) - { - if (ref->refered_type == IPA_REF_CGRAPH - && (DECL_COMDAT (cgraph_function_node (ipa_ref_node (ref), - NULL)->decl) - || (ref->use == IPA_REF_ALIAS - && lookup_attribute - ("weakref", DECL_ATTRIBUTES (ipa_ref_node (ref)->decl)))) - && !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set)) - add_cgraph_node_to_partition (part, ipa_ref_node (ref)); - else - if (ref->refered_type == IPA_REF_VARPOOL - && (DECL_COMDAT (ipa_ref_varpool_node (ref)->decl) - || (ref->use == IPA_REF_ALIAS - && lookup_attribute - ("weakref", - DECL_ATTRIBUTES (ipa_ref_varpool_node (ref)->decl)))) - && !varpool_node_in_set_p (ipa_ref_varpool_node (ref), - part->varpool_set)) - add_varpool_node_to_partition (part, ipa_ref_varpool_node (ref)); - } - for (i = 0; ipa_ref_list_refering_iterate (refs, i, ref); i++) - { - if (ref->refering_type == IPA_REF_CGRAPH - && ref->use == IPA_REF_ALIAS - && !cgraph_node_in_set_p (ipa_ref_refering_node (ref), - part->cgraph_set) - && !lookup_attribute ("weakref", - DECL_ATTRIBUTES - (ipa_ref_refering_node (ref)->decl))) - add_cgraph_node_to_partition (part, ipa_ref_refering_node (ref)); - else - if (ref->refering_type == IPA_REF_VARPOOL - && ref->use == IPA_REF_ALIAS - && !varpool_node_in_set_p (ipa_ref_refering_varpool_node (ref), - part->varpool_set) - && !lookup_attribute ("weakref", - DECL_ATTRIBUTES - (ipa_ref_refering_varpool_node (ref)->decl))) - add_varpool_node_to_partition (part, - ipa_ref_refering_varpool_node (ref)); - } -} - -/* Worker for add_cgraph_node_to_partition. */ - -static bool -add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data) -{ - ltrans_partition part = (ltrans_partition) data; - - /* non-COMDAT aliases of COMDAT functions needs to be output just once. */ - if (!DECL_COMDAT (node->decl) - && !node->global.inlined_to - && node->aux) - { - gcc_assert (node->thunk.thunk_p || node->alias); - return false; - } - - if (node->aux) - { - node->in_other_partition = 1; - if (cgraph_dump_file) - fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n", - cgraph_node_name (node), node->uid); - } - node->aux = (void *)((size_t)node->aux + 1); - cgraph_node_set_add (part->cgraph_set, node); - return false; -} - -/* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */ - -static void -add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node) -{ - struct cgraph_edge *e; - cgraph_node_set_iterator csi; - struct cgraph_node *n; - - /* If NODE is already there, we have nothing to do. */ - csi = cgraph_node_set_find (part->cgraph_set, node); - if (!csi_end_p (csi)) - return; - - cgraph_for_node_thunks_and_aliases (node, add_cgraph_node_to_partition_1, part, true); - - part->insns += inline_summary (node)->self_size; - - - cgraph_node_set_add (part->cgraph_set, node); - - for (e = node->callees; e; e = e->next_callee) - if ((!e->inline_failed - || DECL_COMDAT (cgraph_function_node (e->callee, NULL)->decl)) - && !cgraph_node_in_set_p (e->callee, part->cgraph_set)) - add_cgraph_node_to_partition (part, e->callee); - - /* The only way to assemble non-weakref alias is to add the aliased object into - the unit. */ - add_references_to_partition (part, &node->ref_list); - n = cgraph_function_node (node, NULL); - if (n != node - && !lookup_attribute ("weakref", - DECL_ATTRIBUTES (node->decl))) - add_cgraph_node_to_partition (part, n); - - if (node->same_comdat_group) - for (n = node->same_comdat_group; n != node; n = n->same_comdat_group) - add_cgraph_node_to_partition (part, n); -} - -/* Add VNODE to partition as well as comdat references partition PART. */ - -static void -add_varpool_node_to_partition (ltrans_partition part, struct varpool_node *vnode) -{ - varpool_node_set_iterator vsi; - struct varpool_node *v; - - /* If NODE is already there, we have nothing to do. */ - vsi = varpool_node_set_find (part->varpool_set, vnode); - if (!vsi_end_p (vsi)) - return; - - varpool_node_set_add (part->varpool_set, vnode); - - if (vnode->aux) - { - vnode->in_other_partition = 1; - if (cgraph_dump_file) - fprintf (cgraph_dump_file, "Varpool node %s now used in multiple partitions\n", - varpool_node_name (vnode)); - } - vnode->aux = (void *)((size_t)vnode->aux + 1); - - /* The only way to assemble non-weakref alias is to add the aliased object into - the unit. */ - v = varpool_variable_node (vnode, NULL); - if (v != vnode - && !lookup_attribute ("weakref", - DECL_ATTRIBUTES (vnode->decl))) - add_varpool_node_to_partition (part, v); - - add_references_to_partition (part, &vnode->ref_list); - - if (vnode->same_comdat_group - && !varpool_node_in_set_p (vnode->same_comdat_group, part->varpool_set)) - add_varpool_node_to_partition (part, vnode->same_comdat_group); -} - -/* Undo all additions until number of cgraph nodes in PARITION is N_CGRAPH_NODES - and number of varpool nodes is N_VARPOOL_NODES. */ - -static void -undo_partition (ltrans_partition partition, unsigned int n_cgraph_nodes, - unsigned int n_varpool_nodes) -{ - while (VEC_length (cgraph_node_ptr, partition->cgraph_set->nodes) > - n_cgraph_nodes) - { - struct cgraph_node *node = VEC_index (cgraph_node_ptr, - partition->cgraph_set->nodes, - n_cgraph_nodes); - partition->insns -= inline_summary (node)->self_size; - cgraph_node_set_remove (partition->cgraph_set, node); - node->aux = (void *)((size_t)node->aux - 1); - } - while (VEC_length (varpool_node_ptr, partition->varpool_set->nodes) > - n_varpool_nodes) - { - struct varpool_node *node = VEC_index (varpool_node_ptr, - partition->varpool_set->nodes, - n_varpool_nodes); - varpool_node_set_remove (partition->varpool_set, node); - node->aux = (void *)((size_t)node->aux - 1); - } -} - -/* Return true if NODE should be partitioned. - This means that partitioning algorithm should put NODE into one of partitions. - This apply to most functions with bodies. Functions that are not partitions - are put into every unit needing them. This is the case of i.e. COMDATs. */ - -static bool -partition_cgraph_node_p (struct cgraph_node *node) -{ - /* We will get proper partition based on function they are inlined to. */ - if (node->global.inlined_to) - return false; - /* Nodes without a body do not need partitioning. */ - if (!node->analyzed) - return false; - /* Extern inlines and comdat are always only in partitions they are needed. */ - if (DECL_EXTERNAL (node->decl) - || (DECL_COMDAT (node->decl) - && !cgraph_used_from_object_file_p (node))) - return false; - if (lookup_attribute ("weakref", DECL_ATTRIBUTES (node->decl))) - return false; - return true; -} - -/* Return true if VNODE should be partitioned. - This means that partitioning algorithm should put VNODE into one of partitions. */ - -static bool -partition_varpool_node_p (struct varpool_node *vnode) -{ - if (vnode->alias || !vnode->needed) - return false; - /* Constant pool and comdat are always only in partitions they are needed. */ - if (DECL_IN_CONSTANT_POOL (vnode->decl) - || (DECL_COMDAT (vnode->decl) - && !vnode->force_output - && !varpool_used_from_object_file_p (vnode))) - return false; - if (lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->decl))) - return false; - return true; -} - -/* Group cgrah nodes by input files. This is used mainly for testing - right now. */ - -static void -lto_1_to_1_map (void) -{ - struct cgraph_node *node; - struct varpool_node *vnode; - struct lto_file_decl_data *file_data; - struct pointer_map_t *pmap; - ltrans_partition partition; - void **slot; - int npartitions = 0; - - timevar_push (TV_WHOPR_WPA); - - pmap = pointer_map_create (); - - for (node = cgraph_nodes; node; node = node->next) - { - if (!partition_cgraph_node_p (node) - || node->aux) - continue; - - file_data = node->local.lto_file_data; - - if (file_data) - { - slot = pointer_map_contains (pmap, file_data); - if (slot) - partition = (ltrans_partition) *slot; - else - { - partition = new_partition (file_data->file_name); - slot = pointer_map_insert (pmap, file_data); - *slot = partition; - npartitions++; - } - } - else if (!file_data - && VEC_length (ltrans_partition, ltrans_partitions)) - partition = VEC_index (ltrans_partition, ltrans_partitions, 0); - else - { - partition = new_partition (""); - slot = pointer_map_insert (pmap, NULL); - *slot = partition; - npartitions++; - } - - add_cgraph_node_to_partition (partition, node); - } - - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - { - if (!partition_varpool_node_p (vnode) - || vnode->aux) - continue; - file_data = vnode->lto_file_data; - slot = pointer_map_contains (pmap, file_data); - if (slot) - partition = (ltrans_partition) *slot; - else - { - partition = new_partition (file_data->file_name); - slot = pointer_map_insert (pmap, file_data); - *slot = partition; - npartitions++; - } - - add_varpool_node_to_partition (partition, vnode); - } - for (node = cgraph_nodes; node; node = node->next) - node->aux = NULL; - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - vnode->aux = NULL; - - /* If the cgraph is empty, create one cgraph node set so that there is still - an output file for any variables that need to be exported in a DSO. */ - if (!npartitions) - new_partition ("empty"); - - pointer_map_destroy (pmap); - - timevar_pop (TV_WHOPR_WPA); - - lto_stats.num_cgraph_partitions += VEC_length (ltrans_partition, - ltrans_partitions); -} - -/* Helper function for qsort; sort nodes by order. */ -static int -node_cmp (const void *pa, const void *pb) -{ - const struct cgraph_node *a = *(const struct cgraph_node * const *) pa; - const struct cgraph_node *b = *(const struct cgraph_node * const *) pb; - return b->order - a->order; -} - -/* Helper function for qsort; sort nodes by order. */ -static int -varpool_node_cmp (const void *pa, const void *pb) -{ - const struct varpool_node *a = *(const struct varpool_node * const *) pa; - const struct varpool_node *b = *(const struct varpool_node * const *) pb; - return b->order - a->order; -} - -/* Group cgraph nodes into equally-sized partitions. - - The partitioning algorithm is simple: nodes are taken in predefined order. - The order corresponds to the order we want functions to have in the final - output. In the future this will be given by function reordering pass, but - at the moment we use the topological order, which is a good approximation. - - The goal is to partition this linear order into intervals (partitions) so - that all the partitions have approximately the same size and the number of - callgraph or IPA reference edges crossing boundaries is minimal. - - This is a lot faster (O(n) in size of callgraph) than algorithms doing - priority-based graph clustering that are generally O(n^2) and, since - WHOPR is designed to make things go well across partitions, it leads - to good results. - - We compute the expected size of a partition as: - - max (total_size / lto_partitions, min_partition_size) - - We use dynamic expected size of partition so small programs are partitioned - into enough partitions to allow use of multiple CPUs, while large programs - are not partitioned too much. Creating too many partitions significantly - increases the streaming overhead. - - In the future, we would like to bound the maximal size of partitions so as - to prevent the LTRANS stage from consuming too much memory. At the moment, - however, the WPA stage is the most memory intensive for large benchmarks, - since too many types and declarations are read into memory. - - The function implements a simple greedy algorithm. Nodes are being added - to the current partition until after 3/4 of the expected partition size is - reached. Past this threshold, we keep track of boundary size (number of - edges going to other partitions) and continue adding functions until after - the current partition has grown to twice the expected partition size. Then - the process is undone to the point where the minimal ratio of boundary size - and in-partition calls was reached. */ - -static void -lto_balanced_map (void) -{ - int n_nodes = 0; - int n_varpool_nodes = 0, varpool_pos = 0; - struct cgraph_node **postorder = - XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); - struct cgraph_node **order = XNEWVEC (struct cgraph_node *, cgraph_max_uid); - struct varpool_node **varpool_order = NULL; - int i, postorder_len; - struct cgraph_node *node; - int total_size = 0, best_total_size = 0; - int partition_size; - ltrans_partition partition; - unsigned int last_visited_cgraph_node = 0, last_visited_varpool_node = 0; - struct varpool_node *vnode; - int cost = 0, internal = 0; - int best_n_nodes = 0, best_n_varpool_nodes = 0, best_i = 0, best_cost = - INT_MAX, best_internal = 0; - int npartitions; - int current_order = -1; - - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - gcc_assert (!vnode->aux); - /* Until we have better ordering facility, use toplogical order. - Include only nodes we will partition and compute estimate of program - size. Note that since nodes that are not partitioned might be put into - multiple partitions, this is just an estimate of real size. This is why - we keep partition_size updated after every partition is finalized. */ - postorder_len = ipa_reverse_postorder (postorder); - - for (i = 0; i < postorder_len; i++) - { - node = postorder[i]; - if (partition_cgraph_node_p (node)) - { - order[n_nodes++] = node; - total_size += inline_summary (node)->size; - } - } - free (postorder); - - if (!flag_toplevel_reorder) - { - qsort (order, n_nodes, sizeof (struct cgraph_node *), node_cmp); - - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - if (partition_varpool_node_p (vnode)) - n_varpool_nodes++; - varpool_order = XNEWVEC (struct varpool_node *, n_varpool_nodes); - - n_varpool_nodes = 0; - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - if (partition_varpool_node_p (vnode)) - varpool_order[n_varpool_nodes++] = vnode; - qsort (varpool_order, n_varpool_nodes, sizeof (struct varpool_node *), - varpool_node_cmp); - } - - /* Compute partition size and create the first partition. */ - partition_size = total_size / PARAM_VALUE (PARAM_LTO_PARTITIONS); - if (partition_size < PARAM_VALUE (MIN_PARTITION_SIZE)) - partition_size = PARAM_VALUE (MIN_PARTITION_SIZE); - npartitions = 1; - partition = new_partition (""); - if (cgraph_dump_file) - fprintf (cgraph_dump_file, "Total unit size: %i, partition size: %i\n", - total_size, partition_size); - - for (i = 0; i < n_nodes; i++) - { - if (order[i]->aux) - continue; - - current_order = order[i]->order; - - if (!flag_toplevel_reorder) - while (varpool_pos < n_varpool_nodes && varpool_order[varpool_pos]->order < current_order) - { - if (!varpool_order[varpool_pos]->aux) - add_varpool_node_to_partition (partition, varpool_order[varpool_pos]); - varpool_pos++; - } - - add_cgraph_node_to_partition (partition, order[i]); - total_size -= inline_summary (order[i])->size; - - - /* Once we added a new node to the partition, we also want to add - all referenced variables unless they was already added into some - earlier partition. - add_cgraph_node_to_partition adds possibly multiple nodes and - variables that are needed to satisfy needs of ORDER[i]. - We remember last visited cgraph and varpool node from last iteration - of outer loop that allows us to process every new addition. - - At the same time we compute size of the boundary into COST. Every - callgraph or IPA reference edge leaving the partition contributes into - COST. Every edge inside partition was earlier computed as one leaving - it and thus we need to subtract it from COST. */ - while (last_visited_cgraph_node < - VEC_length (cgraph_node_ptr, partition->cgraph_set->nodes) - || last_visited_varpool_node < VEC_length (varpool_node_ptr, - partition->varpool_set-> - nodes)) - { - struct ipa_ref_list *refs; - int j; - struct ipa_ref *ref; - bool cgraph_p = false; - - if (last_visited_cgraph_node < - VEC_length (cgraph_node_ptr, partition->cgraph_set->nodes)) - { - struct cgraph_edge *edge; - - cgraph_p = true; - node = VEC_index (cgraph_node_ptr, partition->cgraph_set->nodes, - last_visited_cgraph_node); - refs = &node->ref_list; - - last_visited_cgraph_node++; - - gcc_assert (node->analyzed); - - /* Compute boundary cost of callgraph edges. */ - for (edge = node->callees; edge; edge = edge->next_callee) - if (edge->callee->analyzed) - { - int edge_cost = edge->frequency; - cgraph_node_set_iterator csi; - - if (!edge_cost) - edge_cost = 1; - gcc_assert (edge_cost > 0); - csi = cgraph_node_set_find (partition->cgraph_set, edge->callee); - if (!csi_end_p (csi) - && csi.index < last_visited_cgraph_node - 1) - cost -= edge_cost, internal+= edge_cost; - else - cost += edge_cost; - } - for (edge = node->callers; edge; edge = edge->next_caller) - { - int edge_cost = edge->frequency; - cgraph_node_set_iterator csi; - - gcc_assert (edge->caller->analyzed); - if (!edge_cost) - edge_cost = 1; - gcc_assert (edge_cost > 0); - csi = cgraph_node_set_find (partition->cgraph_set, edge->caller); - if (!csi_end_p (csi) - && csi.index < last_visited_cgraph_node) - cost -= edge_cost; - else - cost += edge_cost; - } - } - else - { - refs = - &VEC_index (varpool_node_ptr, partition->varpool_set->nodes, - last_visited_varpool_node)->ref_list; - last_visited_varpool_node++; - } - - /* Compute boundary cost of IPA REF edges and at the same time look into - variables referenced from current partition and try to add them. */ - for (j = 0; ipa_ref_list_reference_iterate (refs, j, ref); j++) - if (ref->refered_type == IPA_REF_VARPOOL) - { - varpool_node_set_iterator vsi; - - vnode = ipa_ref_varpool_node (ref); - if (!vnode->finalized) - continue; - if (!vnode->aux && flag_toplevel_reorder - && partition_varpool_node_p (vnode)) - add_varpool_node_to_partition (partition, vnode); - vsi = varpool_node_set_find (partition->varpool_set, vnode); - if (!vsi_end_p (vsi) - && vsi.index < last_visited_varpool_node - !cgraph_p) - cost--, internal++; - else - cost++; - } - else - { - cgraph_node_set_iterator csi; - - node = ipa_ref_node (ref); - if (!node->analyzed) - continue; - csi = cgraph_node_set_find (partition->cgraph_set, node); - if (!csi_end_p (csi) - && csi.index < last_visited_cgraph_node - cgraph_p) - cost--, internal++; - else - cost++; - } - for (j = 0; ipa_ref_list_refering_iterate (refs, j, ref); j++) - if (ref->refering_type == IPA_REF_VARPOOL) - { - varpool_node_set_iterator vsi; - - vnode = ipa_ref_refering_varpool_node (ref); - gcc_assert (vnode->finalized); - if (!vnode->aux && flag_toplevel_reorder - && partition_varpool_node_p (vnode)) - add_varpool_node_to_partition (partition, vnode); - vsi = varpool_node_set_find (partition->varpool_set, vnode); - if (!vsi_end_p (vsi) - && vsi.index < last_visited_varpool_node) - cost--; - else - cost++; - } - else - { - cgraph_node_set_iterator csi; - - node = ipa_ref_refering_node (ref); - gcc_assert (node->analyzed); - csi = cgraph_node_set_find (partition->cgraph_set, node); - if (!csi_end_p (csi) - && csi.index < last_visited_cgraph_node) - cost--; - else - cost++; - } - } - - /* If the partition is large enough, start looking for smallest boundary cost. */ - if (partition->insns < partition_size * 3 / 4 - || best_cost == INT_MAX - || ((!cost - || (best_internal * (HOST_WIDE_INT) cost - > (internal * (HOST_WIDE_INT)best_cost))) - && partition->insns < partition_size * 5 / 4)) - { - best_cost = cost; - best_internal = internal; - best_i = i; - best_n_nodes = VEC_length (cgraph_node_ptr, - partition->cgraph_set->nodes); - best_n_varpool_nodes = VEC_length (varpool_node_ptr, - partition->varpool_set->nodes); - best_total_size = total_size; - } - if (cgraph_dump_file) - fprintf (cgraph_dump_file, "Step %i: added %s/%i, size %i, cost %i/%i best %i/%i, step %i\n", i, - cgraph_node_name (order[i]), order[i]->uid, partition->insns, cost, internal, - best_cost, best_internal, best_i); - /* Partition is too large, unwind into step when best cost was reached and - start new partition. */ - if (partition->insns > 2 * partition_size) - { - if (best_i != i) - { - if (cgraph_dump_file) - fprintf (cgraph_dump_file, "Unwinding %i insertions to step %i\n", - i - best_i, best_i); - undo_partition (partition, best_n_nodes, best_n_varpool_nodes); - } - i = best_i; - /* When we are finished, avoid creating empty partition. */ - while (i < n_nodes - 1 && order[i + 1]->aux) - i++; - if (i == n_nodes - 1) - break; - partition = new_partition (""); - last_visited_cgraph_node = 0; - last_visited_varpool_node = 0; - total_size = best_total_size; - cost = 0; - - if (cgraph_dump_file) - fprintf (cgraph_dump_file, "New partition\n"); - best_n_nodes = 0; - best_n_varpool_nodes = 0; - best_cost = INT_MAX; - - /* Since the size of partitions is just approximate, update the size after - we finished current one. */ - if (npartitions < PARAM_VALUE (PARAM_LTO_PARTITIONS)) - partition_size = total_size - / (PARAM_VALUE (PARAM_LTO_PARTITIONS) - npartitions); - else - partition_size = INT_MAX; - - if (partition_size < PARAM_VALUE (MIN_PARTITION_SIZE)) - partition_size = PARAM_VALUE (MIN_PARTITION_SIZE); - npartitions ++; - } - } - - /* Varables that are not reachable from the code go into last partition. */ - if (flag_toplevel_reorder) - { - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - if (partition_varpool_node_p (vnode) && !vnode->aux) - add_varpool_node_to_partition (partition, vnode); - } - else - { - while (varpool_pos < n_varpool_nodes) - { - if (!varpool_order[varpool_pos]->aux) - add_varpool_node_to_partition (partition, varpool_order[varpool_pos]); - varpool_pos++; - } - free (varpool_order); - } - free (order); -} - -/* Promote variable VNODE to be static. */ - -static bool -promote_var (struct varpool_node *vnode) -{ - if (TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl)) - return false; - gcc_assert (flag_wpa); - TREE_PUBLIC (vnode->decl) = 1; - DECL_VISIBILITY (vnode->decl) = VISIBILITY_HIDDEN; - DECL_VISIBILITY_SPECIFIED (vnode->decl) = true; - if (cgraph_dump_file) - fprintf (cgraph_dump_file, - "Promoting var as hidden: %s\n", varpool_node_name (vnode)); - return true; -} - -/* Promote function NODE to be static. */ - -static bool -promote_fn (struct cgraph_node *node) -{ - gcc_assert (flag_wpa); - if (TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)) - return false; - TREE_PUBLIC (node->decl) = 1; - DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN; - DECL_VISIBILITY_SPECIFIED (node->decl) = true; - if (cgraph_dump_file) - fprintf (cgraph_dump_file, - "Promoting function as hidden: %s/%i\n", - cgraph_node_name (node), node->uid); - return true; -} - -/* Find out all static decls that need to be promoted to global because - of cross file sharing. This function must be run in the WPA mode after - all inlinees are added. */ - -static void -lto_promote_cross_file_statics (void) -{ - struct varpool_node *vnode; - unsigned i, n_sets; - cgraph_node_set set; - varpool_node_set vset; - cgraph_node_set_iterator csi; - varpool_node_set_iterator vsi; - VEC(varpool_node_ptr, heap) *promoted_initializers = NULL; - struct pointer_set_t *inserted = pointer_set_create (); - - gcc_assert (flag_wpa); - - n_sets = VEC_length (ltrans_partition, ltrans_partitions); - for (i = 0; i < n_sets; i++) - { - ltrans_partition part - = VEC_index (ltrans_partition, ltrans_partitions, i); - set = part->cgraph_set; - vset = part->varpool_set; - - /* If node called or referred to from other partition, it needs to be - globalized. */ - for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) - { - struct cgraph_node *node = csi_node (csi); - if (node->local.externally_visible) - continue; - if (node->global.inlined_to) - continue; - if ((!DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl)) - && (referenced_from_other_partition_p (&node->ref_list, set, vset) - || reachable_from_other_partition_p (node, set))) - promote_fn (node); - } - for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi)) - { - vnode = vsi_node (vsi); - /* Constant pool references use internal labels and thus can not - be made global. It is sensible to keep those ltrans local to - allow better optimization. */ - if (!DECL_IN_CONSTANT_POOL (vnode->decl) && !DECL_COMDAT (vnode->decl) - && !vnode->externally_visible && vnode->analyzed - && referenced_from_other_partition_p (&vnode->ref_list, - set, vset)) - promote_var (vnode); - } - - /* We export the initializer of a read-only var into each partition - referencing the var. Folding might take declarations from the - initializer and use them, so everything referenced from the - initializer can be accessed from this partition after folding. - - This means that we need to promote all variables and functions - referenced from all initializers of read-only vars referenced - from this partition that are not in this partition. This needs - to be done recursively. */ - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - if (const_value_known_p (vnode->decl) - && DECL_INITIAL (vnode->decl) - && !varpool_node_in_set_p (vnode, vset) - && referenced_from_this_partition_p (&vnode->ref_list, set, vset) - && !pointer_set_insert (inserted, vnode)) - VEC_safe_push (varpool_node_ptr, heap, promoted_initializers, vnode); - - while (!VEC_empty (varpool_node_ptr, promoted_initializers)) - { - int i; - struct ipa_ref *ref; - - vnode = VEC_pop (varpool_node_ptr, promoted_initializers); - for (i = 0; - ipa_ref_list_reference_iterate (&vnode->ref_list, i, ref); - i++) - { - if (ref->refered_type == IPA_REF_CGRAPH) - { - struct cgraph_node *n = ipa_ref_node (ref); - gcc_assert (!n->global.inlined_to); - if (!n->local.externally_visible - && !cgraph_node_in_set_p (n, set)) - promote_fn (n); - } - else - { - struct varpool_node *v = ipa_ref_varpool_node (ref); - if (varpool_node_in_set_p (v, vset)) - continue; - - /* Constant pool references use internal labels and thus - cannot be made global. It is sensible to keep those - ltrans local to allow better optimization. */ - if (DECL_IN_CONSTANT_POOL (v->decl)) - { - if (!pointer_set_insert (inserted, vnode)) - VEC_safe_push (varpool_node_ptr, heap, - promoted_initializers, v); - } - else if (!v->externally_visible && v->analyzed) - { - if (promote_var (v) - && DECL_INITIAL (v->decl) - && const_value_known_p (v->decl) - && !pointer_set_insert (inserted, vnode)) - VEC_safe_push (varpool_node_ptr, heap, - promoted_initializers, v); - } - } - } - } - } - pointer_set_destroy (inserted); -} - static lto_file *current_lto_file; /* Helper for qsort; compare partitions and return one with smaller size. @@ -2319,13 +1424,13 @@ cmp_partitions_order (const void *a, const void *b) int ordera = -1, orderb = -1; if (VEC_length (cgraph_node_ptr, pa->cgraph_set->nodes)) - ordera = VEC_index (cgraph_node_ptr, pa->cgraph_set->nodes, 0)->order; + ordera = VEC_index (cgraph_node_ptr, pa->cgraph_set->nodes, 0)->symbol.order; else if (VEC_length (varpool_node_ptr, pa->varpool_set->nodes)) - ordera = VEC_index (varpool_node_ptr, pa->varpool_set->nodes, 0)->order; + ordera = VEC_index (varpool_node_ptr, pa->varpool_set->nodes, 0)->symbol.order; if (VEC_length (cgraph_node_ptr, pb->cgraph_set->nodes)) - orderb = VEC_index (cgraph_node_ptr, pb->cgraph_set->nodes, 0)->order; + orderb = VEC_index (cgraph_node_ptr, pb->cgraph_set->nodes, 0)->symbol.order; else if (VEC_length (varpool_node_ptr, pb->varpool_set->nodes)) - orderb = VEC_index (varpool_node_ptr, pb->varpool_set->nodes, 0)->order; + orderb = VEC_index (varpool_node_ptr, pb->varpool_set->nodes, 0)->symbol.order; return orderb - ordera; } @@ -2763,18 +1868,15 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) lto_symtab_merge_cgraph_nodes (); ggc_collect (); + /* FIXME: ipa_transforms_to_apply holds list of passes that have optimization + summaries computed and needs to apply changes. At the moment WHOPR only + supports inlining, so we can push it here by hand. In future we need to stream + this field into ltrans compilation. */ if (flag_ltrans) - for (node = cgraph_nodes; node; node = node->next) - { - /* FIXME: ipa_transforms_to_apply holds list of passes that have optimization - summaries computed and needs to apply changes. At the moment WHOPR only - supports inlining, so we can push it here by hand. In future we need to stream - this field into ltrans compilation. */ - if (node->analyzed) - VEC_safe_push (ipa_opt_pass, heap, - node->ipa_transforms_to_apply, - (ipa_opt_pass)&pass_ipa_inline); - } + FOR_EACH_DEFINED_FUNCTION (node) + VEC_safe_push (ipa_opt_pass, heap, + node->ipa_transforms_to_apply, + (ipa_opt_pass)&pass_ipa_inline); lto_symtab_free (); timevar_pop (TV_IPA_LTO_CGRAPH_MERGE); @@ -2818,9 +1920,9 @@ materialize_cgraph (void) nodes and read the functions if we are not running in WPA mode. */ timevar_push (TV_IPA_LTO_GIMPLE_IN); - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) { - if (node->local.lto_file_data) + if (node->symbol.lto_file_data) { lto_materialize_function (node); lto_stats.num_input_cgraph_nodes++; diff --git a/gcc/matrix-reorg.c b/gcc/matrix-reorg.c index fbeb1643796..6589e7803d3 100644 --- a/gcc/matrix-reorg.c +++ b/gcc/matrix-reorg.c @@ -446,7 +446,7 @@ may_flatten_matrices (struct cgraph_node *node) basic_block bb; gimple_stmt_iterator gsi; - decl = node->decl; + decl = node->symbol.decl; if (node->analyzed) { func = DECL_STRUCT_FUNCTION (decl); @@ -548,9 +548,9 @@ find_matrices_decl (void) /* For every global variable in the program: Check to see if it's of a candidate type and record it. */ - for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) + FOR_EACH_DEFINED_VARIABLE (vnode) { - tree var_decl = vnode->decl; + tree var_decl = vnode->symbol.decl; if (!var_decl || TREE_CODE (var_decl) != VAR_DECL) continue; @@ -2266,100 +2266,98 @@ matrix_reorg (void) else check_transpose_p = false; /* If there are hand written vectors, we skip this optimization. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_FUNCTION (node) if (!may_flatten_matrices (node)) return 0; matrices_to_reorg = htab_create (37, mtt_info_hash, mtt_info_eq, mat_free); /* Find and record all potential matrices in the program. */ find_matrices_decl (); /* Analyze the accesses of the matrices (escaping analysis). */ - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed) - { - tree temp_fn; + FOR_EACH_DEFINED_FUNCTION (node) + { + tree temp_fn; - temp_fn = current_function_decl; - current_function_decl = node->decl; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - bitmap_obstack_initialize (NULL); - gimple_register_cfg_hooks (); + temp_fn = current_function_decl; + current_function_decl = node->symbol.decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); + bitmap_obstack_initialize (NULL); + gimple_register_cfg_hooks (); - if (!gimple_in_ssa_p (cfun)) - { - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - pop_cfun (); - current_function_decl = temp_fn; - bitmap_obstack_release (NULL); + if (!gimple_in_ssa_p (cfun)) + { + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + pop_cfun (); + current_function_decl = temp_fn; + bitmap_obstack_release (NULL); - return 0; - } + return 0; + } #ifdef ENABLE_CHECKING - verify_flow_info (); + verify_flow_info (); #endif - if (!matrices_to_reorg) - { - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - pop_cfun (); - current_function_decl = temp_fn; - bitmap_obstack_release (NULL); + if (!matrices_to_reorg) + { + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + pop_cfun (); + current_function_decl = temp_fn; + bitmap_obstack_release (NULL); - return 0; - } + return 0; + } - /* Create htap for phi nodes. */ - htab_mat_acc_phi_nodes = htab_create (37, mat_acc_phi_hash, - mat_acc_phi_eq, free); - if (!check_transpose_p) - find_sites_in_func (false); - else - { - find_sites_in_func (true); - loop_optimizer_init (LOOPS_NORMAL); - if (current_loops) - scev_initialize (); - htab_traverse (matrices_to_reorg, analyze_transpose, NULL); - if (current_loops) - { - scev_finalize (); - loop_optimizer_finalize (); - current_loops = NULL; - } - } - /* If the current function is the allocation function for any of - the matrices we check its allocation and the escaping level. */ - htab_traverse (matrices_to_reorg, check_allocation_function, NULL); - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - pop_cfun (); - current_function_decl = temp_fn; - bitmap_obstack_release (NULL); - } + /* Create htap for phi nodes. */ + htab_mat_acc_phi_nodes = htab_create (37, mat_acc_phi_hash, + mat_acc_phi_eq, free); + if (!check_transpose_p) + find_sites_in_func (false); + else + { + find_sites_in_func (true); + loop_optimizer_init (LOOPS_NORMAL); + if (current_loops) + scev_initialize (); + htab_traverse (matrices_to_reorg, analyze_transpose, NULL); + if (current_loops) + { + scev_finalize (); + loop_optimizer_finalize (); + current_loops = NULL; + } + } + /* If the current function is the allocation function for any of + the matrices we check its allocation and the escaping level. */ + htab_traverse (matrices_to_reorg, check_allocation_function, NULL); + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + pop_cfun (); + current_function_decl = temp_fn; + bitmap_obstack_release (NULL); + } htab_traverse (matrices_to_reorg, transform_allocation_sites, NULL); /* Now transform the accesses. */ - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed) - { - /* Remember that allocation sites have been handled. */ - tree temp_fn; - - temp_fn = current_function_decl; - current_function_decl = node->decl; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - bitmap_obstack_initialize (NULL); - gimple_register_cfg_hooks (); - record_all_accesses_in_func (); - htab_traverse (matrices_to_reorg, transform_access_sites, NULL); - cgraph_rebuild_references (); - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - pop_cfun (); - current_function_decl = temp_fn; - bitmap_obstack_release (NULL); - } + FOR_EACH_DEFINED_FUNCTION (node) + { + /* Remember that allocation sites have been handled. */ + tree temp_fn; + + temp_fn = current_function_decl; + current_function_decl = node->symbol.decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); + bitmap_obstack_initialize (NULL); + gimple_register_cfg_hooks (); + record_all_accesses_in_func (); + htab_traverse (matrices_to_reorg, transform_access_sites, NULL); + cgraph_rebuild_references (); + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + pop_cfun (); + current_function_decl = temp_fn; + bitmap_obstack_release (NULL); + } htab_traverse (matrices_to_reorg, dump_matrix_reorg_analysis, NULL); current_function_decl = NULL; @@ -2391,6 +2389,6 @@ struct simple_ipa_opt_pass pass_ipa_matrix_reorg = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_cgraph /* todo_flags_finish */ + TODO_dump_symtab /* todo_flags_finish */ } }; diff --git a/gcc/melt-build.mk b/gcc/melt-build.mk index 58eb5bde4e5..6bf39f80c68 100644 --- a/gcc/melt-build.mk +++ b/gcc/melt-build.mk @@ -3,7 +3,7 @@ #@#@# #@#@# DO NOT EDIT THIS FILE (melt-build.mk) #@#@# -#@#@# It has been AutoGen-ed April 4, 2012 at 11:05:17 AM by AutoGen 5.12 +#@#@# It has been AutoGen-ed April 23, 2012 at 12:54:04 PM by AutoGen 5.12 #@#@# From the definitions melt-build.def #@#@# and the template file melt-build.tpl ##@@ melt-build.mk is generated from melt-build.tpl by 'autogen melt-build.def' @@ -4684,7 +4684,7 @@ melt-sources/xtramelt-ana-base.melt: $(melt_make_source_dir)/xtramelt-ana-base.m ## to exercise the optimized warmelt... melt-sources/xtramelt-ana-base.c: \ melt-sources/xtramelt-ana-base.melt \ - melt-sources/warmelt-optimized.modlis melt-sources/warmelt-quicklybuilt.modlis \ + melt-sources/warmelt-quicklybuilt.modlis melt-sources/warmelt-optimized.modlis \ melt-sources-directory.stamp \ \ $(MELT_TRANSLATOR_SOURCE) \ @@ -4719,33 +4719,35 @@ melt-sources/xtramelt-ana-base.c: \ ## melt application xtramelt-ana-base various flavors of modules -## melt application xtramelt-ana-base flavor optimized from melt-build.tpl line 645 -melt-modules/xtramelt-ana-base.optimized.so: melt-sources-directory.stamp \ +## melt application xtramelt-ana-base flavor quicklybuilt from melt-build.tpl line 645 +melt-modules/xtramelt-ana-base.quicklybuilt.so: melt-sources-directory.stamp \ melt-sources/xtramelt-ana-base.c melt-modules-directory.stamp melt-workdir-directory.stamp \ $(wildcard melt-sources/xtramelt-ana-base+*.c) \ melt-run.h melt-runtime.h @echo doing $@ from melt-build.tpl line 650 +$(MELT_MAKE_MODULE) melt_module \ - GCCMELT_MODULE_FLAVOR=optimized \ + GCCMELT_MODULE_FLAVOR=quicklybuilt \ GCCMELT_CFLAGS="$(melt_cflags)" \ GCCMELT_MODULE_WORKSPACE=melt-workdir \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-ana-base \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-ana-base +#@ from melt-build.tpl line 658 xtramelt-ana-base.quicklybuilt -## melt application xtramelt-ana-base flavor quicklybuilt from melt-build.tpl line 645 -melt-modules/xtramelt-ana-base.quicklybuilt.so: melt-sources-directory.stamp \ +## melt application xtramelt-ana-base flavor optimized from melt-build.tpl line 645 +melt-modules/xtramelt-ana-base.optimized.so: melt-sources-directory.stamp \ melt-sources/xtramelt-ana-base.c melt-modules-directory.stamp melt-workdir-directory.stamp \ $(wildcard melt-sources/xtramelt-ana-base+*.c) \ melt-run.h melt-runtime.h @echo doing $@ from melt-build.tpl line 650 +$(MELT_MAKE_MODULE) melt_module \ - GCCMELT_MODULE_FLAVOR=quicklybuilt \ + GCCMELT_MODULE_FLAVOR=optimized \ GCCMELT_CFLAGS="$(melt_cflags)" \ GCCMELT_MODULE_WORKSPACE=melt-workdir \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-ana-base \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-ana-base +#@ from melt-build.tpl line 658 xtramelt-ana-base.optimized ## melt application xtramelt-ana-base flavor debugnoline from melt-build.tpl line 645 melt-modules/xtramelt-ana-base.debugnoline.so: melt-sources-directory.stamp \ @@ -4760,12 +4762,13 @@ melt-modules/xtramelt-ana-base.debugnoline.so: melt-sources-directory.stamp \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-ana-base \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-ana-base +#@ from melt-build.tpl line 658 xtramelt-ana-base.debugnoline -#@ from melt-build.tpl line 659 +#@ from melt-build.tpl line 660 # end application xtramelt-ana-base -#@ from melt-build.tpl line 663 +#@ from melt-build.tpl line 664 #@ from melt-build.tpl line 597 @@ -4780,7 +4783,7 @@ melt-sources/xtramelt-ana-simple.melt: $(melt_make_source_dir)/xtramelt-ana-simp ## to exercise the optimized warmelt... melt-sources/xtramelt-ana-simple.c: \ melt-sources/xtramelt-ana-simple.melt \ - melt-sources/warmelt-optimized.modlis melt-sources/warmelt-quicklybuilt.modlis \ + melt-sources/warmelt-quicklybuilt.modlis melt-sources/warmelt-optimized.modlis \ melt-sources-directory.stamp \ \ $(MELT_TRANSLATOR_SOURCE) \ @@ -4815,33 +4818,35 @@ melt-sources/xtramelt-ana-simple.c: \ ## melt application xtramelt-ana-simple various flavors of modules -## melt application xtramelt-ana-simple flavor optimized from melt-build.tpl line 645 -melt-modules/xtramelt-ana-simple.optimized.so: melt-sources-directory.stamp \ +## melt application xtramelt-ana-simple flavor quicklybuilt from melt-build.tpl line 645 +melt-modules/xtramelt-ana-simple.quicklybuilt.so: melt-sources-directory.stamp \ melt-sources/xtramelt-ana-simple.c melt-modules-directory.stamp melt-workdir-directory.stamp \ $(wildcard melt-sources/xtramelt-ana-simple+*.c) \ melt-run.h melt-runtime.h @echo doing $@ from melt-build.tpl line 650 +$(MELT_MAKE_MODULE) melt_module \ - GCCMELT_MODULE_FLAVOR=optimized \ + GCCMELT_MODULE_FLAVOR=quicklybuilt \ GCCMELT_CFLAGS="$(melt_cflags)" \ GCCMELT_MODULE_WORKSPACE=melt-workdir \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-ana-simple \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-ana-simple +#@ from melt-build.tpl line 658 xtramelt-ana-simple.quicklybuilt -## melt application xtramelt-ana-simple flavor quicklybuilt from melt-build.tpl line 645 -melt-modules/xtramelt-ana-simple.quicklybuilt.so: melt-sources-directory.stamp \ +## melt application xtramelt-ana-simple flavor optimized from melt-build.tpl line 645 +melt-modules/xtramelt-ana-simple.optimized.so: melt-sources-directory.stamp \ melt-sources/xtramelt-ana-simple.c melt-modules-directory.stamp melt-workdir-directory.stamp \ $(wildcard melt-sources/xtramelt-ana-simple+*.c) \ melt-run.h melt-runtime.h @echo doing $@ from melt-build.tpl line 650 +$(MELT_MAKE_MODULE) melt_module \ - GCCMELT_MODULE_FLAVOR=quicklybuilt \ + GCCMELT_MODULE_FLAVOR=optimized \ GCCMELT_CFLAGS="$(melt_cflags)" \ GCCMELT_MODULE_WORKSPACE=melt-workdir \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-ana-simple \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-ana-simple +#@ from melt-build.tpl line 658 xtramelt-ana-simple.optimized ## melt application xtramelt-ana-simple flavor debugnoline from melt-build.tpl line 645 melt-modules/xtramelt-ana-simple.debugnoline.so: melt-sources-directory.stamp \ @@ -4856,12 +4861,13 @@ melt-modules/xtramelt-ana-simple.debugnoline.so: melt-sources-directory.stamp \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-ana-simple \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-ana-simple +#@ from melt-build.tpl line 658 xtramelt-ana-simple.debugnoline -#@ from melt-build.tpl line 659 +#@ from melt-build.tpl line 660 # end application xtramelt-ana-simple -#@ from melt-build.tpl line 663 +#@ from melt-build.tpl line 664 #@ from melt-build.tpl line 597 @@ -4876,7 +4882,7 @@ melt-sources/xtramelt-c-generator.melt: $(melt_make_source_dir)/xtramelt-c-gener ## to exercise the optimized warmelt... melt-sources/xtramelt-c-generator.c: \ melt-sources/xtramelt-c-generator.melt \ - melt-sources/warmelt-optimized.modlis melt-sources/warmelt-quicklybuilt.modlis \ + melt-sources/warmelt-quicklybuilt.modlis melt-sources/warmelt-optimized.modlis \ melt-sources-directory.stamp \ \ $(MELT_TRANSLATOR_SOURCE) \ @@ -4911,33 +4917,35 @@ melt-sources/xtramelt-c-generator.c: \ ## melt application xtramelt-c-generator various flavors of modules -## melt application xtramelt-c-generator flavor optimized from melt-build.tpl line 645 -melt-modules/xtramelt-c-generator.optimized.so: melt-sources-directory.stamp \ +## melt application xtramelt-c-generator flavor quicklybuilt from melt-build.tpl line 645 +melt-modules/xtramelt-c-generator.quicklybuilt.so: melt-sources-directory.stamp \ melt-sources/xtramelt-c-generator.c melt-modules-directory.stamp melt-workdir-directory.stamp \ $(wildcard melt-sources/xtramelt-c-generator+*.c) \ melt-run.h melt-runtime.h @echo doing $@ from melt-build.tpl line 650 +$(MELT_MAKE_MODULE) melt_module \ - GCCMELT_MODULE_FLAVOR=optimized \ + GCCMELT_MODULE_FLAVOR=quicklybuilt \ GCCMELT_CFLAGS="$(melt_cflags)" \ GCCMELT_MODULE_WORKSPACE=melt-workdir \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-c-generator \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-c-generator +#@ from melt-build.tpl line 658 xtramelt-c-generator.quicklybuilt -## melt application xtramelt-c-generator flavor quicklybuilt from melt-build.tpl line 645 -melt-modules/xtramelt-c-generator.quicklybuilt.so: melt-sources-directory.stamp \ +## melt application xtramelt-c-generator flavor optimized from melt-build.tpl line 645 +melt-modules/xtramelt-c-generator.optimized.so: melt-sources-directory.stamp \ melt-sources/xtramelt-c-generator.c melt-modules-directory.stamp melt-workdir-directory.stamp \ $(wildcard melt-sources/xtramelt-c-generator+*.c) \ melt-run.h melt-runtime.h @echo doing $@ from melt-build.tpl line 650 +$(MELT_MAKE_MODULE) melt_module \ - GCCMELT_MODULE_FLAVOR=quicklybuilt \ + GCCMELT_MODULE_FLAVOR=optimized \ GCCMELT_CFLAGS="$(melt_cflags)" \ GCCMELT_MODULE_WORKSPACE=melt-workdir \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-c-generator \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-c-generator +#@ from melt-build.tpl line 658 xtramelt-c-generator.optimized ## melt application xtramelt-c-generator flavor debugnoline from melt-build.tpl line 645 melt-modules/xtramelt-c-generator.debugnoline.so: melt-sources-directory.stamp \ @@ -4952,12 +4960,13 @@ melt-modules/xtramelt-c-generator.debugnoline.so: melt-sources-directory.stamp \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-c-generator \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-c-generator +#@ from melt-build.tpl line 658 xtramelt-c-generator.debugnoline -#@ from melt-build.tpl line 659 +#@ from melt-build.tpl line 660 # end application xtramelt-c-generator -#@ from melt-build.tpl line 663 +#@ from melt-build.tpl line 664 #@ from melt-build.tpl line 597 @@ -4972,7 +4981,7 @@ melt-sources/xtramelt-opengpu.melt: $(melt_make_source_dir)/xtramelt-opengpu.mel ## to exercise the optimized warmelt... melt-sources/xtramelt-opengpu.c: \ melt-sources/xtramelt-opengpu.melt \ - melt-sources/warmelt-optimized.modlis melt-sources/warmelt-quicklybuilt.modlis \ + melt-sources/warmelt-quicklybuilt.modlis melt-sources/warmelt-optimized.modlis \ melt-sources-directory.stamp \ \ $(MELT_TRANSLATOR_SOURCE) \ @@ -5007,33 +5016,35 @@ melt-sources/xtramelt-opengpu.c: \ ## melt application xtramelt-opengpu various flavors of modules -## melt application xtramelt-opengpu flavor optimized from melt-build.tpl line 645 -melt-modules/xtramelt-opengpu.optimized.so: melt-sources-directory.stamp \ +## melt application xtramelt-opengpu flavor quicklybuilt from melt-build.tpl line 645 +melt-modules/xtramelt-opengpu.quicklybuilt.so: melt-sources-directory.stamp \ melt-sources/xtramelt-opengpu.c melt-modules-directory.stamp melt-workdir-directory.stamp \ $(wildcard melt-sources/xtramelt-opengpu+*.c) \ melt-run.h melt-runtime.h @echo doing $@ from melt-build.tpl line 650 +$(MELT_MAKE_MODULE) melt_module \ - GCCMELT_MODULE_FLAVOR=optimized \ + GCCMELT_MODULE_FLAVOR=quicklybuilt \ GCCMELT_CFLAGS="$(melt_cflags)" \ GCCMELT_MODULE_WORKSPACE=melt-workdir \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-opengpu \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-opengpu +#@ from melt-build.tpl line 658 xtramelt-opengpu.quicklybuilt -## melt application xtramelt-opengpu flavor quicklybuilt from melt-build.tpl line 645 -melt-modules/xtramelt-opengpu.quicklybuilt.so: melt-sources-directory.stamp \ +## melt application xtramelt-opengpu flavor optimized from melt-build.tpl line 645 +melt-modules/xtramelt-opengpu.optimized.so: melt-sources-directory.stamp \ melt-sources/xtramelt-opengpu.c melt-modules-directory.stamp melt-workdir-directory.stamp \ $(wildcard melt-sources/xtramelt-opengpu+*.c) \ melt-run.h melt-runtime.h @echo doing $@ from melt-build.tpl line 650 +$(MELT_MAKE_MODULE) melt_module \ - GCCMELT_MODULE_FLAVOR=quicklybuilt \ + GCCMELT_MODULE_FLAVOR=optimized \ GCCMELT_CFLAGS="$(melt_cflags)" \ GCCMELT_MODULE_WORKSPACE=melt-workdir \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-opengpu \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-opengpu +#@ from melt-build.tpl line 658 xtramelt-opengpu.optimized ## melt application xtramelt-opengpu flavor debugnoline from melt-build.tpl line 645 melt-modules/xtramelt-opengpu.debugnoline.so: melt-sources-directory.stamp \ @@ -5048,27 +5059,28 @@ melt-modules/xtramelt-opengpu.debugnoline.so: melt-sources-directory.stamp \ GCCMELT_MODULE_SOURCEBASE=melt-sources/xtramelt-opengpu \ GCCMELT_MODULE_BINARYBASE=melt-modules/xtramelt-opengpu +#@ from melt-build.tpl line 658 xtramelt-opengpu.debugnoline -#@ from melt-build.tpl line 659 +#@ from melt-build.tpl line 660 # end application xtramelt-opengpu -#@ from melt-build.tpl line 663 +#@ from melt-build.tpl line 664 ################ -#@ from melt-build.tpl line 668 +#@ from melt-build.tpl line 669 melt-sayhello.melt: $(melt_default_modules_list).modlis @date +'(code_chunk say%YM%mhello #{printf("hello_from_MELT on %c pid %%d\n", (int) getpid());}#)' > $@ -#@ from melt-build.tpl line 671 +#@ from melt-build.tpl line 672 melt-tiny-tests: melt-sayhello.melt melt-modules melt-sources \ melt-all-modules melt-all-sources \ melt-default-modules-quicklybuilt.modlis melt-runtime.args \ $(MELT_RUNTIME_C) -# test that a helloworld can be translated from melt-build.tpl line 677 - @echo doing $@ from melt-build.tpl line 678 +# test that a helloworld can be translated from melt-build.tpl line 678 + @echo doing $@ from melt-build.tpl line 679 @echo $(MELTCCAPPLICATION1ARGS) \ $(meltarg_arg)=$< -frandom-seed=$(shell $(MD5SUM) $< | cut -b-24) \ $(meltarg_module_path)=$(realpath melt-modules) \ @@ -5076,9 +5088,9 @@ melt-tiny-tests: melt-sayhello.melt melt-modules melt-sources \ $(meltarg_workdir)=melt-workdir $(meltarg_inhibitautobuild) \ $(meltarg_output)=$(basename $<) empty-file-for-melt.c > $(basename $<).args-tmp @$(melt_move_if_change) $(basename $<).args-tmp $(basename $<).args - @echo; echo; echo; echo -n $(basename $<).args: ; cat $(basename $<).args ; echo "***** doing " $(basename $<) from melt-build.tpl line 686 + @echo; echo; echo; echo -n $(basename $<).args: ; cat $(basename $<).args ; echo "***** doing " $(basename $<) from melt-build.tpl line 687 $(melt_make_cc1) @$(basename $<).args -# test that a helloworld can be run from melt-build.tpl line 688 +# test that a helloworld can be run from melt-build.tpl line 689 @echo $(MELTCCRUNFILE1ARGS) $(meltarg_init)=@melt-default-modules-quicklybuilt \ $(meltarg_arg)=$< -frandom-seed=$(shell $(MD5SUM) $< | cut -b-24) \ $(meltarg_module_path)=$(realpath melt-modules) \ @@ -5086,11 +5098,11 @@ melt-tiny-tests: melt-sayhello.melt melt-modules melt-sources \ $(meltarg_workdir)=melt-workdir $(meltarg_inhibitautobuild) \ $(meltarg_output)=$(basename $<) empty-file-for-melt.c > $(basename $<)-run.args-tmp @$(melt_move_if_change) $(basename $<)-run.args-tmp $(basename $<)-run.args - @echo; echo; echo; echo -n $(basename $<)-run.args: ; cat $(basename $<)-run.args ; echo "***** doing " $(basename $<)-run from melt-build.tpl line 696 + @echo; echo; echo; echo -n $(basename $<)-run.args: ; cat $(basename $<)-run.args ; echo "***** doing " $(basename $<)-run from melt-build.tpl line 697 $(melt_make_cc1) @$(basename $<)-run.args # test that the melt-runtime follows MELT coding rules; this also tests # a real MELT pass on real code, like our melt-runtime.c -# test melt-runtime from melt-build.tpl line 700 +# test melt-runtime from melt-build.tpl line 701 @echo $(melt_make_cc1flags) > meltframe.args-tmp @echo $(meltarg_mode)=meltframe \ $(meltarg_makefile)=$(melt_make_module_makefile) \ @@ -5106,17 +5118,17 @@ melt-tiny-tests: melt-sayhello.melt melt-modules melt-sources \ @echo -O -Wno-shadow >> meltframe.args-tmp @cat melt-runtime.args >> meltframe.args-tmp @$(melt_move_if_change) meltframe.args-tmp meltframe.args - @echo; echo; echo; echo -n meltframe.args: ; cat meltframe.args ; echo "***** doing " meltframe from melt-build.tpl line 716 + @echo; echo; echo; echo -n meltframe.args: ; cat meltframe.args ; echo "***** doing " meltframe from melt-build.tpl line 717 $(melt_make_cc1) @meltframe.args -#@ from melt-build.tpl line 720 +#@ from melt-build.tpl line 721 ################ -#@ from melt-build.tpl line 726 +#@ from melt-build.tpl line 727 melt-all-modules: melt-workdir \ melt-modules/warmelt-first.optimized.so \ melt-modules/warmelt-base.optimized.so \ @@ -5172,11 +5184,11 @@ $(melt_default_modules_list).modlis: melt-all-modules \ cd $(dir $@) ; $(LN_S) -v -f $(melt_default_modules_list)-$(melt_default_variant).modlis $(notdir $@) -#@ from melt-build.tpl line 749 +#@ from melt-build.tpl line 750 ## MELT various variants of module lists -#@ from melt-build.tpl line 753 +#@ from melt-build.tpl line 754 ### quicklybuilt default module list $(melt_default_modules_list)-quicklybuilt.modlis: melt-all-modules melt-modules/ $(wildcard melt-modules/*.quicklybuilt.so) @echo building quicklybuilt module list $@ @@ -5202,7 +5214,7 @@ $(melt_default_modules_list)-quicklybuilt.modlis: melt-all-modules melt-module $(melt_move_if_change) $@-tmp $@ -#@ from melt-build.tpl line 753 +#@ from melt-build.tpl line 754 ### optimized default module list $(melt_default_modules_list)-optimized.modlis: melt-all-modules melt-modules/ $(wildcard melt-modules/*.optimized.so) @echo building optimized module list $@ @@ -5228,7 +5240,7 @@ $(melt_default_modules_list)-optimized.modlis: melt-all-modules melt-modules/ $(melt_move_if_change) $@-tmp $@ -#@ from melt-build.tpl line 753 +#@ from melt-build.tpl line 754 ### debugnoline default module list $(melt_default_modules_list)-debugnoline.modlis: melt-all-modules melt-modules/ $(wildcard melt-modules/*.debugnoline.so) @echo building debugnoline module list $@ @@ -5255,12 +5267,12 @@ $(melt_default_modules_list)-debugnoline.modlis: melt-all-modules melt-modules -#@ from melt-build.tpl line 769 +#@ from melt-build.tpl line 770 ### MELT upgrade .PHONY: warmelt-upgrade-translator meltrun-generate -#@ from melt-build.tpl line 774 +#@ from melt-build.tpl line 775 ####### generate the runtime support files meltrunsup.h meltrunsup-inc.c meltrun-generate: $(WARMELT_LAST) $(WARMELT_LAST_MODLIS) $(WARMELT_LAST_STAGESTAMP) empty-file-for-melt.c \ $(melt_make_cc1_dependency) @@ -5286,7 +5298,7 @@ meltrun-generate: $(WARMELT_LAST) $(WARMELT_LAST_MODLIS) $(WARMELT_LAST_STAGEST ###### generate the translator files warmelt*.c -#@ from melt-build.tpl line 800 +#@ from melt-build.tpl line 801 warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-generate \ $(MELT_LAST_STAGE)/warmelt-first.c \ $(wildcard $(MELT_LAST_STAGE)/warmelt-first+*.c) \ @@ -5312,11 +5324,11 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g ls -l meltrunsup.h meltrunsup-inc.c indent meltrunsup.h indent meltrunsup-inc.c -#@ from melt-build.tpl line 812 +#@ from melt-build.tpl line 813 -#@ from melt-build.tpl line 814 +#@ from melt-build.tpl line 815 @echo upgrading MELT translator warmelt-first -## dont indent the warmelt-first+meltdesc.c or warmelt-first+melttime.h ::: from melt-build.tpl line 816 +## dont indent the warmelt-first+meltdesc.c or warmelt-first+melttime.h ::: from melt-build.tpl line 817 cp $(MELT_LAST_STAGE)/warmelt-first+meltdesc.c $(MELT_LAST_STAGE)/warmelt-first+meltdesc.c~; \ sed s/$(MELT_LAST_STAGE)/MELT-STAGE-ZERO/g $(MELT_LAST_STAGE)/warmelt-first+meltdesc.c > $(srcdir)/melt/generated/warmelt-first+meltdesc.c cp $(MELT_LAST_STAGE)/warmelt-first+melttime.h $(MELT_LAST_STAGE)/warmelt-first+melttime.h~; \ @@ -5335,12 +5347,12 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g $(srcdir)/melt/generated/$$bf ; \ done rm -f $(MELT_STAGE_ZERO)/warmelt-first*.so $(MELT_STAGE_ZERO)/warmelt-first*.c -#@ from melt-build.tpl line 835 +#@ from melt-build.tpl line 836 # -#@ from melt-build.tpl line 814 +#@ from melt-build.tpl line 815 @echo upgrading MELT translator warmelt-base -## dont indent the warmelt-base+meltdesc.c or warmelt-base+melttime.h ::: from melt-build.tpl line 816 +## dont indent the warmelt-base+meltdesc.c or warmelt-base+melttime.h ::: from melt-build.tpl line 817 cp $(MELT_LAST_STAGE)/warmelt-base+meltdesc.c $(MELT_LAST_STAGE)/warmelt-base+meltdesc.c~; \ sed s/$(MELT_LAST_STAGE)/MELT-STAGE-ZERO/g $(MELT_LAST_STAGE)/warmelt-base+meltdesc.c > $(srcdir)/melt/generated/warmelt-base+meltdesc.c cp $(MELT_LAST_STAGE)/warmelt-base+melttime.h $(MELT_LAST_STAGE)/warmelt-base+melttime.h~; \ @@ -5359,12 +5371,12 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g $(srcdir)/melt/generated/$$bf ; \ done rm -f $(MELT_STAGE_ZERO)/warmelt-base*.so $(MELT_STAGE_ZERO)/warmelt-base*.c -#@ from melt-build.tpl line 835 +#@ from melt-build.tpl line 836 # -#@ from melt-build.tpl line 814 +#@ from melt-build.tpl line 815 @echo upgrading MELT translator warmelt-debug -## dont indent the warmelt-debug+meltdesc.c or warmelt-debug+melttime.h ::: from melt-build.tpl line 816 +## dont indent the warmelt-debug+meltdesc.c or warmelt-debug+melttime.h ::: from melt-build.tpl line 817 cp $(MELT_LAST_STAGE)/warmelt-debug+meltdesc.c $(MELT_LAST_STAGE)/warmelt-debug+meltdesc.c~; \ sed s/$(MELT_LAST_STAGE)/MELT-STAGE-ZERO/g $(MELT_LAST_STAGE)/warmelt-debug+meltdesc.c > $(srcdir)/melt/generated/warmelt-debug+meltdesc.c cp $(MELT_LAST_STAGE)/warmelt-debug+melttime.h $(MELT_LAST_STAGE)/warmelt-debug+melttime.h~; \ @@ -5383,12 +5395,12 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g $(srcdir)/melt/generated/$$bf ; \ done rm -f $(MELT_STAGE_ZERO)/warmelt-debug*.so $(MELT_STAGE_ZERO)/warmelt-debug*.c -#@ from melt-build.tpl line 835 +#@ from melt-build.tpl line 836 # -#@ from melt-build.tpl line 814 +#@ from melt-build.tpl line 815 @echo upgrading MELT translator warmelt-macro -## dont indent the warmelt-macro+meltdesc.c or warmelt-macro+melttime.h ::: from melt-build.tpl line 816 +## dont indent the warmelt-macro+meltdesc.c or warmelt-macro+melttime.h ::: from melt-build.tpl line 817 cp $(MELT_LAST_STAGE)/warmelt-macro+meltdesc.c $(MELT_LAST_STAGE)/warmelt-macro+meltdesc.c~; \ sed s/$(MELT_LAST_STAGE)/MELT-STAGE-ZERO/g $(MELT_LAST_STAGE)/warmelt-macro+meltdesc.c > $(srcdir)/melt/generated/warmelt-macro+meltdesc.c cp $(MELT_LAST_STAGE)/warmelt-macro+melttime.h $(MELT_LAST_STAGE)/warmelt-macro+melttime.h~; \ @@ -5407,12 +5419,12 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g $(srcdir)/melt/generated/$$bf ; \ done rm -f $(MELT_STAGE_ZERO)/warmelt-macro*.so $(MELT_STAGE_ZERO)/warmelt-macro*.c -#@ from melt-build.tpl line 835 +#@ from melt-build.tpl line 836 # -#@ from melt-build.tpl line 814 +#@ from melt-build.tpl line 815 @echo upgrading MELT translator warmelt-normal -## dont indent the warmelt-normal+meltdesc.c or warmelt-normal+melttime.h ::: from melt-build.tpl line 816 +## dont indent the warmelt-normal+meltdesc.c or warmelt-normal+melttime.h ::: from melt-build.tpl line 817 cp $(MELT_LAST_STAGE)/warmelt-normal+meltdesc.c $(MELT_LAST_STAGE)/warmelt-normal+meltdesc.c~; \ sed s/$(MELT_LAST_STAGE)/MELT-STAGE-ZERO/g $(MELT_LAST_STAGE)/warmelt-normal+meltdesc.c > $(srcdir)/melt/generated/warmelt-normal+meltdesc.c cp $(MELT_LAST_STAGE)/warmelt-normal+melttime.h $(MELT_LAST_STAGE)/warmelt-normal+melttime.h~; \ @@ -5431,12 +5443,12 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g $(srcdir)/melt/generated/$$bf ; \ done rm -f $(MELT_STAGE_ZERO)/warmelt-normal*.so $(MELT_STAGE_ZERO)/warmelt-normal*.c -#@ from melt-build.tpl line 835 +#@ from melt-build.tpl line 836 # -#@ from melt-build.tpl line 814 +#@ from melt-build.tpl line 815 @echo upgrading MELT translator warmelt-normatch -## dont indent the warmelt-normatch+meltdesc.c or warmelt-normatch+melttime.h ::: from melt-build.tpl line 816 +## dont indent the warmelt-normatch+meltdesc.c or warmelt-normatch+melttime.h ::: from melt-build.tpl line 817 cp $(MELT_LAST_STAGE)/warmelt-normatch+meltdesc.c $(MELT_LAST_STAGE)/warmelt-normatch+meltdesc.c~; \ sed s/$(MELT_LAST_STAGE)/MELT-STAGE-ZERO/g $(MELT_LAST_STAGE)/warmelt-normatch+meltdesc.c > $(srcdir)/melt/generated/warmelt-normatch+meltdesc.c cp $(MELT_LAST_STAGE)/warmelt-normatch+melttime.h $(MELT_LAST_STAGE)/warmelt-normatch+melttime.h~; \ @@ -5455,12 +5467,12 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g $(srcdir)/melt/generated/$$bf ; \ done rm -f $(MELT_STAGE_ZERO)/warmelt-normatch*.so $(MELT_STAGE_ZERO)/warmelt-normatch*.c -#@ from melt-build.tpl line 835 +#@ from melt-build.tpl line 836 # -#@ from melt-build.tpl line 814 +#@ from melt-build.tpl line 815 @echo upgrading MELT translator warmelt-genobj -## dont indent the warmelt-genobj+meltdesc.c or warmelt-genobj+melttime.h ::: from melt-build.tpl line 816 +## dont indent the warmelt-genobj+meltdesc.c or warmelt-genobj+melttime.h ::: from melt-build.tpl line 817 cp $(MELT_LAST_STAGE)/warmelt-genobj+meltdesc.c $(MELT_LAST_STAGE)/warmelt-genobj+meltdesc.c~; \ sed s/$(MELT_LAST_STAGE)/MELT-STAGE-ZERO/g $(MELT_LAST_STAGE)/warmelt-genobj+meltdesc.c > $(srcdir)/melt/generated/warmelt-genobj+meltdesc.c cp $(MELT_LAST_STAGE)/warmelt-genobj+melttime.h $(MELT_LAST_STAGE)/warmelt-genobj+melttime.h~; \ @@ -5479,12 +5491,12 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g $(srcdir)/melt/generated/$$bf ; \ done rm -f $(MELT_STAGE_ZERO)/warmelt-genobj*.so $(MELT_STAGE_ZERO)/warmelt-genobj*.c -#@ from melt-build.tpl line 835 +#@ from melt-build.tpl line 836 # -#@ from melt-build.tpl line 814 +#@ from melt-build.tpl line 815 @echo upgrading MELT translator warmelt-outobj -## dont indent the warmelt-outobj+meltdesc.c or warmelt-outobj+melttime.h ::: from melt-build.tpl line 816 +## dont indent the warmelt-outobj+meltdesc.c or warmelt-outobj+melttime.h ::: from melt-build.tpl line 817 cp $(MELT_LAST_STAGE)/warmelt-outobj+meltdesc.c $(MELT_LAST_STAGE)/warmelt-outobj+meltdesc.c~; \ sed s/$(MELT_LAST_STAGE)/MELT-STAGE-ZERO/g $(MELT_LAST_STAGE)/warmelt-outobj+meltdesc.c > $(srcdir)/melt/generated/warmelt-outobj+meltdesc.c cp $(MELT_LAST_STAGE)/warmelt-outobj+melttime.h $(MELT_LAST_STAGE)/warmelt-outobj+melttime.h~; \ @@ -5503,12 +5515,12 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g $(srcdir)/melt/generated/$$bf ; \ done rm -f $(MELT_STAGE_ZERO)/warmelt-outobj*.so $(MELT_STAGE_ZERO)/warmelt-outobj*.c -#@ from melt-build.tpl line 835 +#@ from melt-build.tpl line 836 # -#@ from melt-build.tpl line 814 +#@ from melt-build.tpl line 815 @echo upgrading MELT translator warmelt-modes -## dont indent the warmelt-modes+meltdesc.c or warmelt-modes+melttime.h ::: from melt-build.tpl line 816 +## dont indent the warmelt-modes+meltdesc.c or warmelt-modes+melttime.h ::: from melt-build.tpl line 817 cp $(MELT_LAST_STAGE)/warmelt-modes+meltdesc.c $(MELT_LAST_STAGE)/warmelt-modes+meltdesc.c~; \ sed s/$(MELT_LAST_STAGE)/MELT-STAGE-ZERO/g $(MELT_LAST_STAGE)/warmelt-modes+meltdesc.c > $(srcdir)/melt/generated/warmelt-modes+meltdesc.c cp $(MELT_LAST_STAGE)/warmelt-modes+melttime.h $(MELT_LAST_STAGE)/warmelt-modes+melttime.h~; \ @@ -5527,18 +5539,18 @@ warmelt-upgrade-translator: $(WARMELT_LAST) $(WARMELT_LAST_STAGESTAMP) meltrun-g $(srcdir)/melt/generated/$$bf ; \ done rm -f $(MELT_STAGE_ZERO)/warmelt-modes*.so $(MELT_STAGE_ZERO)/warmelt-modes*.c -#@ from melt-build.tpl line 835 +#@ from melt-build.tpl line 836 # cp -v meltrunsup*.[ch] $(srcdir)/melt/generated/ -#@ from melt-build.tpl line 839 +#@ from melt-build.tpl line 840 ### Generated MELT documentation -#@ from melt-build.tpl line 846 +#@ from melt-build.tpl line 847 meltgendoc.texi: $(melt_default_modules_list).modlis \ melt-sources/warmelt-first.melt \ melt-sources/warmelt-base.melt \ @@ -5574,7 +5586,7 @@ xtramelt-ana-base.melt,xtramelt-ana-simple.melt,xtramelt-c-generator.melt,xtrame -### MELT cleanup from melt-build.tpl line 871 +### MELT cleanup from melt-build.tpl line 872 .PHONY: melt-clean melt-clean: rm -rf *melt*.args melt-workdir melt-stage0-* melt-sayhello* \ @@ -5585,5 +5597,5 @@ melt-clean: melt-stage3 \ melt-sources melt-modules -#@ from melt-build.tpl line 880 +#@ from melt-build.tpl line 881 ## eof melt-build.mk generated from melt-build.tpl & melt-melt-build.def diff --git a/gcc/melt-build.tpl b/gcc/melt-build.tpl index 8ff1094dc45..6c41c00aae1 100644 --- a/gcc/melt-build.tpl +++ b/gcc/melt-build.tpl @@ -576,19 +576,19 @@ melt-modules/[+base+].quicklybuilt.so: melt-sources/[+base+].c \ #@ [+ (. (tpl-file-line))+] -[+FOR variant IN quicklybuilt optimized debugnoline+] -#@ [+ (. (tpl-file-line))+] -#### melt-sources warmelt-[+variant+] is the sequence of translator files: -melt-sources/warmelt-[+variant+].modlis: [+FOR melt_translator_file " \\\n"+]melt-modules/[+base+].optimized.so [+ENDFOR melt_translator_file+] - @echo building [+variant+] module list $@ [+ (. (tpl-file-line))+] - date +"# MELT warmelt-[+variant+] list $@ generated %F" > $@-tmp - echo "# [+variant+] translator files" >> $@-tmp -[+FOR melt_translator_file+] echo [+base+].[+variant+] >> $@-tmp +[+FOR flavor IN quicklybuilt optimized debugnoline+] +#@ [+ (. (tpl-file-line))+] +#### melt-sources warmelt-[+flavor+] is the sequence of translator files: +melt-sources/warmelt-[+flavor+].modlis: [+FOR melt_translator_file " \\\n"+]melt-modules/[+base+].optimized.so [+ENDFOR melt_translator_file+] + @echo building [+flavor+] module list $@ [+ (. (tpl-file-line))+] + date +"# MELT warmelt-[+flavor+] list $@ generated %F" > $@-tmp + echo "# [+flavor+] translator files" >> $@-tmp +[+FOR melt_translator_file+] echo [+base+].[+flavor+] >> $@-tmp [+ENDFOR melt_translator_file+] echo "# end $@" >> $@-tmp $(melt_move_if_change) $@-tmp $@ -[+ENDFOR variant+] +[+ENDFOR flavor+] #### melt-sources application files [+ (define prevapplbase (list)) +] @@ -606,7 +606,7 @@ melt-sources/[+base+].melt: $(melt_make_source_dir)/[+base+].melt ## to exercise the optimized warmelt... melt-sources/[+base+].c: \ melt-sources/[+base+].melt \ - melt-sources/warmelt-optimized.modlis melt-sources/warmelt-quicklybuilt.modlis \ + melt-sources/warmelt-quicklybuilt.modlis melt-sources/warmelt-optimized.modlis \ melt-sources-directory.stamp \ [+FOR includeload +] melt-sources/[+includeload+] [+ENDFOR includeload+] \ @@ -641,7 +641,7 @@ melt-sources/[+base+].c: \ #@ [+ (. (tpl-file-line))+] ## melt application [+base+] various flavors of modules -[+FOR applflavor IN "optimized" "quicklybuilt" "debugnoline" +] +[+FOR applflavor IN "quicklybuilt" "optimized" "debugnoline" +] ## melt application [+base+] flavor [+applflavor+] [+ (. (tpl-file-line))+] melt-modules/[+base+].[+applflavor+].so: melt-sources-directory.stamp \ melt-sources/[+base+].c melt-modules-directory.stamp melt-workdir-directory.stamp \ @@ -655,6 +655,7 @@ melt-modules/[+base+].[+applflavor+].so: melt-sources-directory.stamp \ GCCMELT_MODULE_SOURCEBASE=melt-sources/[+base+] \ GCCMELT_MODULE_BINARYBASE=melt-modules/[+base+] +#@ [+ (. (tpl-file-line))+] [+base+].[+applflavor+] [+ENDFOR applflavor+] #@ [+ (. (tpl-file-line))+] [+ (define prevapplbase (cons (get "base") prevapplbase)) +] diff --git a/gcc/melt-run.proto.h b/gcc/melt-run.proto.h index a3225e997ed..5ded95b3be4 100644 --- a/gcc/melt-run.proto.h +++ b/gcc/melt-run.proto.h @@ -56,6 +56,12 @@ along with GCC; see the file COPYING3. If not see #include "ggc.h" #include "cgraph.h" +#ifndef MELT_GCC_VERSION +/* Actually, the generated melt-run.h contains a number like 4007 for + GCC 4.7 etc. This is the version of the GCC using this MELT. */ +#define MELT_GCC_VERSION YY +#endif + /* Headers from c-family/ should be included directly with GCC4.6, but not with GCC 4.7 or when compiling with a C++ compiler. */ #if defined(GCCPLUGIN_VERSION) || MELT_GCC_VERSION>4006 || defined(__cplusplus) diff --git a/gcc/melt-runtime.c b/gcc/melt-runtime.c index 4413c11d5c6..acc9b13b1b3 100644 --- a/gcc/melt-runtime.c +++ b/gcc/melt-runtime.c @@ -12287,13 +12287,17 @@ melt_val2passflag(melt_ptr_t val_p) WHENFLAG(PROP_cfglayout); WHENFLAG(PROP_trees); /* likewise for TODO flags */ - WHENFLAG(TODO_dump_func); +#ifdef TODO_dump_func + WHENFLAG(TODO_dump_func); /* not defined in GCC 4.8 */ +#endif /*TODO_dump_func*/ WHENFLAG(TODO_ggc_collect); WHENFLAG(TODO_verify_ssa); WHENFLAG(TODO_verify_flow); WHENFLAG(TODO_verify_stmts); WHENFLAG(TODO_cleanup_cfg); - WHENFLAG(TODO_dump_cgraph); +#ifdef TODO_dump_cgraph + WHENFLAG(TODO_dump_cgraph); /* not defined in GCC 4.8 */ +#endif /*TODO_dump_cgraph*/ WHENFLAG(TODO_remove_functions); WHENFLAG(TODO_rebuild_frequencies); WHENFLAG(TODO_verify_rtl_sharing); diff --git a/gcc/melt/warmelt-base.melt b/gcc/melt/warmelt-base.melt index 112810ea271..62b30e050b6 100644 --- a/gcc/melt/warmelt-base.melt +++ b/gcc/melt/warmelt-base.melt @@ -3147,7 +3147,7 @@ typedef struct meltroutine_st *meltroutine_ptr_t; dst->buflenix = src->buflenix; if (blen > 0) { -#if BUILDING_GCC_VERSION > 4005 +#if BUILDING_GCC_VERSION > 4005 || GCCPLUGIN_VERSION > 4005 || MELT_GCC_VERSION > 4005 dst->bufzn = CONST_CAST (char *, ggc_alloc_string (src->bufzn, blen+1)); #else /*GCC 4.5*/ dst->bufzn = (char *) ggc_alloc_cleared (1 + blen); diff --git a/gcc/melt/warmelt-genobj.melt b/gcc/melt/warmelt-genobj.melt index 439642459e7..bd0310ccc96 100644 --- a/gcc/melt/warmelt-genobj.melt +++ b/gcc/melt/warmelt-genobj.melt @@ -2689,7 +2689,7 @@ $SBUF.}# (statstr (let ( (sbu (make_strbuf discr_strbuf)) ) (put_int boxcntciter cnt) - (add2sbuf_strconst sbu "cit") + (add2sbuf_strconst sbu "meltcit") (add2sbuf_longdec sbu cnt) (add2sbuf_strconst sbu "__") (add2sbuf_cident sbu (unsafe_get_field :named_name nstatsy)) diff --git a/gcc/melt/warmelt-outobj.melt b/gcc/melt/warmelt-outobj.melt index 49a788f0c03..57e15b7eeba 100644 --- a/gcc/melt/warmelt-outobj.melt +++ b/gcc/melt/warmelt-outobj.melt @@ -4693,7 +4693,7 @@ $MODCTX is the module context, and $IX is the index.}# (replmap (make_mapobject discr_map_objects (*i 2 (+i 3 (multiple_length citstaformals))))) (repstatnam (let ( (nbuf (make_strbuf discr_strbuf)) ) - (add2out nbuf "citstate_" ix "_") + (add2out nbuf "meltcitstate_" ix "_") (add2sbuf_cident nbuf (get_field :named_name citstate)) (strbuf2string discr_verbatim_string nbuf))) ) diff --git a/gcc/melt/xtramelt-ana-base.melt b/gcc/melt/xtramelt-ana-base.melt index af8bbc85339..60f5f745fa5 100644 --- a/gcc/melt/xtramelt-ana-base.melt +++ b/gcc/melt/xtramelt-ana-base.melt @@ -4202,24 +4202,39 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar () ; startformals eachcgrfun ;state symbol (:tree funtree :gimple_seq funbody) ;local formals + :doc #{$EACH_CGRAPH_FUN_BODY iterates on every cgraph_node which is + a function declared as $FUNTREE with a body $FUNBODY.}# ;; before expansion - #{ /* $EACHCGRFUN + */ - struct cgraph_node *$eachcgrfun#_nd = NULL; - for ($eachcgrfun#_nd = cgraph_nodes; - $eachcgrfun#_nd != NULL; - $eachcgrfun#_nd = $eachcgrfun#_nd->next) { - tree $eachcgrfun#_dcl = NULL; - gimple_seq $eachcgrfun#_bdy = NULL; - $eachcgrfun#_dcl = $eachcgrfun#_nd->decl; - if (!$eachcgrfun#_dcl) continue; - if (TREE_CODE($eachcgrfun#_dcl) != FUNCTION_DECL) continue; - $eachcgrfun#_bdy = gimple_body($eachcgrfun#_dcl); - if (!$eachcgrfun#_bdy) continue; - $funtree = $eachcgrfun#_dcl; - $funbody = $eachcgrfun#_bdy; + #{ /* each_cgraph_fun_body $EACHCGRFUN + */ + struct cgraph_node *$EACHCGRFUN#_nd = NULL; + /* each_cgraph_fun_body $EACHCGRFUN; GCC 4.8 has FOR_EACH_DEFINED_FUNCTION */ +#ifdef FOR_EACH_DEFINED_FUNCTION + FOR_EACH_DEFINED_FUNCTION($EACHCGRFUN#_nd) +#else /* for GCC 4.6 & 4.7 without FOR_EACH_DEFINED_FUNCTION */ + for ($EACHCGRFUN#_nd = cgraph_nodes; + $EACHCGRFUN#_nd != NULL; + $EACHCGRFUN#_nd = $EACHCGRFUN#_nd->next) +#endif /* FOR_EACH_DEFINED_FUNCTION $EACHCGRFUN */ + { /* each_cgraph_fun_body $EACHCGRFUN inside for */ + tree $EACHCGRFUN#_dcl = NULL; + gimple_seq $EACHCGRFUN#_bdy = NULL; + /* in each_cgraph_fun_body $EACHCGRFUN; + notice that GCCPLUGIN_VERSION exists from GCC 4.7, but not in GCC 4.6 */ +#if (defined(GCCPLUGIN_VERSION) && (GCCPLUGIN_VERSION >= 4008)) \ + || (defined (MELT_GCC_VERSION) && (MELT_GCC_VERSION >= 4008)) + $EACHCGRFUN#_dcl = $EACHCGRFUN#_nd->symbol.decl; +#else /* GCC 4.7 or older */ + $EACHCGRFUN#_dcl = $EACHCGRFUN#_nd->decl; +#endif /* older than GCC 4.8 */ + if (!$EACHCGRFUN#_dcl) continue; + if (TREE_CODE($EACHCGRFUN#_dcl) != FUNCTION_DECL) continue; + $EACHCGRFUN#_bdy = gimple_body($EACHCGRFUN#_dcl); + if (!$EACHCGRFUN#_bdy) continue; + $FUNTREE = $EACHCGRFUN#_dcl; + $FUNBODY = $EACHCGRFUN#_bdy; }# ;;after expansion - #{ } /* $EACHCGRFUN - */ }# ) + #{ } /* each_cgraph_fun_body $EACHCGRFUN - */ }# ) ;;; iterate on every cgraph_node which is a function with a CFG and an @@ -4229,16 +4244,29 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar eachcgrafunentrblo ;state symbol (:tree funtree :basic_block funentrybb funexitbb) ;local formals ;;before expansion - #{ /* $EACHCGRAFUNENTRBLO + */ + #{ /* each_cgraph_fun_entryblock $EACHCGRAFUNENTRBLO + */ struct cgraph_node *$EACHCGRAFUNENTRBLO#_nd = NULL; + /* each_cgraph_fun_entryblock $EACHCGRAFUNENTRBLO; GCC 4.8 has FOR_EACH_DEFINED_FUNCTION */ +#ifdef FOR_EACH_DEFINED_FUNCTION + FOR_EACH_DEFINED_FUNCTION($EACHCGRAFUNENTRBLO#_nd) +#else /* for GCC 4.6 & 4.7 without FOR_EACH_DEFINED_FUNCTION */ for ($EACHCGRAFUNENTRBLO#_nd = cgraph_nodes; - $EACHCGRAFUNENTRBLO#_nd != NULL; - $EACHCGRAFUNENTRBLO#_nd = $EACHCGRAFUNENTRBLO#_nd->next) { + $EACHCGRAFUNENTRBLO#_nd != NULL; + $EACHCGRAFUNENTRBLO#_nd = $EACHCGRAFUNENTRBLO#_nd->next) +#endif /* FOR_EACH_DEFINED_FUNCTION $EACHCGRAFUNENTRBLO */ + { tree $EACHCGRAFUNENTRBLO#_dcl = NULL; basic_block $EACHCGRAFUNENTRBLO#_entrybb = NULL; basic_block $EACHCGRAFUNENTRBLO#_exitbb = NULL; struct function *$EACHCGRAFUNENTRBLO#_fun = NULL; + /* in each_cgraph_fun_entryblock $EACHCGRAFUNENTRBLO; + notice that GCCPLUGIN_VERSION exists from GCC 4.7, but not in GCC 4.6 */ +#if (defined(GCCPLUGIN_VERSION) && (GCCPLUGIN_VERSION >= 4008)) \ + || (defined (MELT_GCC_VERSION) && (MELT_GCC_VERSION >= 4008)) + $EACHCGRAFUNENTRBLO#_dcl = $EACHCGRAFUNENTRBLO#_nd->symbol.decl; +#else /* GCC 4.7 or older */ $EACHCGRAFUNENTRBLO#_dcl = $EACHCGRAFUNENTRBLO#_nd->decl; +#endif /* older than GCC 4.8 */ if (! $EACHCGRAFUNENTRBLO#_dcl) continue; if (TREE_CODE($EACHCGRAFUNENTRBLO#_dcl) != FUNCTION_DECL) continue; $EACHCGRAFUNENTRBLO#_fun = DECL_STRUCT_FUNCTION($EACHCGRAFUNENTRBLO#_dcl); @@ -4257,7 +4285,7 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar $funexitbb = $EACHCGRAFUNENTRBLO#_exitbb; }# ;;after expansion - #{ } /* $EACHCGRAFUNENTRBLO - */ }# ) + #{ } /* each_cgraph_fun_entryblock $EACHCGRAFUNENTRBLO - */ }# ) ;; iterator on every cgraph_node which is a function with a CFG, and @@ -4267,18 +4295,36 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar () ;start formals eachcgrafuncfg (:tree funtree :basic_block funentrybb funexitbb :value bbtup tmpv) + :doc #{$EACH_CGRAPH_FUN_CALL_FLOW_GRAPH iterates on every callgraph + function with a body and a control flow graph, giving the + declaration $FUNTREE, the entry and exit basic blocks $FUNENTRYBB + and $FUNEXITBB, the tuple of boxed basic blocks $BBTUP, and needs an + internal temporary value $TMPV}# ;; before expansion - #{ /* $EACHCGRAFUNCFG + */ + #{ /* each_cgraph_fun_call_flow_graph $EACHCGRAFUNCFG + */ struct cgraph_node *$EACHCGRAFUNCFG#_nd = NULL; + /* each_cgraph_fun_call_flow_graph loop $EACHCGRAFUNCFG; GCC 4.8 has FOR_EACH_DEFINED_FUNCTION */ +#ifdef FOR_EACH_DEFINED_FUNCTION + FOR_EACH_DEFINED_FUNCTION($EACHCGRAFUNCFG#_nd) +#else /* for GCC 4.6 & 4.7 without FOR_EACH_DEFINED_FUNCTION */ for ($EACHCGRAFUNCFG#_nd = cgraph_nodes; $EACHCGRAFUNCFG#_nd != NULL; - $EACHCGRAFUNCFG#_nd = $EACHCGRAFUNCFG#_nd->next) { + $EACHCGRAFUNCFG#_nd = $EACHCGRAFUNCFG#_nd->next) +#endif /* FOR_EACH_DEFINED_FUNCTION each_cgraph_fun_call_flow_graph $EACHCGRAFUNCFG */ + { tree $EACHCGRAFUNCFG#_dcl = NULL; basic_block $EACHCGRAFUNCFG#_curbb = NULL; struct function *$EACHCGRAFUNCFG#_fun = NULL; int $EACHCGRAFUNCFG#_n_bb = 0; int $EACHCGRAFUNCFG#_ix = 0; + /* inside each_cgraph_fun_call_flow_graph loop $EACHCGRAFUNCFG; + notice that GCCPLUGIN_VERSION exists from GCC 4.7, but not in GCC 4.6 */ +#if (defined(GCCPLUGIN_VERSION) && (GCCPLUGIN_VERSION >= 4008)) \ + || (defined (MELT_GCC_VERSION) && (MELT_GCC_VERSION >= 4008)) + $EACHCGRAFUNCFG#_dcl = $EACHCGRAFUNCFG#_nd->symbol.decl; +#else /* GCC 4.7 or older */ $EACHCGRAFUNCFG#_dcl = $EACHCGRAFUNCFG#_nd->decl; +#endif /* older than GCC 4.8 */ if (! $EACHCGRAFUNCFG#_dcl) continue; if (TREE_CODE($EACHCGRAFUNCFG#_dcl) != FUNCTION_DECL) @@ -4288,11 +4334,11 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar continue; debugeprintf("$EACHCGRAFUNCFG#_fun %p", $EACHCGRAFUNCFG#_fun); $TMPV = NULL; - /* this assert fails when in a pass without control flow graph */ + /* each_cgraph_fun_call_flow_graph this assert fails when in a pass without control flow graph */ melt_assertmsg ("no cfg in each_cgraph_fun_call_flow_graph $EACHCGRAFUNCFG", $EACHCGRAFUNCFG#_fun->cfg != NULL); $EACHCGRAFUNCFG#_n_bb = n_basic_blocks_for_function ($EACHCGRAFUNCFG#_fun); - /* $EACHCGRAFUNCFG create the tuple of basic blocks */ + /* each_cgraph_fun_call_flow_graph $EACHCGRAFUNCFG create the tuple of basic blocks */ $BBTUP = meltgc_new_multiple ((meltobject_ptr_t) MELT_PREDEF (DISCR_MULTIPLE), $EACHCGRAFUNCFG#_n_bb); @@ -4310,11 +4356,11 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar meltgc_multiple_put_nth ((melt_ptr_t)$BBTUP, $EACHCGRAFUNCFG#_ix, $TMPV); - } /* $EACHCGRAFUNCFG done bb tuple */ + } /* each_cgraph_fun_call_flow_graph $EACHCGRAFUNCFG done bb tuple */ $TMPV = NULL; }# ;; after expansion - #{ /* $EACHCGRAFUNCFG - */ + #{ /* each_cgraph_fun_call_flow_graph $EACHCGRAFUNCFG - */ $TMPV = NULL; } }# @@ -4322,16 +4368,21 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar ;;;;;;;;;;;;;;;; ;;;; iterate on every cgraph_node which is a declaration +(gccif + ("4.6." "4.7.") (defciterator each_cgraph_decl () eachcgrdcl (:tree decl) + :doc #{$EACH_CGRAPH_DECL iterates on every cgraph_node which is a declaration $DECL; only for GCC 4.6 or 4.7}# ;;before expansion #{ /* each_cgraph_decl $EACHCGRDCL */ struct cgraph_node *$EACHCGRDCL#_nd = NULL; + /* each_cgraph_decl $EACHCGRDCL loop */ for ($EACHCGRDCL#_nd = cgraph_nodes; - $EACHCGRDCL#_nd != NULL; - $EACHCGRDCL#_nd = $EACHCGRDCL#_nd->next) { + $EACHCGRDCL#_nd != NULL; + $EACHCGRDCL#_nd = $EACHCGRDCL#_nd->next) + { tree $EACHCGRDCL#_dcl = NULL; $EACHCGRDCL#_dcl = $EACHCGRDCL#_nd->decl; $DECL = (tree) NULL; @@ -4342,6 +4393,8 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar #{ /* end each_cgraph_decl $EACHCGRDCL */ $DECL = (tree)NULL; } }# ) +(export_values each_cgraph_decl) +) ;end gccif 4.6 & 4.7 ;; iterator to get the current cfun decl @@ -4349,6 +4402,7 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar () withcfundecl (:tree cfundecl) + :doc #{iterator done one giving the current $CFUNDECL, if cfun exists}# #{ /*starting with_cfun_decl $WITHCFUNDECL*/ $CFUNDECL = (tree) NULL; if (cfun) { @@ -4391,7 +4445,9 @@ arguments $ARG0 & $ARG1 & $ARG2 & $ARG3 & $ARG4 & $ARG5 & $ARG6 and number of ar ( ;local formals :basic_block cfunbb :tree cfundecl - ) + ) + :doc #{$EACH_BB_CFUN iterates on every basic block $CFUNBB of the +current function and gives its declaration in $CFUNDECL}# ;;before expansion #{ /* start each_bb_cfun $EACHBBCFUN */ const int $EACHBBCFUN#_line = __LINE__; $CFUNBB = (basic_block) NULL; @@ -5028,7 +5084,6 @@ and discriminant $DIS, usually $DISCR_MIXED_LOCATION.}# each_bb_cfun each_local_decl_cfun each_bb_current_fun - each_cgraph_decl each_cgraph_fun_body each_cgraph_fun_call_flow_graph each_cgraph_fun_entryblock diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 32f7b1af720..6fed845690e 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,8 @@ +2012-04-20 Jan Hubicka <jh@suse.cz> + + * objc-acct.c (mark_referenced_methods); Use + cgraph_mark_force_output_node. + 2012-03-21 Steven Bosscher <steven@gcc.gnu.org> * objc-act (objc_build_ivar_assignment): Do not call assemble_external. diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 78a3cee4abe..ec07971f02d 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -4625,7 +4625,7 @@ mark_referenced_methods (void) chain = CLASS_CLS_METHODS (impent->imp_context); while (chain) { - cgraph_mark_needed_node ( + cgraph_mark_force_output_node ( cgraph_get_create_node (METHOD_DEFINITION (chain))); chain = DECL_CHAIN (chain); } @@ -4633,7 +4633,7 @@ mark_referenced_methods (void) chain = CLASS_NST_METHODS (impent->imp_context); while (chain) { - cgraph_mark_needed_node ( + cgraph_mark_force_output_node ( cgraph_get_create_node (METHOD_DEFINITION (chain))); chain = DECL_CHAIN (chain); } diff --git a/gcc/optabs.c b/gcc/optabs.c index 565db428045..080061a1f57 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -3030,6 +3030,47 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target, /* Widening (or narrowing) bswap needs special treatment. */ if (unoptab == bswap_optab) { + /* HImode is special because in this mode BSWAP is equivalent to ROTATE + or ROTATERT. First try these directly; if this fails, then try the + obvious pair of shifts with allowed widening, as this will probably + be always more efficient than the other fallback methods. */ + if (mode == HImode) + { + rtx last, temp1, temp2; + + if (optab_handler (rotl_optab, mode) != CODE_FOR_nothing) + { + temp = expand_binop (mode, rotl_optab, op0, GEN_INT (8), target, + unsignedp, OPTAB_DIRECT); + if (temp) + return temp; + } + + if (optab_handler (rotr_optab, mode) != CODE_FOR_nothing) + { + temp = expand_binop (mode, rotr_optab, op0, GEN_INT (8), target, + unsignedp, OPTAB_DIRECT); + if (temp) + return temp; + } + + last = get_last_insn (); + + temp1 = expand_binop (mode, ashl_optab, op0, GEN_INT (8), NULL_RTX, + unsignedp, OPTAB_WIDEN); + temp2 = expand_binop (mode, lshr_optab, op0, GEN_INT (8), NULL_RTX, + unsignedp, OPTAB_WIDEN); + if (temp1 && temp2) + { + temp = expand_binop (mode, ior_optab, temp1, temp2, target, + unsignedp, OPTAB_WIDEN); + if (temp) + return temp; + } + + delete_insns_since (last); + } + temp = widen_bswap (mode, op0, target); if (temp) return temp; @@ -3222,10 +3263,10 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target, /* For certain operations, we need not actually extend the narrow operand, as long as we will truncate the results to the same narrowness. */ - xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, (unoptab == neg_optab - || unoptab == one_cmpl_optab) + || unoptab == one_cmpl_optab + || unoptab == bswap_optab) && mclass == MODE_INT); temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX, @@ -3240,6 +3281,20 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target, - GET_MODE_PRECISION (mode)), target, true, OPTAB_DIRECT); + /* Likewise for bswap. */ + if (unoptab == bswap_optab && temp != 0) + { + gcc_assert (GET_MODE_PRECISION (wider_mode) + == GET_MODE_BITSIZE (wider_mode) + && GET_MODE_PRECISION (mode) + == GET_MODE_BITSIZE (mode)); + + temp = expand_shift (RSHIFT_EXPR, wider_mode, temp, + GET_MODE_BITSIZE (wider_mode) + - GET_MODE_BITSIZE (mode), + NULL_RTX, true); + } + if (temp) { if (mclass != MODE_INT) diff --git a/gcc/opts.c b/gcc/opts.c index 6532b56d752..4e8b3c033fe 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1499,6 +1499,10 @@ common_handle_option (struct gcc_options *opts, case OPT_fdiagnostics_show_location_: diagnostic_prefixing_rule (dc) = (diagnostic_prefixing_rule_t) value; break; + + case OPT_fdiagnostics_show_caret: + dc->show_caret = value; + break; case OPT_fdiagnostics_show_option: dc->show_option_requested = value; @@ -1539,6 +1543,7 @@ common_handle_option (struct gcc_options *opts, case OPT_fmessage_length_: pp_set_line_maximum_length (dc->printer, value); + diagnostic_set_caret_max_width (dc, value); break; case OPT_fpack_struct_: diff --git a/gcc/passes.c b/gcc/passes.c index 2c81784f44d..de606f17b9f 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -281,6 +281,107 @@ finish_optimization_passes (void) timevar_pop (TV_DUMP); } +static unsigned int +execute_all_early_local_passes (void) +{ + /* Once this pass (and its sub-passes) are complete, all functions + will be in SSA form. Technically this state change is happening + a tad early, since the sub-passes have not yet run, but since + none of the sub-passes are IPA passes and do not create new + functions, this is ok. We're setting this value for the benefit + of IPA passes that follow. */ + if (cgraph_state < CGRAPH_STATE_IPA_SSA) + cgraph_state = CGRAPH_STATE_IPA_SSA; + return 0; +} + +/* Gate: execute, or not, all of the non-trivial optimizations. */ + +static bool +gate_all_early_local_passes (void) +{ + /* Don't bother doing anything if the program has errors. */ + return (!seen_error () && !in_lto_p); +} + +struct simple_ipa_opt_pass pass_early_local_passes = +{ + { + SIMPLE_IPA_PASS, + "early_local_cleanups", /* name */ + gate_all_early_local_passes, /* gate */ + execute_all_early_local_passes, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_EARLY_LOCAL, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_remove_functions /* todo_flags_finish */ + } +}; + +/* Gate: execute, or not, all of the non-trivial optimizations. */ + +static bool +gate_all_early_optimizations (void) +{ + return (optimize >= 1 + /* Don't bother doing anything if the program has errors. */ + && !seen_error ()); +} + +struct gimple_opt_pass pass_all_early_optimizations = +{ + { + GIMPLE_PASS, + "early_optimizations", /* name */ + gate_all_early_optimizations, /* gate */ + NULL, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_NONE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + } +}; + +/* Gate: execute, or not, all of the non-trivial optimizations. */ + +static bool +gate_all_optimizations (void) +{ + return (optimize >= 1 + /* Don't bother doing anything if the program has errors. + We have to pass down the queue if we already went into SSA */ + && (!seen_error () || gimple_in_ssa_p (cfun))); +} + +struct gimple_opt_pass pass_all_optimizations = +{ + { + GIMPLE_PASS, + "*all_optimizations", /* name */ + gate_all_optimizations, /* gate */ + NULL, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_OPTIMIZE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + } +}; + static bool gate_rest_of_compilation (void) { @@ -602,22 +703,18 @@ dump_passes (void) create_pass_tab(); - n = cgraph_nodes; - while (n) - { - if (DECL_STRUCT_FUNCTION (n->decl)) - { - node = n; - break; - } - n = n->next; - } + FOR_EACH_DEFINED_FUNCTION (n) + if (DECL_STRUCT_FUNCTION (n->symbol.decl)) + { + node = n; + break; + } if (!node) return; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - current_function_decl = node->decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); + current_function_decl = node->symbol.decl; dump_pass_list (all_lowering_passes, 1); dump_pass_list (all_small_ipa_passes, 1); @@ -1561,12 +1658,12 @@ do_per_function (void (*callback) (void *data), void *data) else { struct cgraph_node *node; - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed && gimple_has_body_p (node->decl) - && (!node->clone_of || node->decl != node->clone_of->decl)) + FOR_EACH_DEFINED_FUNCTION (node) + if (gimple_has_body_p (node->symbol.decl) + && (!node->clone_of || node->symbol.decl != node->clone_of->symbol.decl)) { - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - current_function_decl = node->decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); + current_function_decl = node->symbol.decl; callback (data); if (!flag_wpa) { @@ -1613,8 +1710,8 @@ do_per_function_toporder (void (*callback) (void *data), void *data) node->process = 0; if (cgraph_function_with_gimple_body_p (node)) { - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - current_function_decl = node->decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); + current_function_decl = node->symbol.decl; callback (data); free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS); @@ -1765,10 +1862,10 @@ execute_todo (unsigned int flags) cgraph_remove_unreachable_nodes (true, dump_file); } - if ((flags & TODO_dump_cgraph) && dump_file && !current_function_decl) + if ((flags & TODO_dump_symtab) && dump_file && !current_function_decl) { gcc_assert (!cfun); - dump_cgraph (dump_file); + dump_symtab (dump_file); /* Flush the file. If verification fails, we won't be able to close the file before aborting. */ fflush (dump_file); @@ -2240,7 +2337,7 @@ ipa_write_summaries (void) ordering then matches the one IPA-passes get in their stmt_fixup hooks. */ - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); renumber_gimple_stmt_uids (); pop_cfun (); } @@ -2249,8 +2346,8 @@ ipa_write_summaries (void) } vset = varpool_node_set_new (); - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - if (vnode->needed && (!vnode->alias || vnode->alias_of)) + FOR_EACH_DEFINED_VARIABLE (vnode) + if ((!vnode->alias || vnode->alias_of)) varpool_node_set_add (vset, vnode); ipa_write_summaries_1 (set, vset); @@ -2321,9 +2418,9 @@ ipa_write_optimization_summaries (cgraph_node_set set, varpool_node_set vset) For functions newly born at WPA stage we need to initialize the uids here. */ if (node->analyzed - && gimple_has_body_p (node->decl)) + && gimple_has_body_p (node->symbol.decl)) { - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); renumber_gimple_stmt_uids (); pop_cfun (); } @@ -2561,11 +2658,11 @@ function_called_by_processed_nodes_p (void) e; e = e->next_caller) { - if (e->caller->decl == current_function_decl) + if (e->caller->symbol.decl == current_function_decl) continue; if (!cgraph_function_with_gimple_body_p (e->caller)) continue; - if (TREE_ASM_WRITTEN (e->caller->decl)) + if (TREE_ASM_WRITTEN (e->caller->symbol.decl)) continue; if (!e->caller->process && !e->caller->global.inlined_to) break; diff --git a/gcc/predict.c b/gcc/predict.c index c12b45f12de..8ed2e833cf7 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -994,7 +994,7 @@ predict_loops (void) the loop, use it to predict this exit. */ else if (n_exits == 1) { - nitercst = max_stmt_executions_int (loop, false); + nitercst = estimated_stmt_executions_int (loop); if (nitercst < 0) continue; if (nitercst > max) diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h index bb1d156d31d..a7b5a9fbbba 100644 --- a/gcc/pretty-print.h +++ b/gcc/pretty-print.h @@ -201,6 +201,9 @@ struct pretty_print_info #define pp_set_line_maximum_length(PP, L) \ pp_base_set_line_maximum_length (pp_base (PP), L) #define pp_set_prefix(PP, P) pp_base_set_prefix (pp_base (PP), P) +#define pp_get_prefix(PP) pp_base_get_prefix (pp_base (PP)) +static inline const char * +pp_base_get_prefix (const pretty_printer *pp) { return pp->prefix; } #define pp_destroy_prefix(PP) pp_base_destroy_prefix (pp_base (PP)) #define pp_remaining_character_count_for_line(PP) \ pp_base_remaining_character_count_for_line (pp_base (PP)) diff --git a/gcc/reginfo.c b/gcc/reginfo.c index 635312655bc..f3a08f523c2 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -1222,17 +1222,7 @@ reg_scan_mark_refs (rtx x, rtx insn) /* If this is setting a register from a register or from a simple conversion of a register, propagate REG_EXPR. */ if (REG_P (dest) && !REG_ATTRS (dest)) - { - rtx src = SET_SRC (x); - - while (GET_CODE (src) == SIGN_EXTEND - || GET_CODE (src) == ZERO_EXTEND - || GET_CODE (src) == TRUNCATE - || (GET_CODE (src) == SUBREG && subreg_lowpart_p (src))) - src = XEXP (src, 0); - - set_reg_attrs_from_value (dest, src); - } + set_reg_attrs_from_value (dest, SET_SRC (x)); /* ... fall through ... */ diff --git a/gcc/reload.c b/gcc/reload.c index 8420c808073..6994e0d8b9b 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -2258,7 +2258,7 @@ operands_match_p (rtx x, rtx y) if (GET_MODE (x) != GET_MODE (y)) return 0; - /* MEMs refering to different address space are not equivalent. */ + /* MEMs referring to different address space are not equivalent. */ if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) return 0; diff --git a/gcc/rtl.c b/gcc/rtl.c index a812d311820..ec48839f61e 100644 --- a/gcc/rtl.c +++ b/gcc/rtl.c @@ -110,7 +110,8 @@ const enum rtx_class rtx_class[NUM_RTX_CODE] = { const unsigned char rtx_code_size[NUM_RTX_CODE] = { #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) \ - ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE || (ENUM) == CONST_FIXED\ + (((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE \ + || (ENUM) == CONST_FIXED) \ ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT) \ : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)), @@ -380,7 +381,7 @@ rtx_equal_p_cb (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb) if (GET_MODE (x) != GET_MODE (y)) return 0; - /* MEMs refering to different address space are not equivalent. */ + /* MEMs referring to different address space are not equivalent. */ if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) return 0; @@ -519,7 +520,7 @@ rtx_equal_p (const_rtx x, const_rtx y) if (GET_MODE (x) != GET_MODE (y)) return 0; - /* MEMs refering to different address space are not equivalent. */ + /* MEMs referring to different address space are not equivalent. */ if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) return 0; diff --git a/gcc/rtl.def b/gcc/rtl.def index dbf320e7a43..955e8e4709b 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -109,8 +109,8 @@ DEF_RTL_EXPR(INSN_LIST, "insn_list", "ue", RTX_EXTRA) `emit_insn' takes the SEQUENCE apart and makes separate insns. */ DEF_RTL_EXPR(SEQUENCE, "sequence", "E", RTX_EXTRA) -/* Refers to the address of its argument. This is only used in alias.c. */ -DEF_RTL_EXPR(ADDRESS, "address", "e", RTX_MATCH) +/* Represents a non-global base address. This is only used in alias.c. */ +DEF_RTL_EXPR(ADDRESS, "address", "i", RTX_EXTRA) /* ---------------------------------------------------------------------- Expression types used for things in the instruction chain. diff --git a/gcc/rtl.h b/gcc/rtl.h index 915ef136538..1da1792d1a3 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1,6 +1,6 @@ /* Register Transfer Language (RTL) definitions for GCC Copyright (C) 1987, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -1909,6 +1909,7 @@ extern HOST_WIDE_INT get_integer_term (const_rtx); extern rtx get_related_value (const_rtx); extern bool offset_within_block_p (const_rtx, HOST_WIDE_INT); extern void split_const (rtx, rtx *, rtx *); +extern bool unsigned_reg_p (rtx); extern int reg_mentioned_p (const_rtx, const_rtx); extern int count_occurrences (const_rtx, const_rtx, int); extern int reg_referenced_p (const_rtx, const_rtx); @@ -2442,12 +2443,12 @@ extern void add_insn_before (rtx, rtx, struct basic_block_def *); extern void add_insn_after (rtx, rtx, struct basic_block_def *); extern void remove_insn (rtx); extern rtx emit (rtx); -extern rtx delete_insn (rtx); +extern void delete_insn (rtx); extern rtx entry_of_function (void); extern void emit_insn_at_entry (rtx); extern void delete_insn_chain (rtx, rtx, bool); extern rtx unlink_insn_chain (rtx, rtx); -extern rtx delete_insn_and_edges (rtx); +extern void delete_insn_and_edges (rtx); extern rtx gen_lowpart_SUBREG (enum machine_mode, rtx); extern rtx gen_const_mem (enum machine_mode, rtx); extern rtx gen_frame_mem (enum machine_mode, rtx); @@ -2596,7 +2597,7 @@ extern void init_alias_analysis (void); extern void end_alias_analysis (void); extern void vt_equate_reg_base_value (const_rtx, const_rtx); extern bool memory_modified_in_insn_p (const_rtx, const_rtx); -extern rtx find_base_term (rtx); +extern bool may_be_sp_based_p (rtx); extern rtx gen_hard_reg_clobber (enum machine_mode, unsigned int); extern rtx get_reg_known_value (unsigned int); extern bool get_reg_known_equiv_p (unsigned int); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 7c4a49bef09..78365bdb9e1 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -1,7 +1,7 @@ /* Analyze RTL for GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011 Free Software Foundation, Inc. + 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -636,6 +636,25 @@ count_occurrences (const_rtx x, const_rtx find, int count_dest) } +/* Return TRUE if OP is a register or subreg of a register that + holds an unsigned quantity. Otherwise, return FALSE. */ + +bool +unsigned_reg_p (rtx op) +{ + if (REG_P (op) + && REG_EXPR (op) + && TYPE_UNSIGNED (TREE_TYPE (REG_EXPR (op)))) + return true; + + if (GET_CODE (op) == SUBREG + && SUBREG_PROMOTED_UNSIGNED_P (op)) + return true; + + return false; +} + + /* Nonzero if register REG appears somewhere within IN. Also works if REG is not a register; in this case it checks for a subexpression of IN that is Lisp "equal" to REG. */ @@ -3962,7 +3981,7 @@ nonzero_bits1 (const_rtx x, enum machine_mode mode, const_rtx known_x, #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) /* If pointers extend unsigned and this is a pointer in Pmode, say that all the bits above ptr_mode are known to be zero. */ - /* As we do not know which address space the pointer is refering to, + /* As we do not know which address space the pointer is referring to, we can do this only if the target does not support different pointer or address modes depending on the address space. */ if (target_default_pointer_address_modes_p () @@ -4472,7 +4491,7 @@ num_sign_bit_copies1 (const_rtx x, enum machine_mode mode, const_rtx known_x, #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) /* If pointers extend signed and this is a pointer in Pmode, say that all the bits above ptr_mode are known to be sign bit copies. */ - /* As we do not know which address space the pointer is refering to, + /* As we do not know which address space the pointer is referring to, we can do this only if the target does not support different pointer or address modes depending on the address space. */ if (target_default_pointer_address_modes_p () diff --git a/gcc/sel-sched.c b/gcc/sel-sched.c index 2829f60a0cf..6fef60ea0ac 100644 --- a/gcc/sel-sched.c +++ b/gcc/sel-sched.c @@ -1,5 +1,5 @@ /* Instruction scheduling pass. Selective scheduler and pipeliner. - Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 + Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -4265,10 +4265,9 @@ invoke_aftermath_hooks (fence_t fence, rtx best_insn, int issue_more) return issue_more; } -/* Estimate the cost of issuing INSN on DFA state STATE. Write to PEMPTY - true when INSN does not change the processor state. */ +/* Estimate the cost of issuing INSN on DFA state STATE. */ static int -estimate_insn_cost (rtx insn, state_t state, bool *pempty) +estimate_insn_cost (rtx insn, state_t state) { static state_t temp = NULL; int cost; @@ -4278,8 +4277,6 @@ estimate_insn_cost (rtx insn, state_t state, bool *pempty) memcpy (temp, state, dfa_state_size); cost = state_transition (temp, insn); - if (pempty) - *pempty = (memcmp (temp, state, dfa_state_size) == 0); if (cost < 0) return 0; @@ -4310,7 +4307,7 @@ get_expr_cost (expr_t expr, fence_t fence) return 0; } else - return estimate_insn_cost (insn, FENCE_STATE (fence), NULL); + return estimate_insn_cost (insn, FENCE_STATE (fence)); } /* Find the best insn for scheduling, either via max_issue or just take @@ -7023,7 +7020,7 @@ reset_sched_cycles_in_current_ebb (void) { int cost, haifa_cost; int sort_p; - bool asm_p, real_insn, after_stall, all_issued, empty; + bool asm_p, real_insn, after_stall, all_issued; int clock; if (!INSN_P (insn)) @@ -7050,7 +7047,7 @@ reset_sched_cycles_in_current_ebb (void) haifa_cost = 0; } else - haifa_cost = estimate_insn_cost (insn, curr_state, &empty); + haifa_cost = estimate_insn_cost (insn, curr_state); /* Stall for whatever cycles we've stalled before. */ after_stall = 0; @@ -7084,7 +7081,7 @@ reset_sched_cycles_in_current_ebb (void) if (!after_stall && real_insn && haifa_cost > 0 - && estimate_insn_cost (insn, curr_state, NULL) == 0) + && estimate_insn_cost (insn, curr_state) == 0) break; /* When the data dependency stall is longer than the DFA stall, @@ -7096,7 +7093,7 @@ reset_sched_cycles_in_current_ebb (void) if ((after_stall || all_issued) && real_insn && haifa_cost == 0) - haifa_cost = estimate_insn_cost (insn, curr_state, NULL); + haifa_cost = estimate_insn_cost (insn, curr_state); } haifa_clock += i; @@ -7127,8 +7124,14 @@ reset_sched_cycles_in_current_ebb (void) if (real_insn) { + static state_t temp = NULL; + + if (!temp) + temp = xmalloc (dfa_state_size); + memcpy (temp, curr_state, dfa_state_size); + cost = state_transition (curr_state, insn); - if (!empty) + if (memcmp (temp, curr_state, dfa_state_size)) issued_insns++; if (sched_verbose >= 2) diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 1d82a375673..3357ceb1024 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -1140,7 +1140,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) } #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) - /* As we do not know which address space the pointer is refering to, + /* As we do not know which address space the pointer is referring to, we can do this only if the target does not support different pointer or address modes depending on the address space. */ if (target_default_pointer_address_modes_p () @@ -1233,7 +1233,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) } #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) - /* As we do not know which address space the pointer is refering to, + /* As we do not know which address space the pointer is referring to, we can do this only if the target does not support different pointer or address modes depending on the address space. */ if (target_default_pointer_address_modes_p () diff --git a/gcc/stmt.c b/gcc/stmt.c index 93d643a7bf0..8f7b1506eef 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -98,16 +98,6 @@ struct case_node typedef struct case_node case_node; typedef struct case_node *case_node_ptr; -/* These are used by estimate_case_costs and balance_case_nodes. */ - -/* This must be a signed type, and non-ANSI compilers lack signed char. */ -static short cost_table_[129]; -static int use_cost_table; -static int cost_table_initialized; - -/* Special care is needed because we allow -1, but TREE_INT_CST_LOW - is unsigned. */ -#define COST_TABLE(I) cost_table_[(unsigned HOST_WIDE_INT) ((I) + 1)] static int n_occurrences (int, const char *); static bool tree_conflicts_with_clobbers_p (tree, HARD_REG_SET *); @@ -117,7 +107,6 @@ static bool check_unique_operand_names (tree, tree, tree); static char *resolve_operand_name_1 (char *, tree, tree, tree); static void expand_null_return_1 (void); static void expand_value_return (rtx); -static int estimate_case_costs (case_node_ptr); static bool lshift_cheap_p (void); static int case_bit_test_cmp (const void *, const void *); static void emit_case_bit_tests (tree, tree, tree, tree, case_node_ptr, rtx); @@ -1472,102 +1461,6 @@ expand_expr_stmt (tree exp) free_temp_slots (); } -/* Warn if EXP contains any computations whose results are not used. - Return 1 if a warning is printed; 0 otherwise. LOCUS is the - (potential) location of the expression. */ - -int -warn_if_unused_value (const_tree exp, location_t locus) -{ - restart: - if (TREE_USED (exp) || TREE_NO_WARNING (exp)) - return 0; - - /* Don't warn about void constructs. This includes casting to void, - void function calls, and statement expressions with a final cast - to void. */ - if (VOID_TYPE_P (TREE_TYPE (exp))) - return 0; - - if (EXPR_HAS_LOCATION (exp)) - locus = EXPR_LOCATION (exp); - - switch (TREE_CODE (exp)) - { - case PREINCREMENT_EXPR: - case POSTINCREMENT_EXPR: - case PREDECREMENT_EXPR: - case POSTDECREMENT_EXPR: - case MODIFY_EXPR: - case INIT_EXPR: - case TARGET_EXPR: - case CALL_EXPR: - case TRY_CATCH_EXPR: - case WITH_CLEANUP_EXPR: - case EXIT_EXPR: - case VA_ARG_EXPR: - return 0; - - case BIND_EXPR: - /* For a binding, warn if no side effect within it. */ - exp = BIND_EXPR_BODY (exp); - goto restart; - - case SAVE_EXPR: - case NON_LVALUE_EXPR: - exp = TREE_OPERAND (exp, 0); - goto restart; - - case TRUTH_ORIF_EXPR: - case TRUTH_ANDIF_EXPR: - /* In && or ||, warn if 2nd operand has no side effect. */ - exp = TREE_OPERAND (exp, 1); - goto restart; - - case COMPOUND_EXPR: - if (warn_if_unused_value (TREE_OPERAND (exp, 0), locus)) - return 1; - /* Let people do `(foo (), 0)' without a warning. */ - if (TREE_CONSTANT (TREE_OPERAND (exp, 1))) - return 0; - exp = TREE_OPERAND (exp, 1); - goto restart; - - case COND_EXPR: - /* If this is an expression with side effects, don't warn; this - case commonly appears in macro expansions. */ - if (TREE_SIDE_EFFECTS (exp)) - return 0; - goto warn; - - case INDIRECT_REF: - /* Don't warn about automatic dereferencing of references, since - the user cannot control it. */ - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE) - { - exp = TREE_OPERAND (exp, 0); - goto restart; - } - /* Fall through. */ - - default: - /* Referencing a volatile value is a side effect, so don't warn. */ - if ((DECL_P (exp) || REFERENCE_CLASS_P (exp)) - && TREE_THIS_VOLATILE (exp)) - return 0; - - /* If this is an expression which has no operands, there is no value - to be unused. There are no such language-independent codes, - but front ends may define such. */ - if (EXPRESSION_CLASS_P (exp) && TREE_OPERAND_LENGTH (exp) == 0) - return 0; - - warn: - warning_at (locus, OPT_Wunused_value, "value computed is not used"); - return 1; - } -} - /* Generate RTL to return from the current function, with no value. (That is, we do not do anything about returning any value.) */ @@ -1929,66 +1822,25 @@ expand_stack_restore (tree var) fed to us in descending order from the sorted vector of case labels used in the tree part of the middle end. So the list we construct is sorted in ascending order. The bounds on the case range, LOW and HIGH, - are converted to case's index type TYPE. */ + are converted to case's index type TYPE. Note that the original type + of the case index in the source code is usually "lost" during + gimplification due to type promotion, but the case labels retain the + original type. */ static struct case_node * add_case_node (struct case_node *head, tree type, tree low, tree high, tree label, alloc_pool case_node_pool) { - tree min_value, max_value; struct case_node *r; - gcc_assert (TREE_CODE (low) == INTEGER_CST); - gcc_assert (!high || TREE_CODE (high) == INTEGER_CST); - - min_value = TYPE_MIN_VALUE (type); - max_value = TYPE_MAX_VALUE (type); - - /* If there's no HIGH value, then this is not a case range; it's - just a simple case label. But that's just a degenerate case - range. - If the bounds are equal, turn this into the one-value case. */ - if (!high || tree_int_cst_equal (low, high)) - { - /* If the simple case value is unreachable, ignore it. */ - if ((TREE_CODE (min_value) == INTEGER_CST - && tree_int_cst_compare (low, min_value) < 0) - || (TREE_CODE (max_value) == INTEGER_CST - && tree_int_cst_compare (low, max_value) > 0)) - return head; - low = fold_convert (type, low); - high = low; - } - else - { - /* If the entire case range is unreachable, ignore it. */ - if ((TREE_CODE (min_value) == INTEGER_CST - && tree_int_cst_compare (high, min_value) < 0) - || (TREE_CODE (max_value) == INTEGER_CST - && tree_int_cst_compare (low, max_value) > 0)) - return head; - - /* If the lower bound is less than the index type's minimum - value, truncate the range bounds. */ - if (TREE_CODE (min_value) == INTEGER_CST - && tree_int_cst_compare (low, min_value) < 0) - low = min_value; - low = fold_convert (type, low); - - /* If the upper bound is greater than the index type's maximum - value, truncate the range bounds. */ - if (TREE_CODE (max_value) == INTEGER_CST - && tree_int_cst_compare (high, max_value) > 0) - high = max_value; - high = fold_convert (type, high); - } - + gcc_checking_assert (low); + gcc_checking_assert (! high || (TREE_TYPE (low) == TREE_TYPE (high))); /* Add this label to the chain. Make sure to drop overflow flags. */ r = (struct case_node *) pool_alloc (case_node_pool); - r->low = build_int_cst_wide (TREE_TYPE (low), TREE_INT_CST_LOW (low), + r->low = build_int_cst_wide (type, TREE_INT_CST_LOW (low), TREE_INT_CST_HIGH (low)); - r->high = build_int_cst_wide (TREE_TYPE (high), TREE_INT_CST_LOW (high), + r->high = build_int_cst_wide (type, TREE_INT_CST_LOW (high), TREE_INT_CST_HIGH (high)); r->code_label = label; r->parent = r->left = NULL; @@ -2258,9 +2110,12 @@ expand_case (gimple stmt) gcc_assert (low); high = CASE_HIGH (elt); - /* Discard empty ranges. */ - if (high && tree_int_cst_lt (high, low)) - continue; + /* The canonical from of a case label in GIMPLE is that a simple case + has an empty CASE_HIGH. For the casesi and tablejump expanders, + the back ends want simple cases to have high == low. */ + gcc_assert (! high || tree_int_cst_lt (low, high)); + if (! high) + high = low; case_list = add_case_node (case_list, index_type, low, high, CASE_LABEL (elt), case_node_pool); @@ -2306,16 +2161,10 @@ expand_case (gimple stmt) BITMAP_FREE (label_bitmap); /* cleanup_tree_cfg removes all SWITCH_EXPR with a single - destination, such as one with a default case only. However, - it doesn't remove cases that are out of range for the switch - type, so we may still get a zero here. */ - if (count == 0) - { - if (default_label) - emit_jump (default_label); - free_alloc_pool (case_node_pool); - return; - } + destination, such as one with a default case only. + It also removes cases that are out of range for the switch + type, so we should never get a zero here. */ + gcc_assert (count > 0); /* Compute span of values. */ range = fold_build2 (MINUS_EXPR, index_type, maxval, minval); @@ -2381,7 +2230,11 @@ expand_case (gimple stmt) do_pending_stack_adjust (); if (MEM_P (index)) - index = copy_to_reg (index); + { + index = copy_to_reg (index); + if (TREE_CODE (index_expr) == SSA_NAME) + set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (index_expr), index); + } /* We generate a binary decision tree to select the appropriate target code. This is done as follows: @@ -2396,7 +2249,6 @@ expand_case (gimple stmt) decision tree an unconditional jump to the default code is emitted. */ - use_cost_table = estimate_case_costs (case_list); balance_case_nodes (&case_list, NULL); emit_case_nodes (index, case_list, default_label, index_type); if (default_label) @@ -2495,86 +2347,6 @@ do_jump_if_equal (enum machine_mode mode, rtx op0, rtx op1, rtx label, NULL_RTX, NULL_RTX, label, -1); } -/* Not all case values are encountered equally. This function - uses a heuristic to weight case labels, in cases where that - looks like a reasonable thing to do. - - Right now, all we try to guess is text, and we establish the - following weights: - - chars above space: 16 - digits: 16 - default: 12 - space, punct: 8 - tab: 4 - newline: 2 - other "\" chars: 1 - remaining chars: 0 - - If we find any cases in the switch that are not either -1 or in the range - of valid ASCII characters, or are control characters other than those - commonly used with "\", don't treat this switch scanning text. - - Return 1 if these nodes are suitable for cost estimation, otherwise - return 0. */ - -static int -estimate_case_costs (case_node_ptr node) -{ - tree min_ascii = integer_minus_one_node; - tree max_ascii = build_int_cst (TREE_TYPE (node->high), 127); - case_node_ptr n; - int i; - - /* If we haven't already made the cost table, make it now. Note that the - lower bound of the table is -1, not zero. */ - - if (! cost_table_initialized) - { - cost_table_initialized = 1; - - for (i = 0; i < 128; i++) - { - if (ISALNUM (i)) - COST_TABLE (i) = 16; - else if (ISPUNCT (i)) - COST_TABLE (i) = 8; - else if (ISCNTRL (i)) - COST_TABLE (i) = -1; - } - - COST_TABLE (' ') = 8; - COST_TABLE ('\t') = 4; - COST_TABLE ('\0') = 4; - COST_TABLE ('\n') = 2; - COST_TABLE ('\f') = 1; - COST_TABLE ('\v') = 1; - COST_TABLE ('\b') = 1; - } - - /* See if all the case expressions look like text. It is text if the - constant is >= -1 and the highest constant is <= 127. Do all comparisons - as signed arithmetic since we don't want to ever access cost_table with a - value less than -1. Also check that none of the constants in a range - are strange control characters. */ - - for (n = node; n; n = n->right) - { - if (tree_int_cst_lt (n->low, min_ascii) - || tree_int_cst_lt (max_ascii, n->high)) - return 0; - - for (i = (HOST_WIDE_INT) TREE_INT_CST_LOW (n->low); - i <= (HOST_WIDE_INT) TREE_INT_CST_LOW (n->high); i++) - if (COST_TABLE (i) < 0) - return 0; - } - - /* All interesting values are within the range of interesting - ASCII characters. */ - return 1; -} - /* Take an ordered list of case nodes and transform them into a near optimal binary tree, on the assumption that any target code selection value is as @@ -2593,7 +2365,6 @@ balance_case_nodes (case_node_ptr *head, case_node_ptr parent) np = *head; if (np) { - int cost = 0; int i = 0; int ranges = 0; case_node_ptr *npp; @@ -2604,14 +2375,7 @@ balance_case_nodes (case_node_ptr *head, case_node_ptr parent) while (np) { if (!tree_int_cst_equal (np->low, np->high)) - { - ranges++; - if (use_cost_table) - cost += COST_TABLE (TREE_INT_CST_LOW (np->high)); - } - - if (use_cost_table) - cost += COST_TABLE (TREE_INT_CST_LOW (np->low)); + ranges++; i++; np = np->right; @@ -2622,37 +2386,9 @@ balance_case_nodes (case_node_ptr *head, case_node_ptr parent) /* Split this list if it is long enough for that to help. */ npp = head; left = *npp; - if (use_cost_table) - { - /* Find the place in the list that bisects the list's total cost, - Here I gets half the total cost. */ - int n_moved = 0; - i = (cost + 1) / 2; - while (1) - { - /* Skip nodes while their cost does not reach that amount. */ - if (!tree_int_cst_equal ((*npp)->low, (*npp)->high)) - i -= COST_TABLE (TREE_INT_CST_LOW ((*npp)->high)); - i -= COST_TABLE (TREE_INT_CST_LOW ((*npp)->low)); - if (i <= 0) - break; - npp = &(*npp)->right; - n_moved += 1; - } - if (n_moved == 0) - { - /* Leave this branch lopsided, but optimize left-hand - side and fill in `parent' fields for right-hand side. */ - np = *head; - np->parent = parent; - balance_case_nodes (&np->left, np); - for (; np->right; np = np->right) - np->right->parent = np; - return; - } - } + /* If there are just three nodes, split at the middle one. */ - else if (i == 3) + if (i == 3) npp = &(*npp)->right; else { diff --git a/gcc/store-motion.c b/gcc/store-motion.c index 03b2c3d4c84..e00cb16d16f 100644 --- a/gcc/store-motion.c +++ b/gcc/store-motion.c @@ -395,7 +395,7 @@ store_killed_in_pat (const_rtx x, const_rtx pat, int after) static bool store_killed_in_insn (const_rtx x, const_rtx x_regs, const_rtx insn, int after) { - const_rtx reg, base, note, pat; + const_rtx reg, note, pat; if (! NONDEBUG_INSN_P (insn)) return false; @@ -410,14 +410,8 @@ store_killed_in_insn (const_rtx x, const_rtx x_regs, const_rtx insn, int after) /* But even a const call reads its parameters. Check whether the base of some of registers used in mem is stack pointer. */ for (reg = x_regs; reg; reg = XEXP (reg, 1)) - { - base = find_base_term (XEXP (reg, 0)); - if (!base - || (GET_CODE (base) == ADDRESS - && GET_MODE (base) == Pmode - && XEXP (base, 0) == stack_pointer_rtx)) - return true; - } + if (may_be_sp_based_p (XEXP (reg, 0))) + return true; return false; } diff --git a/gcc/symtab.c b/gcc/symtab.c new file mode 100644 index 00000000000..975fdef89b1 --- /dev/null +++ b/gcc/symtab.c @@ -0,0 +1,607 @@ +/* Symbol table. + Copyright (C) 2012 Free Software Foundation, Inc. + Contributed by Jan Hubicka + +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/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "tree-inline.h" +#include "langhooks.h" +#include "hashtab.h" +#include "ggc.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "timevar.h" + +/* Hash table used to convert declarations into nodes. */ +static GTY((param_is (union symtab_node_def))) htab_t symtab_hash; +/* Hash table used to convert assembler names into nodes. */ +static GTY((param_is (union symtab_node_def))) htab_t assembler_name_hash; + +/* Linked list of symbol table nodes. */ +symtab_node symtab_nodes; + +/* The order index of the next symtab node to be created. This is + used so that we can sort the cgraph nodes in order by when we saw + them, to support -fno-toplevel-reorder. */ +int symtab_order; + +/* Returns a hash code for P. */ + +static hashval_t +hash_node (const void *p) +{ + const_symtab_node n = (const_symtab_node ) p; + return (hashval_t) DECL_UID (n->symbol.decl); +} + + +/* Returns nonzero if P1 and P2 are equal. */ + +static int +eq_node (const void *p1, const void *p2) +{ + const_symtab_node n1 = (const_symtab_node) p1; + const_symtab_node n2 = (const_symtab_node) p2; + return DECL_UID (n1->symbol.decl) == DECL_UID (n2->symbol.decl); +} + +/* Returns a hash code for P. */ + +static hashval_t +hash_node_by_assembler_name (const void *p) +{ + const_symtab_node n = (const_symtab_node) p; + return (hashval_t) decl_assembler_name_hash (DECL_ASSEMBLER_NAME (n->symbol.decl)); +} + +/* Returns nonzero if P1 and P2 are equal. */ + +static int +eq_assembler_name (const void *p1, const void *p2) +{ + const_symtab_node n1 = (const_symtab_node) p1; + const_tree name = (const_tree)p2; + return (decl_assembler_name_equal (n1->symbol.decl, name)); +} + +/* Insert NODE to assembler name hash. */ + +static void +insert_to_assembler_name_hash (symtab_node node) +{ + gcc_checking_assert (!node->symbol.previous_sharing_asm_name + && !node->symbol.next_sharing_asm_name); + if (assembler_name_hash) + { + void **aslot; + tree name = DECL_ASSEMBLER_NAME (node->symbol.decl); + + aslot = htab_find_slot_with_hash (assembler_name_hash, name, + decl_assembler_name_hash (name), + INSERT); + gcc_assert (*aslot != node); + node->symbol.next_sharing_asm_name = (symtab_node)*aslot; + if (*aslot != NULL) + ((symtab_node)*aslot)->symbol.previous_sharing_asm_name = node; + *aslot = node; + } + +} + +/* Remove NODE from assembler name hash. */ + +static void +unlink_from_assembler_name_hash (symtab_node node) +{ + if (assembler_name_hash) + { + if (node->symbol.next_sharing_asm_name) + node->symbol.next_sharing_asm_name->symbol.previous_sharing_asm_name + = node->symbol.previous_sharing_asm_name; + if (node->symbol.previous_sharing_asm_name) + { + node->symbol.previous_sharing_asm_name->symbol.next_sharing_asm_name + = node->symbol.next_sharing_asm_name; + } + else + { + tree name = DECL_ASSEMBLER_NAME (node->symbol.decl); + void **slot; + slot = htab_find_slot_with_hash (assembler_name_hash, name, + decl_assembler_name_hash (name), + NO_INSERT); + gcc_assert (*slot == node); + if (!node->symbol.next_sharing_asm_name) + htab_clear_slot (assembler_name_hash, slot); + else + *slot = node->symbol.next_sharing_asm_name; + } + } +} + + +/* Add node into symbol table. This function is not used directly, but via + cgraph/varpool node creation routines. */ + +void +symtab_register_node (symtab_node node) +{ + struct symtab_node_base key; + symtab_node *slot; + + node->symbol.next = symtab_nodes; + node->symbol.previous = NULL; + if (symtab_nodes) + symtab_nodes->symbol.previous = node; + symtab_nodes = node; + + if (!symtab_hash) + symtab_hash = htab_create_ggc (10, hash_node, eq_node, NULL); + key.decl = node->symbol.decl; + slot = (symtab_node *) htab_find_slot (symtab_hash, &key, INSERT); + if (*slot == NULL) + *slot = node; + + insert_to_assembler_name_hash (node); + + node->symbol.order = symtab_order++; + + ipa_empty_ref_list (&node->symbol.ref_list); +} + +/* Make NODE to be the one symtab hash is pointing to. Used when reshaping tree + of inline clones. */ + +void +symtab_insert_node_to_hashtable (symtab_node node) +{ + struct symtab_node_base key; + symtab_node *slot; + + if (!symtab_hash) + symtab_hash = htab_create_ggc (10, hash_node, eq_node, NULL); + key.decl = node->symbol.decl; + slot = (symtab_node *) htab_find_slot (symtab_hash, &key, INSERT); + *slot = node; +} + +/* Remove node from symbol table. This function is not used directly, but via + cgraph/varpool node removal routines. */ + +void +symtab_unregister_node (symtab_node node) +{ + void **slot; + ipa_remove_all_references (&node->symbol.ref_list); + ipa_remove_all_referring (&node->symbol.ref_list); + + if (node->symbol.same_comdat_group) + { + symtab_node prev; + for (prev = node->symbol.same_comdat_group; + prev->symbol.same_comdat_group != node; + prev = prev->symbol.same_comdat_group) + ; + if (node->symbol.same_comdat_group == prev) + prev->symbol.same_comdat_group = NULL; + else + prev->symbol.same_comdat_group = node->symbol.same_comdat_group; + node->symbol.same_comdat_group = NULL; + } + + if (node->symbol.previous) + node->symbol.previous->symbol.next = node->symbol.next; + else + symtab_nodes = node->symbol.next; + if (node->symbol.next) + node->symbol.next->symbol.previous = node->symbol.previous; + node->symbol.next = NULL; + node->symbol.previous = NULL; + + slot = htab_find_slot (symtab_hash, node, NO_INSERT); + if (*slot == node) + { + symtab_node replacement_node = NULL; + if (symtab_function_p (node)) + replacement_node = (symtab_node)cgraph_find_replacement_node (cgraph (node)); + if (!replacement_node) + htab_clear_slot (symtab_hash, slot); + else + *slot = replacement_node; + } + unlink_from_assembler_name_hash (node); +} + +/* Return symbol table node associated with DECL, if any, + and NULL otherwise. */ + +symtab_node +symtab_get_node (const_tree decl) +{ + symtab_node *slot; + struct symtab_node_base key; + + gcc_checking_assert (TREE_CODE (decl) == FUNCTION_DECL + || (TREE_CODE (decl) == VAR_DECL + && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) + || in_lto_p))); + + if (!symtab_hash) + return NULL; + + key.decl = CONST_CAST2 (tree, const_tree, decl); + + slot = (symtab_node *) htab_find_slot (symtab_hash, &key, + NO_INSERT); + + if (slot) + return *slot; + return NULL; +} + +/* Remove symtab NODE from the symbol table. */ + +void +symtab_remove_node (symtab_node node) +{ + if (symtab_function_p (node)) + cgraph_remove_node (cgraph (node)); + else if (symtab_variable_p (node)) + varpool_remove_node (varpool (node)); +} + +/* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME. + Return NULL if there's no such node. */ + +symtab_node +symtab_node_for_asm (const_tree asmname) +{ + symtab_node node; + void **slot; + + if (!assembler_name_hash) + { + assembler_name_hash = + htab_create_ggc (10, hash_node_by_assembler_name, eq_assembler_name, + NULL); + FOR_EACH_SYMBOL (node) + insert_to_assembler_name_hash (node); + } + + slot = htab_find_slot_with_hash (assembler_name_hash, asmname, + decl_assembler_name_hash (asmname), + NO_INSERT); + + if (slot) + { + node = (symtab_node) *slot; + return node; + } + return NULL; +} + +/* Set the DECL_ASSEMBLER_NAME and update symtab hashtables. */ + +void +change_decl_assembler_name (tree decl, tree name) +{ + symtab_node node = NULL; + + /* We can have user ASM names on things, like global register variables, that + are not in the symbol table. */ + if ((TREE_CODE (decl) == VAR_DECL + && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) + || TREE_CODE (decl) == FUNCTION_DECL) + node = symtab_get_node (decl); + if (!DECL_ASSEMBLER_NAME_SET_P (decl)) + { + SET_DECL_ASSEMBLER_NAME (decl, name); + if (node) + insert_to_assembler_name_hash (node); + } + else + { + if (name == DECL_ASSEMBLER_NAME (decl)) + return; + + if (node) + unlink_from_assembler_name_hash (node); + if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + && DECL_RTL_SET_P (decl)) + warning (0, "%D renamed after being referenced in assembly", decl); + + SET_DECL_ASSEMBLER_NAME (decl, name); + if (node) + insert_to_assembler_name_hash (node); + } +} + +/* Return printable assembler name of NODE. + This function is used only for debugging. When assembler name + is unknown go with identifier name. */ + +const char * +symtab_node_asm_name (symtab_node node) +{ + if (!DECL_ASSEMBLER_NAME_SET_P (node->symbol.decl)) + return lang_hooks.decl_printable_name (node->symbol.decl, 2); + return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->symbol.decl)); +} + +/* Return printable identifier name. */ + +const char * +symtab_node_name (symtab_node node) +{ + return lang_hooks.decl_printable_name (node->symbol.decl, 2); +} + +static const char * const symtab_type_names[] = {"symbol", "function", "variable"}; + +/* Dump base fields of symtab nodes. Not to be used directly. */ + +void +dump_symtab_base (FILE *f, symtab_node node) +{ + static const char * const visibility_types[] = { + "default", "protected", "hidden", "internal" + }; + + fprintf (f, "%s/%i (%s)", + symtab_node_asm_name (node), + node->symbol.order, + symtab_node_name (node)); + dump_addr (f, " @", (void *)node); + fprintf (f, "\n Type: %s\n", symtab_type_names[node->symbol.type]); + fprintf (f, " Visibility:"); + + if (node->symbol.in_other_partition) + fprintf (f, " in_other_partition"); + if (node->symbol.used_from_other_partition) + fprintf (f, " used_from_other_partition"); + if (node->symbol.force_output) + fprintf (f, " force_output"); + if (node->symbol.resolution != LDPR_UNKNOWN) + fprintf (f, " %s", + ld_plugin_symbol_resolution_names[(int)node->symbol.resolution]); + if (TREE_ASM_WRITTEN (node->symbol.decl)) + fprintf (f, " asm_written"); + if (DECL_EXTERNAL (node->symbol.decl)) + fprintf (f, " external"); + if (TREE_PUBLIC (node->symbol.decl)) + fprintf (f, " public"); + if (DECL_COMMON (node->symbol.decl)) + fprintf (f, " common"); + if (DECL_WEAK (node->symbol.decl)) + fprintf (f, " weak"); + if (DECL_DLLIMPORT_P (node->symbol.decl)) + fprintf (f, " dll_import"); + if (DECL_COMDAT (node->symbol.decl)) + fprintf (f, " comdat"); + if (DECL_COMDAT_GROUP (node->symbol.decl)) + fprintf (f, " comdat_group:%s", + IDENTIFIER_POINTER (DECL_COMDAT_GROUP (node->symbol.decl))); + if (DECL_ONE_ONLY (node->symbol.decl)) + fprintf (f, " one_only"); + if (DECL_SECTION_NAME (node->symbol.decl)) + fprintf (f, " section_name:%s", + TREE_STRING_POINTER (DECL_SECTION_NAME (node->symbol.decl))); + if (DECL_VISIBILITY_SPECIFIED (node->symbol.decl)) + fprintf (f, " visibility_specified"); + if (DECL_VISIBILITY (node->symbol.decl)) + fprintf (f, " visibility:%s", + visibility_types [DECL_VISIBILITY (node->symbol.decl)]); + if (DECL_VIRTUAL_P (node->symbol.decl)) + fprintf (f, " virtual"); + if (DECL_ARTIFICIAL (node->symbol.decl)) + fprintf (f, " artificial"); + fprintf (f, "\n"); + + if (node->symbol.same_comdat_group) + fprintf (f, " Same comdat group as: %s/%i\n", + symtab_node_asm_name (node->symbol.same_comdat_group), + node->symbol.same_comdat_group->symbol.order); + if (node->symbol.next_sharing_asm_name) + fprintf (f, " next sharing asm name: %i\n", + node->symbol.next_sharing_asm_name->symbol.order); + if (node->symbol.previous_sharing_asm_name) + fprintf (f, " previous sharing asm name: %i\n", + node->symbol.previous_sharing_asm_name->symbol.order); + + if (node->symbol.address_taken) + fprintf (f, " Address is taken.\n"); + if (node->symbol.aux) + { + fprintf (f, " Aux:"); + dump_addr (f, " @", (void *)node->symbol.aux); + } + + fprintf (f, " References: "); + ipa_dump_references (f, &node->symbol.ref_list); + fprintf (f, " Referring: "); + ipa_dump_referring (f, &node->symbol.ref_list); +} + +/* Dump symtab node. */ + +void +dump_symtab_node (FILE *f, symtab_node node) +{ + if (symtab_function_p (node)) + dump_cgraph_node (f, cgraph (node)); + else if (symtab_variable_p (node)) + dump_varpool_node (f, varpool (node)); +} + +/* Dump symbol table. */ + +void +dump_symtab (FILE *f) +{ + symtab_node node; + fprintf (f, "Symbol table:\n\n"); + FOR_EACH_SYMBOL (node) + dump_symtab_node (f, node); +} + +/* Dump symtab node NODE to stderr. */ + +DEBUG_FUNCTION void +debug_symtab_node (symtab_node node) +{ + dump_symtab_node (stderr, node); +} + +/* Dump symbol table to stderr. */ + +DEBUG_FUNCTION void +debug_symtab (void) +{ + dump_symtab (stderr); +} + +/* Verify common part of symtab nodes. */ + +DEBUG_FUNCTION bool +verify_symtab_base (symtab_node node) +{ + bool error_found = false; + symtab_node hashed_node; + + if (symtab_function_p (node)) + { + if (TREE_CODE (node->symbol.decl) != FUNCTION_DECL) + { + error ("function symbol is not function"); + error_found = true; + } + } + else if (symtab_variable_p (node)) + { + if (TREE_CODE (node->symbol.decl) != VAR_DECL) + { + error ("variable symbol is not variable"); + error_found = true; + } + } + else + { + error ("node has unknown type"); + error_found = true; + } + + hashed_node = symtab_get_node (node->symbol.decl); + if (!hashed_node) + { + error ("node not found in symtab decl hashtable"); + error_found = true; + } + if (assembler_name_hash) + { + hashed_node = symtab_node_for_asm (DECL_ASSEMBLER_NAME (node->symbol.decl)); + if (hashed_node && hashed_node->symbol.previous_sharing_asm_name) + { + error ("assembler name hash list corrupted"); + error_found = true; + } + while (hashed_node) + { + if (hashed_node == node) + break; + hashed_node = hashed_node->symbol.next_sharing_asm_name; + } + if (!hashed_node) + { + error ("node not found in symtab assembler name hash"); + error_found = true; + } + } + if (node->symbol.previous_sharing_asm_name + && node->symbol.previous_sharing_asm_name->symbol.next_sharing_asm_name != node) + { + error ("double linked list of assembler names corrupted"); + } + if (node->symbol.same_comdat_group) + { + symtab_node n = node->symbol.same_comdat_group; + + if (!DECL_ONE_ONLY (n->symbol.decl)) + { + error ("non-DECL_ONE_ONLY node in a same_comdat_group list"); + error_found = true; + } + if (n->symbol.type != node->symbol.type) + { + error ("mixing different types of symbol in same comdat groups is not supported"); + error_found = true; + } + if (n == node) + { + error ("node is alone in a comdat group"); + error_found = true; + } + do + { + if (!n->symbol.same_comdat_group) + { + error ("same_comdat_group is not a circular list"); + error_found = true; + break; + } + n = n->symbol.same_comdat_group; + } + while (n != node); + } + return error_found; +} + +/* Verify consistency of NODE. */ + +DEBUG_FUNCTION void +verify_symtab_node (symtab_node node) +{ + if (seen_error ()) + return; + + timevar_push (TV_CGRAPH_VERIFY); + if (symtab_function_p (node)) + verify_cgraph_node (cgraph (node)); + else + if (verify_symtab_base (node)) + { + dump_symtab_node (stderr, node); + internal_error ("verify_symtab_node failed"); + } + timevar_pop (TV_CGRAPH_VERIFY); +} + +/* Verify symbol table for internal consistency. */ + +DEBUG_FUNCTION void +verify_symtab (void) +{ + symtab_node node; + FOR_EACH_SYMBOL (node) + verify_symtab_node (node); +} + +#include "gt-symtab.h" diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 8e3d74ea356..da0b029cdbe 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -1200,7 +1200,8 @@ default_target_can_inline_p (tree caller, tree callee) this means extra overhead for dispatch tables, which raises the threshold for using them. */ -unsigned int default_case_values_threshold (void) +unsigned int +default_case_values_threshold (void) { return (HAVE_casesi ? 4 : 5); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8fcfca90cbf..d2877e72304 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,8 +1,465 @@ +2012-04-22 Tobias Burnus <burnus@net-b.de> + + PR fortran/53051 + * gfortran.dg/read_float_4.f90: New. + +2012-04-21 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR 35441 + * c-c++-common/pr35441.C: New. + +2012-04-20 Ian Lance Taylor <iant@google.com> + + * go.test/go-test.exp (go-set-goarch): Recognize powerpc*-*-*. + (go-gc-tests): Skip nilptr.go on powerpc*-*-*. + +2012-04-20 Uros Bizjak <ubizjak@gmail.com> + + * gcc.target/x86_64/abi/avx/test_passing_unions.c: Avoid undefined + array access. + * gcc.target/x86_64/abi/avx/test_passing_structs.c: Likewise. + +2012-04-20 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR rtl-optimization/44214 + * gcc.dg/pr44214-1.c: New test. + * gcc.dg/pr44214-2.c: Likewise. + * gcc.dg/pr44214-3.c: Likewise. + +2012-04-20 Richard Guenther <rguenther@suse.de> + + * g++.dg/torture/20120420-1.C: New testcase. + +2012-04-19 Steven Bosscher <steven@gcc.gnu.org> + + * gcc.target/i386/pr45830.c: Update scan-tree-dump. + +2012-04-19 Christian Bruel <christian.bruel@st.com> + + * gcc.dg/pr52283.c: New test. + +2012-04-19 Manuel López-Ibáñez <manu@gcc.gnu.org> + + * gcc.dg/pr37985.c: New test. + +2012-04-19 Richard Guenther <rguenther@suse.de> + + PR rtl-optimization/44688 + * gcc.dg/var-expand1.c: Increase array size to make unrolling + possibly profitable. + +2012-04-18 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR tree-optimization/52976 + gfortran.dg/reassoc_11.f: New test. + +2012-04-18 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR tree-optimization/52976 + gfortran.dg/reassoc_7.f: New test. + gfortran.dg/reassoc_8.f: Likewise. + gfortran.dg/reassoc_9.f: Likewise. + gfortran.dg/reassoc_10.f: Likewise. + +2012-04-18 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/52422 + * g++.dg/cpp0x/sfinae33.C: New. + * g++.dg/cpp0x/sfinae34.C: Likewise. + +2012-04-18 Joey Ye <joey.ye@arm.com> + + * gcc.target/arm/thumb1-imm.c: Skip it in non-thumb1 target. + +2012-04-18 Richard Guenther <rguenther@suse.de> + + * gcc.target/x86_64/abi/test_passing_unions.c: Avoid undefined + array access. + * gcc.target/x86_64/abi/test_passing_structs.c: Likewise. + * gcc.target/i386/avx256-unaligned-load-4.c: Fix array sizes. + +2012-04-17 Tom de Vries <tom@codesourcery.com> + + * g++.dg/pr51264-4.C: New test. + +2012-04-17 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/52599 + * g++.dg/cpp0x/constexpr-ctor10.C: New. + +2012-04-17 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/53003 + * g++.dg/parse/crash59.C: New. + +2012-04-17 Michael Matz <matz@suse.de> + + PR tree-optimization/18437 + * gfortran.dg/vect/rnflow-trs2a2.f90: New test. + +2012-04-17 Richard Guenther <rguenther@suse.de> + + PR middle-end/53011 + * g++.dg/torture/pr53011.C: New testcase. + +2012-04-16 Jason Merrill <jason@redhat.com> + + PR c++/38543 + * g++.dg/cpp0x/variadic131.C: New. + + PR c++/52008 + * g++.dg/cpp0x/variadic130.C: New. + + PR c++/50830 + * g++.dg/cpp0x/variadic129.C: New. + + PR c++/50303 + * g++.dg/cpp0x/variadic128.C: New. + +2012-04-16 Tobias Burnus <burnus@net-b.de> + + PR fortran/52864 + * gfortran.dg/pointer_intent_6.f90: New. + +2012-04-16 Tobias Burnus <burnus@net-b.de> + + PR fortran/52916 + * gfortran.dg/public_private_module_3.f90: Use dg-additional-sources + to include public_private_module_4.f90. + * gfortran.dg/public_private_module_4.f90: Skip this test on all + targets. + +2012-04-16 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/49152 + * g++.dg/diagnostic/operator1.C: New. + * g++.dg/ext/label5.C: Adjust. + * g++.dg/ext/va-arg1.C: Likewise. + * g++.dg/other/error20.C: Likewise. + * g++.dg/other/error20.C: Likewise. + * g++.dg/other/error16.C: Likewise. + * g++.dg/other/error10.C: Likewise. + * g++.dg/parse/error30.C: Likewise. + * g++.dg/cpp0x/lambda/lambda-err1.C: Likewise. + +2012-04-16 Jason Merrill <jason@redhat.com> + + PR c++/51148 + * g++.dg/cpp0x/variadic127.C: New. + +2012-04-16 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * lib/plugin-support.exp (plugin-test-execute): Properly determine + testcase name. + Use fail, pass instead of unresolved. + Don't log $optstr. + + PR testsuite/52948 + * g++.dg/plugin/dumb_plugin.c (pass_dumb_plugin_example): Remove + TODO_dump_func. + * g++.dg/plugin/selfassign.c (pass_warn_self_assign): Likewise. + * gcc.dg/plugin/one_time_plugin.c (one_pass): Likewise. + * gcc.dg/plugin/selfassign.c (pass_warn_self_assign): Likewise. + +2012-04-16 Janus Weil <janus@gcc.gnu.org> + + PR fortran/52968 + * gfortran.dg/typebound_call_23.f03: New test case. + +2012-04-15 Jason Merrill <jason@redhat.com> + + PR c++/47220 + * g++.dg/cpp0x/variadic126.C: New. + + PR c++/52380 + * g++.dg/cpp0x/variadic125.C: New. + + PR c++/52292 + * g++.dg/cpp0x/variadic124.C: New. + + PR c++/52706 + * g++.dg/cpp0x/nullptr27.C: New. + + PR c++/52818 + * g++.dg/warn/format8.C: New. + +2012-04-15 Janus Weil <janus@gcc.gnu.org> + + PR fortran/51082 + * gfortran.dg/proc_ptr_comp_34.f90: New test case. + +2012-04-14 Tobias Burnus <burnus@net-b.de> + + PR fortran/52916 + PR fortran/40973 + * gfortran.dg/public_private_module_3.f90: New. + * gfortran.dg/public_private_module_4.f90: New. + +2012-04-14 Tom de Vries <tom@codesourcery.com> + + * gcc.dg/superblock.c: New test. + +2012-04-14 Tom de Vries <tom@codesourcery.com> + + * gcc.dg/pr51879-12.c: New test. + +2012-04-13 Jason Merrill <jason@redhat.com> + + PR c++/52824 + * g++.dg/cpp0x/variadic123.C: New. + * g++.dg/cpp0x/alias-decl-15.C: Remove dg-errors. + + PR c++/52905 + * g++.dg/cpp0x/initlist-ctor1.C: New. + + PR c++/52915 + * g++.dg/other/anon-union2.C: New. + +2012-04-13 Martin Jambor <mjambor@suse.cz> + + PR middle-end/52939 + * g++.dg/ipa/pr52939.C: New test. + +2012-04-13 Tom de Vries <tom@codesourcery.com> + + * gcc.dg/pr52734.c: New test. + +2012-04-13 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/52969 + * gcc.dg/torture/pr52969.c: New testcase. + +2012-04-13 Richard Guenther <rguenther@suse.de> + + PR c/52549 + * gcc.dg/pr52549.c: New testcase. + +2012-04-13 Richard Guenther <rguenther@suse.de> + + PR c/52862 + * gcc.dg/pr52862.c: New testcase. + +2012-04-13 Joey Ye <joey.ye@arm.com> + + * gcc.target/arm/thumb1-imm.c: New testcase. + +2012-04-12 Uros Bizjak <ubizjak@gmail.com> + + PR target/52932 + * gcc.target/i386/avx2-vpermps-1.c (avx2_test): Use __m256i type for + second function argument. + * gcc.target/i386/avx2-vpermps-2.c (init_permps): Update declaration. + (calc_permps): Update declaration. Calculate result correctly. + (avx2_test): Change src2 type to union256i_d. + * gcc.target/i386/avx2-vpermd-2.c (calc_permd): Calculate result + correctly. + +2012-04-12 Michael Meissner <meissner@linux.vnet.ibm.com> + + PR target/52775 + * gcc.target/powerpc/pr52775.c: New file. + +2012-04-12 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR tree-optimization/18589 + * gcc.dg/tree-ssa/pr18589-1.c: New test. + * gcc.dg/tree-ssa/pr18589-2.c: Likewise. + * gcc.dg/tree-ssa/pr18589-3.c: Likewise. + * gcc.dg/tree-ssa/pr18589-4.c: Likewise. + * gcc.dg/tree-ssa/pr18589-5.c: Likewise. + * gcc.dg/tree-ssa/pr18589-6.c: Likewise. + * gcc.dg/tree-ssa/pr18589-7.c: Likewise. + * gcc.dg/tree-ssa/pr18589-8.c: Likewise. + * gcc.dg/tree-ssa/pr18589-9.c: Likewise. + * gcc.dg/tree-ssa/pr18589-10.c: Likewise. + +2012-04-12 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/52943 + * gcc.dg/torture/pr52943.c: New testcase. + +2012-04-12 Oleg Endo <olegendo@gcc.gnu.org> + + PR target/50751 + * gcc/target/sh/pr50751-4.c: New. + * gcc/target/sh/pr50751-5.c: New. + * gcc/target/sh/pr50751-6.c: New. + * gcc/target/sh/pr50751-7.c: New. + +2012-04-11 Fabien Chêne <fabien@gcc.gnu.org> + + PR c++/52465 + * g++.dg/lookup/using52.C: New. + +2012-04-11 Manuel López-Ibáñez <manu@gcc.gnu.org> + + * lib/prune.exp (TEST_ALWAYS_FLAGS): If undefined, set to empty. + +2012-04-11 H.J. Lu <hongjiu.lu@intel.com> + + PR rtl-optimization/52876 + * gcc.target/i386/pr52876.c: New. + +2012-04-11 Bernd Schmidt <bernds@codesourcery.com> + + * gcc.dg/c99-const-expr-9.c (old_offsetof): Insert a cast to + __UINTPTR_TYPE__. + * gcc.c-torture/execute/pr15296.c (intptr_t): Likewise, with + __INTPTR_TYPE__. + * gcc.dg/pr14092-1.c (intptr_t): Likewise. + * gcc.dg/tree-ssa/foldcast-1.c (ssize_t): Likewise. + * gcc.dg/c90-const-expr-6.c (intptr_t): New typedef to replace ... + (ptrdiff_t): ... this. All uses changed. + * gcc.dg/c99-const-expr-6.c (intptr_t, ptrdiff_t): Likewise. + * gcc.dg/torture/pta-escape-1.c (foo): Change arg type to + __INTPTR_TYPE__. + (main): Cast argument to __INTPTR_TYPE__. + * gcc.dg/20041106-1.c (main): Cast to __UINTPTR_TYPE__ rather than + size_t. + * gcc.dg/mallign.c (main): Likewise. + * gcc.dg/pr38700.c (foo): Likewise. + * gcc.dg/long-long-cst1.c (t): Likewise. + * gcc.dg/c99-const-expr-10.c (p, q, f, h, h2): Likewise. + * gcc.dg/array-10.c (c0, c1, c2, c3, c4, c5): Likewise. + * gcc.dg/pointer-arith-10.c (foo): Likewise. + * gcc.dg/pr25682.c (d, foo): Likewise. + * gcc.dg/format/cast-1.c (f): Likewise. + * gcc.dg/c90-const-expr-10.c + * gcc.dg/pr41551.c (uintptr_t): New typedef, replacing... + (size_t): ...this. All uses changed. + * gcc.c-torture/execute/pr22098-1.c (uintptr_t): Likewise. + * gcc.c-torture/execute/pr22098-2.c (uintptr_t): Likewise. + * gcc.c-torture/execute/pr22098-3.c (uintptr_t): Likewise. + * gcc.dg/pr34856.c (uintptr_t): Likewise. + * gcc.dg/sequence-pt-1.c: Likewise. + * gcc.dg/c90-const-expr-9.c (uintptr_t): Likewise. + * gcc.dg/max-1.c (intptr_t): Likewise, replacing ssize_t. + * gcc.dg/pr39074.c (intptr_t): Define using __INTPTR_TYPE__. + * gcc.dg/pr30744-1.c (my_intptr_t): New typedef. Replace all uses + of ptrdiff_t with it. + * gcc.dg/inline-23.c (my_intptr_t): Likewise. + * gcc.dg/pr37561.c (p): Use __INTPTR_TYPE__. + * gcc.dg/vla-11.c (foo11b): Use __UINTPTR_TYPE__. + +2012-04-11 Jason Merrill <jason@redhat.com> + + PR debug/45088 + * g++.dg/debug/dwarf2/self-ref-1.C: Define virtual destructor. + * g++.dg/debug/dwarf2/self-ref-1.C: Likewise. + + PR c++/52906 + * g++.dg/ext/attrib45.C: New. + + * g++.dg/eh/dtor3.C: New. + +2012-04-11 Richard Guenther <rguenther@suse.de> + + PR middle-end/52621 + * gfortran.dg/pr52621.f90: New testcase. + +2012-04-11 Richard Guenther <rguenther@suse.de> + + PR middle-end/52918 + * g++.dg/torture/pr52918-1.C: New testcase. + * g++.dg/torture/pr52918-2.C: Likewise. + +2012-04-11 Tobias Burnus <burnus@net-b.de> + + PR fortran/52729 + * gfortran.dg/block_11.f90: New. + +2012-04-11 Nick Clifton <nickc@redhat.com> + + * gcc.dg/stack-usage-1.c (SIZE): Define for the RL78. + +2012-04-11 Peter Bergner <bergner@vnet.ibm.com> + + PR target/16458 + * gcc.target/powerpc/pr16458-1.c: New test. + * gcc.target/powerpc/pr16458-2.c: Likewise. + * gcc.target/powerpc/pr16458-3.c: Likewise. + * gcc.target/powerpc/pr16458-4.c: Likewise. + +2012-04-11 Eric Botcazou <ebotcazou@adacore.com> + + * gcc.dg/builtin-bswap-1.c: Test __builtin_bswap16 & __builtin_bswap64. + * gcc.dg/builtin-bswap-4.c: Test __builtin_bswap16. + * gcc.dg/builtin-bswap-5.c: Likewise. + * gcc.target/i386/builtin-bswap-4.c: New test. + +2012-04-11 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR 24985 + * lib/prune.exp: Add -fno-diagnostics-show-caret. + +2012-04-11 Richard Guenther <rguenther@suse.de> + + PR rtl-optimization/52881 + * gcc.dg/torture/pr52881.c: New testcase. + * gcc.dg/torture/pr52913.c: Likewise. + +2012-04-11 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/52912 + * gcc.dg/torture/pr52912.c: New testcase. + +2010-04-10 Michael Matz <matz@suse.de> + + * gcc.dg/vect/vect-outer-1-big-array.c: Adjust. + * gcc.dg/vect/vect-outer-1.c: Adjust. + * gcc.dg/vect/vect-outer-1a-big-array.c: Adjust. + * gcc.dg/vect/vect-outer-1a.c: Adjust. + * gcc.dg/vect/vect-outer-1b-big-array.c: Adjust. + * gcc.dg/vect/vect-outer-1b.c: Adjust. + * gcc.dg/vect/vect-outer-2b.c: Adjust. + * gcc.dg/vect/vect-outer-3b.c: Adjust. + +2012-04-10 Ulrich Weigand <ulrich.weigand@linaro.org> + + PR tree-optimization/52870 + * gcc.dg/vect/pr52870.c: New test. + 2012-04-09 Mike Stump <mikestump@comcast.net> * g++.dg/cpp0x/udlit-raw-op.C: Don't use CRLF endings. * gcc.dg/tree-ssa/vrp59.c: Likewise. * gcc.dg/tree-ssa/vrp60.c: Likewise. + * gnat.dg/aggr11.adb: Likewise. + * gnat.dg/aggr11_pkg.ads: Likewise. + * gnat.dg/aggr15.adb: Likewise. + * gnat.dg/aggr15.ads: Likewise. + * gnat.dg/aggr17.adb: Likewise. + * gnat.dg/aggr18.adb: Likewise. + * gnat.dg/array14.adb: Likewise. + * gnat.dg/array14.ads: Likewise. + * gnat.dg/array14_pkg.ads: Likewise. + * gnat.dg/array19.adb: Likewise. + * gnat.dg/array19.ads: Likewise. + * gnat.dg/discr27.adb: Likewise. + * gnat.dg/discr27.ads: Likewise. + * gnat.dg/discr35.adb: Likewise. + * gnat.dg/discr35.ads: Likewise. + * gnat.dg/discr6.adb: Likewise. + * gnat.dg/discr6_pkg.ads: Likewise. + * gnat.dg/import1.adb: Likewise. + * gnat.dg/import1.ads: Likewise. + * gnat.dg/loop_address2.adb: Likewise. + * gnat.dg/opt7.adb: Likewise. + * gnat.dg/opt7.ads: Likewise. + * gnat.dg/pointer_variable_bounds.adb: Likewise. + * gnat.dg/pointer_variable_bounds.ads: Likewise. + * gnat.dg/rep_clause2.adb: Likewise. + * gnat.dg/rep_clause2.ads: Likewise. + * gnat.dg/slice2.adb: Likewise. + * gnat.dg/slice2.ads: Likewise. + * gnat.dg/slice6.adb: Likewise. + * gnat.dg/slice6_pkg.ads: Likewise. + * gnat.dg/specs/unchecked_union2.ads: Likewise. + * gnat.dg/taft_type2.adb: Likewise. + * gnat.dg/taft_type2.ads: Likewise. + * gnat.dg/taft_type2_pkg.ads: Likewise. + * gnat.dg/volatile10.adb: Likewise. + * gnat.dg/volatile10_pkg.ads: Likewise. * gcc.dg/dll-8.c: Remove execute permissions. * g++.dg/ext/dllexport5.C: Likewise. @@ -11,7 +468,7 @@ PR lto/52722 PR lto/51765 - PR lto/52634 + PR lto/52634 * gcc.dg/lto/pr52634_1.c: New testcase. * gcc.dg/lto/pr52634_0.c: New testcase. @@ -370,7 +827,7 @@ int32plus. * gcc.dg/torture/pr48124-4.c: Ditto: * gcc.dg/torture/pr52530.c: Use long instead of int if int=16. - + 2012-03-20 Jason Merrill <jason@redhat.com> PR c++/52510 @@ -465,11 +922,11 @@ 2012-03-15 Janne Blomqvist <jb@gcc.gnu.org> - PR libfortran/52434 - PR libfortran/48878 - PR libfortran/38199 - * gfortran.dg/edit_real_1.f90: Don't assume roundTiesToAway. - * gfortran.dg/round_1.f03: Likewise. + PR libfortran/52434 + PR libfortran/48878 + PR libfortran/38199 + * gfortran.dg/edit_real_1.f90: Don't assume roundTiesToAway. + * gfortran.dg/round_1.f03: Likewise. 2012-03-15 Jakub Jelinek <jakub@redhat.com> Andrew Pinski <apinski@cavium.com> @@ -1632,7 +2089,7 @@ 2012-02-06 Andrey Belevantsev <abel@ispras.ru> - * gcc.dg/pr48374.c: Actually add the test I forgot + * gcc.dg/pr48374.c: Actually add the test I forgot in the 2012-01-25 commit. 2012-02-05 Thomas König <tkoenig@gcc.gnu.org> @@ -2040,7 +2497,7 @@ * gcc.dg/lto/trans-mem-3_1.c: Provide correct argument types for TM builtins. -2012-01-25 Georg-Johann Lay <avr@gjlay.de> +2012-01-25 Georg-Johann Lay <avr@gjlay.de> * gcc.target/avr/torture/int24-mul.c: Rename __pgm to __flash. diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-15.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-15.C index 2bc9b11843d..b23e4029f79 100644 --- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-15.C +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-15.C @@ -2,7 +2,7 @@ // { dg-options "-std=c++0x" } template<class U, class V> //#1 -struct foo {}; // { dg-error "provided for|foo" } +struct foo {}; template<class U, class V=char> struct P {}; @@ -10,8 +10,8 @@ struct P {}; template<template<class... U> class... TT> struct bar { template<class... Args> - using mem = P<TT<Args...>...>;//#2 { dg-error "wrong number of|arguments" } + using mem = P<TT<Args...>...>;//#2 }; -bar<foo>::mem<int, char> b;//#3 { dg-error "invalid type" } +bar<foo>::mem<int, char> b;//#3 diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor10.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor10.C new file mode 100644 index 00000000000..c1279e2b7fc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor10.C @@ -0,0 +1,6 @@ +// PR c++/52599 +// { dg-options -std=c++11 } + +struct foo { + constexpr foo() try { } catch(...) { }; // { dg-error "constructor" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-ctor1.C b/gcc/testsuite/g++.dg/cpp0x/initlist-ctor1.C new file mode 100644 index 00000000000..82031cbcc84 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-ctor1.C @@ -0,0 +1,13 @@ +// PR c++/52905 +// { dg-options -std=c++11 } + +#include <initializer_list> + +enum E { e1, e2 }; +struct A +{ + A(std::initializer_list<E>); // { dg-message "A::A" } + A(int, E); // { dg-message "A::A" } +}; + +A a{e1,2}; // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-err1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-err1.C index ebf0cbd078d..932ff1bee92 100644 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-err1.C +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-err1.C @@ -4,5 +4,5 @@ void foo() { int x[1]; - [x]{} = 0; // { dg-error "lambda closure" } + [x]{} = 0; // { dg-error "lambda" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr27.C b/gcc/testsuite/g++.dg/cpp0x/nullptr27.C new file mode 100644 index 00000000000..1b86868aa19 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr27.C @@ -0,0 +1,8 @@ +// PR c++/52706 +// { dg-options "-std=c++11 -fabi-version=0" } +// { dg-final { scan-assembler "_Z1fIDnLDn0EEiT_" } } + +template<class T, decltype(nullptr) = nullptr> +int f(T); + +int i2 = f(nullptr); // 17 diff --git a/gcc/testsuite/g++.dg/cpp0x/pr39639.C b/gcc/testsuite/g++.dg/cpp0x/pr39639.C index 4fd8b56fd30..0838a0ba25f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr39639.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr39639.C @@ -2,6 +2,7 @@ // Origin: PR c++/39639 // { dg-do compile } // { dg-options "-std=c++0x" } +// { dg-prune-output "template argument 1 is invalid" } template <class... Types> struct S diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae33.C b/gcc/testsuite/g++.dg/cpp0x/sfinae33.C new file mode 100644 index 00000000000..3a5e6f77dfb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae33.C @@ -0,0 +1,27 @@ +// PR c++/52422 +// { dg-options -std=c++11 } + +template<class T> +struct add_rval_ref +{ + typedef T&& type; +}; + +template<> +struct add_rval_ref<void> +{ + typedef void type; +}; + +template<class T> +typename add_rval_ref<T>::type create(); + +template<class T, + class = decltype(create<T>()()) +> +auto f(int) -> char(&)[1]; + +template<class> +auto f(...) -> char(&)[2]; + +static_assert(sizeof(f<void>(0)) != 1, ""); diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae34.C b/gcc/testsuite/g++.dg/cpp0x/sfinae34.C new file mode 100644 index 00000000000..d5d1ca4646b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae34.C @@ -0,0 +1,27 @@ +// PR c++/52422 +// { dg-options -std=c++11 } + +template<class T> +struct add_rval_ref +{ + typedef T&& type; +}; + +template<> +struct add_rval_ref<void> +{ + typedef void type; +}; + +template<class T> +typename add_rval_ref<T>::type create(); + +template<class T, class U, + class = decltype( (create<T>().*create<U>())() ) +> +auto f(int) -> char(&)[1]; + +template<class, class> +auto f(...) -> char(&)[2]; + +static_assert(sizeof(f<void, void>(0)) != 1, ""); diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic123.C b/gcc/testsuite/g++.dg/cpp0x/variadic123.C new file mode 100644 index 00000000000..f0ab9fc22a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic123.C @@ -0,0 +1,14 @@ +// PR c++/52824 +// { dg-do compile { target c++11 } } + +template<typename G, typename H> +struct foo +{}; + +template<typename... G> +struct bar : foo<G...> +{}; + +int main() { + bar<int, float> f; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic124.C b/gcc/testsuite/g++.dg/cpp0x/variadic124.C new file mode 100644 index 00000000000..8ddc810b313 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic124.C @@ -0,0 +1,29 @@ +// PR c++/52292 +// { dg-options -std=c++11 } + +template <template <typename...> class T> +struct foo { + template <typename... U> + foo(T<U...> x) { } +}; + +template <typename T> +struct bar { + bar(T x) : value(x) { } + + T value; +}; + +struct generic : private foo<bar> { + template <typename T> + generic(bar<T> x) : foo(x) + { + } + +}; + +int main() +{ + bar<int> x(32); + generic y(x); // FAILS +} diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic125.C b/gcc/testsuite/g++.dg/cpp0x/variadic125.C new file mode 100644 index 00000000000..89fd6b00d14 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic125.C @@ -0,0 +1,25 @@ +// PR c++/52380 +// { dg-do compile { target c++11 } } + +template<typename T> +struct S +{ + template<typename U> + struct Unary // Line 5 + {}; + + template<unsigned, typename... Args> + struct Dispatch // Line 9 + : public Unary<Args...> + {}; + + template<typename... Args> + struct Variadic + : public Dispatch<sizeof...(Args), Args...> + {}; +}; + +int main() +{ + S<void>::Variadic<void> z; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic126.C b/gcc/testsuite/g++.dg/cpp0x/variadic126.C new file mode 100644 index 00000000000..513c7e54a07 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic126.C @@ -0,0 +1,8 @@ +// PR c++/47220 +// { dg-do compile { target c++11 } } + +template < typename ... > struct A; + +struct B : A < // { dg-error "invalid" } +{ +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic127.C b/gcc/testsuite/g++.dg/cpp0x/variadic127.C new file mode 100644 index 00000000000..2e0d593ac9b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic127.C @@ -0,0 +1,15 @@ +// PR c++/51148 +// { dg-do compile { target c++11 } } + +template<typename... Types> +struct S +{}; + +template<typename... Types> +struct T +{ + friend class S<Types>; // { dg-error "parameter packs not expanded" } +}; + +int main() +{} diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic128.C b/gcc/testsuite/g++.dg/cpp0x/variadic128.C new file mode 100644 index 00000000000..8c2d3b23359 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic128.C @@ -0,0 +1,16 @@ +// PR c++/50303 +// { dg-do compile { target c++11 } } + +template<typename Interface> +struct A1 { +}; + +template<template<class I> class... Actions> +void g2() { + g2<Actions...>(); +} + +int main() +{ + g2<A1>(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic129.C b/gcc/testsuite/g++.dg/cpp0x/variadic129.C new file mode 100644 index 00000000000..7118301418a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic129.C @@ -0,0 +1,19 @@ +// PR c++/50830 +// { dg-do compile { target c++11 } } + +template<template<class> class...> +struct list_templates {}; + +template<class> +struct aa {}; + +template<class... T> +struct test {}; + +template<template<class> class... F, class T> +struct test<list_templates<F...>, T> +{ + struct inner {}; +}; + +test<list_templates<aa>, int> a4; // error diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic130.C b/gcc/testsuite/g++.dg/cpp0x/variadic130.C new file mode 100644 index 00000000000..f73c8b5126c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic130.C @@ -0,0 +1,8 @@ +// PR c++/52008 +// { dg-do compile { target c++11 } } + +template <int I, typename T, typename... Ts> +struct A; + +template<typename... Ts> +struct A<0, Ts...>; // { dg-error "not more specialized" } diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic131.C b/gcc/testsuite/g++.dg/cpp0x/variadic131.C new file mode 100644 index 00000000000..3006f87ed23 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic131.C @@ -0,0 +1,11 @@ +// PR c++/38543 +// { dg-do compile { target c++11 } } + +template< typename ... T > void foo( T ... args ); +template<> void foo( ){} +template<> void foo(int,double){} +int main() +{ + foo( 0, 0.0 ); + return 55; +} diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pr52260.C b/gcc/testsuite/g++.dg/debug/dwarf2/pr52260.C index 9ab2589ce11..024afc8bc54 100644 --- a/gcc/testsuite/g++.dg/debug/dwarf2/pr52260.C +++ b/gcc/testsuite/g++.dg/debug/dwarf2/pr52260.C @@ -22,7 +22,7 @@ namespace A { template <typename T> struct I : H <T> {}; - template <typename ...> struct J; + template <typename ...> struct J {}; template <typename> struct K; struct L { @@ -36,7 +36,7 @@ namespace A template <typename T, typename B2, typename ... B4> struct N <T (B4 ...), B2> : L::M <B2> {}; template <typename T, typename ... B4> - struct K <T (B4 ...)> :J <,>, L + struct K <T (B4 ...)> :J <>, L { typedef T O (B4 ...); struct P {}; diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-1.C index 81bcb2775aa..06db9dcf636 100644 --- a/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-1.C +++ b/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-1.C @@ -5,7 +5,7 @@ struct A { - virtual ~A(); + virtual ~A(){} }; struct B : public A diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-2.C index b1c5401da07..d5463c03e22 100644 --- a/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-2.C +++ b/gcc/testsuite/g++.dg/debug/dwarf2/self-ref-2.C @@ -6,7 +6,7 @@ template<class T> struct A { - virtual ~A(); + virtual ~A(){} }; struct B : public A<int> diff --git a/gcc/testsuite/g++.dg/eh/dtor3.C b/gcc/testsuite/g++.dg/eh/dtor3.C new file mode 100644 index 00000000000..ed9e6d94449 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/dtor3.C @@ -0,0 +1,36 @@ +// Red Hat bug 750545 +// { dg-do run { target c++98 } } + +class excep {}; +class A +{ +public: + ~A() { throw excep(); } +}; + +class B +{ + A a; +}; + +class C +{ + B b; +}; + +void f() +{ + C* c = new C(); + + try + { + delete c; + } + catch(...) + {} +} + +int main() +{ + f(); +} diff --git a/gcc/testsuite/g++.dg/ext/attrib45.C b/gcc/testsuite/g++.dg/ext/attrib45.C new file mode 100644 index 00000000000..0be1322cab2 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib45.C @@ -0,0 +1,3 @@ +// PR c++/52906 + +__attribute__ ((__deprecated__)); // { dg-error "does not declare anything" } diff --git a/gcc/testsuite/g++.dg/ext/label5.C b/gcc/testsuite/g++.dg/ext/label5.C index fc611cd4159..34ca90d87b3 100644 --- a/gcc/testsuite/g++.dg/ext/label5.C +++ b/gcc/testsuite/g++.dg/ext/label5.C @@ -2,5 +2,5 @@ // PR c++/24052 struct A { }; -int main() { b: A() && && b; } // { dg-error "A\\(\\) && && *b" } +int main() { b: A() && && b; } // { dg-error "operand types are 'A' and 'void\\*'" } // { dg-message "candidate|operator&&|no known conversion" "additional" { target *-*-* } 5 } diff --git a/gcc/testsuite/g++.dg/ext/va-arg1.C b/gcc/testsuite/g++.dg/ext/va-arg1.C index 079db2e5c6e..5606128e5f7 100644 --- a/gcc/testsuite/g++.dg/ext/va-arg1.C +++ b/gcc/testsuite/g++.dg/ext/va-arg1.C @@ -4,5 +4,5 @@ struct A {}; void foo() { - ++__builtin_va_arg(0, A); // { dg-error "'\\+\\+va_arg\\(0, A\\)'" } + ++__builtin_va_arg(0, A); // { dg-error "operand type is 'A'" } } diff --git a/gcc/testsuite/g++.dg/ipa/pr52939.C b/gcc/testsuite/g++.dg/ipa/pr52939.C new file mode 100644 index 00000000000..e120827bd1d --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/pr52939.C @@ -0,0 +1,58 @@ +/* Verify that we do not ICE on invalid devirtualizations (which might + be OK at run-time because never executed). */ +/* { dg-do run } */ +/* { dg-options "-O3 -fno-early-inlining -fno-inline" } */ + +extern "C" void abort (void); + +class A +{ +public: + int data; + virtual int foo (int i); +}; + +class B : public A +{ +public: + virtual int foo (int i); + virtual int bar (int i); +}; + +int A::foo (int i) +{ + return i + 1; +} + +int B::foo (int i) +{ + return i + 2; +} + +int B::bar (int i) +{ + return i + 3; +} + +static int middleman (class A *obj, int i) +{ + class B *b = (class B *) obj; + + if (i != 1) + return b->bar (i); + else + return i; +} + +int __attribute__ ((noinline,noclone)) get_input(void) +{ + return 1; +} + +int main (int argc, char *argv[]) +{ + class A o; + if (middleman (&o, get_input ()) != 1) + abort (); + return 0; +} diff --git a/gcc/testsuite/g++.dg/lookup/using52.C b/gcc/testsuite/g++.dg/lookup/using52.C new file mode 100644 index 00000000000..bf2620714e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/using52.C @@ -0,0 +1,16 @@ +// { dg-do compile } +// PR c++/52645 + +class A +{ +protected: + struct B {}; +}; + +class C : A +{ +protected: + using A::B; + + struct D : public B {}; +}; diff --git a/gcc/testsuite/g++.dg/other/anon-union2.C b/gcc/testsuite/g++.dg/other/anon-union2.C new file mode 100644 index 00000000000..31bb74fa99c --- /dev/null +++ b/gcc/testsuite/g++.dg/other/anon-union2.C @@ -0,0 +1,10 @@ +// PR c++/52915 + +struct S { + int val; + S(int v) : val(v) {} +}; + +void f() { + union { S a; }; // { dg-error "constructor|no match" } +} diff --git a/gcc/testsuite/g++.dg/other/error10.C b/gcc/testsuite/g++.dg/other/error10.C index 5c17277abbf..546a4d65c4a 100644 --- a/gcc/testsuite/g++.dg/other/error10.C +++ b/gcc/testsuite/g++.dg/other/error10.C @@ -6,10 +6,9 @@ template<int> struct A {}; template<int N> void foo(const A<N> &a) -{ -A<N>(a); } // { dg-error "\\(\\* & a\\)" "" } +{ -A<N>(a); } // { dg-error "operand type is 'A<0>'" } void bar() { foo(A<0>()); // { dg-message "required from here" "" } } - diff --git a/gcc/testsuite/g++.dg/other/error16.C b/gcc/testsuite/g++.dg/other/error16.C index 1e34647145d..38c0fd63fd1 100644 --- a/gcc/testsuite/g++.dg/other/error16.C +++ b/gcc/testsuite/g++.dg/other/error16.C @@ -10,5 +10,5 @@ typedef Outer<X> XOuter; int main() { Outer<int> ab; - ab.foo() == 1; // { dg-error "ab.Outer" } + ab.foo() == 1; // { dg-error "operand types are 'Outer<int>::Inner' and 'int'" } } diff --git a/gcc/testsuite/g++.dg/other/error20.C b/gcc/testsuite/g++.dg/other/error20.C index f3b17aa196a..bb7d7b3b078 100644 --- a/gcc/testsuite/g++.dg/other/error20.C +++ b/gcc/testsuite/g++.dg/other/error20.C @@ -8,6 +8,6 @@ struct A // { dg-message "operator=|no known conversion" } void bar (A& a) { - a.foo () = 0; // { dg-error "A::foo\\(\\) = 0" } + a.foo () = 0; // { dg-error "operand types are 'A' and 'int'" } // { dg-message "candidate" "candidate note" { target *-*-* } 11 } } diff --git a/gcc/testsuite/g++.dg/parse/crash59.C b/gcc/testsuite/g++.dg/parse/crash59.C new file mode 100644 index 00000000000..e5e62986a3e --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/crash59.C @@ -0,0 +1,3 @@ +// PR c++/53003 + +struct A{ void a{} return b // { dg-error "function definition|expected" } diff --git a/gcc/testsuite/g++.dg/parse/error30.C b/gcc/testsuite/g++.dg/parse/error30.C index 26c55c49c68..aabdcc701c5 100644 --- a/gcc/testsuite/g++.dg/parse/error30.C +++ b/gcc/testsuite/g++.dg/parse/error30.C @@ -8,5 +8,5 @@ struct A A(int); }; -A a = -A(); // { dg-error "10:no match for.*operator-.*in.*-A\\(\\)" } -A b = -A(5); // { dg-error "11:no match for.*operator-.*in.*-A\\(5\\)" } +A a = -A(); // { dg-error "operand type is 'A'" } +A b = -A(5); // { dg-error "operand type is 'A'" } diff --git a/gcc/testsuite/g++.dg/plugin/dumb_plugin.c b/gcc/testsuite/g++.dg/plugin/dumb_plugin.c index 5bbd5d790fe..8913e8694e3 100644 --- a/gcc/testsuite/g++.dg/plugin/dumb_plugin.c +++ b/gcc/testsuite/g++.dg/plugin/dumb_plugin.c @@ -72,7 +72,7 @@ static struct gimple_opt_pass pass_dumb_plugin_example = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0 /* todo_flags_finish */ } }; diff --git a/gcc/testsuite/g++.dg/plugin/selfassign.c b/gcc/testsuite/g++.dg/plugin/selfassign.c index 84d2801d202..feb4130e532 100644 --- a/gcc/testsuite/g++.dg/plugin/selfassign.c +++ b/gcc/testsuite/g++.dg/plugin/selfassign.c @@ -276,7 +276,7 @@ static struct gimple_opt_pass pass_warn_self_assign = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0 /* todo_flags_finish */ } }; diff --git a/gcc/testsuite/g++.dg/pr51264-4.C b/gcc/testsuite/g++.dg/pr51264-4.C new file mode 100644 index 00000000000..58a1b14c409 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr51264-4.C @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -Werror -Wreturn-type" } */ + +/* Test-case from http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25973#c4. */ + +struct Block +{ + public: + Block (); + ~Block (); +}; + +bool func (bool bar) +{ + Block block; + bool foo = false; + + if (!foo || bar) + do + { + return true; + } + while (0); + else + do + { + return false; + } + while (0); +} diff --git a/gcc/testsuite/g++.dg/torture/20120420-1.C b/gcc/testsuite/g++.dg/torture/20120420-1.C new file mode 100644 index 00000000000..ada0ab67e93 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/20120420-1.C @@ -0,0 +1,29 @@ +// { dg-do compile } + +int g, *gp[100]; +struct V { + int* x; + int y; +}; + +void foo (V **p, V* end, int i) +{ + *p = 0; + V* pp = *p; + int s = 100; + for (; pp < end; ) + { + pp++; + (pp-1)->x = &g; + if (g) + { + if (g>10) + g++; + int *t = (int*) operator new (100); + (pp-1)->x = t; + } + else + s--; + gp[end-pp] = (pp-1)->x + s; + } +} diff --git a/gcc/testsuite/g++.dg/torture/pr52918-1.C b/gcc/testsuite/g++.dg/torture/pr52918-1.C new file mode 100644 index 00000000000..9e7b21ba6a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr52918-1.C @@ -0,0 +1,39 @@ +// { dg-do compile } + +typedef __SIZE_TYPE__ size_t; +class bad_alloc { }; +typedef struct { +} __gthread_mutex_t; +int __gthread_mutex_unlock (__gthread_mutex_t *__mutex); +class __concurrence_unlock_error { +}; +inline void __throw_concurrence_unlock_error() { + throw __concurrence_unlock_error(); +} +class __mutex { + __gthread_mutex_t _M_mutex; +public: + void unlock() { + if (__gthread_mutex_unlock(&_M_mutex) != 0) + __throw_concurrence_unlock_error(); + } +}; +class free_list { + typedef __mutex __mutex_type; + __mutex_type& _M_get_mutex(); + void _M_get(size_t __sz) throw(bad_alloc); +}; +void free_list::_M_get(size_t __sz) throw(bad_alloc) +{ + __mutex_type& __bfl_mutex = _M_get_mutex(); + __bfl_mutex.unlock(); + int __ctr = 2; + while (__ctr) { + size_t* __ret = 0; + --__ctr; + try { + __ret = (size_t*) (::operator new(__sz + sizeof(size_t))); + } + catch(const bad_alloc&) { } + } +} diff --git a/gcc/testsuite/g++.dg/torture/pr52918-2.C b/gcc/testsuite/g++.dg/torture/pr52918-2.C new file mode 100644 index 00000000000..ba31295e41e --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr52918-2.C @@ -0,0 +1,40 @@ +// { dg-do compile } + +typedef __SIZE_TYPE__ size_t; +void* __cxa_allocate_exception(size_t) throw(); +typedef struct { } __gthread_mutex_t; +extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *); +int __gthread_mutex_lock (__gthread_mutex_t *__mutex); +int __gthread_mutex_unlock (__gthread_mutex_t *__mutex); +void __throw_concurrence_lock_error(); +void __throw_concurrence_unlock_error(); +class __mutex { + __gthread_mutex_t _M_mutex; +public: + void lock() { + if (__gthread_mutex_lock(&_M_mutex) != 0) + __throw_concurrence_lock_error(); + } + void unlock() { + if (__gthread_mutex_unlock(&_M_mutex) != 0) + __throw_concurrence_unlock_error(); + } +}; +class __scoped_lock { + typedef __mutex __mutex_type; + __mutex_type& _M_device; +public: + explicit __scoped_lock(__mutex_type& __name) : _M_device(__name) { + _M_device.lock(); + } + ~__scoped_lock() throw() { + _M_device.unlock(); + } +}; +__mutex emergency_mutex; +void * __cxa_allocate_exception(size_t thrown_size) throw() +{ + void *ret; + if (! ret) + __scoped_lock sentry(emergency_mutex); +} diff --git a/gcc/testsuite/g++.dg/torture/pr53011.C b/gcc/testsuite/g++.dg/torture/pr53011.C new file mode 100644 index 00000000000..2cd8a60332d --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr53011.C @@ -0,0 +1,66 @@ +// { dg-do compile } + +extern "C" class WvFastString; +typedef WvFastString& WvStringParm; +struct WvFastString { + ~WvFastString(); + operator char* () {} +}; +class WvString : WvFastString {}; +class WvAddr {}; +class WvIPAddr : WvAddr {}; +struct WvIPNet : WvIPAddr { + bool is_default() {} +}; +template<class T, bool> struct WvTraits_Helper { + static void release(T *obj) { + delete obj; + } +}; +template<class From> struct WvTraits { + static void release(From *obj) { + WvTraits_Helper<From, 0>::release(obj); + } +}; +struct WvLink { + void *data; + WvLink *next; + bool autofree; + WvLink(bool, int) : autofree() {} + bool get_autofree() {} + + void unlink() { + delete this; + } +}; +struct WvListBase { + WvLink head, *tail; + WvListBase() : head(0, 0) {} +}; +template<class T> struct WvList : WvListBase { + ~WvList() { + zap(); + } + + void zap(bool destroy = 1) { + while (head.next) unlink_after(&head, destroy); + } + + void unlink_after(WvLink *after, bool destroy) { + WvLink *next = 0; + T *obj = (destroy && next->get_autofree()) ? + static_cast<T*>(next->data) : 0; + + if (tail) tail = after; + next->unlink(); + WvTraits<T>::release(obj); + } +}; +typedef WvList<WvString>WvStringListBase; +class WvStringList : WvStringListBase {}; +class WvSubProc { + WvStringList last_args, env; +}; +void addroute(WvIPNet& dest, WvStringParm table) { + if (dest.is_default() || (table != "default")) WvSubProc checkProc; +} diff --git a/gcc/testsuite/g++.dg/warn/format8.C b/gcc/testsuite/g++.dg/warn/format8.C new file mode 100644 index 00000000000..ffceb797a7d --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/format8.C @@ -0,0 +1,7 @@ +// PR c++/52818 +// { dg-options "-pedantic-errors -Wformat" } + +extern "C" int printf (const char *, ...); +void f() { + printf("%lf", 0.0); // { dg-warning "%lf" "" { target c++98 } } +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr15296.c b/gcc/testsuite/gcc.c-torture/execute/pr15296.c index d2468e425af..a3b53cb976e 100644 --- a/gcc/testsuite/gcc.c-torture/execute/pr15296.c +++ b/gcc/testsuite/gcc.c-torture/execute/pr15296.c @@ -3,7 +3,7 @@ fall-through code, while that register held a pointer used in code at the branch target. */ -typedef int __attribute__ ((mode (__pointer__))) intptr_t; +typedef __INTPTR_TYPE__ intptr_t; typedef intptr_t W; union u0 { diff --git a/gcc/testsuite/gcc.c-torture/execute/pr22098-1.c b/gcc/testsuite/gcc.c-torture/execute/pr22098-1.c index 142530f62c1..7e876fa8cd1 100644 --- a/gcc/testsuite/gcc.c-torture/execute/pr22098-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/pr22098-1.c @@ -1,13 +1,13 @@ extern void abort (void); extern void exit (int); -typedef __SIZE_TYPE__ size_t; +typedef __UINTPTR_TYPE__ uintptr_t; int main (void) { int a = 0; int *p; - size_t b; - b = (size_t)(p = &(int []){0, 1, 2}[++a]); + uintptr_t b; + b = (uintptr_t)(p = &(int []){0, 1, 2}[++a]); if (a != 1 || *p != 1 || *(int *)b != 1) abort (); exit (0); diff --git a/gcc/testsuite/gcc.c-torture/execute/pr22098-2.c b/gcc/testsuite/gcc.c-torture/execute/pr22098-2.c index 249647dc570..035a755a522 100644 --- a/gcc/testsuite/gcc.c-torture/execute/pr22098-2.c +++ b/gcc/testsuite/gcc.c-torture/execute/pr22098-2.c @@ -1,13 +1,13 @@ extern void abort (void); extern void exit (int); -typedef __SIZE_TYPE__ size_t; +typedef __UINTPTR_TYPE__ uintptr_t; int main (void) { int a = 0; int *p; - size_t b; - b = (size_t)(p = &(int []){0, 1, 2}[1]); + uintptr_t b; + b = (uintptr_t)(p = &(int []){0, 1, 2}[1]); if (*p != 1 || *(int *)b != 1) abort (); exit (0); diff --git a/gcc/testsuite/gcc.c-torture/execute/pr22098-3.c b/gcc/testsuite/gcc.c-torture/execute/pr22098-3.c index 4c8a1c62ce0..4f37be86c8c 100644 --- a/gcc/testsuite/gcc.c-torture/execute/pr22098-3.c +++ b/gcc/testsuite/gcc.c-torture/execute/pr22098-3.c @@ -1,6 +1,6 @@ extern void abort (void); extern void exit (int); -typedef __SIZE_TYPE__ size_t; +typedef __UINTPTR_TYPE__ uintptr_t; int n = 0; int f (void) { return ++n; } int @@ -8,8 +8,8 @@ main (void) { int a = 0; int *p; - size_t b; - b = (size_t)(p = &(int []){0, f(), 2}[1]); + uintptr_t b; + b = (uintptr_t)(p = &(int []){0, f(), 2}[1]); if (*p != 1 || *(int *)b != 1 || n != 1) abort (); exit (0); diff --git a/gcc/testsuite/gcc.dg/20041106-1.c b/gcc/testsuite/gcc.dg/20041106-1.c index f83e835ed1d..f33ba01c8cd 100644 --- a/gcc/testsuite/gcc.dg/20041106-1.c +++ b/gcc/testsuite/gcc.dg/20041106-1.c @@ -21,7 +21,7 @@ int main () struct S *s; ptr = malloc (3*ps); - page = (char *)(((size_t)ptr + (ps - 1)) & -ps); + page = (char *)(((__UINTPTR_TYPE__)ptr + (ps - 1)) & -ps); munmap (page + ps, ps); s = (struct S *)(page + ps - sizeof(struct S)); diff --git a/gcc/testsuite/gcc.dg/array-10.c b/gcc/testsuite/gcc.dg/array-10.c index 3b4d512ba5a..44457d12c06 100644 --- a/gcc/testsuite/gcc.dg/array-10.c +++ b/gcc/testsuite/gcc.dg/array-10.c @@ -13,12 +13,12 @@ struct b3 { int x[a]; }; /* { dg-error "17:at file scope" } */ struct b4 { int (*x)[a]; }; /* { dg-error "19:at file scope" } */ typeof (int [a]) b5; /* { dg-error "at file scope|outside of any function" } */ -int c0[(__SIZE_TYPE__)&a]; /* { dg-error "5:at file scope" } */ -int (*c1)[(__SIZE_TYPE__)&a]; /* { dg-error "7:at file scope" } */ -int (*c2())[(__SIZE_TYPE__)&a]; /* { dg-error "7:at file scope" } */ -struct c3 { int x[(__SIZE_TYPE__)&a]; }; /* { dg-error "17:at file scope" } */ -struct c4 { int (*x)[(__SIZE_TYPE__)&a]; }; /* { dg-error "19:at file scope" } */ -typeof (int [(__SIZE_TYPE__)&a]) c5; /* { dg-error "34:at file scope" } */ +int c0[(__UINTPTR_TYPE__)&a]; /* { dg-error "5:at file scope" } */ +int (*c1)[(__UINTPTR_TYPE__)&a]; /* { dg-error "7:at file scope" } */ +int (*c2())[(__UINTPTR_TYPE__)&a]; /* { dg-error "7:at file scope" } */ +struct c3 { int x[(__UINTPTR_TYPE__)&a]; }; /* { dg-error "17:at file scope" } */ +struct c4 { int (*x)[(__UINTPTR_TYPE__)&a]; }; /* { dg-error "19:at file scope" } */ +typeof (int [(__UINTPTR_TYPE__)&a]) c5; /* { dg-error "37:at file scope" } */ int d0[1/0]; /* { dg-error "5:at file scope" } */ /* { dg-warning "9:division by zero" "" { target *-*-* } 23 } */ diff --git a/gcc/testsuite/gcc.dg/builtin-bswap-1.c b/gcc/testsuite/gcc.dg/builtin-bswap-1.c index 6b4a805536c..724ba1e9847 100644 --- a/gcc/testsuite/gcc.dg/builtin-bswap-1.c +++ b/gcc/testsuite/gcc.dg/builtin-bswap-1.c @@ -5,11 +5,29 @@ #include <stdint.h> -uint32_t foo (uint32_t a) +uint16_t foo16 (uint16_t a) { - int b; + uint16_t b; + + b = __builtin_bswap16 (a); + + return b; +} + +uint32_t foo32 (uint32_t a) +{ + uint32_t b; b = __builtin_bswap32 (a); return b; } + +uint64_t foo64 (uint64_t a) +{ + uint64_t b; + + b = __builtin_bswap64 (a); + + return b; +} diff --git a/gcc/testsuite/gcc.dg/builtin-bswap-4.c b/gcc/testsuite/gcc.dg/builtin-bswap-4.c index 03e190ad782..da8ee68cd51 100644 --- a/gcc/testsuite/gcc.dg/builtin-bswap-4.c +++ b/gcc/testsuite/gcc.dg/builtin-bswap-4.c @@ -16,11 +16,19 @@ return result; \ } \ +MAKE_FUN(16, uint16_t); MAKE_FUN(32, uint32_t); MAKE_FUN(64, uint64_t); extern void abort (void); +#define NUMS16 \ + { \ + 0x0000, \ + 0x1122, \ + 0xffff, \ + } + #define NUMS32 \ { \ 0x00000000UL, \ @@ -35,6 +43,9 @@ extern void abort (void); 0xffffffffffffffffULL, \ } +uint16_t uint16_ts[] = + NUMS16; + uint32_t uint32_ts[] = NUMS32; @@ -48,6 +59,10 @@ main (void) { int i; + for (i = 0; i < N(uint16_ts); i++) + if (__builtin_bswap16 (uint16_ts[i]) != my_bswap16 (uint16_ts[i])) + abort (); + for (i = 0; i < N(uint32_ts); i++) if (__builtin_bswap32 (uint32_ts[i]) != my_bswap32 (uint32_ts[i])) abort (); diff --git a/gcc/testsuite/gcc.dg/builtin-bswap-5.c b/gcc/testsuite/gcc.dg/builtin-bswap-5.c index ccac9663334..b29931e4e10 100644 --- a/gcc/testsuite/gcc.dg/builtin-bswap-5.c +++ b/gcc/testsuite/gcc.dg/builtin-bswap-5.c @@ -6,6 +6,9 @@ main (void) /* Test constant folding. */ extern void link_error (void); + if (__builtin_bswap16(0xaabb) != 0xbbaa) + link_error (); + if (__builtin_bswap32(0xaabbccdd) != 0xddccbbaa) link_error (); diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-6.c b/gcc/testsuite/gcc.dg/c90-const-expr-6.c index c432cca6343..50239ce2eba 100644 --- a/gcc/testsuite/gcc.dg/c90-const-expr-6.c +++ b/gcc/testsuite/gcc.dg/c90-const-expr-6.c @@ -4,13 +4,13 @@ /* { dg-do compile } */ /* { dg-options "-std=iso9899:1990 -pedantic-errors" } */ -__extension__ typedef __PTRDIFF_TYPE__ ptrdiff_t; +__extension__ typedef __INTPTR_TYPE__ intptr_t; /* PR 29116. */ int n = 0, p[n * 0 + 1]; /* { dg-error "variabl|can't be evaluated" } */ /* PR 31871. */ -extern int c[1 + ((ptrdiff_t) (void *) 0)]; /* { dg-error "variab|can't be evaluated" } */ +extern int c[1 + ((intptr_t) (void *) 0)]; /* { dg-error "variab|can't be evaluated" } */ /* Implicit conversions from floating-point constants are not OK, although explicit ones are. */ @@ -34,7 +34,7 @@ struct s { }; enum e { - E = (1 + ((ptrdiff_t) (void *) 0)), /* { dg-error "constant" } */ + E = (1 + ((intptr_t) (void *) 0)), /* { dg-error "constant" } */ E2 = 0 }; @@ -46,7 +46,7 @@ enum f { void f (int a) { - int v[1 + ((ptrdiff_t) (void *) 0)]; /* { dg-error "variab|can't be evaluated" } */ + int v[1 + ((intptr_t) (void *) 0)]; /* { dg-error "variab|can't be evaluated" } */ switch (a) { case (n * 0 + 1): /* { dg-error "constant" } */ diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-9.c b/gcc/testsuite/gcc.dg/c90-const-expr-9.c index a06cdd951b2..0d5d8c1ae00 100644 --- a/gcc/testsuite/gcc.dg/c90-const-expr-9.c +++ b/gcc/testsuite/gcc.dg/c90-const-expr-9.c @@ -15,8 +15,9 @@ struct t { }; __extension__ typedef __SIZE_TYPE__ size_t; +__extension__ typedef __UINTPTR_TYPE__ uintptr_t; -#define old_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define old_offsetof(TYPE, MEMBER) ((size_t) (uintptr_t) &((TYPE *)0)->MEMBER) enum e { E1 = old_offsetof (struct s, a), /* { dg-error "constant" } */ diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-6.c b/gcc/testsuite/gcc.dg/c99-const-expr-6.c index 1a31ddc40c4..ca602438d35 100644 --- a/gcc/testsuite/gcc.dg/c99-const-expr-6.c +++ b/gcc/testsuite/gcc.dg/c99-const-expr-6.c @@ -8,7 +8,7 @@ int n = 0, p[n * 0 + 1]; /* { dg-error "variabl" } */ /* PR 31871. */ -extern int c[1 + ((__PTRDIFF_TYPE__) (void *) 0)]; /* { dg-error "variab" } */ +extern int c[1 + ((__INTPTR_TYPE__) (void *) 0)]; /* { dg-error "variab" } */ /* Implicit conversions from floating-point constants are not OK, although explicit ones are. */ @@ -32,7 +32,7 @@ struct s { }; enum e { - E = (1 + ((__PTRDIFF_TYPE__) (void *) 0)), /* { dg-error "constant" } */ + E = (1 + ((__INTPTR_TYPE__) (void *) 0)), /* { dg-error "constant" } */ E2 = 0 }; diff --git a/gcc/testsuite/gcc.dg/c99-const-expr-9.c b/gcc/testsuite/gcc.dg/c99-const-expr-9.c index 48f43edece6..a0a6a9635c3 100644 --- a/gcc/testsuite/gcc.dg/c99-const-expr-9.c +++ b/gcc/testsuite/gcc.dg/c99-const-expr-9.c @@ -14,7 +14,7 @@ struct t { int b[2]; }; -#define old_offsetof(TYPE, MEMBER) ((__SIZE_TYPE__) &((TYPE *)0)->MEMBER) +#define old_offsetof(TYPE, MEMBER) ((__SIZE_TYPE__)(__UINTPTR_TYPE__) &((TYPE *)0)->MEMBER) enum e { E1 = old_offsetof (struct s, a), /* { dg-error "constant" } */ diff --git a/gcc/testsuite/gcc.dg/format/cast-1.c b/gcc/testsuite/gcc.dg/format/cast-1.c index 03e624a5cca..5d1d47709b7 100644 --- a/gcc/testsuite/gcc.dg/format/cast-1.c +++ b/gcc/testsuite/gcc.dg/format/cast-1.c @@ -11,6 +11,6 @@ void f (int x) { printf("%s", x); /* { dg-warning "format" } */ - printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */ + printf((char *)(__UINTPTR_TYPE__)"%s", x); /* { dg-warning "format" } */ printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */ } diff --git a/gcc/testsuite/gcc.dg/inline-23.c b/gcc/testsuite/gcc.dg/inline-23.c index 55bd72a59e6..2829ecbf7e1 100644 --- a/gcc/testsuite/gcc.dg/inline-23.c +++ b/gcc/testsuite/gcc.dg/inline-23.c @@ -3,16 +3,19 @@ /* Make sure we can inline a varargs function whose variable arguments are not used. See PR32493. */ #include <stddef.h> + +typedef __INTPTR_TYPE__ my_intptr_t; + static inline __attribute__((always_inline)) void __check_printsym_format(const char *fmt, ...) { } static inline __attribute__((always_inline)) void print_symbol(const char *fmt, -ptrdiff_t addr) +my_intptr_t addr) { __check_printsym_format(fmt, ""); } void do_initcalls(void **call) { - print_symbol(": %s()", (ptrdiff_t) *call); + print_symbol(": %s()", (my_intptr_t) *call); } diff --git a/gcc/testsuite/gcc.dg/long-long-cst1.c b/gcc/testsuite/gcc.dg/long-long-cst1.c index 7c60648d281..800d6d64b9f 100644 --- a/gcc/testsuite/gcc.dg/long-long-cst1.c +++ b/gcc/testsuite/gcc.dg/long-long-cst1.c @@ -7,7 +7,7 @@ extern void abort(); struct st{ int _mark; }; -unsigned long long t = ((int)(__SIZE_TYPE__)&(((struct st*)16)->_mark) - 32); +unsigned long long t = ((int)(__UINTPTR_TYPE__)&(((struct st*)16)->_mark) - 32); int main() { diff --git a/gcc/testsuite/gcc.dg/mallign.c b/gcc/testsuite/gcc.dg/mallign.c index 6a0041e6466..349cdaa343f 100644 --- a/gcc/testsuite/gcc.dg/mallign.c +++ b/gcc/testsuite/gcc.dg/mallign.c @@ -9,7 +9,7 @@ typedef int word __attribute__((mode(word))); int main() { - if ((size_t)malloc (1) & (sizeof(word)-1)) + if ((__UINTPTR_TYPE__)malloc (1) & (sizeof(word)-1)) abort (); return 0; } diff --git a/gcc/testsuite/gcc.dg/max-1.c b/gcc/testsuite/gcc.dg/max-1.c index 40f2145c038..9823dca597e 100644 --- a/gcc/testsuite/gcc.dg/max-1.c +++ b/gcc/testsuite/gcc.dg/max-1.c @@ -7,19 +7,16 @@ /* m32c has varying sized pointers */ /* { dg-skip-if "" { "m32c-*-*" } { "*" } { "-mcpu=m32c" "-mcpu=m32cm" } } */ -/* Kludge to make it signed. */ -#define unsigned signed -__extension__ typedef __SIZE_TYPE__ ssize_t; -#undef unsigned +__extension__ typedef __INTPTR_TYPE__ intptr_t; extern void abort (void); -ssize_t fff[10]; +intptr_t fff[10]; -void f(ssize_t a, ssize_t b) +void f(intptr_t a, intptr_t b) { - ssize_t crcc = b; - ssize_t d = *((ssize_t*)(a+1)); + intptr_t crcc = b; + intptr_t d = *((intptr_t*)(a+1)); int i; a = d >= b? d:b; @@ -32,11 +29,11 @@ void f(ssize_t a, ssize_t b) /* The variable a cannot be a local variable as we get better aliasing now and decide that the store to a is dead. The better aliasing comes from better representation of pointer arithmetic. */ -ssize_t a = 10; +intptr_t a = 10; int main(void) { int i; - f((ssize_t)(&a)-1,0); + f((intptr_t)(&a)-1,0); for(i = 0;i<10;i++) if (fff[i]!=10) abort (); diff --git a/gcc/testsuite/gcc.dg/plugin/one_time_plugin.c b/gcc/testsuite/gcc.dg/plugin/one_time_plugin.c index 2c4cd497192..4bd99f12830 100644 --- a/gcc/testsuite/gcc.dg/plugin/one_time_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/one_time_plugin.c @@ -42,7 +42,7 @@ struct gimple_opt_pass one_pass = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0 /* todo_flags_finish */ } }; diff --git a/gcc/testsuite/gcc.dg/plugin/selfassign.c b/gcc/testsuite/gcc.dg/plugin/selfassign.c index 84d2801d202..feb4130e532 100644 --- a/gcc/testsuite/gcc.dg/plugin/selfassign.c +++ b/gcc/testsuite/gcc.dg/plugin/selfassign.c @@ -276,7 +276,7 @@ static struct gimple_opt_pass pass_warn_self_assign = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0 /* todo_flags_finish */ } }; diff --git a/gcc/testsuite/gcc.dg/pointer-arith-10.c b/gcc/testsuite/gcc.dg/pointer-arith-10.c index 220891e2097..52b1989ef93 100644 --- a/gcc/testsuite/gcc.dg/pointer-arith-10.c +++ b/gcc/testsuite/gcc.dg/pointer-arith-10.c @@ -1,9 +1,9 @@ /* { dg-do compile } */ /* { dg-options "-fdump-tree-original" } */ -char *foo(char *p, __SIZE_TYPE__ i) +char *foo(char *p, __UINTPTR_TYPE__ i) { - return (char *)i + (__SIZE_TYPE__)p; + return (char *)i + (__UINTPTR_TYPE__)p; } /* { dg-final { scan-tree-dump "p +" "original" } } */ diff --git a/gcc/testsuite/gcc.dg/pr14092-1.c b/gcc/testsuite/gcc.dg/pr14092-1.c index 927ecf6aa3b..1c103ccb312 100644 --- a/gcc/testsuite/gcc.dg/pr14092-1.c +++ b/gcc/testsuite/gcc.dg/pr14092-1.c @@ -6,7 +6,7 @@ /* Define this so that we are more portable. The testcase in the PR failed on 64-bit hosts. */ -typedef int __attribute__ ((mode (__pointer__))) intptr_t; +typedef __INTPTR_TYPE__ intptr_t; typedef struct _PLCI { unsigned char x; diff --git a/gcc/testsuite/gcc.dg/pr25682.c b/gcc/testsuite/gcc.dg/pr25682.c index 8c51d82403a..e8cab1d05e5 100644 --- a/gcc/testsuite/gcc.dg/pr25682.c +++ b/gcc/testsuite/gcc.dg/pr25682.c @@ -11,7 +11,7 @@ struct S }; char c[(char *) &((struct S *) 0)->b - (char *) 0]; /* { dg-warning "variably modified" } */ -char d[(__SIZE_TYPE__) &((struct S *) 8)->b]; /* { dg-warning "variably modified" } */ +char d[(__UINTPTR_TYPE__) &((struct S *) 8)->b]; /* { dg-warning "variably modified" } */ char e[sizeof (c) == __builtin_offsetof (struct S, b) ? 1 : -1]; char f[sizeof (d) == __builtin_offsetof (struct S, b) + 8 ? 1 : -1]; @@ -21,7 +21,7 @@ void foo (void) { char g[(char *) &((struct S *) 0)->b - (char *) 0]; - char h[(__SIZE_TYPE__) &((struct S *) 8)->b]; + char h[(__UINTPTR_TYPE__) &((struct S *) 8)->b]; char i[sizeof (g) == __builtin_offsetof (struct S, b) ? 1 : -1]; char j[sizeof (h) == __builtin_offsetof (struct S, b) + 8 ? 1 : -1]; bar (g, h); diff --git a/gcc/testsuite/gcc.dg/pr30744-1.c b/gcc/testsuite/gcc.dg/pr30744-1.c index a35c5526aa1..f08f3be172a 100644 --- a/gcc/testsuite/gcc.dg/pr30744-1.c +++ b/gcc/testsuite/gcc.dg/pr30744-1.c @@ -2,15 +2,17 @@ /* { dg-options "-O2" } */ #include <stddef.h> +typedef __INTPTR_TYPE__ my_intptr_t; + typedef struct { - ptrdiff_t unique; + my_intptr_t unique; } G; void r(G* n) { - ptrdiff_t p; - if (((G *) ((void *)((~(ptrdiff_t)(p))))) != ((void *)0)) { - ((G *) ((void *)((~(ptrdiff_t)(p)))))->unique = n->unique; + my_intptr_t p; + if (((G *) ((void *)((~(my_intptr_t)(p))))) != ((void *)0)) { + ((G *) ((void *)((~(my_intptr_t)(p)))))->unique = n->unique; } } diff --git a/gcc/testsuite/gcc.dg/pr34856.c b/gcc/testsuite/gcc.dg/pr34856.c index 6bfc704774f..62041e248ba 100644 --- a/gcc/testsuite/gcc.dg/pr34856.c +++ b/gcc/testsuite/gcc.dg/pr34856.c @@ -3,7 +3,7 @@ /* { dg-options "-O2 -msse2" { target { i?86-*-* x86_64-*-* } } } */ /* { dg-options "-O2 -maltivec" { target { powerpc*-*-linux* && powerpc_altivec_ok } } } */ -typedef unsigned __attribute__ ((__mode__ (__pointer__))) uintptr_t; +typedef __UINTPTR_TYPE__ uintptr_t; #undef __vector #define __vector __attribute__ ((__vector_size__ (16))) diff --git a/gcc/testsuite/gcc.dg/pr37561.c b/gcc/testsuite/gcc.dg/pr37561.c index ec712a7841d..3ad826329f9 100644 --- a/gcc/testsuite/gcc.dg/pr37561.c +++ b/gcc/testsuite/gcc.dg/pr37561.c @@ -1,7 +1,7 @@ /* PR c++/37561 */ /* { dg-do compile } */ -__extension__ __PTRDIFF_TYPE__ p; +__extension__ __INTPTR_TYPE__ p; char q; void diff --git a/gcc/testsuite/gcc.dg/pr37985.c b/gcc/testsuite/gcc.dg/pr37985.c new file mode 100644 index 00000000000..93e640b4a36 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr37985.c @@ -0,0 +1,8 @@ +/* PR c37985 */ +/* { dg-do compile } */ +/* { dg-options " -Wall -Wextra " } */ +unsigned char foo(unsigned char a) +{ + a >> 2; /* { dg-warning "no effect" } */ + return a; +} diff --git a/gcc/testsuite/gcc.dg/pr38700.c b/gcc/testsuite/gcc.dg/pr38700.c index bfa75b0c7cb..ebece7f0ff4 100644 --- a/gcc/testsuite/gcc.dg/pr38700.c +++ b/gcc/testsuite/gcc.dg/pr38700.c @@ -5,7 +5,7 @@ int foo () { - __SIZE_TYPE__ s = __builtin_expect ((__SIZE_TYPE__)&&L, 0); + __UINTPTR_TYPE__ s = __builtin_expect ((__UINTPTR_TYPE__)&&L, 0); L: return 0; } diff --git a/gcc/testsuite/gcc.dg/pr41551.c b/gcc/testsuite/gcc.dg/pr41551.c index e24fbc33db4..2f2ad2be97e 100644 --- a/gcc/testsuite/gcc.dg/pr41551.c +++ b/gcc/testsuite/gcc.dg/pr41551.c @@ -3,10 +3,10 @@ /* Make sure we do not ICE. */ -__extension__ typedef __SIZE_TYPE__ size_t; +__extension__ typedef __UINTPTR_TYPE__ uintptr_t; int main(void) { int var, *p = &var; - return (double)(size_t)(p); + return (double)(uintptr_t)(p); } diff --git a/gcc/testsuite/gcc.dg/pr44214-1.c b/gcc/testsuite/gcc.dg/pr44214-1.c new file mode 100644 index 00000000000..292ce57c30e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr44214-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -freciprocal-math -fdump-tree-ccp1" } */ + +typedef double v2df __attribute__ ((vector_size (16))); + +void do_div (v2df *a, v2df *b) +{ + *a = *b / (v2df) { 2.0, 3.0 }; +} + +/* Constant folding should multiply *b by the reciprocals of the + vector elements. The fold does not take place for generic + vectors until the first CCP pass. The string " * " occurs 3 + times: one multiply and two indirect parameters. */ + +/* { dg-final { scan-tree-dump-times " \\\* " 3 "ccp1" } } */ +/* { dg-final { scan-tree-dump-times " / " 0 "ccp1" } } */ +/* { dg-final { cleanup-tree-dump "ccp1" } } */ diff --git a/gcc/testsuite/gcc.dg/pr44214-2.c b/gcc/testsuite/gcc.dg/pr44214-2.c new file mode 100644 index 00000000000..7e8581a2bb3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr44214-2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -freciprocal-math -fdump-tree-original" } */ + +void do_div (_Complex double *a, _Complex double *b) +{ + *a = *b / (4.0 - 5.0fi); +} + +/* Constant folding should multiply *b by the reciprocal of 4 - 5i + = 4/41 + (5/41)i. */ + +/* { dg-final { scan-tree-dump-times " \\\* " 1 "original" } } */ +/* { dg-final { scan-tree-dump-times " / " 0 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/gcc.dg/pr44214-3.c b/gcc/testsuite/gcc.dg/pr44214-3.c new file mode 100644 index 00000000000..46d5ee8c78e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr44214-3.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ccp1" } */ + +typedef double v2df __attribute__ ((vector_size (16))); + +void do_div (v2df *a, v2df *b) +{ + *a = *b / (v2df) { 2.0, 2.0 }; +} + +/* Since 2.0 has an exact reciprocal, constant folding should multiply *b + by the reciprocals of the vector elements. As a result there should be + one vector multiply and zero divides in the optimized code. The fold + does not take place for generic vectors until the first CCP pass. The + string " * " occurs 3 times: one multiply and two indirect parameters. */ + +/* { dg-final { scan-tree-dump-times " \\\* " 3 "ccp1" } } */ +/* { dg-final { scan-tree-dump-times " / " 0 "ccp1" } } */ +/* { dg-final { cleanup-tree-dump "ccp1" } } */ diff --git a/gcc/testsuite/gcc.dg/pr51879-12.c b/gcc/testsuite/gcc.dg/pr51879-12.c new file mode 100644 index 00000000000..1b25e296fbf --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr51879-12.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre" } */ + +__attribute__((pure)) int bar (int); +__attribute__((pure)) int bar2 (int); +void baz (int); + +int x, z; + +void +foo (int y) +{ + int a = 0; + if (y == 6) + { + a += bar (7); + a += bar2 (6); + } + else + { + a += bar2 (6); + a += bar (7); + } + baz (a); +} + +/* { dg-final { scan-tree-dump-times "bar \\(" 1 "pre"} } */ +/* { dg-final { scan-tree-dump-times "bar2 \\(" 1 "pre"} } */ +/* { dg-final { cleanup-tree-dump "pre" } } */ diff --git a/gcc/testsuite/gcc.dg/pr52283.c b/gcc/testsuite/gcc.dg/pr52283.c new file mode 100644 index 00000000000..33785a598e2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr52283.c @@ -0,0 +1,16 @@ +/* Test for case labels not integer constant expressions but folding + to integer constants (used in Linux kernel). */ +/* { dg-do compile } */ + +extern unsigned int u; + +void +b (int c) +{ + switch (c) + { + case (int) (2 | ((4 < 8) ? 8 : u)): + ; + } +} + diff --git a/gcc/testsuite/gcc.dg/pr52549.c b/gcc/testsuite/gcc.dg/pr52549.c new file mode 100644 index 00000000000..89ec2aaf6cc --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr52549.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ + +_mark (long obj, int i, char *a) +{ + (char *)&(((long *)(obj)) [i]) - a; +} diff --git a/gcc/testsuite/gcc.dg/pr52734.c b/gcc/testsuite/gcc.dg/pr52734.c new file mode 100644 index 00000000000..a6894954e71 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr52734.c @@ -0,0 +1,35 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +int bbb = 0; + +int __attribute__((noinline,noclone)) aaa(void) +{ + ++bbb; + return 0; +} + +int __attribute__((noinline,noclone)) ccc(void) +{ + int ddd; + /* bbb == 0 */ + if (aaa()) + return bbb; + + /* bbb == 1 */ + ddd = bbb; + /* bbb == ddd == 1 */ + if (aaa ()) + return 0; + /* bbb == 2, ddd == 1 */ + + return ddd; +} + +int main(void) +{ + if (ccc() != 1) + __builtin_abort(); + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/pr52862.c b/gcc/testsuite/gcc.dg/pr52862.c new file mode 100644 index 00000000000..febe7a8289b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr52862.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +void ASMAtomicWritePtrVoid(const void *pv); +void rtThreadDestroy(void) +{ + void * const pvTypeChecked = ((void *)0); + ASMAtomicWritePtrVoid((void *)(pvTypeChecked)); +} diff --git a/gcc/testsuite/gcc.dg/sequence-pt-1.c b/gcc/testsuite/gcc.dg/sequence-pt-1.c index 05eee82c176..2e22b662a46 100644 --- a/gcc/testsuite/gcc.dg/sequence-pt-1.c +++ b/gcc/testsuite/gcc.dg/sequence-pt-1.c @@ -15,7 +15,7 @@ extern int fnb (int, int); extern int fnc (int *); extern int sprintf (char *, const char *, ...); -typedef __SIZE_TYPE__ size_t; +typedef __UINTPTR_TYPE__ uintptr_t; void foo (int a, int b, int n, int p, int *ptr, struct s *sptr, @@ -32,9 +32,9 @@ foo (int a, int b, int n, int p, int *ptr, struct s *sptr, ap[++n] = bp[--n]; /* { dg-warning "undefined" "sequence point warning" } */ cp[n][n] = cp[n][n]++; /* { dg-warning "undefined" "sequence point warning" } */ cp[n][p] = cp[n][n++]; /* { dg-warning "undefined" "sequence point warning" } */ - *ptr++ = (size_t)ptr++; /* { dg-warning "undefined" "sequence point warning" } */ + *ptr++ = (uintptr_t)ptr++; /* { dg-warning "undefined" "sequence point warning" } */ sptr->a = sptr->a++; /* { dg-warning "undefined" "sequence point warning" } */ - sptr->a = (size_t)(sptr++); /* { dg-warning "undefined" "sequence point warning" } */ + sptr->a = (uintptr_t)(sptr++); /* { dg-warning "undefined" "sequence point warning" } */ *ptr++ = fn (*ptr); /* { dg-warning "undefined" "sequence point warning" } */ a = b = a++; /* { dg-warning "undefined" "sequence point warning" } */ b = a = --b; /* { dg-warning "undefined" "sequence point warning" } */ diff --git a/gcc/testsuite/gcc.dg/stack-usage-1.c b/gcc/testsuite/gcc.dg/stack-usage-1.c index c852f78f5cd..78bb51d9bb2 100644 --- a/gcc/testsuite/gcc.dg/stack-usage-1.c +++ b/gcc/testsuite/gcc.dg/stack-usage-1.c @@ -58,6 +58,8 @@ # define SIZE 224 #elif defined (__epiphany__) # define SIZE (256 - __EPIPHANY_STACK_OFFSET__) +#elif defined (__RL78__) +# define SIZE 254 #else # define SIZE 256 #endif diff --git a/gcc/testsuite/gcc.dg/superblock.c b/gcc/testsuite/gcc.dg/superblock.c new file mode 100644 index 00000000000..2b9aedfdac4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/superblock.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-asynchronous-unwind-tables -fsched2-use-superblocks -fdump-rtl-sched2 -fdump-rtl-bbro" } */ + +typedef int aligned __attribute__ ((aligned (64))); +extern void abort (void); + +int bar (void *p); + +void +foo (void) +{ + char *p = __builtin_alloca (13); + aligned i; + + if (bar (p) || bar (&i)) + abort (); +} + +/* { dg-final { scan-rtl-dump-times "0 uses" 0 "bbro"} } */ +/* { dg-final { scan-rtl-dump-times "ADVANCING TO" 2 "sched2"} } */ +/* { dg-final { cleanup-rtl-dump "bbro" } } */ +/* { dg-final { cleanup-rtl-dump "sched2" } } */ + diff --git a/gcc/testsuite/gcc.dg/torture/pr39074.c b/gcc/testsuite/gcc.dg/torture/pr39074.c index 4775062d964..89c4ac6ca9f 100644 --- a/gcc/testsuite/gcc.dg/torture/pr39074.c +++ b/gcc/testsuite/gcc.dg/torture/pr39074.c @@ -2,7 +2,7 @@ /* { dg-options "-fdump-tree-alias" } */ /* { dg-skip-if "" { *-*-* } { "-O0" "-fno-fat-lto-objects" } { "" } } */ -typedef __PTRDIFF_TYPE__ intptr_t; +typedef __INTPTR_TYPE__ intptr_t; int i; void __attribute__((noinline)) diff --git a/gcc/testsuite/gcc.dg/torture/pr52881.c b/gcc/testsuite/gcc.dg/torture/pr52881.c new file mode 100644 index 00000000000..c101c80338d --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr52881.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ + +int a, b, c, d, e, f, h, i, j, k, l, m, n, o; +static int g; +int +fn1 () { + for (;; ++f) + if (e) + break; + return 0; +} +unsigned char fn2 (); +void +fn3 () { +lbl_220: + if (j) { +lbl_221: + l = (g || b) <= fn1 (); + for (;;) { + g = 0; + fn2 (); + if (k) + goto lbl_220; + break; + } + if (l) + goto lbl_221; + } +} +unsigned char +fn2 () { + o = d ? 0 : c; + h = m | a % o != n; + return i; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr52912.c b/gcc/testsuite/gcc.dg/torture/pr52912.c new file mode 100644 index 00000000000..3ae57588f26 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr52912.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +int a, b, c; +static int +fn1 (p1) +{ +lbl_549: + if (p1) + goto lbl_549; + return 0; +} + +void +fn2 () +{ + b = (c && a) > fn1 (c) >= c; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr52913.c b/gcc/testsuite/gcc.dg/torture/pr52913.c new file mode 100644 index 00000000000..ad99884bfed --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr52913.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ + +int a, b, c, d, e; +void +fn1 () +{ +lbl_101: + e = 0; +lbl_274: + for (c = 0; c < 1; c = a) + if (d) + if (b) + goto lbl_101; + else + break; + d = 1; + goto lbl_274; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr52943.c b/gcc/testsuite/gcc.dg/torture/pr52943.c new file mode 100644 index 00000000000..da35c9d184b --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr52943.c @@ -0,0 +1,20 @@ +/* { dg-do run } */ + +extern void abort (void); +int a[] = { 0, 0, 0, 6 }; + +int b; +int +main () +{ + for (;;) + { + b = 3; + for (; b; b -= 1) + a[b] = a[3] > 1; + break; + } + if (a[1] != 0) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr52969.c b/gcc/testsuite/gcc.dg/torture/pr52969.c new file mode 100644 index 00000000000..05331d93f34 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr52969.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-ftree-loop-if-convert-stores" } */ + +int a, b; +float xsum[100]; +void foo (float *cluster) +{ + int j; + for (; a ; ++j) { + xsum[j] = cluster[j]; + if (xsum[j] > 0) + xsum[j] = 0; + } + if (xsum[0]) + b = 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pta-escape-1.c b/gcc/testsuite/gcc.dg/torture/pta-escape-1.c index dbfd4c9d387..d3cb25437cc 100644 --- a/gcc/testsuite/gcc.dg/torture/pta-escape-1.c +++ b/gcc/testsuite/gcc.dg/torture/pta-escape-1.c @@ -9,7 +9,7 @@ bar (void) *p = 1; } int __attribute__((noinline,noclone)) -foo (__SIZE_TYPE__ addr) +foo (__INTPTR_TYPE__ addr) { int i; /* q points to ANYTHING */ @@ -25,7 +25,7 @@ extern void abort (void); int main() { - if (foo ((__SIZE_TYPE__)&p) != 1) + if (foo ((__INTPTR_TYPE__)&p) != 1) abort (); return 0; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/foldcast-1.c b/gcc/testsuite/gcc.dg/tree-ssa/foldcast-1.c index 08b827c1d3b..9444f0be204 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/foldcast-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/foldcast-1.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-fdump-tree-original" } */ -typedef int ssize_t __attribute__((mode(pointer))); +typedef __INTPTR_TYPE__ ssize_t; ssize_t foo (ssize_t x) { return (ssize_t)(char *)x; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-1.c new file mode 100644 index 00000000000..48c904d0f8f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +double baz (double x, double y) +{ + return x * x * x * x * y * y * y * y; +} + +/* { dg-final { scan-tree-dump-times " \\* " 3 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-10.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-10.c new file mode 100644 index 00000000000..4a6120abd6d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-10.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +double baz (double x, double y, double z) +{ + return (__builtin_pow (x, 4.0) * __builtin_pow (y, 2.0) + * __builtin_pow (z, 4.0)); +} + +/* { dg-final { scan-tree-dump-times " \\* " 5 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-2.c new file mode 100644 index 00000000000..d8b7fca00ee --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +double baz (double x, double y) +{ + return x * y * y * x * y * x * x * y; +} + +/* { dg-final { scan-tree-dump-times " \\* " 3 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-3.c new file mode 100644 index 00000000000..26c1893bae7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +double baz (double x, double y, double z) +{ + return x * x * y * y * y * z * z * z * z; +} + +/* { dg-final { scan-tree-dump-times " \\* " 5 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-4.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-4.c new file mode 100644 index 00000000000..55c2d43b397 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-4.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +double baz (double x, double y, double z, double u) +{ + return x * x * y * y * y * z * z * z * z * u; +} + +/* { dg-final { scan-tree-dump-times " \\* " 6 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-5.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-5.c new file mode 100644 index 00000000000..ea60f8eca1c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-5.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +double baz (double x, double y, double z, double u) +{ + return x * x * x * y * y * y * z * z * z * z * u * u * u * u; +} + +/* { dg-final { scan-tree-dump-times " \\* " 6 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-6.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-6.c new file mode 100644 index 00000000000..5044020cf44 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-6.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +double baz (double x, double y) +{ + return __builtin_pow (x, 3.0) * __builtin_pow (y, 4.0); +} + +/* { dg-final { scan-tree-dump-times " \\* " 4 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-7.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-7.c new file mode 100644 index 00000000000..d4c5241583a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-7.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +float baz (float x, float y) +{ + return x * x * x * x * y * y * y * y; +} + +/* { dg-final { scan-tree-dump-times " \\* " 3 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-8.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-8.c new file mode 100644 index 00000000000..5335fa229e8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-8.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +long double baz (long double x, long double y) +{ + return x * x * x * x * y * y * y * y; +} + +/* { dg-final { scan-tree-dump-times " \\* " 3 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18589-9.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-9.c new file mode 100644 index 00000000000..08d5798e2cd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18589-9.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -ffast-math -fdump-tree-optimized" } */ + +double baz (double x, double y, double z) +{ + return (__builtin_pow (x, 3.0) * __builtin_pow (y, 2.0) + * __builtin_pow (z, 5.0)); +} + +/* { dg-final { scan-tree-dump-times " \\* " 6 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/var-expand1.c b/gcc/testsuite/gcc.dg/var-expand1.c index 3904407c44d..a784ea1a041 100644 --- a/gcc/testsuite/gcc.dg/var-expand1.c +++ b/gcc/testsuite/gcc.dg/var-expand1.c @@ -6,7 +6,7 @@ extern void abort (void); -float array[10] = { 1,2,3,4,5,6,7,8,9,10 }; +float array[30] = { 1,2,3,4,5,6,7,8,9,10 }; int foo (int n) { diff --git a/gcc/testsuite/gcc.dg/vect/pr52870.c b/gcc/testsuite/gcc.dg/vect/pr52870.c new file mode 100644 index 00000000000..38518508bf6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr52870.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -ftree-vectorize" } */ + +long +test (int *x) +{ + unsigned long sx, xprec; + + sx = *x >= 0 ? *x : -*x; + + xprec = sx * 64; + + if (sx < 16384) + foo (sx); + + return xprec; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-1-big-array.c b/gcc/testsuite/gcc.dg/vect/vect-outer-1-big-array.c index 804c3867bd0..b896faa7f95 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-1-big-array.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-1-big-array.c @@ -22,6 +22,6 @@ foo (){ } /* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ /* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-1.c b/gcc/testsuite/gcc.dg/vect/vect-outer-1.c index 2ce8f8ebac8..2abcb179458 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-1.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-1.c @@ -22,6 +22,6 @@ foo (){ } /* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ /* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-1a-big-array.c b/gcc/testsuite/gcc.dg/vect/vect-outer-1a-big-array.c index 9b418fabaa9..0a53c25484a 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-1a-big-array.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-1a-big-array.c @@ -20,6 +20,6 @@ foo (){ } /* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ /* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-1a.c b/gcc/testsuite/gcc.dg/vect/vect-outer-1a.c index a9b786e235c..acd504c9e0b 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-1a.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-1a.c @@ -20,6 +20,6 @@ foo (){ } /* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ /* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-1b-big-array.c b/gcc/testsuite/gcc.dg/vect/vect-outer-1b-big-array.c index 48b7180784e..551c89fba38 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-1b-big-array.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-1b-big-array.c @@ -22,6 +22,6 @@ foo (){ } /* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ /* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-1b.c b/gcc/testsuite/gcc.dg/vect/vect-outer-1b.c index 815758c766f..c475a5e443e 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-1b.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-1b.c @@ -22,6 +22,6 @@ foo (){ } /* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ /* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-2b.c b/gcc/testsuite/gcc.dg/vect/vect-outer-2b.c index cb62881f004..2b3351626ec 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-2b.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-2b.c @@ -37,6 +37,6 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */ /* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-3b.c b/gcc/testsuite/gcc.dg/vect/vect-outer-3b.c index fda8727bf68..4a86af28d8a 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-outer-3b.c +++ b/gcc/testsuite/gcc.dg/vect/vect-outer-3b.c @@ -49,6 +49,6 @@ int main (void) } /* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { xfail vect_multiple_sizes } } } */ -/* { dg-final { scan-tree-dump-times "strided access in outer loop" 4 "vect" { target vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 2 "vect" { xfail vect_multiple_sizes } } } */ +/* { dg-final { scan-tree-dump-times "grouped access in outer loop" 4 "vect" { target vect_multiple_sizes } } } */ /* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vla-11.c b/gcc/testsuite/gcc.dg/vla-11.c index 8948e6b77a3..9c23e860a53 100644 --- a/gcc/testsuite/gcc.dg/vla-11.c +++ b/gcc/testsuite/gcc.dg/vla-11.c @@ -7,7 +7,7 @@ /* { dg-options "-std=c99 -pedantic-errors" } */ void foo11a(int x[sizeof(int *(*)[*])]); /* { dg-warning "not in a declaration" } */ -void foo11b(__SIZE_TYPE__ x, int y[(__SIZE_TYPE__)(int (*)[*])x]); /* { dg-warning "not in a declaration" } */ +void foo11b(__SIZE_TYPE__ x, int y[(__UINTPTR_TYPE__)(int (*)[*])x]); /* { dg-warning "not in a declaration" } */ void foo11c(struct s { int (*x)[*]; } *y); /* { dg-error "a member of a structure or union cannot have a variably modified type" "variably modified" } */ /* { dg-warning "'struct s' declared inside parameter list" "struct decl" { target *-*-* } 11 } */ /* { dg-warning "its scope is only this definition or declaration" "struct scope" { target *-*-* } 11 } */ diff --git a/gcc/testsuite/gcc.target/arm/thumb1-imm.c b/gcc/testsuite/gcc.target/arm/thumb1-imm.c new file mode 100644 index 00000000000..6d950aa182c --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/thumb1-imm.c @@ -0,0 +1,12 @@ +/* Check for thumb1 imm [255-510] moves. */ +/* { dg-require-effective-target arm_thumb1_ok } */ +/* { dg-options "-Os" } */ +/* { dg-skip-if "" { ! { arm_thumb1 } } } */ + +int f() +{ + return 257; +} + +/* { dg-final { scan-assembler-not "ldr" } } */ + diff --git a/gcc/testsuite/gcc.target/i386/avx2-vpermd-2.c b/gcc/testsuite/gcc.target/i386/avx2-vpermd-2.c index 4a4e73c78fb..a663337e9a9 100644 --- a/gcc/testsuite/gcc.target/i386/avx2-vpermd-2.c +++ b/gcc/testsuite/gcc.target/i386/avx2-vpermd-2.c @@ -29,8 +29,8 @@ calc_permd (int *src1, int *src2, int *dst) memcpy (dst, src1, 32); for (i = 0; i < 8; i++) { - temp = src1[i]; - dst[i] = src2[temp & 7]; + temp = src2[i]; + dst[i] = src1[temp & 7]; } } diff --git a/gcc/testsuite/gcc.target/i386/avx2-vpermps-1.c b/gcc/testsuite/gcc.target/i386/avx2-vpermps-1.c index 3346b23531f..bf436599d54 100644 --- a/gcc/testsuite/gcc.target/i386/avx2-vpermps-1.c +++ b/gcc/testsuite/gcc.target/i386/avx2-vpermps-1.c @@ -5,9 +5,10 @@ #include <immintrin.h> __m256 x; +__m256i y; void extern avx2_test (void) { - x = _mm256_permutevar8x32_ps (x, x); + x = _mm256_permutevar8x32_ps (x, y); } diff --git a/gcc/testsuite/gcc.target/i386/avx2-vpermps-2.c b/gcc/testsuite/gcc.target/i386/avx2-vpermps-2.c index f145aa1d214..4190189a89c 100644 --- a/gcc/testsuite/gcc.target/i386/avx2-vpermps-2.c +++ b/gcc/testsuite/gcc.target/i386/avx2-vpermps-2.c @@ -8,7 +8,7 @@ #define NUM 10 static void -init_permps (float *src1, float *src2, int seed) +init_permps (float *src1, int *src2, int seed) { int i, sign = 1; @@ -21,24 +21,24 @@ init_permps (float *src1, float *src2, int seed) } static void -calc_permps (float *src1, float *src2, float *dst) +calc_permps (float *src1, int *src2, float *dst) { int i; unsigned temp; - unsigned *idx = (int *) src1; memcpy (dst, src1, 32); for (i = 0; i < 8; i++) { - temp = idx[i]; - dst[i] = src2[temp & 7]; + temp = src2[i]; + dst[i] = src1[temp & 7]; } } static void avx2_test (void) { - union256 src1, src2, dst; + union256 src1, dst; + union256i_d src2; float dst_ref[8]; int i; diff --git a/gcc/testsuite/gcc.target/i386/avx256-unaligned-load-4.c b/gcc/testsuite/gcc.target/i386/avx256-unaligned-load-4.c index 0d3ef333120..2c087a17e37 100644 --- a/gcc/testsuite/gcc.target/i386/avx256-unaligned-load-4.c +++ b/gcc/testsuite/gcc.target/i386/avx256-unaligned-load-4.c @@ -3,7 +3,7 @@ #define N 1024 -float a[N], b[N+3]; +float a[N+3], b[N]; void avx_test (void) diff --git a/gcc/testsuite/gcc.target/i386/builtin-bswap-4.c b/gcc/testsuite/gcc.target/i386/builtin-bswap-4.c new file mode 100644 index 00000000000..65198aee89e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/builtin-bswap-4.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-not "bswap\[ \t\]" } } */ + +short foo (short x) +{ + return __builtin_bswap16 (x); +} diff --git a/gcc/testsuite/gcc.target/i386/pr45830.c b/gcc/testsuite/gcc.target/i386/pr45830.c index a74d4345464..85d5a3c5ab0 100644 --- a/gcc/testsuite/gcc.target/i386/pr45830.c +++ b/gcc/testsuite/gcc.target/i386/pr45830.c @@ -26,6 +26,6 @@ foo (int *a) } } -/* { dg-final { scan-tree-dump "Expanding as bit test is preferable" "switchconv" } } */ +/* { dg-final { scan-tree-dump "expanding as bit test is preferable" "switchconv" } } */ /* { dg-final { scan-assembler-not "CSWTCH" } } */ /* { dg-final { cleanup-tree-dump "switchconv" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr52876.c b/gcc/testsuite/gcc.target/i386/pr52876.c new file mode 100644 index 00000000000..6d5e47a94d0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr52876.c @@ -0,0 +1,25 @@ +/* { dg-do run { target { x32 } } } */ +/* { dg-options "-O2 -mx32 -maddress-mode=long" } */ + +extern void abort (void); + +long long li; + +long long +__attribute__ ((noinline)) +testfunc (void* addr) +{ + li = (long long)(int)addr; + li &= 0xffffffff; + return li; +} + +int main (void) +{ + volatile long long rv_test; + rv_test = testfunc((void*)0x87651234); + if (rv_test != 0x87651234ULL) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr16458-1.c b/gcc/testsuite/gcc.target/powerpc/pr16458-1.c new file mode 100644 index 00000000000..45b8c75c069 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr16458-1.c @@ -0,0 +1,18 @@ +/* Test cse'ing of unsigned compares. */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* { dg-final { scan-assembler-not "cmpw" } } */ +/* { dg-final { scan-assembler-times "cmplw" 1 } } */ + +unsigned int a, b; + +int +foo (void) +{ + if (a == b) return 1; + if (a > b) return 2; + if (a < b) return 3; + if (a != b) return 4; + return 0; +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr16458-2.c b/gcc/testsuite/gcc.target/powerpc/pr16458-2.c new file mode 100644 index 00000000000..95e97de5560 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr16458-2.c @@ -0,0 +1,18 @@ +/* Test cse'ing of unsigned compares. */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* { dg-final { scan-assembler-not "cmpw" } } */ +/* { dg-final { scan-assembler-times "cmplw" 1 } } */ + +unsigned int *a, *b; + +int +foo (void) +{ + if (*a == *b) return 1; + if (*a > *b) return 2; + if (*a < *b) return 3; + if (*a != *b) return 4; + return 0; +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr16458-3.c b/gcc/testsuite/gcc.target/powerpc/pr16458-3.c new file mode 100644 index 00000000000..740d61dcc74 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr16458-3.c @@ -0,0 +1,41 @@ +/* Test cse'ing of unsigned compares. */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-jump-tables" } */ + +/* { dg-final { scan-assembler-not "cmpwi" } } */ +/* { dg-final { scan-assembler-times "cmplwi" 5 } } */ + +extern int case0 (void); +extern int case1 (void); +extern int case2 (void); +extern int case3 (void); +extern int case4 (void); + +enum CASE_VALUES +{ + CASE0 = 1, + CASE1, + CASE2, + CASE3, + CASE4 +}; + +int +foo (enum CASE_VALUES index) +{ + switch (index) + { + case CASE0: + return case0 (); + case CASE1: + return case1 (); + case CASE2: + return case2 (); + case CASE3: + return case3 (); + case CASE4: + return case4 (); + } + + return 0; +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr16458-4.c b/gcc/testsuite/gcc.target/powerpc/pr16458-4.c new file mode 100644 index 00000000000..8db43e82384 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr16458-4.c @@ -0,0 +1,44 @@ +/* Test cse'ing of unsigned compares. */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-jump-tables" } */ + +/* The following tests fail due to an issue in expand not + attaching an type expression information on *index's reg rtx. */ + +/* { dg-final { scan-assembler-not "cmpwi" } } */ +/* { dg-final { scan-assembler-times "cmplwi" 5 } } */ + +extern int case0 (void); +extern int case1 (void); +extern int case2 (void); +extern int case3 (void); +extern int case4 (void); + +enum CASE_VALUES +{ + CASE0 = 1, + CASE1, + CASE2, + CASE3, + CASE4 +}; + +int +foo (enum CASE_VALUES *index) +{ + switch (*index) + { + case CASE0: + return case0 (); + case CASE1: + return case1 (); + case CASE2: + return case2 (); + case CASE3: + return case3 (); + case CASE4: + return case4 (); + } + + return 0; +} diff --git a/gcc/testsuite/gcc.target/powerpc/pr52775.c b/gcc/testsuite/gcc.target/powerpc/pr52775.c new file mode 100644 index 00000000000..4027819ee63 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr52775.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target { powerpc*-*-* && ilp32 } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-options "-O1 -mcpu=power4" } */ +/* { dg-final { scan-assembler-times "fcfid" 2 } } */ + +double +int_to_double (int *p) +{ + return (double)*p; +} + +double +long_long_to_double (long long *p) +{ + return (double)*p; +} diff --git a/gcc/testsuite/gcc.target/sh/pr50751-4.c b/gcc/testsuite/gcc.target/sh/pr50751-4.c new file mode 100644 index 00000000000..f3f0357707a --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr50751-4.c @@ -0,0 +1,30 @@ +/* Check that the mov.w displacement addressing insn is generated. + If the insn is generated as expected, there should be no address + calculations outside the mov insns. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ +/* { dg-final { scan-assembler-not "add|sub" } } */ + +void +testfunc_00 (const short* ap, short* bp, short val) +{ + bp[0] = ap[15]; + bp[2] = ap[5]; + bp[9] = ap[7]; + bp[0] = ap[15]; + bp[4] = val; + bp[14] = val; +} + +void +testfunc_01 (volatile const short* ap, volatile short* bp, short val) +{ + bp[0] = ap[15]; + bp[2] = ap[5]; + bp[9] = ap[7]; + bp[0] = ap[15]; + bp[4] = val; + bp[14] = val; +} + diff --git a/gcc/testsuite/gcc.target/sh/pr50751-5.c b/gcc/testsuite/gcc.target/sh/pr50751-5.c new file mode 100644 index 00000000000..48d5403b2d4 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr50751-5.c @@ -0,0 +1,27 @@ +/* Check that the mov.w displacement addressing insn is generated and the + base address is adjusted only once. On SH2A this test is skipped because + there is a 4 byte mov.w insn that can handle larger displacements. Thus + on SH2A the base address will not be adjusted in this case. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" "-m2a*" } { "" } } */ +/* { dg-final { scan-assembler-times "add" 2 } } */ + +void +testfunc_00 (const short* ap, short* bp) +{ + bp[0] = ap[15]; + bp[2] = ap[5]; + bp[9] = ap[7]; + bp[0] = ap[25]; +} + +void +testfunc_01 (volatile const short* ap, volatile short* bp) +{ + bp[0] = ap[15]; + bp[2] = ap[5]; + bp[9] = ap[7]; + bp[0] = ap[25]; +} + diff --git a/gcc/testsuite/gcc.target/sh/pr50751-6.c b/gcc/testsuite/gcc.target/sh/pr50751-6.c new file mode 100644 index 00000000000..83fb5abeafe --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr50751-6.c @@ -0,0 +1,26 @@ +/* Check that on SH2A the 4 byte mov.w displacement insn is generated to + handle larger displacements. If it is generated correctly, there should + be no base address adjustments outside the mov.w insns. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */ +/* { dg-final { scan-assembler-not "add|sub" } } */ + +void +testfunc_00 (const short* ap, short* bp) +{ + bp[100] = ap[15]; + bp[200] = ap[50]; + bp[900] = ap[71]; + bp[0] = ap[25]; +} + +void +testfunc_01 (volatile const short* ap, volatile short* bp) +{ + bp[100] = ap[15]; + bp[200] = ap[50]; + bp[900] = ap[71]; + bp[0] = ap[25]; +} + diff --git a/gcc/testsuite/gcc.target/sh/pr50751-7.c b/gcc/testsuite/gcc.target/sh/pr50751-7.c new file mode 100644 index 00000000000..859cba42f61 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr50751-7.c @@ -0,0 +1,35 @@ +/* Check that mov.b and mov.w displacement insns are generated. + If this is working properly, there should be no base address adjustments + outside the mov insns. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ +/* { dg-final { scan-assembler-not "add|sub" } } */ + +typedef struct +{ + char a; + char b; + char c; + char d; + + short e; + short f; + + int g; + int h; +} X; + +void +testfunc_00 (X* x) +{ + x->g = x->b | x->c; + x->h = x->e | x->f; + x->d = x->g; + x->f = x->h; +} + +int testfunc_01 (X* x) +{ + return x->b | x->e | x->g; +} diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx/test_passing_structs.c b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_passing_structs.c index 9a8f71dbb8f..7dbf6a59bbb 100644 --- a/gcc/testsuite/gcc.target/x86_64/abi/avx/test_passing_structs.c +++ b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_passing_structs.c @@ -53,7 +53,7 @@ avx_test (void) clear_struct_registers; for (i = 0; i < 8; i++) - fregs.ymm0._m256[i] = m256s[i].x; + (&fregs.ymm0)[i]._m256[0] = m256s[i].x; num_fregs = 8; WRAP_CALL (check_struct_passing1)(m256s[0], m256s[1], m256s[2], m256s[3], m256s[4], m256s[5], m256s[6], m256s[7]); diff --git a/gcc/testsuite/gcc.target/x86_64/abi/avx/test_passing_unions.c b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_passing_unions.c index f83209b2767..127dd5f3014 100644 --- a/gcc/testsuite/gcc.target/x86_64/abi/avx/test_passing_unions.c +++ b/gcc/testsuite/gcc.target/x86_64/abi/avx/test_passing_unions.c @@ -113,7 +113,7 @@ avx_test (void) clear_struct_registers; for (i = 0; i < 8; i++) - fregs.ymm0._m256[i] = u1[i].x; + (&fregs.ymm0)[i]._m256[0] = u1[i].x; num_fregs = 8; check_union_passing1(u1[0], u1[1], u1[2], u1[3], u1[4], u1[5], u1[6], u1[7]); @@ -122,7 +122,7 @@ avx_test (void) for (i = 0; i < 8; i++) { u2[i].x = u1[i].x; - fregs.ymm0._m256[i] = u2[i].x; + (&fregs.ymm0)[i]._m256[0] = u2[i].x; } num_fregs = 8; check_union_passing2(u2[0], u2[1], u2[2], u2[3], @@ -132,7 +132,7 @@ avx_test (void) for (i = 0; i < 8; i++) { u3[i].x = u1[i].x; - fregs.ymm0._m256[i] = u3[i].x; + (&fregs.ymm0)[i]._m256[0] = u3[i].x; } num_fregs = 8; check_union_passing3(u3[0], u3[1], u3[2], u3[3], diff --git a/gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c b/gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c index 299bc80caba..ad6d835ba03 100644 --- a/gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c +++ b/gcc/testsuite/gcc.target/x86_64/abi/test_passing_structs.c @@ -216,7 +216,7 @@ main (void) for (i = 0; i < 8; i++) { m128s[i].x = (__m128){32+i, 0, i, 0}; - fregs.xmm0._m128[i] = m128s[i].x; + (&fregs.xmm0)[i]._m128[0] = m128s[i].x; } num_fregs = 8; clear_float_hardware_registers; diff --git a/gcc/testsuite/gcc.target/x86_64/abi/test_passing_unions.c b/gcc/testsuite/gcc.target/x86_64/abi/test_passing_unions.c index 1e3e85fdb50..cff244abb97 100644 --- a/gcc/testsuite/gcc.target/x86_64/abi/test_passing_unions.c +++ b/gcc/testsuite/gcc.target/x86_64/abi/test_passing_unions.c @@ -206,7 +206,7 @@ main (void) for (i = 0; i < 8; i++) { u4[i].x = (__m128){32+i, 0, i, 0}; - fregs.xmm0._m128[i] = u4[i].x; + (&fregs.xmm0)[i]._m128[0] = u4[i].x; } num_fregs = 8; clear_float_hardware_registers; diff --git a/gcc/testsuite/gfortran.dg/block_11.f90 b/gcc/testsuite/gfortran.dg/block_11.f90 new file mode 100644 index 00000000000..83c6519d970 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/block_11.f90 @@ -0,0 +1,68 @@ +! { dg-do link } +! +! PR fortran/52729 +! +! Based on a contribution of Andrew Benson +! +module testMod + type testType + end type testType +contains + subroutine testSub() + implicit none + procedure(double precision ), pointer :: r + class (testType ), pointer :: testObject + double precision :: testVal + + ! Failed as testFunc was BT_UNKNOWN + select type (testObject) + class is (testType) + testVal=testFunc() + r => testFunc + end select + return + end subroutine testSub + + double precision function testFunc() + implicit none + return + end function testFunc +end module testMod + +module testMod2 + implicit none +contains + subroutine testSub() + procedure(double precision ), pointer :: r + double precision :: testVal + ! Failed as testFunc was BT_UNKNOWN + block + r => testFunc + testVal=testFunc() + end block + end subroutine testSub + + double precision function testFunc() + end function testFunc +end module testMod2 + +module m3 + implicit none +contains + subroutine my_test() + procedure(), pointer :: ptr + ! Before the fix, one had the link error + ! "undefined reference to `sub.1909'" + block + ptr => sub + call sub() + end block + end subroutine my_test + subroutine sub(a) + integer, optional :: a + end subroutine sub +end module m3 + +end + +! { dg-final { cleanup-modules "testmod testmod2 m3" } } diff --git a/gcc/testsuite/gfortran.dg/pointer_intent_6.f90 b/gcc/testsuite/gfortran.dg/pointer_intent_6.f90 new file mode 100644 index 00000000000..56c7de5ebba --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pointer_intent_6.f90 @@ -0,0 +1,19 @@ +! { dg-do compile } +! +! PR fortran/52864 +! +! Assigning to an intent(in) pointer (which is valid). +! + program test + type PoisFFT_Solver3D + complex, dimension(:,:,:), & + pointer :: work => null() + end type PoisFFT_Solver3D + contains + subroutine PoisFFT_Solver3D_FullPeriodic(D, p) + type(PoisFFT_Solver3D), intent(in) :: D + real, intent(in), pointer :: p(:) + D%work(i,j,k) = 0.0 + p = 0.0 + end subroutine + end diff --git a/gcc/testsuite/gfortran.dg/pr52621.f90 b/gcc/testsuite/gfortran.dg/pr52621.f90 new file mode 100644 index 00000000000..d305e4db9b6 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr52621.f90 @@ -0,0 +1,20 @@ +! { dg-do compile } +! { dg-options "-O2 -fprefetch-loop-arrays" } + + SUBROUTINE GHDSYM(IZ,IS,LMMAX,S,LMS,Y,L2M,DRL,NLAY2,K0,DCUT)!, +! + COMPLEX Y(L2M,L2M),H(33),S(LMS) + COMPLEX RU,CI,CZ,K0,FF,Z,Z1,Z2,Z3,ST +! + DO 140 KK=1,4 + DO 130 L=1,L2M + L1=L*L-L + DO 120 M=1,L + IPM=L1+M + IMM=L1-M+2 + S(IPM)=S(IPM)+Z3*Y(L,M) + IF (M.NE.1) S(IMM)=S(IMM)+Z3*Y(M-1,L)*CSGN +120 CONTINUE +130 CONTINUE +140 CONTINUE + END diff --git a/gcc/testsuite/gfortran.dg/proc_ptr_comp_34.f90 b/gcc/testsuite/gfortran.dg/proc_ptr_comp_34.f90 new file mode 100644 index 00000000000..031f74418ca --- /dev/null +++ b/gcc/testsuite/gfortran.dg/proc_ptr_comp_34.f90 @@ -0,0 +1,30 @@ +! { dg-do run } +! +! PR 51082: [F03] Wrong result for a pointer to a proc-pointer component +! +! Contributed by Tobias Burnus <burnus@gcc.gnu.org> + +program ala + implicit none + + type process_list + procedure(ala1), pointer, nopass :: process + end type + + type(process_list), target :: p_list + type(process_list), pointer :: p + + p_list%process => ala1 + p => p_list + + write(*,*) p_list%process(1.0) + write(*,*) p%process(1.0) !!!! failed + +contains + + real function ala1(x) + real, intent(in) :: x + ala1 = x + end function + +end program diff --git a/gcc/testsuite/gfortran.dg/public_private_module_3.f90 b/gcc/testsuite/gfortran.dg/public_private_module_3.f90 new file mode 100644 index 00000000000..03f00c200e7 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/public_private_module_3.f90 @@ -0,0 +1,59 @@ +! { dg-do link } +! { dg-additional-sources public_private_module_4.f90 } +! +! PR fortran/52916 +! Cf. PR fortran/40973 +! +! Ensure that PRIVATE specific functions do not get +! marked as TREE_PUBLIC() = 0, if the generic name is +! PUBLIC. +! +module m + interface gen + module procedure bar + end interface gen + + type t + end type t + + interface operator(.myop.) + module procedure my_op + end interface + + interface operator(+) + module procedure my_plus + end interface + + interface assignment(=) + module procedure my_assign + end interface + + private :: bar, my_op, my_plus, my_assign +contains + subroutine bar() + print *, "bar" + end subroutine bar + function my_op(op1, op2) result(res) + type(t) :: res + type(t), intent(in) :: op1, op2 + end function my_op + function my_plus(op1, op2) result(res) + type(t) :: res + type(t), intent(in) :: op1, op2 + end function my_plus + subroutine my_assign(lhs, rhs) + type(t), intent(out) :: lhs + type(t), intent(in) :: rhs + end subroutine my_assign +end module m + +module m2 + type t2 + contains + procedure, nopass :: func => foo + end type t2 + private :: foo +contains + subroutine foo() + end subroutine foo +end module m2 diff --git a/gcc/testsuite/gfortran.dg/public_private_module_4.f90 b/gcc/testsuite/gfortran.dg/public_private_module_4.f90 new file mode 100644 index 00000000000..82600e46b04 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/public_private_module_4.f90 @@ -0,0 +1,23 @@ +! { dg-do compile { target skip-all-targets } } +! +! To be used by public_private_module_3.f90 +! +! PR fortran/52916 +! Cf. PR fortran/40973 +! +! Ensure that PRIVATE specific functions do not get +! marked as TREE_PUBLIC() = 0, if the generic name is +! PUBLIC. +! +use m +use m2 +implicit none + +type(t) :: a, b, c +type(t2) :: x + +call gen() +a = b + (c .myop. a) + +call x%func() +end diff --git a/gcc/testsuite/gfortran.dg/read_float_4.f90 b/gcc/testsuite/gfortran.dg/read_float_4.f90 new file mode 100644 index 00000000000..01a0de8c04f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/read_float_4.f90 @@ -0,0 +1,18 @@ +! { dg-do run } +! +! PR libgfortran/53051 +! +! Check that reading "4.0q0" works, i.e. floating-point +! numbers which use "q" to indicate the exponential. +! (Which is a vendor extension.) +! + character(len=20) :: str + real :: r + integer :: i + + r = 0 + str = '1.0q0' + read(str, *, iostat=i) r + if (r /= 1.0 .or. i /= 0) call abort() + !print *, r + end diff --git a/gcc/testsuite/gfortran.dg/reassoc_10.f b/gcc/testsuite/gfortran.dg/reassoc_10.f new file mode 100644 index 00000000000..698e2c49bb4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/reassoc_10.f @@ -0,0 +1,17 @@ +! { dg-do compile } +! { dg-options "-O3 -ffast-math -fdump-tree-optimized" } + + SUBROUTINE S55199(P,Q,Dvdph) + implicit none + real(8) :: c1,c2,c3,P,Q,Dvdph + c1=0.1d0 + c2=0.2d0 + c3=0.3d0 + Dvdph = c1 + 2.*P*c2 + 3.*P**2*Q**3*c3 + END + +! There should be five multiplies following un-distribution +! and power expansion. + +! { dg-final { scan-tree-dump-times " \\\* " 5 "optimized" } } +! { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/reassoc_11.f b/gcc/testsuite/gfortran.dg/reassoc_11.f new file mode 100644 index 00000000000..242201680b3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/reassoc_11.f @@ -0,0 +1,17 @@ +! { dg-do compile } +! { dg-options "-O3 -ffast-math" } + +! This tests only for compile-time failure, which formerly occurred +! when a __builtin_powi was introduced by reassociation in a bad place. + + SUBROUTINE GRDURBAN(URBWSTR, ZIURB, GRIDHT) + + IMPLICIT NONE + INTEGER :: I + REAL :: SW2, URBWSTR, ZIURB, GRIDHT(87) + + SAVE + + SW2 = 1.6*(GRIDHT(I)/ZIURB)**0.667*URBWSTR**2 + + END diff --git a/gcc/testsuite/gfortran.dg/reassoc_7.f b/gcc/testsuite/gfortran.dg/reassoc_7.f new file mode 100644 index 00000000000..4f70ef6f9dd --- /dev/null +++ b/gcc/testsuite/gfortran.dg/reassoc_7.f @@ -0,0 +1,16 @@ +! { dg-do compile } +! { dg-options "-O3 -ffast-math -fdump-tree-optimized" } + + SUBROUTINE S55199(P,Dvdph) + implicit none + real(8) :: c1,c2,c3,P,Dvdph + c1=0.1d0 + c2=0.2d0 + c3=0.3d0 + Dvdph = c1 + 2.*P*c2 + 3.*P**2*c3 + END + +! There should be two multiplies following un-distribution. + +! { dg-final { scan-tree-dump-times " \\\* " 2 "optimized" } } +! { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/reassoc_8.f b/gcc/testsuite/gfortran.dg/reassoc_8.f new file mode 100644 index 00000000000..4a6ea72f220 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/reassoc_8.f @@ -0,0 +1,17 @@ +! { dg-do compile } +! { dg-options "-O3 -ffast-math -fdump-tree-optimized" } + + SUBROUTINE S55199(P,Dvdph) + implicit none + real(8) :: c1,c2,c3,P,Dvdph + c1=0.1d0 + c2=0.2d0 + c3=0.3d0 + Dvdph = c1 + 2.*P**2*c2 + 3.*P**3*c3 + END + +! There should be three multiplies following un-distribution +! and power expansion. + +! { dg-final { scan-tree-dump-times " \\\* " 3 "optimized" } } +! { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/reassoc_9.f b/gcc/testsuite/gfortran.dg/reassoc_9.f new file mode 100644 index 00000000000..53950ee9bc9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/reassoc_9.f @@ -0,0 +1,17 @@ +! { dg-do compile } +! { dg-options "-O3 -ffast-math -fdump-tree-optimized" } + + SUBROUTINE S55199(P,Dvdph) + implicit none + real(8) :: c1,c2,c3,P,Dvdph + c1=0.1d0 + c2=0.2d0 + c3=0.3d0 + Dvdph = c1 + 2.*P**2*c2 + 3.*P**4*c3 + END + +! There should be three multiplies following un-distribution +! and power expansion. + +! { dg-final { scan-tree-dump-times " \\\* " 3 "optimized" } } +! { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/typebound_call_23.f03 b/gcc/testsuite/gfortran.dg/typebound_call_23.f03 new file mode 100644 index 00000000000..5baa26179d4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/typebound_call_23.f03 @@ -0,0 +1,28 @@ +! { dg-do compile } +! +! PR 52968: [OOP] Call to type-bound procedure wrongly rejected +! +! Contributed by Reuben Budiardja <reubendb@gmail.com> + +module SolverModule + + type :: SolverType + class ( EquationTemplate ), pointer :: Equation + end type + + type :: EquationTemplate + contains + procedure, nopass :: Evaluate + end type + +contains + + subroutine Evaluate () + end subroutine + + subroutine Solve + type ( SolverType ) :: S + call S % Equation % Evaluate () + end subroutine + +end module diff --git a/gcc/testsuite/gfortran.dg/vect/rnflow-trs2a2.f90 b/gcc/testsuite/gfortran.dg/vect/rnflow-trs2a2.f90 new file mode 100644 index 00000000000..1d13cea80e0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/vect/rnflow-trs2a2.f90 @@ -0,0 +1,33 @@ +! { dg-do compile } +! { dg-require-effective-target vect_double } + + function trs2a2 (j, k, u, d, m) +! matrice de transition intermediaire, partant de k sans descendre +! sous j. R = IjU(I-Ik)DIj, avec Ii = deltajj, j >= i. +! alternative: trs2a2 = 0 +! trs2a2 (j:k-1, j:k-1) = matmul (utrsft (j:k-1,j:k-1), +! dtrsft (j:k-1,j:k-1)) +! + real, dimension (1:m,1:m) :: trs2a2 ! resultat + real, dimension (1:m,1:m) :: u, d ! matrices utrsft, dtrsft + integer, intent (in) :: j, k, m ! niveaux vallee pic +! +!##### following line replaced by Prentice to make less system dependent +! real (kind = kind (1.0d0)) :: dtmp + real (kind = selected_real_kind (10,50)) :: dtmp +! + trs2a2 = 0.0 + do iclw1 = j, k - 1 + do iclw2 = j, k - 1 + dtmp = 0.0d0 + do iclww = j, k - 1 + dtmp = dtmp + u (iclw1, iclww) * d (iclww, iclw2) + enddo + trs2a2 (iclw1, iclw2) = dtmp + enddo + enddo + return + end function trs2a2 + +! { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } +! { dg-final { cleanup-tree-dump "vect" } } diff --git a/gcc/testsuite/gnat.dg/aggr11.adb b/gcc/testsuite/gnat.dg/aggr11.adb index 1771d62cacb..12547063c66 100644 --- a/gcc/testsuite/gnat.dg/aggr11.adb +++ b/gcc/testsuite/gnat.dg/aggr11.adb @@ -1,17 +1,17 @@ --- { dg-do compile }
--- { dg-options "-O" }
-
-with Aggr11_Pkg; use Aggr11_Pkg;
-
-procedure Aggr11 is
-
- A : Arr := ((1 => (Kind => No_Error, B => True),
- 2 => (Kind => Error),
- 3 => (Kind => Error),
- 4 => (Kind => No_Error, B => True),
- 5 => (Kind => No_Error, B => True),
- 6 => (Kind => No_Error, B => True)));
-
-begin
- null;
-end;
+-- { dg-do compile } +-- { dg-options "-O" } + +with Aggr11_Pkg; use Aggr11_Pkg; + +procedure Aggr11 is + + A : Arr := ((1 => (Kind => No_Error, B => True), + 2 => (Kind => Error), + 3 => (Kind => Error), + 4 => (Kind => No_Error, B => True), + 5 => (Kind => No_Error, B => True), + 6 => (Kind => No_Error, B => True))); + +begin + null; +end; diff --git a/gcc/testsuite/gnat.dg/aggr11_pkg.ads b/gcc/testsuite/gnat.dg/aggr11_pkg.ads index 37008605a30..139c9efdac6 100644 --- a/gcc/testsuite/gnat.dg/aggr11_pkg.ads +++ b/gcc/testsuite/gnat.dg/aggr11_pkg.ads @@ -1,14 +1,14 @@ -package Aggr11_Pkg is
-
- type Error_Type is (No_Error, Error);
-
- type Rec (Kind : Error_Type := No_Error) is record
- case Kind is
- when Error => null;
- when others => B : Boolean;
- end case;
- end record;
-
- type Arr is array (1..6) of Rec;
-
-end Aggr11_Pkg;
+package Aggr11_Pkg is + + type Error_Type is (No_Error, Error); + + type Rec (Kind : Error_Type := No_Error) is record + case Kind is + when Error => null; + when others => B : Boolean; + end case; + end record; + + type Arr is array (1..6) of Rec; + +end Aggr11_Pkg; diff --git a/gcc/testsuite/gnat.dg/aggr15.adb b/gcc/testsuite/gnat.dg/aggr15.adb index e69e9d346e1..a4eeb231ac2 100644 --- a/gcc/testsuite/gnat.dg/aggr15.adb +++ b/gcc/testsuite/gnat.dg/aggr15.adb @@ -1,18 +1,18 @@ --- { dg-do compile }
--- { dg-options "-gnatws" }
-
-package body Aggr15 is
-
- function CREATE return DATA_T is
- D : DATA_T;
- begin
- return D;
- end;
-
- function ALL_CREATE return ALL_DATA_T is
- C : constant ALL_DATA_T := (others => (others => Create));
- begin
- return C;
- end;
-
-end Aggr15;
+-- { dg-do compile } +-- { dg-options "-gnatws" } + +package body Aggr15 is + + function CREATE return DATA_T is + D : DATA_T; + begin + return D; + end; + + function ALL_CREATE return ALL_DATA_T is + C : constant ALL_DATA_T := (others => (others => Create)); + begin + return C; + end; + +end Aggr15; diff --git a/gcc/testsuite/gnat.dg/aggr15.ads b/gcc/testsuite/gnat.dg/aggr15.ads index 23f26a8df7d..70eb22398ee 100644 --- a/gcc/testsuite/gnat.dg/aggr15.ads +++ b/gcc/testsuite/gnat.dg/aggr15.ads @@ -1,15 +1,15 @@ -package Aggr15 is
-
- type T is tagged record
- I : Integer;
- end record;
-
- type DATA_T is record
- D : T;
- end record;
-
- type ALL_DATA_T is array (1..2, 1..2) of DATA_T;
-
- function ALL_CREATE return ALL_DATA_T;
-
-end Aggr15;
+package Aggr15 is + + type T is tagged record + I : Integer; + end record; + + type DATA_T is record + D : T; + end record; + + type ALL_DATA_T is array (1..2, 1..2) of DATA_T; + + function ALL_CREATE return ALL_DATA_T; + +end Aggr15; diff --git a/gcc/testsuite/gnat.dg/aggr17.adb b/gcc/testsuite/gnat.dg/aggr17.adb index 3ba41985f72..89e385e7983 100644 --- a/gcc/testsuite/gnat.dg/aggr17.adb +++ b/gcc/testsuite/gnat.dg/aggr17.adb @@ -1,28 +1,28 @@ --- { dg-do compile }
--- { dg-options "-gnatws" }
-
-procedure Aggr17 is
-
- type Enum is (A, B);
-
- type Rec (D : Enum := Enum'First) is record
- case D is
- when A => X : Integer;
- when B => null;
- end case;
- end record;
- for Rec'Size use 128;
- pragma Volatile (Rec);
-
- type Config_T (D : Enum := Enum'First) is record
- N : Natural;
- R : Rec (D);
- end record;
-
- C : constant Config_T := (D => A, N => 1, R => (D => A, X => 0));
-
- type Arr is array (Natural range 1 .. C.N) of Boolean;
-
-begin
- null;
-end;
+-- { dg-do compile } +-- { dg-options "-gnatws" } + +procedure Aggr17 is + + type Enum is (A, B); + + type Rec (D : Enum := Enum'First) is record + case D is + when A => X : Integer; + when B => null; + end case; + end record; + for Rec'Size use 128; + pragma Volatile (Rec); + + type Config_T (D : Enum := Enum'First) is record + N : Natural; + R : Rec (D); + end record; + + C : constant Config_T := (D => A, N => 1, R => (D => A, X => 0)); + + type Arr is array (Natural range 1 .. C.N) of Boolean; + +begin + null; +end; diff --git a/gcc/testsuite/gnat.dg/aggr18.adb b/gcc/testsuite/gnat.dg/aggr18.adb index 511add8a17d..6b5281e4164 100644 --- a/gcc/testsuite/gnat.dg/aggr18.adb +++ b/gcc/testsuite/gnat.dg/aggr18.adb @@ -1,28 +1,28 @@ --- { dg-do compile }
--- { dg-options "-gnatws" }
-
-procedure Aggr18 is
-
- type Enum is (A, B);
-
- type Rec (D : Enum := Enum'First) is record
- case D is
- when A => X : Integer;
- when B => null;
- end case;
- end record;
- for Rec'Size use 128;
- pragma Volatile (Rec);
-
- type Config_T (D : Enum := Enum'First) is record
- N : Natural;
- R : Rec (D);
- end record;
-
- C : Config_T := (D => A, N => 1, R => (D => A, X => 0));
-
- type Arr is array (Natural range 1 .. C.N) of Boolean;
-
-begin
- null;
-end;
+-- { dg-do compile } +-- { dg-options "-gnatws" } + +procedure Aggr18 is + + type Enum is (A, B); + + type Rec (D : Enum := Enum'First) is record + case D is + when A => X : Integer; + when B => null; + end case; + end record; + for Rec'Size use 128; + pragma Volatile (Rec); + + type Config_T (D : Enum := Enum'First) is record + N : Natural; + R : Rec (D); + end record; + + C : Config_T := (D => A, N => 1, R => (D => A, X => 0)); + + type Arr is array (Natural range 1 .. C.N) of Boolean; + +begin + null; +end; diff --git a/gcc/testsuite/gnat.dg/array14.adb b/gcc/testsuite/gnat.dg/array14.adb index aed29015a9a..2d45cf10db4 100644 --- a/gcc/testsuite/gnat.dg/array14.adb +++ b/gcc/testsuite/gnat.dg/array14.adb @@ -1,35 +1,35 @@ --- { dg-do compile }
--- { dg-options "-gnatws" }
-
-with Array14_Pkg; use Array14_Pkg;
-
-package body Array14 is
-
- package Nested is
-
- Length : constant SSE.Storage_Count := Length2;
-
- subtype Encoded_Index_Type is SSE.Storage_Count range 1 .. Length;
- subtype Encoded_Type is SSE.Storage_Array (Encoded_Index_Type'Range);
-
- procedure Encode (Input : in Integer; Output : out Encoded_Type);
-
- end;
-
- package body Nested is
-
- procedure Encode (Input : in Integer; Output : out Encoded_Type) is
- begin
- Encode2 (Input, Output);
- end;
-
- end;
-
- procedure Init is
- O : Nested.Encoded_Type;
- for O'Alignment use 4;
- begin
- null;
- end;
-
-end Array14;
+-- { dg-do compile } +-- { dg-options "-gnatws" } + +with Array14_Pkg; use Array14_Pkg; + +package body Array14 is + + package Nested is + + Length : constant SSE.Storage_Count := Length2; + + subtype Encoded_Index_Type is SSE.Storage_Count range 1 .. Length; + subtype Encoded_Type is SSE.Storage_Array (Encoded_Index_Type'Range); + + procedure Encode (Input : in Integer; Output : out Encoded_Type); + + end; + + package body Nested is + + procedure Encode (Input : in Integer; Output : out Encoded_Type) is + begin + Encode2 (Input, Output); + end; + + end; + + procedure Init is + O : Nested.Encoded_Type; + for O'Alignment use 4; + begin + null; + end; + +end Array14; diff --git a/gcc/testsuite/gnat.dg/array14.ads b/gcc/testsuite/gnat.dg/array14.ads index 9d38eeb8895..051a52e56ae 100644 --- a/gcc/testsuite/gnat.dg/array14.ads +++ b/gcc/testsuite/gnat.dg/array14.ads @@ -1,5 +1,5 @@ -package Array14 is
-
- procedure Init;
-
-end Array14;
+package Array14 is + + procedure Init; + +end Array14; diff --git a/gcc/testsuite/gnat.dg/array14_pkg.ads b/gcc/testsuite/gnat.dg/array14_pkg.ads index 804090586e3..7186c5dc82c 100644 --- a/gcc/testsuite/gnat.dg/array14_pkg.ads +++ b/gcc/testsuite/gnat.dg/array14_pkg.ads @@ -1,16 +1,16 @@ -with System.Storage_Elements;
-
-package Array14_Pkg is
-
- package SSE renames System.Storage_Elements;
-
- function Parity_Byte_Count return SSE.Storage_Count;
-
- Length2 : constant SSE.Storage_Count := Parity_Byte_Count;
-
- subtype Encoded_Index_Type2 is SSE.Storage_Count range 1 .. Length2;
- subtype Encoded_Type2 is SSE.Storage_Array (Encoded_Index_Type2'Range);
-
- procedure Encode2 (Input : in Integer; Output : out Encoded_Type2);
-
-end Array14_Pkg;
+with System.Storage_Elements; + +package Array14_Pkg is + + package SSE renames System.Storage_Elements; + + function Parity_Byte_Count return SSE.Storage_Count; + + Length2 : constant SSE.Storage_Count := Parity_Byte_Count; + + subtype Encoded_Index_Type2 is SSE.Storage_Count range 1 .. Length2; + subtype Encoded_Type2 is SSE.Storage_Array (Encoded_Index_Type2'Range); + + procedure Encode2 (Input : in Integer; Output : out Encoded_Type2); + +end Array14_Pkg; diff --git a/gcc/testsuite/gnat.dg/array19.adb b/gcc/testsuite/gnat.dg/array19.adb index 56b05d6490b..8667a3f0650 100644 --- a/gcc/testsuite/gnat.dg/array19.adb +++ b/gcc/testsuite/gnat.dg/array19.adb @@ -1,34 +1,34 @@ --- { dg-do compile }
-
-package body Array19 is
-
- function N return Integer is
- begin
- return 1;
- end;
-
- type Array_Type is array (1 .. N) of Float;
-
- type Enum is (One, Two);
-
- type Rec (D : Enum := Enum'First) is record
- case D is
- when One => null;
- when Two => A : Array_Type;
- end case;
- end record;
-
- procedure Proc is
-
- R : Rec;
-
- function F return Array_Type is
- begin
- return (others => 0.0);
- end F;
-
- begin
- R.A := F;
- end;
-
-end Array19;
+-- { dg-do compile } + +package body Array19 is + + function N return Integer is + begin + return 1; + end; + + type Array_Type is array (1 .. N) of Float; + + type Enum is (One, Two); + + type Rec (D : Enum := Enum'First) is record + case D is + when One => null; + when Two => A : Array_Type; + end case; + end record; + + procedure Proc is + + R : Rec; + + function F return Array_Type is + begin + return (others => 0.0); + end F; + + begin + R.A := F; + end; + +end Array19; diff --git a/gcc/testsuite/gnat.dg/array19.ads b/gcc/testsuite/gnat.dg/array19.ads index 48947f590fa..fa24aae08ac 100644 --- a/gcc/testsuite/gnat.dg/array19.ads +++ b/gcc/testsuite/gnat.dg/array19.ads @@ -1,5 +1,5 @@ -package Array19 is
-
- procedure Proc;
-
-end Array19;
+package Array19 is + + procedure Proc; + +end Array19; diff --git a/gcc/testsuite/gnat.dg/discr27.adb b/gcc/testsuite/gnat.dg/discr27.adb index 875fe435b66..4b77f8efab9 100644 --- a/gcc/testsuite/gnat.dg/discr27.adb +++ b/gcc/testsuite/gnat.dg/discr27.adb @@ -1,33 +1,33 @@ --- { dg-do compile }
-
-package body Discr27 is
-
- subtype Index is Positive range 1..4096;
-
- function F return String is
- S : String(1..1) := (others =>'w');
- begin
- return S;
- end;
-
- type Enum is (One, Two);
-
- type Rec (D : Enum := One; Len : Index := 1) is record
- case D is
- when One => I : Integer;
- when Two => A : String(1..Len);
- end case;
- end record;
-
- procedure Nothing is
- M : constant String := F;
- C : constant Rec := (Two, M'Length, M);
- begin
- null;
- end;
-
- procedure Proc is begin
- null;
- end;
-
-end Discr27;
+-- { dg-do compile } + +package body Discr27 is + + subtype Index is Positive range 1..4096; + + function F return String is + S : String(1..1) := (others =>'w'); + begin + return S; + end; + + type Enum is (One, Two); + + type Rec (D : Enum := One; Len : Index := 1) is record + case D is + when One => I : Integer; + when Two => A : String(1..Len); + end case; + end record; + + procedure Nothing is + M : constant String := F; + C : constant Rec := (Two, M'Length, M); + begin + null; + end; + + procedure Proc is begin + null; + end; + +end Discr27; diff --git a/gcc/testsuite/gnat.dg/discr27.ads b/gcc/testsuite/gnat.dg/discr27.ads index 247134a9916..1d3c4e99979 100644 --- a/gcc/testsuite/gnat.dg/discr27.ads +++ b/gcc/testsuite/gnat.dg/discr27.ads @@ -1,5 +1,5 @@ -package Discr27 is
-
- procedure Proc;
-
-end Discr27;
+package Discr27 is + + procedure Proc; + +end Discr27; diff --git a/gcc/testsuite/gnat.dg/discr35.adb b/gcc/testsuite/gnat.dg/discr35.adb index 8b73773bac0..16bacd6c19b 100644 --- a/gcc/testsuite/gnat.dg/discr35.adb +++ b/gcc/testsuite/gnat.dg/discr35.adb @@ -1,17 +1,17 @@ --- { dg-do compile }
-
-package body Discr35 is
-
- procedure Proc1 is
- R : Rec2 := Null_Rec2;
- begin
- null;
- end;
-
- procedure Proc2 is
- R : Rec2;
- begin
- R := Null_Rec2;
- end;
-
-end Discr35;
+-- { dg-do compile } + +package body Discr35 is + + procedure Proc1 is + R : Rec2 := Null_Rec2; + begin + null; + end; + + procedure Proc2 is + R : Rec2; + begin + R := Null_Rec2; + end; + +end Discr35; diff --git a/gcc/testsuite/gnat.dg/discr35.ads b/gcc/testsuite/gnat.dg/discr35.ads index beb2c40fd9c..7cde6cd66c7 100644 --- a/gcc/testsuite/gnat.dg/discr35.ads +++ b/gcc/testsuite/gnat.dg/discr35.ads @@ -1,25 +1,25 @@ -package Discr35 is
-
- type Rec1 is tagged null record;
-
- type Enum is (One, Two);
-
- type Rec2 (D : Enum := One) is
- record
- case D is
- when One => null;
- when Two => R : Rec1;
- end case;
- end record;
-
- Null_Rec2 : Constant Rec2;
-
- procedure Proc1;
-
- procedure Proc2;
-
-private
-
- Null_Rec2 : Constant Rec2 := (D => One);
-
-end Discr35;
+package Discr35 is + + type Rec1 is tagged null record; + + type Enum is (One, Two); + + type Rec2 (D : Enum := One) is + record + case D is + when One => null; + when Two => R : Rec1; + end case; + end record; + + Null_Rec2 : Constant Rec2; + + procedure Proc1; + + procedure Proc2; + +private + + Null_Rec2 : Constant Rec2 := (D => One); + +end Discr35; diff --git a/gcc/testsuite/gnat.dg/discr6.adb b/gcc/testsuite/gnat.dg/discr6.adb index 441b19bdf29..52a94b1d6ad 100644 --- a/gcc/testsuite/gnat.dg/discr6.adb +++ b/gcc/testsuite/gnat.dg/discr6.adb @@ -1,33 +1,33 @@ --- { dg-do compile }
--- { dg-options "-gnatdm -gnatws" }
-
-with Discr6_Pkg;
-
-procedure Discr6 is
-
- type T_Bit is range 0..1;
- type T_Entier_16 is range -2**15 .. 2**15-1;
-
- package My_Q is new Discr6_Pkg(T_Entier_16);
-
- type T_Valeur is (BIT, Entier_16);
-
- type R(D : T_Valeur) is record
- case D is
- when BIT => V_BIT : T_Bit;
- when Entier_16 => V_E16 : T_Entier_16;
- end case;
- end record;
- for R use record
- V_BIT at 0 range 0..7;
- V_E16 at 0 range 0..15;
- D at 8 range 0..7;
- end record;
- for R'size use 128;
-
- A : R(Entier_16);
- I : Integer;
-
-begin
- I := My_Q.X(A.V_E16);
-end;
+-- { dg-do compile } +-- { dg-options "-gnatdm -gnatws" } + +with Discr6_Pkg; + +procedure Discr6 is + + type T_Bit is range 0..1; + type T_Entier_16 is range -2**15 .. 2**15-1; + + package My_Q is new Discr6_Pkg(T_Entier_16); + + type T_Valeur is (BIT, Entier_16); + + type R(D : T_Valeur) is record + case D is + when BIT => V_BIT : T_Bit; + when Entier_16 => V_E16 : T_Entier_16; + end case; + end record; + for R use record + V_BIT at 0 range 0..7; + V_E16 at 0 range 0..15; + D at 8 range 0..7; + end record; + for R'size use 128; + + A : R(Entier_16); + I : Integer; + +begin + I := My_Q.X(A.V_E16); +end; diff --git a/gcc/testsuite/gnat.dg/discr6_pkg.ads b/gcc/testsuite/gnat.dg/discr6_pkg.ads index 11d713c244d..81404d4613f 100644 --- a/gcc/testsuite/gnat.dg/discr6_pkg.ads +++ b/gcc/testsuite/gnat.dg/discr6_pkg.ads @@ -1,16 +1,16 @@ -generic
-
- type T(<>) is private;
-
-package Discr6_Pkg is
-
- function X (A : T) return Integer;
-
- pragma Interface(C, X);
- pragma IMPORT_FUNCTION (
- INTERNAL => X,
- EXTERNAL => X,
- PARAMETER_TYPES => (T),
- MECHANISM => (Descriptor(S)));
-
-end Discr6_Pkg;
+generic + + type T(<>) is private; + +package Discr6_Pkg is + + function X (A : T) return Integer; + + pragma Interface(C, X); + pragma IMPORT_FUNCTION ( + INTERNAL => X, + EXTERNAL => X, + PARAMETER_TYPES => (T), + MECHANISM => (Descriptor(S))); + +end Discr6_Pkg; diff --git a/gcc/testsuite/gnat.dg/import1.adb b/gcc/testsuite/gnat.dg/import1.adb index 4e4056098b5..6de432dcab4 100644 --- a/gcc/testsuite/gnat.dg/import1.adb +++ b/gcc/testsuite/gnat.dg/import1.adb @@ -1,17 +1,17 @@ --- { dg-do compile }
--- { dg-options "-g" }
-
-package body Import1 is
-
- procedure Create (Bounds : Arr) is
- type Bound_Array is array (Bounds'Range) of Integer;
-
- procedure Proc (Ptr : access Bound_Array);
- pragma Import (C, Proc);
-
- Temp : aliased Bound_Array;
- begin
- Proc (Temp'Access);
- end;
-
-end Import1;
+-- { dg-do compile } +-- { dg-options "-g" } + +package body Import1 is + + procedure Create (Bounds : Arr) is + type Bound_Array is array (Bounds'Range) of Integer; + + procedure Proc (Ptr : access Bound_Array); + pragma Import (C, Proc); + + Temp : aliased Bound_Array; + begin + Proc (Temp'Access); + end; + +end Import1; diff --git a/gcc/testsuite/gnat.dg/import1.ads b/gcc/testsuite/gnat.dg/import1.ads index cb00a0caf40..3afcfcc83da 100644 --- a/gcc/testsuite/gnat.dg/import1.ads +++ b/gcc/testsuite/gnat.dg/import1.ads @@ -1,7 +1,7 @@ -package Import1 is
-
- type Arr is array (Positive range <>) of Integer;
-
- procedure Create (Bounds : Arr);
-
-end Import1;
+package Import1 is + + type Arr is array (Positive range <>) of Integer; + + procedure Create (Bounds : Arr); + +end Import1; diff --git a/gcc/testsuite/gnat.dg/loop_address2.adb b/gcc/testsuite/gnat.dg/loop_address2.adb index aa955d771b2..57bed171ecd 100644 --- a/gcc/testsuite/gnat.dg/loop_address2.adb +++ b/gcc/testsuite/gnat.dg/loop_address2.adb @@ -1,26 +1,26 @@ --- { dg-do compile }
--- { dg-options "-O" }
-
-with System, Ada.Unchecked_Conversion;
-with System.Storage_Elements; use System.Storage_Elements;
-
-procedure Loop_Address2 is
-
- type Ptr is access all Integer;
-
- function To_Ptr is new Ada.Unchecked_Conversion (System.Address, Ptr);
-
- function F (BM : System.Address; I : Integer) return System.Address is
- begin
- return BM + Storage_Offset (4*I);
- end;
-
- B : Integer;
- P : Ptr;
-
-begin
- for I in 0 .. 2 loop
- P := To_Ptr (F (B'Address, I));
- P.all := 0;
- end loop;
-end ;
+-- { dg-do compile } +-- { dg-options "-O" } + +with System, Ada.Unchecked_Conversion; +with System.Storage_Elements; use System.Storage_Elements; + +procedure Loop_Address2 is + + type Ptr is access all Integer; + + function To_Ptr is new Ada.Unchecked_Conversion (System.Address, Ptr); + + function F (BM : System.Address; I : Integer) return System.Address is + begin + return BM + Storage_Offset (4*I); + end; + + B : Integer; + P : Ptr; + +begin + for I in 0 .. 2 loop + P := To_Ptr (F (B'Address, I)); + P.all := 0; + end loop; +end ; diff --git a/gcc/testsuite/gnat.dg/opt7.adb b/gcc/testsuite/gnat.dg/opt7.adb index da3b0e6dfa2..51b56f32bf2 100644 --- a/gcc/testsuite/gnat.dg/opt7.adb +++ b/gcc/testsuite/gnat.dg/opt7.adb @@ -1,44 +1,44 @@ --- { dg-do compile }
--- { dg-options "-Os -g" }
-
-with Opt7_Pkg;
-
-package body Opt7 is
-
- procedure Parse (Str : String;
- Time_Type : out time_t;
- Abs_Time : out Time;
- Delt_Time : out Duration) is
- Year : Year_Number;
- Month : Month_Number;
- Day : Day_Number;
- Minute : Integer := 0;
- Idx : Integer := Str'First;
- Ch : Character := Str (Idx);
- Current_Time : Time;
-
- begin
- if Ch = '-' then
- Time_Type := Absolute_Time;
- Current_Time := Clock;
- Day := Ada.Calendar.Day (Current_Time);
- Month := Ada.Calendar.Month (Current_Time);
- Year := Ada.Calendar.Year (Current_Time);
- else
- Time_Type := Delta_Time;
- end if;
- while Ch in '0' .. '9' loop
- Minute := Minute + Character'Pos (Ch);
- Idx := Idx + 1;
- Ch := Str (Idx);
- end loop;
- if Time_Type = Absolute_Time then
- Abs_Time := Time_Of (Year, Month, Day, Day_Duration (1));
- else
- Delt_Time := Duration (Float (Minute));
- end if;
- exception
- when others => Opt7_Pkg.My_Raise_Exception;
- end;
-
-end Opt7;
+-- { dg-do compile } +-- { dg-options "-Os -g" } + +with Opt7_Pkg; + +package body Opt7 is + + procedure Parse (Str : String; + Time_Type : out time_t; + Abs_Time : out Time; + Delt_Time : out Duration) is + Year : Year_Number; + Month : Month_Number; + Day : Day_Number; + Minute : Integer := 0; + Idx : Integer := Str'First; + Ch : Character := Str (Idx); + Current_Time : Time; + + begin + if Ch = '-' then + Time_Type := Absolute_Time; + Current_Time := Clock; + Day := Ada.Calendar.Day (Current_Time); + Month := Ada.Calendar.Month (Current_Time); + Year := Ada.Calendar.Year (Current_Time); + else + Time_Type := Delta_Time; + end if; + while Ch in '0' .. '9' loop + Minute := Minute + Character'Pos (Ch); + Idx := Idx + 1; + Ch := Str (Idx); + end loop; + if Time_Type = Absolute_Time then + Abs_Time := Time_Of (Year, Month, Day, Day_Duration (1)); + else + Delt_Time := Duration (Float (Minute)); + end if; + exception + when others => Opt7_Pkg.My_Raise_Exception; + end; + +end Opt7; diff --git a/gcc/testsuite/gnat.dg/opt7.ads b/gcc/testsuite/gnat.dg/opt7.ads index c9803532670..99224bf3612 100644 --- a/gcc/testsuite/gnat.dg/opt7.ads +++ b/gcc/testsuite/gnat.dg/opt7.ads @@ -1,12 +1,12 @@ -with Ada.Calendar; use Ada.Calendar;
-
-package Opt7 is
-
- type time_t is (Absolute_Time, Delta_Time);
-
- procedure Parse (Str : String;
- Time_Type : out time_t;
- Abs_Time : out Time;
- Delt_Time : out Duration);
-
-end Opt7;
+with Ada.Calendar; use Ada.Calendar; + +package Opt7 is + + type time_t is (Absolute_Time, Delta_Time); + + procedure Parse (Str : String; + Time_Type : out time_t; + Abs_Time : out Time; + Delt_Time : out Duration); + +end Opt7; diff --git a/gcc/testsuite/gnat.dg/pointer_variable_bounds.adb b/gcc/testsuite/gnat.dg/pointer_variable_bounds.adb index 5cc838a383e..43d683e0420 100644 --- a/gcc/testsuite/gnat.dg/pointer_variable_bounds.adb +++ b/gcc/testsuite/gnat.dg/pointer_variable_bounds.adb @@ -1,26 +1,26 @@ --- { dg-do compile }
--- { dg-options "-gnatws" }
-
-package body pointer_variable_bounds is
-
- function COMPONENT_DAT(BP : in BUNDLE_POINTER_TYPE; CP : in COMP_POINTER_TYPE) return HALF_INTEGER is
- type CP_TYPE is access COMP_POINTER_TYPE;
- type CD_TYPE is access HALF_INTEGER;
- CD : CD_TYPE;
- begin
- return CD.all;
- end;
-
- procedure BUNDLE_DAT(BP : in BUNDLE_POINTER_TYPE) is
- N0 : C_POINTER_TYPE := COMPONENT_DAT(BP, 4);
- begin
- null;
- end;
-
- procedure SEQUENCE_DAT(BP : in BUNDLE_POINTER_TYPE) is
- N0 : C_POINTER_TYPE := COMPONENT_DAT(BP, 4);
- begin
- null;
- end;
-
-end pointer_variable_bounds;
+-- { dg-do compile } +-- { dg-options "-gnatws" } + +package body pointer_variable_bounds is + + function COMPONENT_DAT(BP : in BUNDLE_POINTER_TYPE; CP : in COMP_POINTER_TYPE) return HALF_INTEGER is + type CP_TYPE is access COMP_POINTER_TYPE; + type CD_TYPE is access HALF_INTEGER; + CD : CD_TYPE; + begin + return CD.all; + end; + + procedure BUNDLE_DAT(BP : in BUNDLE_POINTER_TYPE) is + N0 : C_POINTER_TYPE := COMPONENT_DAT(BP, 4); + begin + null; + end; + + procedure SEQUENCE_DAT(BP : in BUNDLE_POINTER_TYPE) is + N0 : C_POINTER_TYPE := COMPONENT_DAT(BP, 4); + begin + null; + end; + +end pointer_variable_bounds; diff --git a/gcc/testsuite/gnat.dg/pointer_variable_bounds.ads b/gcc/testsuite/gnat.dg/pointer_variable_bounds.ads index b18c354077d..39d502ab3ca 100644 --- a/gcc/testsuite/gnat.dg/pointer_variable_bounds.ads +++ b/gcc/testsuite/gnat.dg/pointer_variable_bounds.ads @@ -1,16 +1,16 @@ -with pointer_variable_bounds_q; use pointer_variable_bounds_q;
-
-package pointer_variable_bounds is
-
- type HALF_INTEGER is range -32768 .. 32767;
- subtype HALF_NATURAL is HALF_INTEGER range 0 .. 32767;
-
- MAX_COMPS : constant HALF_NATURAL := HALF_NATURAL(A_MAX_COMPS);
- subtype COMP_POINTER_TYPE is HALF_NATURAL range 0 .. MAX_COMPS;
- subtype BUNDLE_POINTER_TYPE is HALF_NATURAL range 0 .. 1;
- subtype C_POINTER_TYPE is HALF_NATURAL range 0 .. 1;
-
- procedure BUNDLE_DAT(BP : in BUNDLE_POINTER_TYPE);
- procedure SEQUENCE_DAT(BP : in BUNDLE_POINTER_TYPE);
-
-end pointer_variable_bounds;
+with pointer_variable_bounds_q; use pointer_variable_bounds_q; + +package pointer_variable_bounds is + + type HALF_INTEGER is range -32768 .. 32767; + subtype HALF_NATURAL is HALF_INTEGER range 0 .. 32767; + + MAX_COMPS : constant HALF_NATURAL := HALF_NATURAL(A_MAX_COMPS); + subtype COMP_POINTER_TYPE is HALF_NATURAL range 0 .. MAX_COMPS; + subtype BUNDLE_POINTER_TYPE is HALF_NATURAL range 0 .. 1; + subtype C_POINTER_TYPE is HALF_NATURAL range 0 .. 1; + + procedure BUNDLE_DAT(BP : in BUNDLE_POINTER_TYPE); + procedure SEQUENCE_DAT(BP : in BUNDLE_POINTER_TYPE); + +end pointer_variable_bounds; diff --git a/gcc/testsuite/gnat.dg/rep_clause2.adb b/gcc/testsuite/gnat.dg/rep_clause2.adb index b6cd49f9f98..1c26e1255b1 100644 --- a/gcc/testsuite/gnat.dg/rep_clause2.adb +++ b/gcc/testsuite/gnat.dg/rep_clause2.adb @@ -1,10 +1,10 @@ --- { dg-do compile }
-
-package body Rep_Clause2 is
-
- procedure Assign (From : Data; Offset : Positive; I : Index; To : out Bit_Array) is
- begin
- To (Offset .. Offset + 7) := Bit_Array (Conv (From.D(I).S.N));
- end;
-
-end Rep_Clause2;
+-- { dg-do compile } + +package body Rep_Clause2 is + + procedure Assign (From : Data; Offset : Positive; I : Index; To : out Bit_Array) is + begin + To (Offset .. Offset + 7) := Bit_Array (Conv (From.D(I).S.N)); + end; + +end Rep_Clause2; diff --git a/gcc/testsuite/gnat.dg/rep_clause2.ads b/gcc/testsuite/gnat.dg/rep_clause2.ads index cc8b33e8b4c..c4d07236899 100644 --- a/gcc/testsuite/gnat.dg/rep_clause2.ads +++ b/gcc/testsuite/gnat.dg/rep_clause2.ads @@ -1,53 +1,53 @@ -with Unchecked_Conversion;
-
-package Rep_Clause2 is
-
- type Tiny is range 0 .. 3;
- for Tiny'Size use 2;
-
- type Small is range 0 .. 255;
- for Small'Size use 8;
-
- type Small_Data is record
- D : Tiny;
- N : Small;
- end record;
- pragma Pack (Small_Data);
-
- type Chunk is
- record
- S : Small_Data;
- C : Character;
- end record;
-
- for Chunk use record
- S at 0 range 0 .. 15;
- C at 2 range 0 .. 7;
- end record;
-
- type Index is range 1 .. 10;
-
- type Data_Array is array (Index) of Chunk;
- for Data_Array'Alignment use 2;
- pragma Pack (Data_Array);
-
- type Data is record
- D : Data_Array;
- end record;
-
- type Bit is range 0 .. 1;
- for Bit'Size use 1;
-
- type Bit_Array is array (Positive range <>) of Bit;
- pragma Pack (Bit_Array);
-
- type Byte is new Bit_Array (1 .. 8);
- for Byte'Size use 8;
- for Byte'Alignment use 1;
-
- function Conv
- is new Unchecked_Conversion(Source => Small, Target => Byte);
-
- procedure Assign (From : Data; Offset : Positive; I : Index; To : out Bit_Array);
-
-end Rep_Clause2;
+with Unchecked_Conversion; + +package Rep_Clause2 is + + type Tiny is range 0 .. 3; + for Tiny'Size use 2; + + type Small is range 0 .. 255; + for Small'Size use 8; + + type Small_Data is record + D : Tiny; + N : Small; + end record; + pragma Pack (Small_Data); + + type Chunk is + record + S : Small_Data; + C : Character; + end record; + + for Chunk use record + S at 0 range 0 .. 15; + C at 2 range 0 .. 7; + end record; + + type Index is range 1 .. 10; + + type Data_Array is array (Index) of Chunk; + for Data_Array'Alignment use 2; + pragma Pack (Data_Array); + + type Data is record + D : Data_Array; + end record; + + type Bit is range 0 .. 1; + for Bit'Size use 1; + + type Bit_Array is array (Positive range <>) of Bit; + pragma Pack (Bit_Array); + + type Byte is new Bit_Array (1 .. 8); + for Byte'Size use 8; + for Byte'Alignment use 1; + + function Conv + is new Unchecked_Conversion(Source => Small, Target => Byte); + + procedure Assign (From : Data; Offset : Positive; I : Index; To : out Bit_Array); + +end Rep_Clause2; diff --git a/gcc/testsuite/gnat.dg/slice2.adb b/gcc/testsuite/gnat.dg/slice2.adb index ab73074313e..87c0bcd8790 100644 --- a/gcc/testsuite/gnat.dg/slice2.adb +++ b/gcc/testsuite/gnat.dg/slice2.adb @@ -1,13 +1,13 @@ --- { dg-do compile }
--- { dg-options "-O" }
-
-package body Slice2 is
-
- function F (I : R1) return R2 is
- Val : R2;
- begin
- Val.Text (1 .. 8) := I.Text (1 .. 8);
- return Val;
- end F;
-
-end Slice2;
+-- { dg-do compile } +-- { dg-options "-O" } + +package body Slice2 is + + function F (I : R1) return R2 is + Val : R2; + begin + Val.Text (1 .. 8) := I.Text (1 .. 8); + return Val; + end F; + +end Slice2; diff --git a/gcc/testsuite/gnat.dg/slice2.ads b/gcc/testsuite/gnat.dg/slice2.ads index f1b8674fb8e..d1f943a80cf 100644 --- a/gcc/testsuite/gnat.dg/slice2.ads +++ b/gcc/testsuite/gnat.dg/slice2.ads @@ -1,14 +1,14 @@ -package Slice2 is
-
- type R1 is record
- Text : String (1 .. 30);
- end record;
-
- type R2 is record
- Text : String (1 .. 8);
- B : Boolean := True;
- end record;
-
- function F (I : R1) return R2;
-
-end Slice2;
+package Slice2 is + + type R1 is record + Text : String (1 .. 30); + end record; + + type R2 is record + Text : String (1 .. 8); + B : Boolean := True; + end record; + + function F (I : R1) return R2; + +end Slice2; diff --git a/gcc/testsuite/gnat.dg/slice6.adb b/gcc/testsuite/gnat.dg/slice6.adb index 8d96bbf8cf3..de71ac608ef 100644 --- a/gcc/testsuite/gnat.dg/slice6.adb +++ b/gcc/testsuite/gnat.dg/slice6.adb @@ -1,23 +1,23 @@ --- { dg-do compile }
--- { dg-options "-gnatws" }
-
-with Slice6_Pkg; use Slice6_Pkg;
-
-procedure Slice6 is
-
- procedure Send (V_LENGTH : SHORT_INTEGER) is
-
- V : Integer;
-
- V_BLOCK : T_BLOCK (1 .. 4096);
- for V_BLOCK use at V'Address;
-
- V_MSG : T_MSG ;
-
- begin
- V_MSG := (V_LENGTH, 1, V_BLOCK (1 .. V_LENGTH));
- end;
-
-begin
- null;
-end;
+-- { dg-do compile } +-- { dg-options "-gnatws" } + +with Slice6_Pkg; use Slice6_Pkg; + +procedure Slice6 is + + procedure Send (V_LENGTH : SHORT_INTEGER) is + + V : Integer; + + V_BLOCK : T_BLOCK (1 .. 4096); + for V_BLOCK use at V'Address; + + V_MSG : T_MSG ; + + begin + V_MSG := (V_LENGTH, 1, V_BLOCK (1 .. V_LENGTH)); + end; + +begin + null; +end; diff --git a/gcc/testsuite/gnat.dg/slice6_pkg.ads b/gcc/testsuite/gnat.dg/slice6_pkg.ads index 3154c2959a6..ef2047311a9 100644 --- a/gcc/testsuite/gnat.dg/slice6_pkg.ads +++ b/gcc/testsuite/gnat.dg/slice6_pkg.ads @@ -1,15 +1,15 @@ -package Slice6_Pkg is
-
- subtype LENGTH_RANGE is SHORT_INTEGER range 0 .. 8184;
-
- type T_BLOCK is array (SHORT_INTEGER range <>) of SHORT_SHORT_INTEGER;
- for T_BLOCK'alignment use 4;
-
- type T_MSG (V_LENGTH : LENGTH_RANGE := 0) is
- record
- HEADER : Integer;
- DATAS : T_BLOCK (1 .. V_LENGTH) := (others => 0);
- end record;
- for T_MSG'alignment use 4;
-
-end Slice6_Pkg;
+package Slice6_Pkg is + + subtype LENGTH_RANGE is SHORT_INTEGER range 0 .. 8184; + + type T_BLOCK is array (SHORT_INTEGER range <>) of SHORT_SHORT_INTEGER; + for T_BLOCK'alignment use 4; + + type T_MSG (V_LENGTH : LENGTH_RANGE := 0) is + record + HEADER : Integer; + DATAS : T_BLOCK (1 .. V_LENGTH) := (others => 0); + end record; + for T_MSG'alignment use 4; + +end Slice6_Pkg; diff --git a/gcc/testsuite/gnat.dg/specs/unchecked_union2.ads b/gcc/testsuite/gnat.dg/specs/unchecked_union2.ads index f13421cc474..4ed3493f676 100644 --- a/gcc/testsuite/gnat.dg/specs/unchecked_union2.ads +++ b/gcc/testsuite/gnat.dg/specs/unchecked_union2.ads @@ -1,30 +1,30 @@ --- { dg-do compile }
-
-package Unchecked_Union2 is
-
- type Small_Int is range 0 .. 2**19 - 1;
-
- type R1 (B : Boolean := True) is record
- case B is
- when True => Data1 : Small_Int;
- when False => Data2 : Small_Int;
- end case;
- end record;
-
- for R1 use record
- Data1 at 0 range 0 .. 18;
- Data2 at 0 range 0 .. 18;
- end record;
- for R1'Size use 24;
-
- pragma Unchecked_Union (R1);
-
- type R2 is record
- Data : R1;
- end record;
-
- for R2 use record
- Data at 0 range 3 .. 26;
- end record;
-
-end Unchecked_Union2;
+-- { dg-do compile } + +package Unchecked_Union2 is + + type Small_Int is range 0 .. 2**19 - 1; + + type R1 (B : Boolean := True) is record + case B is + when True => Data1 : Small_Int; + when False => Data2 : Small_Int; + end case; + end record; + + for R1 use record + Data1 at 0 range 0 .. 18; + Data2 at 0 range 0 .. 18; + end record; + for R1'Size use 24; + + pragma Unchecked_Union (R1); + + type R2 is record + Data : R1; + end record; + + for R2 use record + Data at 0 range 3 .. 26; + end record; + +end Unchecked_Union2; diff --git a/gcc/testsuite/gnat.dg/taft_type2.adb b/gcc/testsuite/gnat.dg/taft_type2.adb index c855ab6e967..3a7a318cf6a 100644 --- a/gcc/testsuite/gnat.dg/taft_type2.adb +++ b/gcc/testsuite/gnat.dg/taft_type2.adb @@ -1,22 +1,22 @@ --- { dg-do compile }
--- { dg-options "-g" }
-
-with Taft_Type2_Pkg; use Taft_Type2_Pkg;
-
-package body Taft_Type2 is
-
- procedure Proc is
- A : T;
-
- function F return T is
- My_T : T;
- begin
- My_T := Open;
- return My_T;
- end;
-
- begin
- A := F;
- end;
-
-end Taft_Type2;
+-- { dg-do compile } +-- { dg-options "-g" } + +with Taft_Type2_Pkg; use Taft_Type2_Pkg; + +package body Taft_Type2 is + + procedure Proc is + A : T; + + function F return T is + My_T : T; + begin + My_T := Open; + return My_T; + end; + + begin + A := F; + end; + +end Taft_Type2; diff --git a/gcc/testsuite/gnat.dg/taft_type2.ads b/gcc/testsuite/gnat.dg/taft_type2.ads index 539c1069875..812bc93b946 100644 --- a/gcc/testsuite/gnat.dg/taft_type2.ads +++ b/gcc/testsuite/gnat.dg/taft_type2.ads @@ -1,5 +1,5 @@ -package Taft_Type2 is
-
- procedure Proc;
-
-end Taft_Type2;
+package Taft_Type2 is + + procedure Proc; + +end Taft_Type2; diff --git a/gcc/testsuite/gnat.dg/taft_type2_pkg.ads b/gcc/testsuite/gnat.dg/taft_type2_pkg.ads index 689b3f1a6a8..ffacda289cc 100644 --- a/gcc/testsuite/gnat.dg/taft_type2_pkg.ads +++ b/gcc/testsuite/gnat.dg/taft_type2_pkg.ads @@ -1,12 +1,12 @@ -package Taft_Type2_Pkg is
-
- type T is private;
-
- function Open return T;
-
-private
-
- type Buffer_T;
- type T is access Buffer_T;
-
-end Taft_Type2_Pkg;
+package Taft_Type2_Pkg is + + type T is private; + + function Open return T; + +private + + type Buffer_T; + type T is access Buffer_T; + +end Taft_Type2_Pkg; diff --git a/gcc/testsuite/gnat.dg/volatile10.adb b/gcc/testsuite/gnat.dg/volatile10.adb index 5f295b96644..945d562d570 100644 --- a/gcc/testsuite/gnat.dg/volatile10.adb +++ b/gcc/testsuite/gnat.dg/volatile10.adb @@ -1,10 +1,10 @@ --- { dg-do compile }
-
-with Volatile10_Pkg; use Volatile10_Pkg;
-
-procedure Volatile10 is
- N : Num;
-begin
- N := F.N1;
- N := F.N2;
-end;
+-- { dg-do compile } + +with Volatile10_Pkg; use Volatile10_Pkg; + +procedure Volatile10 is + N : Num; +begin + N := F.N1; + N := F.N2; +end; diff --git a/gcc/testsuite/gnat.dg/volatile10_pkg.ads b/gcc/testsuite/gnat.dg/volatile10_pkg.ads index 3ad2a79635c..2bdd4104618 100644 --- a/gcc/testsuite/gnat.dg/volatile10_pkg.ads +++ b/gcc/testsuite/gnat.dg/volatile10_pkg.ads @@ -1,29 +1,29 @@ -package Volatile10_Pkg is
-
- type Num is mod 2**9;
-
- type Rec is record
- B1 : Boolean;
- N1 : Num;
- B2 : Boolean;
- N2 : Num;
- B3 : Boolean;
- B4 : Boolean;
- B5 : Boolean;
- B6 : Boolean;
- B7 : Boolean;
- B8 : Boolean;
- B9 : Boolean;
- B10 : Boolean;
- B11 : Boolean;
- B12 : Boolean;
- B13 : Boolean;
- B14 : Boolean;
- end record;
- pragma Pack (Rec);
- for Rec'Size use 32;
- pragma Volatile(Rec);
-
- function F return Rec;
-
-end Volatile10_Pkg;
+package Volatile10_Pkg is + + type Num is mod 2**9; + + type Rec is record + B1 : Boolean; + N1 : Num; + B2 : Boolean; + N2 : Num; + B3 : Boolean; + B4 : Boolean; + B5 : Boolean; + B6 : Boolean; + B7 : Boolean; + B8 : Boolean; + B9 : Boolean; + B10 : Boolean; + B11 : Boolean; + B12 : Boolean; + B13 : Boolean; + B14 : Boolean; + end record; + pragma Pack (Rec); + for Rec'Size use 32; + pragma Volatile(Rec); + + function F return Rec; + +end Volatile10_Pkg; diff --git a/gcc/testsuite/go.test/go-test.exp b/gcc/testsuite/go.test/go-test.exp index c55924431d3..943a7f1a1a7 100644 --- a/gcc/testsuite/go.test/go-test.exp +++ b/gcc/testsuite/go.test/go-test.exp @@ -217,6 +217,13 @@ proc go-set-goarch { } { return "" } } + "powerpc*-*-*" { + if [check_effective_target_ilp32] { + set goarch "ppc" + } else { + set goarch "ppc64" + } + } "sparc*-*-*" { if [check_effective_target_ilp32] { set goarch "sparc" @@ -302,7 +309,7 @@ proc go-gc-tests { } { } # Handle certain tests in a target-dependant way. - if { [istarget "alpha*-*-*"] || [istarget "sparc*-*-solaris*"] } { + if { [istarget "alpha*-*-*"] || [istarget "sparc*-*-solaris*"] || [istarget "powerpc*-*-*"] } { if { [string match "*go.test/test/nilptr.go" $test] } { untested $test continue diff --git a/gcc/testsuite/lib/plugin-support.exp b/gcc/testsuite/lib/plugin-support.exp index 7d04bf17fc0..fcbbb675c58 100644 --- a/gcc/testsuite/lib/plugin-support.exp +++ b/gcc/testsuite/lib/plugin-support.exp @@ -1,4 +1,4 @@ -# Copyright (C) 2009, 2010 Free Software Foundation, Inc. +# Copyright (C) 2009, 2010, 2012 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -70,7 +70,8 @@ proc plugin-test-execute { plugin_src plugin_tests } { set base [file rootname $basename] set plugin_lib $base.so - verbose "Test the plugin $basename" 1 + set testcase [dg-trim-dirname $srcdir $plugin_src] + verbose "Test the plugin $testcase" 1 # Build the plugin itself set extra_flags [plugin-get-options $plugin_src] @@ -113,8 +114,12 @@ proc plugin-test-execute { plugin_src plugin_tests } { set_ld_library_path_env_vars if { $status != 0 } then { - unresolved "$basename compilation, $optstr" + fail "$testcase compilation" + # Strictly, this is wrong: the tests compiled with the plugin should + # become unresolved instead. return + } else { + pass "$testcase compilation" } # Compile the input source files with the plugin diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp index 68a77b6ac48..60a4bd4b994 100644 --- a/gcc/testsuite/lib/prune.exp +++ b/gcc/testsuite/lib/prune.exp @@ -17,6 +17,11 @@ # Prune messages from gcc that aren't useful. +if ![info exists TEST_ALWAYS_FLAGS] { + set TEST_ALWAYS_FLAGS "" +} +set TEST_ALWAYS_FLAGS "-fno-diagnostics-show-caret $TEST_ALWAYS_FLAGS" + proc prune_gcc_output { text } { #send_user "Before:$text\n" diff --git a/gcc/toplev.c b/gcc/toplev.c index bd67e16c099..6820e671ed4 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -425,7 +425,7 @@ wrapup_global_declaration_2 (tree decl) && (TREE_USED (decl) || TREE_USED (DECL_ASSEMBLER_NAME (decl)))) /* needed */; - else if (node && node->needed) + else if (node && node->analyzed) /* needed */; else if (DECL_COMDAT (decl)) needed = false; @@ -593,6 +593,7 @@ compile_file (void) basically finished. */ if (in_lto_p || !flag_lto || flag_fat_lto_objects) { + varpool_remove_unreferenced_decls (); varpool_assemble_pending_decls (); finish_aliases_2 (); @@ -1186,6 +1187,8 @@ general_init (const char *argv0) /* Set a default printer. Language specific initializations will override it later. */ pp_format_decoder (global_dc->printer) = &default_tree_printer; + global_dc->show_caret + = global_options_init.x_flag_diagnostics_show_caret; global_dc->show_option_requested = global_options_init.x_flag_diagnostics_show_option; global_dc->show_column diff --git a/gcc/toplev.h b/gcc/toplev.h index 3d7b2f3aaed..16699d560d6 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -29,7 +29,6 @@ extern unsigned int save_decoded_options_count; extern int toplev_main (int, char **); extern void rest_of_decl_compilation (tree, int, int); extern void rest_of_type_compilation (tree, int); -extern void tree_rest_of_compilation (tree); extern void init_optimization_passes (void); extern void finish_optimization_passes (void); extern bool enable_rtl_dump_file (void); diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c index 65f40e69c1b..b1dd2a05e2f 100644 --- a/gcc/trans-mem.c +++ b/gcc/trans-mem.c @@ -1730,7 +1730,7 @@ struct gimple_opt_pass pass_lower_tm = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0, /* todo_flags_finish */ } }; @@ -2543,8 +2543,7 @@ struct gimple_opt_pass pass_tm_mark = 0, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_update_ssa - | TODO_verify_ssa - | TODO_dump_func, /* todo_flags_finish */ + | TODO_verify_ssa, /* todo_flags_finish */ } }; @@ -2818,8 +2817,7 @@ struct gimple_opt_pass pass_tm_edges = 0, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_update_ssa - | TODO_verify_ssa - | TODO_dump_func, /* todo_flags_finish */ + | TODO_verify_ssa, /* todo_flags_finish */ } }; @@ -3483,7 +3481,7 @@ struct gimple_opt_pass pass_tm_memopt = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ + 0, /* todo_flags_finish */ } }; @@ -3589,13 +3587,13 @@ get_cg_data (struct cgraph_node **node, bool traverse_aliases) if (traverse_aliases && (*node)->alias) *node = cgraph_get_node ((*node)->thunk.alias); - d = (struct tm_ipa_cg_data *) (*node)->aux; + d = (struct tm_ipa_cg_data *) (*node)->symbol.aux; if (d == NULL) { d = (struct tm_ipa_cg_data *) obstack_alloc (&tm_obstack.obstack, sizeof (*d)); - (*node)->aux = (void *) d; + (*node)->symbol.aux = (void *) d; memset (d, 0, sizeof (*d)); } @@ -3691,7 +3689,7 @@ static void ipa_tm_scan_calls_clone (struct cgraph_node *node, cgraph_node_queue *callees_p) { - struct function *fn = DECL_STRUCT_FUNCTION (node->decl); + struct function *fn = DECL_STRUCT_FUNCTION (node->symbol.decl); basic_block bb; FOR_EACH_BB_FN (bb, fn) @@ -3720,7 +3718,7 @@ ipa_tm_note_irrevocable (struct cgraph_node *node, continue; /* Even if we think we can go irrevocable, believe the user above all. */ - if (is_tm_safe_or_pure (e->caller->decl)) + if (is_tm_safe_or_pure (e->caller->symbol.decl)) continue; caller = e->caller; @@ -3977,12 +3975,12 @@ ipa_tm_scan_irr_function (struct cgraph_node *node, bool for_clone) bool ret = false; /* Builtin operators (operator new, and such). */ - if (DECL_STRUCT_FUNCTION (node->decl) == NULL - || DECL_STRUCT_FUNCTION (node->decl)->cfg == NULL) + if (DECL_STRUCT_FUNCTION (node->symbol.decl) == NULL + || DECL_STRUCT_FUNCTION (node->symbol.decl)->cfg == NULL) return false; - current_function_decl = node->decl; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + current_function_decl = node->symbol.decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); calculate_dominance_info (CDI_DOMINATORS); d = get_cg_data (&node, true); @@ -4069,7 +4067,7 @@ ipa_tm_mayenterirr_function (struct cgraph_node *node) unsigned flags; d = get_cg_data (&node, true); - decl = node->decl; + decl = node->symbol.decl; flags = flags_from_decl_or_type (decl); /* Handle some TM builtins. Ordinarily these aren't actually generated @@ -4129,11 +4127,11 @@ ipa_tm_diagnose_tm_safe (struct cgraph_node *node) struct cgraph_edge *e; for (e = node->callees; e ; e = e->next_callee) - if (!is_tm_callable (e->callee->decl) + if (!is_tm_callable (e->callee->symbol.decl) && e->callee->local.tm_may_enter_irr) error_at (gimple_location (e->call_stmt), "unsafe function call %qD within " - "%<transaction_safe%> function", e->callee->decl); + "%<transaction_safe%> function", e->callee->symbol.decl); } /* Diagnose call from atomic transactions to unmarked functions @@ -4269,9 +4267,9 @@ tm_mangle (tree old_asm_id) } static inline void -ipa_tm_mark_needed_node (struct cgraph_node *node) +ipa_tm_mark_force_output_node (struct cgraph_node *node) { - cgraph_mark_needed_node (node); + cgraph_mark_force_output_node (node); /* ??? function_and_variable_visibility will reset the needed bit, without actually checking. */ node->analyzed = 1; @@ -4298,7 +4296,7 @@ ipa_tm_create_version_alias (struct cgraph_node *node, void *data) if (!node->same_body_alias) return false; - old_decl = node->decl; + old_decl = node->symbol.decl; tm_name = tm_mangle (DECL_ASSEMBLER_NAME (old_decl)); new_decl = build_decl (DECL_SOURCE_LOCATION (old_decl), TREE_CODE (old_decl), tm_name, @@ -4324,14 +4322,14 @@ ipa_tm_create_version_alias (struct cgraph_node *node, void *data) new_node = cgraph_same_body_alias (NULL, new_decl, info->new_decl); new_node->tm_clone = true; - new_node->local.externally_visible = info->old_node->local.externally_visible; + new_node->symbol.externally_visible = info->old_node->symbol.externally_visible; /* ?? Do not traverse aliases here. */ get_cg_data (&node, false)->clone = new_node; record_tm_clone_pair (old_decl, new_decl); - if (info->old_node->needed) - ipa_tm_mark_needed_node (new_node); + if (info->old_node->symbol.force_output) + ipa_tm_mark_force_output_node (new_node); return false; } @@ -4344,7 +4342,7 @@ ipa_tm_create_version (struct cgraph_node *old_node) tree new_decl, old_decl, tm_name; struct cgraph_node *new_node; - old_decl = old_node->decl; + old_decl = old_node->symbol.decl; new_decl = copy_node (old_decl); /* DECL_ASSEMBLER_NAME needs to be set before we call @@ -4360,7 +4358,7 @@ ipa_tm_create_version (struct cgraph_node *old_node) DECL_COMDAT_GROUP (new_decl) = tm_mangle (DECL_COMDAT_GROUP (old_decl)); new_node = cgraph_copy_node_for_versioning (old_node, new_decl, NULL, NULL); - new_node->local.externally_visible = old_node->local.externally_visible; + new_node->symbol.externally_visible = old_node->symbol.externally_visible; new_node->lowered = true; new_node->tm_clone = 1; get_cg_data (&old_node, true)->clone = new_node; @@ -4383,8 +4381,8 @@ ipa_tm_create_version (struct cgraph_node *old_node) record_tm_clone_pair (old_decl, new_decl); cgraph_call_function_insertion_hooks (new_node); - if (old_node->needed) - ipa_tm_mark_needed_node (new_node); + if (old_node->symbol.force_output) + ipa_tm_mark_force_output_node (new_node); /* Do the same thing, but for any aliases of the original node. */ { @@ -4418,7 +4416,7 @@ ipa_tm_insert_irr_call (struct cgraph_node *node, struct tm_region *region, cgraph_get_create_node (builtin_decl_explicit (BUILT_IN_TM_IRREVOCABLE)), g, 0, - compute_call_stmt_bb_frequency (node->decl, + compute_call_stmt_bb_frequency (node->symbol.decl, gimple_bb (g))); } @@ -4469,7 +4467,7 @@ ipa_tm_insert_gettmclone_call (struct cgraph_node *node, gsi_insert_before (gsi, g, GSI_SAME_STMT); cgraph_create_edge (node, cgraph_get_create_node (gettm_fn), g, 0, - compute_call_stmt_bb_frequency (node->decl, + compute_call_stmt_bb_frequency (node->symbol.decl, gimple_bb(g))); /* Cast return value from tm_gettmclone* into appropriate function @@ -4597,7 +4595,7 @@ ipa_tm_transform_calls_redirect (struct cgraph_node *node, return; } - fndecl = new_node->decl; + fndecl = new_node->symbol.decl; } cgraph_redirect_edge_callee (e, new_node); @@ -4691,8 +4689,8 @@ ipa_tm_transform_transaction (struct cgraph_node *node) d = get_cg_data (&node, true); - current_function_decl = node->decl; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + current_function_decl = node->symbol.decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); calculate_dominance_info (CDI_DOMINATORS); for (region = d->all_tm_regions; region; region = region->next) @@ -4735,7 +4733,7 @@ ipa_tm_transform_clone (struct cgraph_node *node) if (!node->callees && !d->irrevocable_blocks_clone) return; - current_function_decl = d->clone->decl; + current_function_decl = d->clone->symbol.decl; push_cfun (DECL_STRUCT_FUNCTION (current_function_decl)); calculate_dominance_info (CDI_DOMINATORS); @@ -4771,8 +4769,8 @@ ipa_tm_execute (void) bitmap_obstack_initialize (&tm_obstack); /* For all local functions marked tm_callable, queue them. */ - for (node = cgraph_nodes; node; node = node->next) - if (is_tm_callable (node->decl) + FOR_EACH_DEFINED_FUNCTION (node) + if (is_tm_callable (node->symbol.decl) && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) { d = get_cg_data (&node, true); @@ -4780,22 +4778,22 @@ ipa_tm_execute (void) } /* For all local reachable functions... */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) if (node->reachable && node->lowered && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) { /* ... marked tm_pure, record that fact for the runtime by indicating that the pure function is its own tm_callable. No need to do this if the function's address can't be taken. */ - if (is_tm_pure (node->decl)) + if (is_tm_pure (node->symbol.decl)) { if (!node->local.local) - record_tm_clone_pair (node->decl, node->decl); + record_tm_clone_pair (node->symbol.decl, node->symbol.decl); continue; } - current_function_decl = node->decl; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + current_function_decl = node->symbol.decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); calculate_dominance_info (CDI_DOMINATORS); tm_region_init (NULL); @@ -4833,14 +4831,14 @@ ipa_tm_execute (void) /* Some callees cannot be arbitrarily cloned. These will always be irrevocable. Mark these now, so that we need not scan them. */ - if (is_tm_irrevocable (node->decl)) + if (is_tm_irrevocable (node->symbol.decl)) ipa_tm_note_irrevocable (node, &irr_worklist); else if (a <= AVAIL_NOT_AVAILABLE - && !is_tm_safe_or_pure (node->decl)) + && !is_tm_safe_or_pure (node->symbol.decl)) ipa_tm_note_irrevocable (node, &irr_worklist); else if (a >= AVAIL_OVERWRITABLE) { - if (!tree_versionable_function_p (node->decl)) + if (!tree_versionable_function_p (node->symbol.decl)) ipa_tm_note_irrevocable (node, &irr_worklist); else if (!d->is_irrevocable) { @@ -4924,7 +4922,7 @@ ipa_tm_execute (void) for (e = node->callers; e ; e = e->next_caller) { caller = e->caller; - if (!is_tm_safe_or_pure (caller->decl) + if (!is_tm_safe_or_pure (caller->symbol.decl) && !caller->local.tm_may_enter_irr) { d = get_cg_data (&caller, true); @@ -4933,9 +4931,9 @@ ipa_tm_execute (void) } /* Propagate back to referring aliases as well. */ - for (j = 0; ipa_ref_list_refering_iterate (&node->ref_list, j, ref); j++) + for (j = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, j, ref); j++) { - caller = ref->refering.cgraph_node; + caller = cgraph (ref->referring); if (ref->use == IPA_REF_ALIAS && !caller->local.tm_may_enter_irr) { @@ -4948,12 +4946,12 @@ ipa_tm_execute (void) /* Now validate all tm_safe functions, and all atomic regions in other functions. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) if (node->reachable && node->lowered && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) { d = get_cg_data (&node, true); - if (is_tm_safe (node->decl)) + if (is_tm_safe (node->symbol.decl)) ipa_tm_diagnose_tm_safe (node); else if (d->all_tm_regions) ipa_tm_diagnose_transaction (node, d->all_tm_regions); @@ -4974,8 +4972,8 @@ ipa_tm_execute (void) d = get_cg_data (&node, true); if (a <= AVAIL_NOT_AVAILABLE) - doit = is_tm_callable (node->decl); - else if (a <= AVAIL_AVAILABLE && is_tm_callable (node->decl)) + doit = is_tm_callable (node->symbol.decl); + else if (a <= AVAIL_AVAILABLE && is_tm_callable (node->symbol.decl)) doit = true; else if (!d->is_irrevocable && d->tm_callers_normal + d->tm_callers_clone > 0) @@ -4996,7 +4994,7 @@ ipa_tm_execute (void) ipa_tm_transform_clone (node); } } - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) if (node->reachable && node->lowered && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) { @@ -5010,8 +5008,8 @@ ipa_tm_execute (void) VEC_free (cgraph_node_p, heap, irr_worklist); bitmap_obstack_release (&tm_obstack); - for (node = cgraph_nodes; node; node = node->next) - node->aux = NULL; + FOR_EACH_FUNCTION (node) + node->symbol.aux = NULL; #ifdef ENABLE_CHECKING verify_cgraph (); @@ -5035,7 +5033,7 @@ struct simple_ipa_opt_pass pass_ipa_tm = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func, /* todo_flags_finish */ + 0, /* todo_flags_finish */ }, }; diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 1f59c03cfcd..e32daa75e0f 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -56,7 +56,7 @@ static const int initial_cfg_capacity = 20; /* This hash table allows us to efficiently lookup all CASE_LABEL_EXPRs which use a particular edge. The CASE_LABEL_EXPRs are chained together - via their TREE_CHAIN field, which we clear after we're done with the + via their CASE_CHAIN field, which we clear after we're done with the hash table to prevent problems with duplication of GIMPLE_SWITCHes. Access to this list of CASE_LABEL_EXPRs allows us to efficiently @@ -5595,6 +5595,20 @@ gimple_duplicate_sese_region (edge entry, edge exit, return true; } +/* Checks if BB is part of the region defined by N_REGION BBS. */ +static bool +bb_part_of_region_p (basic_block bb, basic_block* bbs, unsigned n_region) +{ + unsigned int n; + + for (n = 0; n < n_region; n++) + { + if (bb == bbs[n]) + return true; + } + return false; +} + /* Duplicates REGION consisting of N_REGION blocks. The new blocks are stored to REGION_COPY in the same order in that they appear in REGION, if REGION_COPY is not NULL. ENTRY is the entry to @@ -5645,6 +5659,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU gimple_stmt_iterator psi; gimple phi; tree def; + struct loop *target, *aloop, *cloop; gcc_assert (EDGE_COUNT (exit->src->succs) == 2); exits[0] = exit; @@ -5655,7 +5670,16 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU initialize_original_copy_tables (); set_loop_copy (orig_loop, loop); - duplicate_subloops (orig_loop, loop); + + target= loop; + for (aloop = orig_loop->inner; aloop; aloop = aloop->next) + { + if (bb_part_of_region_p (aloop->header, region, n_region)) + { + cloop = duplicate_loop (aloop, target); + duplicate_subloops (aloop, cloop); + } + } if (!region_copy) { @@ -5758,7 +5782,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU add_phi_arg (phi, def, e, gimple_phi_arg_location_from_edge (phi, e)); } } - e = redirect_edge_and_branch (nexits[0], nexits[1]->dest); + e = redirect_edge_and_branch (nexits[1], nexits[0]->dest); PENDING_STMT (e) = NULL; /* Anything that is outside of the region, but was dominated by something diff --git a/gcc/tree-chrec.c b/gcc/tree-chrec.c index fbd61c08ea6..38dca4ab1dd 100644 --- a/gcc/tree-chrec.c +++ b/gcc/tree-chrec.c @@ -1011,6 +1011,8 @@ evolution_function_is_invariant_rec_p (tree chrec, int loopnum) if (TREE_CODE (chrec) == POLYNOMIAL_CHREC) { if (CHREC_VARIABLE (chrec) == (unsigned) loopnum + || flow_loop_nested_p (get_loop (loopnum), + get_loop (CHREC_VARIABLE (chrec))) || !evolution_function_is_invariant_rec_p (CHREC_RIGHT (chrec), loopnum) || !evolution_function_is_invariant_rec_p (CHREC_LEFT (chrec), @@ -1114,6 +1116,8 @@ evolution_function_is_univariate_p (const_tree chrec) break; default: + if (tree_contains_chrecs (CHREC_LEFT (chrec), NULL)) + return false; break; } @@ -1127,6 +1131,8 @@ evolution_function_is_univariate_p (const_tree chrec) break; default: + if (tree_contains_chrecs (CHREC_RIGHT (chrec), NULL)) + return false; break; } diff --git a/gcc/tree-chrec.h b/gcc/tree-chrec.h index bf9bff0f999..83678026752 100644 --- a/gcc/tree-chrec.h +++ b/gcc/tree-chrec.h @@ -77,7 +77,6 @@ extern void for_each_scev_op (tree *, bool (*) (tree *, void *), void *); /* Observers. */ extern bool eq_evolutions_p (const_tree, const_tree); extern bool is_multivariate_chrec (const_tree); -extern bool chrec_is_positive (tree, bool *); extern bool chrec_contains_symbols (const_tree); extern bool chrec_contains_symbols_defined_in_loop (const_tree, unsigned); extern bool chrec_contains_undetermined (const_tree); diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c index 6fb0d23f74e..1381b535bd3 100644 --- a/gcc/tree-data-ref.c +++ b/gcc/tree-data-ref.c @@ -1709,7 +1709,7 @@ max_stmt_executions_tree (struct loop *loop) { double_int nit; - if (!max_stmt_executions (loop, true, &nit)) + if (!max_stmt_executions (loop, &nit)) return chrec_dont_know; if (!double_int_fits_to_tree_p (unsigned_type_node, nit)) @@ -1718,6 +1718,76 @@ max_stmt_executions_tree (struct loop *loop) return double_int_to_tree (unsigned_type_node, nit); } +/* Determine whether the CHREC is always positive/negative. If the expression + cannot be statically analyzed, return false, otherwise set the answer into + VALUE. */ + +static bool +chrec_is_positive (tree chrec, bool *value) +{ + bool value0, value1, value2; + tree end_value, nb_iter; + + switch (TREE_CODE (chrec)) + { + case POLYNOMIAL_CHREC: + if (!chrec_is_positive (CHREC_LEFT (chrec), &value0) + || !chrec_is_positive (CHREC_RIGHT (chrec), &value1)) + return false; + + /* FIXME -- overflows. */ + if (value0 == value1) + { + *value = value0; + return true; + } + + /* Otherwise the chrec is under the form: "{-197, +, 2}_1", + and the proof consists in showing that the sign never + changes during the execution of the loop, from 0 to + loop->nb_iterations. */ + if (!evolution_function_is_affine_p (chrec)) + return false; + + nb_iter = number_of_latch_executions (get_chrec_loop (chrec)); + if (chrec_contains_undetermined (nb_iter)) + return false; + +#if 0 + /* TODO -- If the test is after the exit, we may decrease the number of + iterations by one. */ + if (after_exit) + nb_iter = chrec_fold_minus (type, nb_iter, build_int_cst (type, 1)); +#endif + + end_value = chrec_apply (CHREC_VARIABLE (chrec), chrec, nb_iter); + + if (!chrec_is_positive (end_value, &value2)) + return false; + + *value = value0; + return value0 == value1; + + case INTEGER_CST: + switch (tree_int_cst_sgn (chrec)) + { + case -1: + *value = false; + break; + case 1: + *value = true; + break; + default: + return false; + } + return true; + + default: + return false; + } +} + + /* Analyze a SIV (Single Index Variable) subscript where CHREC_A is a constant, and CHREC_B is an affine function. *OVERLAPS_A and *OVERLAPS_B are initialized to the functions that describe the @@ -1741,6 +1811,15 @@ analyze_siv_subscript_cst_affine (tree chrec_a, chrec_b = chrec_convert (type, chrec_b, NULL); difference = chrec_fold_minus (type, initial_condition (chrec_b), chrec_a); + /* Special case overlap in the first iteration. */ + if (integer_zerop (difference)) + { + *overlaps_a = conflict_fn (1, affine_fn_cst (integer_zero_node)); + *overlaps_b = conflict_fn (1, affine_fn_cst (integer_zero_node)); + *last_conflicts = integer_one_node; + return; + } + if (!chrec_is_positive (initial_condition (difference), &value0)) { if (dump_file && (dump_flags & TDF_DETAILS)) @@ -1791,7 +1870,7 @@ analyze_siv_subscript_cst_affine (tree chrec_a, /* Perform weak-zero siv test to see if overlap is outside the loop bounds. */ - numiter = max_stmt_executions_int (loop, true); + numiter = max_stmt_executions_int (loop); if (numiter >= 0 && compare_tree_int (tmp, numiter) > 0) @@ -1869,7 +1948,7 @@ analyze_siv_subscript_cst_affine (tree chrec_a, /* Perform weak-zero siv test to see if overlap is outside the loop bounds. */ - numiter = max_stmt_executions_int (loop, true); + numiter = max_stmt_executions_int (loop); if (numiter >= 0 && compare_tree_int (tmp, numiter) > 0) @@ -2049,10 +2128,9 @@ compute_overlap_steps_for_affine_1_2 (tree chrec_a, tree chrec_b, step_y = int_cst_value (CHREC_RIGHT (chrec_a)); step_z = int_cst_value (CHREC_RIGHT (chrec_b)); - niter_x = - max_stmt_executions_int (get_chrec_loop (CHREC_LEFT (chrec_a)), true); - niter_y = max_stmt_executions_int (get_chrec_loop (chrec_a), true); - niter_z = max_stmt_executions_int (get_chrec_loop (chrec_b), true); + niter_x = max_stmt_executions_int (get_chrec_loop (CHREC_LEFT (chrec_a))); + niter_y = max_stmt_executions_int (get_chrec_loop (chrec_a)); + niter_z = max_stmt_executions_int (get_chrec_loop (chrec_b)); if (niter_x < 0 || niter_y < 0 || niter_z < 0) { @@ -2377,8 +2455,8 @@ analyze_subscript_affine_affine (tree chrec_a, HOST_WIDE_INT niter, niter_a, niter_b; affine_fn ova, ovb; - niter_a = max_stmt_executions_int (get_chrec_loop (chrec_a), true); - niter_b = max_stmt_executions_int (get_chrec_loop (chrec_b), true); + niter_a = max_stmt_executions_int (get_chrec_loop (chrec_a)); + niter_b = max_stmt_executions_int (get_chrec_loop (chrec_b)); niter = MIN (niter_a, niter_b); step_a = int_cst_value (CHREC_RIGHT (chrec_a)); step_b = int_cst_value (CHREC_RIGHT (chrec_b)); @@ -2485,10 +2563,10 @@ analyze_subscript_affine_affine (tree chrec_a, if (i1 > 0 && j1 > 0) { - HOST_WIDE_INT niter_a = max_stmt_executions_int - (get_chrec_loop (chrec_a), true); - HOST_WIDE_INT niter_b = max_stmt_executions_int - (get_chrec_loop (chrec_b), true); + HOST_WIDE_INT niter_a + = max_stmt_executions_int (get_chrec_loop (chrec_a)); + HOST_WIDE_INT niter_b + = max_stmt_executions_int (get_chrec_loop (chrec_b)); HOST_WIDE_INT niter = MIN (niter_a, niter_b); /* (X0, Y0) is a solution of the Diophantine equation: @@ -3782,7 +3860,7 @@ init_omega_for_ddr_1 (struct data_reference *dra, struct data_reference *drb, for (i = 0; i <= DDR_INNER_LOOP (ddr) && VEC_iterate (loop_p, DDR_LOOP_NEST (ddr), i, loopi); i++) { - HOST_WIDE_INT nbi = max_stmt_executions_int (loopi, true); + HOST_WIDE_INT nbi = max_stmt_executions_int (loopi); /* 0 <= loop_x */ ineq = omega_add_zero_geq (pb, omega_black); diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c index 07442a5163c..1932f3d7ec9 100644 --- a/gcc/tree-dump.c +++ b/gcc/tree-dump.c @@ -1,6 +1,6 @@ /* Tree-dumping functionality for intermediate representation. Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - 2010, 2011 Free Software Foundation, Inc. + 2010, 2011, 2012 Free Software Foundation, Inc. Written by Mark Mitchell <mark@codesourcery.com> This file is part of GCC. @@ -596,6 +596,7 @@ dequeue_and_dump (dump_info_p di) break; case COMPONENT_REF: + case BIT_FIELD_REF: dump_child ("op 0", TREE_OPERAND (t, 0)); dump_child ("op 1", TREE_OPERAND (t, 1)); dump_child ("op 2", TREE_OPERAND (t, 2)); diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index b78d9e9bd3a..0241a5f1bc4 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -2533,7 +2533,7 @@ tree_could_trap_p (tree expr) if (!DECL_EXTERNAL (expr)) return false; node = cgraph_function_node (cgraph_get_node (expr), NULL); - if (node && node->in_other_partition) + if (node && node->symbol.in_other_partition) return false; return true; } @@ -2549,7 +2549,7 @@ tree_could_trap_p (tree expr) if (!DECL_EXTERNAL (expr)) return false; node = varpool_variable_node (varpool_get_node (expr), NULL); - if (node && node->in_other_partition) + if (node && node->symbol.in_other_partition) return false; return true; } @@ -3916,6 +3916,21 @@ cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb, for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)); ) if (e->flags & EDGE_EH) { + /* ??? CFG manipluation routines do not try to update loop + form on edge redirection. Do so manually here for now. */ + /* If we redirect a loop entry or latch edge that will either create + a multiple entry loop or rotate the loop. If the loops merge + we may have created a loop with multiple latches. + All of this isn't easily fixed thus cancel the affected loop + and mark the other loop as possibly having multiple latches. */ + if (current_loops + && e->dest == e->dest->loop_father->header) + { + e->dest->loop_father->header = NULL; + e->dest->loop_father->latch = NULL; + new_bb->loop_father->latch = NULL; + loops_state_set (LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES); + } redirect_eh_edge_1 (e, new_bb, change_region); redirect_edge_succ (e, new_bb); flush_pending_stmts (e); diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c index abf5657ab9d..92b7d81e257 100644 --- a/gcc/tree-emutls.c +++ b/gcc/tree-emutls.c @@ -338,7 +338,7 @@ new_emutls_decl (tree decl, tree alias_of) else varpool_create_variable_alias (to, varpool_node_for_asm - (DECL_ASSEMBLER_NAME (alias_of))->decl); + (DECL_ASSEMBLER_NAME (alias_of))->symbol.decl); return to; } @@ -366,7 +366,7 @@ emutls_decl (tree decl) i = emutls_index (decl); var = VEC_index (varpool_node_ptr, control_vars, i); - return var->decl; + return var->symbol.decl; } /* Generate a call statement to initialize CONTROL_DECL for TLS_DECL. @@ -428,7 +428,7 @@ gen_emutls_addr (tree decl, struct lower_emutls_data *d) gimple x; cvar = VEC_index (varpool_node_ptr, control_vars, index); - cdecl = cvar->decl; + cdecl = cvar->symbol.decl; TREE_ADDRESSABLE (cdecl) = 1; addr = create_tmp_var (build_pointer_type (TREE_TYPE (decl)), NULL); @@ -446,7 +446,7 @@ gen_emutls_addr (tree decl, struct lower_emutls_data *d) /* We may be adding a new reference to a new variable to the function. This means we have to play with the ipa-reference web. */ - ipa_record_reference (d->cfun_node, NULL, NULL, cvar, IPA_REF_ADDR, x); + ipa_record_reference ((symtab_node)d->cfun_node, (symtab_node)cvar, IPA_REF_ADDR, x); /* Record this ssa_name for possible use later in the basic block. */ VEC_replace (tree, access_vars, index, addr); @@ -619,8 +619,8 @@ lower_emutls_function_body (struct cgraph_node *node) struct lower_emutls_data d; bool any_edge_inserts = false; - current_function_decl = node->decl; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + current_function_decl = node->symbol.decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); d.cfun_node = node; d.builtin_decl = builtin_decl_explicit (BUILT_IN_EMUTLS_GET_ADDRESS); @@ -703,7 +703,7 @@ create_emultls_var (struct varpool_node *var, void *data) tree cdecl; struct varpool_node *cvar; - cdecl = new_emutls_decl (var->decl, var->alias_of); + cdecl = new_emutls_decl (var->symbol.decl, var->alias_of); cvar = varpool_get_node (cdecl); VEC_quick_push (varpool_node_ptr, control_vars, cvar); @@ -713,7 +713,7 @@ create_emultls_var (struct varpool_node *var, void *data) /* Make sure the COMMON block control variable gets initialized. Note that there's no point in doing this for aliases; we only need to do this once for the main variable. */ - emutls_common_1 (var->decl, cdecl, (tree *)data); + emutls_common_1 (var->symbol.decl, cdecl, (tree *)data); } if (var->alias && !var->alias_of) cvar->alias = true; @@ -722,8 +722,8 @@ create_emultls_var (struct varpool_node *var, void *data) preventing the variable from re-appearing in the GIMPLE. We cheat and use the control variable here (rather than a full call_expr), which is special-cased inside the DWARF2 output routines. */ - SET_DECL_VALUE_EXPR (var->decl, cdecl); - DECL_HAS_VALUE_EXPR_P (var->decl) = 1; + SET_DECL_VALUE_EXPR (var->symbol.decl, cdecl); + DECL_HAS_VALUE_EXPR_P (var->symbol.decl) = 1; return false; } @@ -741,11 +741,11 @@ ipa_lower_emutls (void) tls_vars = varpool_node_set_new (); /* Examine all global variables for TLS variables. */ - for (var = varpool_nodes; var ; var = var->next) - if (DECL_THREAD_LOCAL_P (var->decl)) + FOR_EACH_VARIABLE (var) + if (DECL_THREAD_LOCAL_P (var->symbol.decl)) { - gcc_checking_assert (TREE_STATIC (var->decl) - || DECL_EXTERNAL (var->decl)); + gcc_checking_assert (TREE_STATIC (var->symbol.decl) + || DECL_EXTERNAL (var->symbol.decl)); varpool_node_set_add (tls_vars, var); if (var->alias && var->analyzed) varpool_node_set_add (tls_vars, varpool_variable_node (var, NULL)); @@ -790,7 +790,7 @@ ipa_lower_emutls (void) } /* Adjust all uses of TLS variables within the function bodies. */ - for (func = cgraph_nodes; func; func = func->next) + FOR_EACH_DEFINED_FUNCTION (func) if (func->reachable && func->lowered) lower_emutls_function_body (func); diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 3dd6a7d019d..2a17ff171ec 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -685,8 +685,7 @@ bool number_of_iterations_exit (struct loop *, edge, tree find_loop_niter (struct loop *, edge *); tree loop_niter_by_eval (struct loop *, edge); tree find_loop_niter_by_eval (struct loop *, edge *); -void estimate_numbers_of_iterations (bool); -bool array_at_struct_end_p (tree); +void estimate_numbers_of_iterations (void); bool scev_probably_wraps_p (tree, tree, gimple, struct loop *, bool); bool convert_affine_scev (struct loop *, tree, tree *, tree *, gimple, bool); @@ -853,7 +852,6 @@ rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool); void get_address_description (tree, struct mem_address *); tree maybe_fold_tmr (tree); -unsigned int execute_free_datastructures (void); unsigned int execute_fixup_cfg (void); bool fixup_noreturn_call (gimple stmt); diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index 55616d57667..31bb610af08 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -968,7 +968,7 @@ predicate_bbs (loop_p loop) case GIMPLE_COND: { - tree c2, tem; + tree c2; edge true_edge, false_edge; location_t loc = gimple_location (stmt); tree c = fold_build2_loc (loc, gimple_cond_code (stmt), @@ -986,10 +986,8 @@ predicate_bbs (loop_p loop) unshare_expr (c)); /* If C is false, then FALSE_EDGE is taken. */ - c2 = invert_truthvalue_loc (loc, unshare_expr (c)); - tem = canonicalize_cond_expr_cond (c2); - if (tem) - c2 = tem; + c2 = build1_loc (loc, TRUTH_NOT_EXPR, + boolean_type_node, unshare_expr (c)); add_to_dst_predicate_list (loop, false_edge, unshare_expr (cond), c2); @@ -1543,11 +1541,19 @@ predicate_mem_writes (loop_p loop) gimple_stmt_iterator gsi; basic_block bb = ifc_bbs[i]; tree cond = bb_predicate (bb); + bool swap; gimple stmt; if (is_true_predicate (cond)) continue; + swap = false; + if (TREE_CODE (cond) == TRUTH_NOT_EXPR) + { + swap = true; + cond = TREE_OPERAND (cond, 0); + } + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) if ((stmt = gsi_stmt (gsi)) && gimple_assign_single_p (stmt) @@ -1559,6 +1565,15 @@ predicate_mem_writes (loop_p loop) lhs = ifc_temp_var (type, unshare_expr (lhs), &gsi); rhs = ifc_temp_var (type, unshare_expr (rhs), &gsi); + if (swap) + { + tree tem = lhs; + lhs = rhs; + rhs = tem; + } + cond = force_gimple_operand_gsi_1 (&gsi, unshare_expr (cond), + is_gimple_condexpr, NULL_TREE, + true, GSI_SAME_STMT); rhs = build3 (COND_EXPR, type, unshare_expr (cond), rhs, lhs); gimple_assign_set_rhs1 (stmt, ifc_temp_var (type, rhs, &gsi)); update_stmt (stmt); diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index d61b6b6a023..d0710c0ddf7 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1702,7 +1702,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, doing so would introduce roundoff errors and make verifier unhappy. */ edge->frequency - = compute_call_stmt_bb_frequency (id->dst_node->decl, + = compute_call_stmt_bb_frequency (id->dst_node->symbol.decl, copy_basic_block); if (dump_file && profile_status_for_function (cfun) != PROFILE_ABSENT @@ -1755,21 +1755,22 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, producing dead clone (for further cloning). In all other cases we hit a bug (incorrect node sharing is the most common reason for missing edges). */ - gcc_assert (dest->needed || !dest->analyzed - || dest->address_taken + gcc_assert (!dest->analyzed + || dest->symbol.address_taken || !id->src_node->analyzed || !id->dst_node->analyzed); if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES) cgraph_create_edge_including_clones (id->dst_node, dest, orig_stmt, stmt, bb->count, - compute_call_stmt_bb_frequency (id->dst_node->decl, + compute_call_stmt_bb_frequency (id->dst_node->symbol.decl, copy_basic_block), CIF_ORIGINALLY_INDIRECT_CALL); else cgraph_create_edge (id->dst_node, dest, stmt, bb->count, compute_call_stmt_bb_frequency - (id->dst_node->decl, copy_basic_block))->inline_failed + (id->dst_node->symbol.decl, + copy_basic_block))->inline_failed = CIF_ORIGINALLY_INDIRECT_CALL; if (dump_file) { @@ -3790,7 +3791,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id) If we cannot, then there is no hope of inlining the function. */ if (cg_edge->indirect_unknown_callee) goto egress; - fn = cg_edge->callee->decl; + fn = cg_edge->callee->symbol.decl; gcc_checking_assert (fn); /* If FN is a declaration of a function in a nested scope that was @@ -3841,10 +3842,10 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id) } goto egress; } - fn = cg_edge->callee->decl; + fn = cg_edge->callee->symbol.decl; #ifdef ENABLE_CHECKING - if (cg_edge->callee->decl != id->dst_node->decl) + if (cg_edge->callee->symbol.decl != id->dst_node->symbol.decl) verify_cgraph_node (cg_edge->callee); #endif @@ -3852,9 +3853,9 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id) id->eh_lp_nr = lookup_stmt_eh_lp (stmt); /* Update the callers EH personality. */ - if (DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl)) - DECL_FUNCTION_PERSONALITY (cg_edge->caller->decl) - = DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl); + if (DECL_FUNCTION_PERSONALITY (cg_edge->callee->symbol.decl)) + DECL_FUNCTION_PERSONALITY (cg_edge->caller->symbol.decl) + = DECL_FUNCTION_PERSONALITY (cg_edge->callee->symbol.decl); /* Split the block holding the GIMPLE_CALL. */ e = split_block (bb, stmt); @@ -4066,7 +4067,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id) inlined. If we don't do this now, we can lose the information about the variables in the function when the blocks get blown away as soon as we remove the cgraph node. */ - (*debug_hooks->outlining_inline_function) (cg_edge->callee->decl); + (*debug_hooks->outlining_inline_function) (cg_edge->callee->symbol.decl); /* Update callgraph if needed. */ cgraph_remove_node (cg_edge->callee); diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c index 44b6bed7ad8..e4175fd46ec 100644 --- a/gcc/tree-iterator.c +++ b/gcc/tree-iterator.c @@ -74,6 +74,13 @@ append_to_statement_list_1 (tree t, tree *list_p) } *list_p = list = alloc_stmt_list (); } + else if (TREE_CODE (list) != STATEMENT_LIST) + { + tree first = list; + *list_p = list = alloc_stmt_list (); + i = tsi_last (list); + tsi_link_after (&i, first, TSI_CONTINUE_LINKING); + } i = tsi_last (list); tsi_link_after (&i, t, TSI_CONTINUE_LINKING); diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index 8851f3c748a..042137f09ad 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -698,11 +698,12 @@ check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl) for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) { - for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = DECL_CHAIN (arg)) + for (arg = DECL_ARGUMENTS (cgn->symbol.decl); arg; arg = DECL_CHAIN (arg)) if (variably_modified_type_p (TREE_TYPE (arg), orig_fndecl)) return true; - if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl)) + if (check_for_nested_with_variably_modified (cgn->symbol.decl, + orig_fndecl)) return true; } @@ -720,7 +721,7 @@ create_nesting_tree (struct cgraph_node *cgn) info->var_map = pointer_map_create (); info->mem_refs = pointer_set_create (); info->suppress_expansion = BITMAP_ALLOC (&nesting_info_bitmap_obstack); - info->context = cgn->decl; + info->context = cgn->symbol.decl; for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) { @@ -2589,8 +2590,8 @@ static void gimplify_all_functions (struct cgraph_node *root) { struct cgraph_node *iter; - if (!gimple_body (root->decl)) - gimplify_function_tree (root->decl); + if (!gimple_body (root->symbol.decl)) + gimplify_function_tree (root->symbol.decl); for (iter = root->nested; iter; iter = iter->next_nested) gimplify_all_functions (iter); } diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c index 3d18d20a003..d69a504d7de 100644 --- a/gcc/tree-optimize.c +++ b/gcc/tree-optimize.c @@ -45,108 +45,6 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "except.h" #include "plugin.h" -#include "regset.h" /* FIXME: For reg_obstack. */ - -/* Gate: execute, or not, all of the non-trivial optimizations. */ - -static bool -gate_all_optimizations (void) -{ - return (optimize >= 1 - /* Don't bother doing anything if the program has errors. - We have to pass down the queue if we already went into SSA */ - && (!seen_error () || gimple_in_ssa_p (cfun))); -} - -struct gimple_opt_pass pass_all_optimizations = -{ - { - GIMPLE_PASS, - "*all_optimizations", /* name */ - gate_all_optimizations, /* gate */ - NULL, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_OPTIMIZE, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0 /* todo_flags_finish */ - } -}; - -/* Gate: execute, or not, all of the non-trivial optimizations. */ - -static bool -gate_all_early_local_passes (void) -{ - /* Don't bother doing anything if the program has errors. */ - return (!seen_error () && !in_lto_p); -} - -static unsigned int -execute_all_early_local_passes (void) -{ - /* Once this pass (and its sub-passes) are complete, all functions - will be in SSA form. Technically this state change is happening - a tad early, since the sub-passes have not yet run, but since - none of the sub-passes are IPA passes and do not create new - functions, this is ok. We're setting this value for the benefit - of IPA passes that follow. */ - if (cgraph_state < CGRAPH_STATE_IPA_SSA) - cgraph_state = CGRAPH_STATE_IPA_SSA; - return 0; -} - -struct simple_ipa_opt_pass pass_early_local_passes = -{ - { - SIMPLE_IPA_PASS, - "early_local_cleanups", /* name */ - gate_all_early_local_passes, /* gate */ - execute_all_early_local_passes, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_EARLY_LOCAL, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_remove_functions /* todo_flags_finish */ - } -}; - -/* Gate: execute, or not, all of the non-trivial optimizations. */ - -static bool -gate_all_early_optimizations (void) -{ - return (optimize >= 1 - /* Don't bother doing anything if the program has errors. */ - && !seen_error ()); -} - -struct gimple_opt_pass pass_all_early_optimizations = -{ - { - GIMPLE_PASS, - "early_optimizations", /* name */ - gate_all_early_optimizations, /* gate */ - NULL, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_NONE, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0 /* todo_flags_finish */ - } -}; /* Pass: cleanup the CFG just before expanding trees to RTL. @@ -214,21 +112,6 @@ struct gimple_opt_pass pass_cleanup_cfg_post_optimizing = } }; -/* Pass: do the actions required to finish with tree-ssa optimization - passes. */ - -unsigned int -execute_free_datastructures (void) -{ - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - - /* And get rid of annotations we no longer need. */ - delete_tree_cfg_annotations (); - - return 0; -} - /* IPA passes, compilation of earlier functions or inlining might have changed some properties, such as marked functions nothrow, pure, const or noreturn. @@ -336,140 +219,3 @@ struct gimple_opt_pass pass_fixup_cfg = 0 /* todo_flags_finish */ } }; - -/* Do the actions required to initialize internal data structures used - in tree-ssa optimization passes. */ - -static unsigned int -execute_init_datastructures (void) -{ - /* Allocate hash tables, arrays and other structures. */ - init_tree_ssa (cfun); - return 0; -} - -struct gimple_opt_pass pass_init_datastructures = -{ - { - GIMPLE_PASS, - "*init_datastructures", /* name */ - NULL, /* gate */ - execute_init_datastructures, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_NONE, /* tv_id */ - PROP_cfg, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0 /* todo_flags_finish */ - } -}; - -void -tree_lowering_passes (tree fn) -{ - tree saved_current_function_decl = current_function_decl; - - current_function_decl = fn; - push_cfun (DECL_STRUCT_FUNCTION (fn)); - gimple_register_cfg_hooks (); - bitmap_obstack_initialize (NULL); - execute_pass_list (all_lowering_passes); - if (optimize && cgraph_global_info_ready) - execute_pass_list (pass_early_local_passes.pass.sub); - free_dominance_info (CDI_POST_DOMINATORS); - free_dominance_info (CDI_DOMINATORS); - compact_blocks (); - current_function_decl = saved_current_function_decl; - bitmap_obstack_release (NULL); - pop_cfun (); -} - -/* For functions-as-trees languages, this performs all optimization and - compilation for FNDECL. */ - -void -tree_rest_of_compilation (tree fndecl) -{ - location_t saved_loc; - - timevar_push (TV_REST_OF_COMPILATION); - - gcc_assert (cgraph_global_info_ready); - - /* Initialize the default bitmap obstack. */ - bitmap_obstack_initialize (NULL); - - /* Initialize the RTL code for the function. */ - current_function_decl = fndecl; - saved_loc = input_location; - input_location = DECL_SOURCE_LOCATION (fndecl); - init_function_start (fndecl); - - gimple_register_cfg_hooks (); - - bitmap_obstack_initialize (®_obstack); /* FIXME, only at RTL generation*/ - - execute_all_ipa_transforms (); - - /* Perform all tree transforms and optimizations. */ - - /* Signal the start of passes. */ - invoke_plugin_callbacks (PLUGIN_ALL_PASSES_START, NULL); - - execute_pass_list (all_passes); - - /* Signal the end of passes. */ - invoke_plugin_callbacks (PLUGIN_ALL_PASSES_END, NULL); - - bitmap_obstack_release (®_obstack); - - /* Release the default bitmap obstack. */ - bitmap_obstack_release (NULL); - - set_cfun (NULL); - - /* If requested, warn about function definitions where the function will - return a value (usually of some struct or union type) which itself will - take up a lot of stack space. */ - if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl)) - { - tree ret_type = TREE_TYPE (TREE_TYPE (fndecl)); - - if (ret_type && TYPE_SIZE_UNIT (ret_type) - && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST - && 0 < compare_tree_int (TYPE_SIZE_UNIT (ret_type), - larger_than_size)) - { - unsigned int size_as_int - = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type)); - - if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0) - warning (OPT_Wlarger_than_, "size of return value of %q+D is %u bytes", - fndecl, size_as_int); - else - warning (OPT_Wlarger_than_, "size of return value of %q+D is larger than %wd bytes", - fndecl, larger_than_size); - } - } - - gimple_set_body (fndecl, NULL); - if (DECL_STRUCT_FUNCTION (fndecl) == 0 - && !cgraph_get_node (fndecl)->origin) - { - /* Stop pointing to the local nodes about to be freed. - But DECL_INITIAL must remain nonzero so we know this - was an actual function definition. - For a nested function, this is done in c_pop_function_context. - If rest_of_compilation set this to 0, leave it 0. */ - if (DECL_INITIAL (fndecl) != 0) - DECL_INITIAL (fndecl) = error_mark_node; - } - - input_location = saved_loc; - - ggc_collect (); - timevar_pop (TV_REST_OF_COMPILATION); -} diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c index abae3fd6e1d..18bf645366e 100644 --- a/gcc/tree-parloops.c +++ b/gcc/tree-parloops.c @@ -1481,8 +1481,6 @@ transform_to_exit_first_loop (struct loop *loop, htab_t reduction_list, tree nit gimple phi, nphi, cond_stmt, stmt, cond_nit; gimple_stmt_iterator gsi; tree nit_1; - edge exit_1; - tree new_rhs; split_block_after_labels (loop->header); orig_header = single_succ (loop->header); @@ -1512,41 +1510,10 @@ transform_to_exit_first_loop (struct loop *loop, htab_t reduction_list, tree nit } } - /* Setting the condition towards peeling the last iteration: - If the block consisting of the exit condition has the latch as - successor, then the body of the loop is executed before - the exit condition is tested. In such case, moving the - condition to the entry, causes that the loop will iterate - one less iteration (which is the wanted outcome, since we - peel out the last iteration). If the body is executed after - the condition, moving the condition to the entry requires - decrementing one iteration. */ - exit_1 = EDGE_SUCC (exit->src, EDGE_SUCC (exit->src, 0) == exit); - if (exit_1->dest == loop->latch) - new_rhs = gimple_cond_rhs (cond_stmt); - else - { - new_rhs = fold_build2 (MINUS_EXPR, TREE_TYPE (gimple_cond_rhs (cond_stmt)), - gimple_cond_rhs (cond_stmt), - build_int_cst (TREE_TYPE (gimple_cond_rhs (cond_stmt)), 1)); - if (TREE_CODE (gimple_cond_rhs (cond_stmt)) == SSA_NAME) - { - basic_block preheader; - gimple_stmt_iterator gsi1; - - preheader = loop_preheader_edge(loop)->src; - gsi1 = gsi_after_labels (preheader); - new_rhs = force_gimple_operand_gsi (&gsi1, new_rhs, true, - NULL_TREE,false,GSI_CONTINUE_LINKING); - } - } - gimple_cond_set_rhs (cond_stmt, unshare_expr (new_rhs)); - gimple_cond_set_lhs (cond_stmt, unshare_expr (gimple_cond_lhs (cond_stmt))); - bbs = get_loop_body_in_dom_order (loop); - for (n = 0; bbs[n] != loop->latch; n++) - continue; + for (n = 0; bbs[n] != exit->src; n++) + continue; nbbs = XNEWVEC (basic_block, n); ok = gimple_duplicate_sese_tail (single_succ_edge (loop->header), exit, bbs + 1, n, nbbs); @@ -1557,7 +1524,7 @@ transform_to_exit_first_loop (struct loop *loop, htab_t reduction_list, tree nit /* Other than reductions, the only gimple reg that should be copied out of the loop is the control variable. */ - + exit = single_dom_exit (loop); control_name = NULL_TREE; for (gsi = gsi_start_phis (ex_bb); !gsi_end_p (gsi); ) { @@ -1574,8 +1541,6 @@ transform_to_exit_first_loop (struct loop *loop, htab_t reduction_list, tree nit PHI_RESULT of this phi is the resulting value of the reduction variable when exiting the loop. */ - exit = single_dom_exit (loop); - if (htab_elements (reduction_list) > 0) { struct reduction_info *red; @@ -2187,17 +2152,17 @@ parallelize_loops (void) || loop_has_blocks_with_irreducible_flag (loop) || (loop_preheader_edge (loop)->src->flags & BB_IRREDUCIBLE_LOOP) /* FIXME: the check for vector phi nodes could be removed. */ - || loop_has_vector_phi_nodes (loop) - /* FIXME: transform_to_exit_first_loop does not handle not - header-copied loops correctly - see PR46886. */ - || !do_while_loop_p (loop)) + || loop_has_vector_phi_nodes (loop)) continue; - estimated = max_stmt_executions_int (loop, false); + + estimated = estimated_stmt_executions_int (loop); + if (estimated == -1) + estimated = max_stmt_executions_int (loop); /* FIXME: Bypass this check as graphite doesn't update the - count and frequency correctly now. */ + count and frequency correctly now. */ if (!flag_loop_parallelize_all - && ((estimated !=-1 - && estimated <= (HOST_WIDE_INT) n_threads * MIN_PER_THREAD) + && ((estimated != -1 + && estimated <= (HOST_WIDE_INT) n_threads * MIN_PER_THREAD) /* Do not bother with loops in cold areas. */ || optimize_loop_nest_for_size_p (loop))) continue; diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index f849a542465..1c902bc1648 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -245,13 +245,12 @@ struct dump_file_info (PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_gimple_lomp) /* To-do flags. */ -#define TODO_dump_func (1 << 0) #define TODO_ggc_collect (1 << 1) #define TODO_verify_ssa (1 << 2) #define TODO_verify_flow (1 << 3) #define TODO_verify_stmts (1 << 4) #define TODO_cleanup_cfg (1 << 5) -#define TODO_dump_cgraph (1 << 7) +#define TODO_dump_symtab (1 << 7) #define TODO_remove_functions (1 << 8) #define TODO_rebuild_frequencies (1 << 9) #define TODO_verify_rtl_sharing (1 << 10) @@ -349,8 +348,6 @@ struct register_pass_info enum pass_positioning_ops pos_op; /* how to insert the new pass. */ }; -extern void tree_lowering_passes (tree decl); - extern struct gimple_opt_pass pass_mudflap_1; extern struct gimple_opt_pass pass_mudflap_2; extern struct gimple_opt_pass pass_lower_cf; diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c index c56650c066e..55ea0fa8a22 100644 --- a/gcc/tree-profile.c +++ b/gcc/tree-profile.c @@ -87,7 +87,6 @@ init_ic_make_global_vars (void) decl_default_tls_model (ic_void_ptr_var); varpool_finalize_decl (ic_void_ptr_var); - varpool_mark_needed_node (varpool_node (ic_void_ptr_var)); gcov_type_ptr = build_pointer_type (get_gcov_type ()); ic_gcov_type_ptr_var @@ -103,7 +102,6 @@ init_ic_make_global_vars (void) decl_default_tls_model (ic_gcov_type_ptr_var); varpool_finalize_decl (ic_gcov_type_ptr_var); - varpool_mark_needed_node (varpool_node (ic_gcov_type_ptr_var)); } void @@ -479,19 +477,18 @@ tree_profiling (void) init_node_map(); - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { - if (!node->analyzed - || !gimple_has_body_p (node->decl)) + if (!gimple_has_body_p (node->symbol.decl)) continue; /* Don't profile functions produced for builtin stuff. */ - if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION - || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) + if (DECL_SOURCE_LOCATION (node->symbol.decl) == BUILTINS_LOCATION + || DECL_STRUCT_FUNCTION (node->symbol.decl)->after_tree_profile) continue; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - current_function_decl = node->decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); + current_function_decl = node->symbol.decl; /* Re-set global shared temporary variable for edge-counters. */ gcov_type_tmp_var = NULL_TREE; @@ -520,16 +517,16 @@ tree_profiling (void) } /* Drop pure/const flags from instrumented functions. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { - if (!node->analyzed - || !gimple_has_body_p (node->decl) - || !(!node->clone_of || node->decl != node->clone_of->decl)) + if (!gimple_has_body_p (node->symbol.decl) + || !(!node->clone_of + || node->symbol.decl != node->clone_of->symbol.decl)) continue; /* Don't profile functions produced for builtin stuff. */ - if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION - || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) + if (DECL_SOURCE_LOCATION (node->symbol.decl) == BUILTINS_LOCATION + || DECL_STRUCT_FUNCTION (node->symbol.decl)->after_tree_profile) continue; cgraph_set_const_flag (node, false, false); @@ -537,22 +534,22 @@ tree_profiling (void) } /* Update call statements and rebuild the cgraph. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { basic_block bb; - if (!node->analyzed - || !gimple_has_body_p (node->decl) - || !(!node->clone_of || node->decl != node->clone_of->decl)) + if (!gimple_has_body_p (node->symbol.decl) + || !(!node->clone_of + || node->symbol.decl != node->clone_of->symbol.decl)) continue; /* Don't profile functions produced for builtin stuff. */ - if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION - || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) + if (DECL_SOURCE_LOCATION (node->symbol.decl) == BUILTINS_LOCATION + || DECL_STRUCT_FUNCTION (node->symbol.decl)->after_tree_profile) continue; - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - current_function_decl = node->decl; + push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); + current_function_decl = node->symbol.decl; FOR_EACH_BB (bb) { diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c index c6631b856b8..21d1fd0a4a1 100644 --- a/gcc/tree-scalar-evolution.c +++ b/gcc/tree-scalar-evolution.c @@ -501,65 +501,6 @@ compute_overall_effect_of_inner_loop (struct loop *loop, tree evolution_fn) return chrec_dont_know; } -/* Determine whether the CHREC is always positive/negative. If the expression - cannot be statically analyzed, return false, otherwise set the answer into - VALUE. */ - -bool -chrec_is_positive (tree chrec, bool *value) -{ - bool value0, value1, value2; - tree end_value, nb_iter; - - switch (TREE_CODE (chrec)) - { - case POLYNOMIAL_CHREC: - if (!chrec_is_positive (CHREC_LEFT (chrec), &value0) - || !chrec_is_positive (CHREC_RIGHT (chrec), &value1)) - return false; - - /* FIXME -- overflows. */ - if (value0 == value1) - { - *value = value0; - return true; - } - - /* Otherwise the chrec is under the form: "{-197, +, 2}_1", - and the proof consists in showing that the sign never - changes during the execution of the loop, from 0 to - loop->nb_iterations. */ - if (!evolution_function_is_affine_p (chrec)) - return false; - - nb_iter = number_of_latch_executions (get_chrec_loop (chrec)); - if (chrec_contains_undetermined (nb_iter)) - return false; - -#if 0 - /* TODO -- If the test is after the exit, we may decrease the number of - iterations by one. */ - if (after_exit) - nb_iter = chrec_fold_minus (type, nb_iter, build_int_cst (type, 1)); -#endif - - end_value = chrec_apply (CHREC_VARIABLE (chrec), chrec, nb_iter); - - if (!chrec_is_positive (end_value, &value2)) - return false; - - *value = value0; - return value0 == value1; - - case INTEGER_CST: - *value = (tree_int_cst_sgn (chrec) == 1); - return true; - - default: - return false; - } -} - /* Associate CHREC to SCALAR. */ static void diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index c5f105a2297..70b241d5237 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -1489,70 +1489,32 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset, return fold_build2_loc (loc, MEM_REF, exp_type, base, off); } -DEF_VEC_ALLOC_P_STACK (tree); -#define VEC_tree_stack_alloc(alloc) VEC_stack_alloc (tree, alloc) - /* Construct a memory reference to a part of an aggregate BASE at the given - OFFSET and of the type of MODEL. In case this is a chain of references - to component, the function will replicate the chain of COMPONENT_REFs of - the expression of MODEL to access it. GSI and INSERT_AFTER have the same - meaning as in build_ref_for_offset. */ + OFFSET and of the same type as MODEL. In case this is a reference to a + bit-field, the function will replicate the last component_ref of model's + expr to access it. GSI and INSERT_AFTER have the same meaning as in + build_ref_for_offset. */ static tree build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset, struct access *model, gimple_stmt_iterator *gsi, bool insert_after) { - tree type = model->type, t; - VEC(tree,stack) *cr_stack = NULL; - - if (TREE_CODE (model->expr) == COMPONENT_REF) - { - tree expr = model->expr; - - /* Create a stack of the COMPONENT_REFs so later we can walk them in - order from inner to outer. */ - cr_stack = VEC_alloc (tree, stack, 6); - - do { - tree field = TREE_OPERAND (expr, 1); - tree cr_offset = component_ref_field_offset (expr); - HOST_WIDE_INT bit_pos - = tree_low_cst (cr_offset, 1) * BITS_PER_UNIT - + TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)); - - /* We can be called with a model different from the one associated - with BASE so we need to avoid going up the chain too far. */ - if (offset - bit_pos < 0) - break; - - offset -= bit_pos; - VEC_safe_push (tree, stack, cr_stack, expr); - - expr = TREE_OPERAND (expr, 0); - type = TREE_TYPE (expr); - } while (TREE_CODE (expr) == COMPONENT_REF); - } - - t = build_ref_for_offset (loc, base, offset, type, gsi, insert_after); - - if (TREE_CODE (model->expr) == COMPONENT_REF) + if (TREE_CODE (model->expr) == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1))) { - unsigned i; - tree expr; - - /* Now replicate the chain of COMPONENT_REFs from inner to outer. */ - FOR_EACH_VEC_ELT_REVERSE (tree, cr_stack, i, expr) - { - tree field = TREE_OPERAND (expr, 1); - t = fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (field), t, field, - TREE_OPERAND (expr, 2)); - } - - VEC_free (tree, stack, cr_stack); + /* This access represents a bit-field. */ + tree t, exp_type, fld = TREE_OPERAND (model->expr, 1); + + offset -= int_bit_position (fld); + exp_type = TREE_TYPE (TREE_OPERAND (model->expr, 0)); + t = build_ref_for_offset (loc, base, offset, exp_type, gsi, insert_after); + return fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (fld), t, fld, + NULL_TREE); } - - return t; + else + return build_ref_for_offset (loc, base, offset, model->type, + gsi, insert_after); } /* Construct a memory reference consisting of component_refs and array_refs to @@ -4644,8 +4606,8 @@ convert_callers_for_node (struct cgraph_node *node, for (cs = node->callers; cs; cs = cs->next_caller) { - current_function_decl = cs->caller->decl; - push_cfun (DECL_STRUCT_FUNCTION (cs->caller->decl)); + current_function_decl = cs->caller->symbol.decl; + push_cfun (DECL_STRUCT_FUNCTION (cs->caller->symbol.decl)); if (dump_file) fprintf (dump_file, "Adjusting call (%i -> %i) %s -> %s\n", @@ -4660,7 +4622,7 @@ convert_callers_for_node (struct cgraph_node *node, for (cs = node->callers; cs; cs = cs->next_caller) if (bitmap_set_bit (recomputed_callers, cs->caller->uid) - && gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->decl))) + && gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->symbol.decl))) compute_inline_parameters (cs->caller, true); BITMAP_FREE (recomputed_callers); @@ -4699,7 +4661,7 @@ convert_callers (struct cgraph_node *node, tree old_decl, { if (dump_file) fprintf (dump_file, "Adjusting recursive call"); - gimple_call_set_fndecl (stmt, node->decl); + gimple_call_set_fndecl (stmt, node->symbol.decl); ipa_modify_call_arguments (NULL, stmt, adjustments); } } @@ -4725,13 +4687,13 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments) new_node = cgraph_function_versioning (node, redirect_callers, NULL, NULL, false, NULL, NULL, "isra"); - current_function_decl = new_node->decl; - push_cfun (DECL_STRUCT_FUNCTION (new_node->decl)); + current_function_decl = new_node->symbol.decl; + push_cfun (DECL_STRUCT_FUNCTION (new_node->symbol.decl)); ipa_modify_formal_parameters (current_function_decl, adjustments, "ISRA"); cfg_changed = ipa_sra_modify_function_body (adjustments); sra_ipa_reset_debug_stmts (adjustments); - convert_callers (new_node, node->decl, adjustments); + convert_callers (new_node, node->symbol.decl, adjustments); cgraph_make_node_local (new_node); return cfg_changed; } @@ -4757,7 +4719,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node) return false; } - if (!tree_versionable_function_p (node->decl)) + if (!tree_versionable_function_p (node->symbol.decl)) { if (dump_file) fprintf (dump_file, "Function is not versionable.\n"); @@ -4771,7 +4733,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node) return false; } - if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl)) + if ((DECL_COMDAT (node->symbol.decl) || DECL_EXTERNAL (node->symbol.decl)) && inline_summary(node)->size >= MAX_INLINE_INSNS_AUTO) { if (dump_file) @@ -4794,7 +4756,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node) return false; } - if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl))) + if (TYPE_ATTRIBUTES (TREE_TYPE (node->symbol.decl))) return false; return true; @@ -4903,6 +4865,6 @@ struct gimple_opt_pass pass_early_ipa_sra = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_cgraph /* todo_flags_finish */ + TODO_dump_symtab /* todo_flags_finish */ } }; diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index dd90432b920..4a859eb9f8a 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -1010,7 +1010,7 @@ refs_may_alias_p_1 (ao_ref *ref1, ao_ref *ref2, bool tbaa_p) || CONSTANT_CLASS_P (base2)) return false; - /* We can end up refering to code via function and label decls. + /* We can end up referring to code via function and label decls. As we likely do not properly track code aliases conservatively bail out. */ if (TREE_CODE (base1) == FUNCTION_DECL diff --git a/gcc/tree-ssa-copy.c b/gcc/tree-ssa-copy.c index 4c6d9927bbd..45b5c92c999 100644 --- a/gcc/tree-ssa-copy.c +++ b/gcc/tree-ssa-copy.c @@ -257,13 +257,11 @@ propagate_tree_value_into_stmt (gimple_stmt_iterator *gsi, tree val) else if (is_gimple_call (stmt) && gimple_call_lhs (stmt) != NULL_TREE) { - gimple new_stmt; - tree expr = NULL_TREE; + bool res; propagate_tree_value (&expr, val); - new_stmt = gimple_build_assign (gimple_call_lhs (stmt), expr); - move_ssa_defining_stmt_for_defs (new_stmt, stmt); - gsi_replace (gsi, new_stmt, false); + res = update_call_from_tree (gsi, expr); + gcc_assert (res); } else if (gimple_code (stmt) == GIMPLE_SWITCH) propagate_tree_value (gimple_switch_index_ptr (stmt), val); diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index c99af1a8c43..965f44150e6 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -1,5 +1,5 @@ /* Forward propagation of expressions for single use variables. - Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011 + Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -632,6 +632,58 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p) return 0; } +/* Propagate from the ssa name definition statements of COND_EXPR + values in the rhs of statement STMT into the conditional arms + if that simplifies it. + Returns true if the stmt was changed. */ + +static bool +combine_cond_exprs (gimple_stmt_iterator *gsi_p) +{ + gimple stmt = gsi_stmt (*gsi_p); + tree cond, val1, val2; + bool changed = false; + + cond = gimple_assign_rhs1 (stmt); + val1 = gimple_assign_rhs2 (stmt); + if (TREE_CODE (val1) == SSA_NAME) + { + gimple def_stmt = SSA_NAME_DEF_STMT (val1); + if (is_gimple_assign (def_stmt) + && gimple_assign_rhs_code (def_stmt) == gimple_assign_rhs_code (stmt) + && operand_equal_p (gimple_assign_rhs1 (def_stmt), cond, 0)) + { + val1 = unshare_expr (gimple_assign_rhs2 (def_stmt)); + gimple_assign_set_rhs2 (stmt, val1); + changed = true; + } + } + val2 = gimple_assign_rhs3 (stmt); + if (TREE_CODE (val2) == SSA_NAME) + { + gimple def_stmt = SSA_NAME_DEF_STMT (val2); + if (is_gimple_assign (def_stmt) + && gimple_assign_rhs_code (def_stmt) == gimple_assign_rhs_code (stmt) + && operand_equal_p (gimple_assign_rhs1 (def_stmt), cond, 0)) + { + val2 = unshare_expr (gimple_assign_rhs3 (def_stmt)); + gimple_assign_set_rhs3 (stmt, val2); + changed = true; + } + } + if (operand_equal_p (val1, val2, 0)) + { + gimple_assign_set_rhs_from_tree (gsi_p, val1); + stmt = gsi_stmt (*gsi_p); + changed = true; + } + + if (changed) + update_stmt (stmt); + + return changed; +} + /* We've just substituted an ADDR_EXPR into stmt. Update all the relevant data structures to match. */ @@ -2274,7 +2326,7 @@ combine_conversions (gimple_stmt_iterator *gsi) && inter_prec >= inside_prec && (inter_float || inter_vec || inter_unsignedp == inside_unsignedp) - && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type)) && ! final_ptr && (! final_vec || inter_prec == inside_prec)) @@ -2319,7 +2371,7 @@ combine_conversions (gimple_stmt_iterator *gsi) == (final_unsignedp && final_prec > inter_prec)) && ! (inside_ptr && inter_prec != final_prec) && ! (final_ptr && inside_prec != inter_prec) - && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type))) { gimple_assign_set_rhs1 (stmt, defop0); @@ -2480,11 +2532,16 @@ ssa_forward_propagate_and_combine (void) || code == NEGATE_EXPR) && TREE_CODE (rhs1) == SSA_NAME) changed = simplify_not_neg_expr (&gsi); - else if (code == COND_EXPR) + else if (code == COND_EXPR + || code == VEC_COND_EXPR) { /* In this case the entire COND_EXPR is in rhs1. */ - changed |= forward_propagate_into_cond (&gsi); - stmt = gsi_stmt (gsi); + if (forward_propagate_into_cond (&gsi) + || combine_cond_exprs (&gsi)) + { + changed = true; + stmt = gsi_stmt (gsi); + } } else if (TREE_CODE_CLASS (code) == tcc_comparison) { diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 527c911e4a7..3c11c0e4834 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -115,7 +115,7 @@ along with GCC; see the file COPYING3. If not see static inline HOST_WIDE_INT avg_loop_niter (struct loop *loop) { - HOST_WIDE_INT niter = max_stmt_executions_int (loop, false); + HOST_WIDE_INT niter = estimated_stmt_executions_int (loop); if (niter == -1) return AVG_LOOP_NITER (loop); @@ -4694,7 +4694,7 @@ may_eliminate_iv (struct ivopts_data *data, /* See if we can take advantage of infered loop bound information. */ if (data->loop_single_exit_p) { - if (!estimated_loop_iterations (loop, true, &max_niter)) + if (!max_loop_iterations (loop, &max_niter)) return false; /* The loop bound is already adjusted by adding 1. */ if (double_int_ucmp (max_niter, period_value) > 0) diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c index 4acfc67b41f..8d99408d54b 100644 --- a/gcc/tree-ssa-loop-niter.c +++ b/gcc/tree-ssa-loop-niter.c @@ -2494,12 +2494,12 @@ derive_constant_upper_bound_ops (tree type, tree op0, of iterations. UPPER is true if we are sure the loop iterates at most I_BOUND times. */ -static void +void record_niter_bound (struct loop *loop, double_int i_bound, bool realistic, bool upper) { - /* Update the bounds only when there is no previous estimation, or when the current - estimation is smaller. */ + /* Update the bounds only when there is no previous estimation, or when the + current estimation is smaller. */ if (upper && (!loop->any_upper_bound || double_int_ucmp (i_bound, loop->nb_iterations_upper_bound) < 0)) @@ -2514,6 +2514,14 @@ record_niter_bound (struct loop *loop, double_int i_bound, bool realistic, loop->any_estimate = true; loop->nb_iterations_estimate = i_bound; } + + /* If an upper bound is smaller than the realistic estimate of the + number of iterations, use the upper bound instead. */ + if (loop->any_upper_bound + && loop->any_estimate + && double_int_ucmp (loop->nb_iterations_upper_bound, + loop->nb_iterations_estimate) < 0) + loop->nb_iterations_estimate = loop->nb_iterations_upper_bound; } /* Records that AT_STMT is executed at most BOUND + 1 times in LOOP. IS_EXIT @@ -2640,47 +2648,6 @@ record_nonwrapping_iv (struct loop *loop, tree base, tree step, gimple stmt, record_estimate (loop, niter_bound, max, stmt, false, realistic, upper); } -/* Returns true if REF is a reference to an array at the end of a dynamically - allocated structure. If this is the case, the array may be allocated larger - than its upper bound implies. */ - -bool -array_at_struct_end_p (tree ref) -{ - tree base = get_base_address (ref); - tree parent, field; - - /* Unless the reference is through a pointer, the size of the array matches - its declaration. */ - if (!base || (!INDIRECT_REF_P (base) && TREE_CODE (base) != MEM_REF)) - return false; - - for (;handled_component_p (ref); ref = parent) - { - parent = TREE_OPERAND (ref, 0); - - if (TREE_CODE (ref) == COMPONENT_REF) - { - /* All fields of a union are at its end. */ - if (TREE_CODE (TREE_TYPE (parent)) == UNION_TYPE) - continue; - - /* Unless the field is at the end of the struct, we are done. */ - field = TREE_OPERAND (ref, 1); - if (DECL_CHAIN (field)) - return false; - } - - /* The other options are ARRAY_REF, ARRAY_RANGE_REF, VIEW_CONVERT_EXPR. - In all these cases, we might be accessing the last element, and - although in practice this will probably never happen, it is legal for - the indices of this last element to exceed the bounds of the array. - Therefore, continue checking. */ - } - - return true; -} - /* Determine information about number of iterations a LOOP from the index IDX of a data reference accessed in STMT. RELIABLE is true if STMT is guaranteed to be executed in every iteration of LOOP. Callback for @@ -2991,7 +2958,7 @@ gcov_type_to_double_int (gcov_type val) is true also use estimates derived from undefined behavior. */ void -estimate_numbers_of_iterations_loop (struct loop *loop, bool use_undefined_p) +estimate_numbers_of_iterations_loop (struct loop *loop) { VEC (edge, heap) *exits; tree niter, type; @@ -3003,8 +2970,9 @@ estimate_numbers_of_iterations_loop (struct loop *loop, bool use_undefined_p) /* Give up if we already have tried to compute an estimation. */ if (loop->estimate_state != EST_NOT_COMPUTED) return; + loop->estimate_state = EST_AVAILABLE; - loop->any_upper_bound = false; + /* Force estimate compuation but leave any existing upper bound in place. */ loop->any_estimate = false; exits = get_loop_exit_edges (loop); @@ -3025,8 +2993,7 @@ estimate_numbers_of_iterations_loop (struct loop *loop, bool use_undefined_p) } VEC_free (edge, heap, exits); - if (use_undefined_p) - infer_loop_bounds_from_undefined (loop); + infer_loop_bounds_from_undefined (loop); /* If we have a measured profile, use it to estimate the number of iterations. */ @@ -3036,14 +3003,6 @@ estimate_numbers_of_iterations_loop (struct loop *loop, bool use_undefined_p) bound = gcov_type_to_double_int (nit); record_niter_bound (loop, bound, true, false); } - - /* If an upper bound is smaller than the realistic estimate of the - number of iterations, use the upper bound instead. */ - if (loop->any_upper_bound - && loop->any_estimate - && double_int_ucmp (loop->nb_iterations_upper_bound, - loop->nb_iterations_estimate) < 0) - loop->nb_iterations_estimate = loop->nb_iterations_upper_bound; } /* Sets NIT to the estimated number of executions of the latch of the @@ -3052,25 +3011,28 @@ estimate_numbers_of_iterations_loop (struct loop *loop, bool use_undefined_p) the function returns false, otherwise returns true. */ bool -estimated_loop_iterations (struct loop *loop, bool conservative, - double_int *nit) +estimated_loop_iterations (struct loop *loop, double_int *nit) { - estimate_numbers_of_iterations_loop (loop, true); - if (conservative) - { - if (!loop->any_upper_bound) - return false; + estimate_numbers_of_iterations_loop (loop); + if (!loop->any_estimate) + return false; - *nit = loop->nb_iterations_upper_bound; - } - else - { - if (!loop->any_estimate) - return false; + *nit = loop->nb_iterations_estimate; + return true; +} - *nit = loop->nb_iterations_estimate; - } +/* Sets NIT to an upper bound for the maximum number of executions of the + latch of the LOOP. If we have no reliable estimate, the function returns + false, otherwise returns true. */ +bool +max_loop_iterations (struct loop *loop, double_int *nit) +{ + estimate_numbers_of_iterations_loop (loop); + if (!loop->any_upper_bound) + return false; + + *nit = loop->nb_iterations_upper_bound; return true; } @@ -3079,12 +3041,32 @@ estimated_loop_iterations (struct loop *loop, bool conservative, on the number of iterations of LOOP could not be derived, returns -1. */ HOST_WIDE_INT -estimated_loop_iterations_int (struct loop *loop, bool conservative) +estimated_loop_iterations_int (struct loop *loop) { double_int nit; HOST_WIDE_INT hwi_nit; - if (!estimated_loop_iterations (loop, conservative, &nit)) + if (!estimated_loop_iterations (loop, &nit)) + return -1; + + if (!double_int_fits_in_shwi_p (nit)) + return -1; + hwi_nit = double_int_to_shwi (nit); + + return hwi_nit < 0 ? -1 : hwi_nit; +} + +/* Similar to max_loop_iterations, but returns the estimate only + if it fits to HOST_WIDE_INT. If this is not the case, or the estimate + on the number of iterations of LOOP could not be derived, returns -1. */ + +HOST_WIDE_INT +max_loop_iterations_int (struct loop *loop) +{ + double_int nit; + HOST_WIDE_INT hwi_nit; + + if (!max_loop_iterations (loop, &nit)) return -1; if (!double_int_fits_in_shwi_p (nit)) @@ -3099,9 +3081,9 @@ estimated_loop_iterations_int (struct loop *loop, bool conservative) the number of execution of the latch by one. */ HOST_WIDE_INT -max_stmt_executions_int (struct loop *loop, bool conservative) +max_stmt_executions_int (struct loop *loop) { - HOST_WIDE_INT nit = estimated_loop_iterations_int (loop, conservative); + HOST_WIDE_INT nit = max_loop_iterations_int (loop); HOST_WIDE_INT snit; if (nit == -1) @@ -3113,17 +3095,54 @@ max_stmt_executions_int (struct loop *loop, bool conservative) return snit < 0 ? -1 : snit; } +/* Returns an estimate for the number of executions of statements + in the LOOP. For statements before the loop exit, this exceeds + the number of execution of the latch by one. */ + +HOST_WIDE_INT +estimated_stmt_executions_int (struct loop *loop) +{ + HOST_WIDE_INT nit = estimated_loop_iterations_int (loop); + HOST_WIDE_INT snit; + + if (nit == -1) + return -1; + + snit = (HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) nit + 1); + + /* If the computation overflows, return -1. */ + return snit < 0 ? -1 : snit; +} + +/* Sets NIT to the estimated maximum number of executions of the latch of the + LOOP, plus one. If we have no reliable estimate, the function returns + false, otherwise returns true. */ + +bool +max_stmt_executions (struct loop *loop, double_int *nit) +{ + double_int nit_minus_one; + + if (!max_loop_iterations (loop, nit)) + return false; + + nit_minus_one = *nit; + + *nit = double_int_add (*nit, double_int_one); + + return double_int_ucmp (*nit, nit_minus_one) > 0; +} + /* Sets NIT to the estimated number of executions of the latch of the - LOOP, plus one. If CONSERVATIVE is true, we must be sure that NIT is at - least as large as the number of iterations. If we have no reliable - estimate, the function returns false, otherwise returns true. */ + LOOP, plus one. If we have no reliable estimate, the function returns + false, otherwise returns true. */ bool -max_stmt_executions (struct loop *loop, bool conservative, double_int *nit) +estimated_stmt_executions (struct loop *loop, double_int *nit) { double_int nit_minus_one; - if (!estimated_loop_iterations (loop, conservative, nit)) + if (!estimated_loop_iterations (loop, nit)) return false; nit_minus_one = *nit; @@ -3136,7 +3155,7 @@ max_stmt_executions (struct loop *loop, bool conservative, double_int *nit) /* Records estimates on numbers of iterations of loops. */ void -estimate_numbers_of_iterations (bool use_undefined_p) +estimate_numbers_of_iterations (void) { loop_iterator li; struct loop *loop; @@ -3147,7 +3166,7 @@ estimate_numbers_of_iterations (bool use_undefined_p) FOR_EACH_LOOP (li, loop, 0) { - estimate_numbers_of_iterations_loop (loop, use_undefined_p); + estimate_numbers_of_iterations_loop (loop); } fold_undefer_and_ignore_overflow_warnings (); @@ -3343,7 +3362,7 @@ scev_probably_wraps_p (tree base, tree step, valid_niter = fold_build2 (FLOOR_DIV_EXPR, unsigned_type, delta, step_abs); - estimate_numbers_of_iterations_loop (loop, true); + estimate_numbers_of_iterations_loop (loop); for (bound = loop->bounds; bound; bound = bound->next) { if (n_of_executions_at_most (at_stmt, bound, valid_niter)) diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c index 264d97bc1b5..19a6a22d959 100644 --- a/gcc/tree-ssa-loop-prefetch.c +++ b/gcc/tree-ssa-loop-prefetch.c @@ -1548,8 +1548,8 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs, continue; aloop = VEC_index (loop_p, vloops, i); - vol = max_stmt_executions_int (aloop, false); - if (vol < 0) + vol = estimated_stmt_executions_int (aloop); + if (vol == -1) vol = expected_loop_iterations (aloop); volume *= vol; } @@ -1800,7 +1800,9 @@ loop_prefetch_arrays (struct loop *loop) return false; ahead = (PREFETCH_LATENCY + time - 1) / time; - est_niter = max_stmt_executions_int (loop, false); + est_niter = estimated_stmt_executions_int (loop); + if (est_niter == -1) + est_niter = max_stmt_executions_int (loop); /* Prefetching is not likely to be profitable if the trip count to ahead ratio is too small. */ diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c index a91bf3919ad..3d650bfcbfd 100644 --- a/gcc/tree-ssa-loop.c +++ b/gcc/tree-ssa-loop.c @@ -420,7 +420,7 @@ tree_ssa_loop_bounds (void) if (number_of_loops () <= 1) return 0; - estimate_numbers_of_iterations (true); + estimate_numbers_of_iterations (); scev_reset (); return 0; } diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 554ba3abe76..f440d174258 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -61,6 +61,10 @@ along with GCC; see the file COPYING3. If not see 3. Optimization of the operand lists, eliminating things like a + -a, a & a, etc. + 3a. Combine repeated factors with the same occurrence counts + into a __builtin_powi call that will later be optimized into + an optimal number of multiplies. + 4. Rewrite the expression trees we linearized and optimized so they are in proper rank order. @@ -169,6 +173,8 @@ static struct int constants_eliminated; int ops_eliminated; int rewritten; + int pows_encountered; + int pows_created; } reassociate_stats; /* Operator, rank pair. */ @@ -177,6 +183,7 @@ typedef struct operand_entry unsigned int rank; int id; tree op; + unsigned int count; } *operand_entry_t; static alloc_pool operand_entry_pool; @@ -515,9 +522,28 @@ add_to_ops_vec (VEC(operand_entry_t, heap) **ops, tree op) oe->op = op; oe->rank = get_rank (op); oe->id = next_operand_entry_id++; + oe->count = 1; VEC_safe_push (operand_entry_t, heap, *ops, oe); } +/* Add an operand entry to *OPS for the tree operand OP with repeat + count REPEAT. */ + +static void +add_repeat_to_ops_vec (VEC(operand_entry_t, heap) **ops, tree op, + HOST_WIDE_INT repeat) +{ + operand_entry_t oe = (operand_entry_t) pool_alloc (operand_entry_pool); + + oe->op = op; + oe->rank = get_rank (op); + oe->id = next_operand_entry_id++; + oe->count = repeat; + VEC_safe_push (operand_entry_t, heap, *ops, oe); + + reassociate_stats.pows_encountered++; +} + /* Return true if STMT is reassociable operation containing a binary operation with tree code CODE, and is inside LOOP. */ @@ -972,6 +998,98 @@ oecount_cmp (const void *p1, const void *p2) return c1->id - c2->id; } +/* Return TRUE iff STMT represents a builtin call that raises OP + to some exponent. */ + +static bool +stmt_is_power_of_op (gimple stmt, tree op) +{ + tree fndecl; + + if (!is_gimple_call (stmt)) + return false; + + fndecl = gimple_call_fndecl (stmt); + + if (!fndecl + || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) + return false; + + switch (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))) + { + CASE_FLT_FN (BUILT_IN_POW): + CASE_FLT_FN (BUILT_IN_POWI): + return (operand_equal_p (gimple_call_arg (stmt, 0), op, 0)); + + default: + return false; + } +} + +/* Given STMT which is a __builtin_pow* call, decrement its exponent + in place and return the result. Assumes that stmt_is_power_of_op + was previously called for STMT and returned TRUE. */ + +static HOST_WIDE_INT +decrement_power (gimple stmt) +{ + REAL_VALUE_TYPE c, cint; + HOST_WIDE_INT power; + tree arg1; + + switch (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))) + { + CASE_FLT_FN (BUILT_IN_POW): + arg1 = gimple_call_arg (stmt, 1); + c = TREE_REAL_CST (arg1); + power = real_to_integer (&c) - 1; + real_from_integer (&cint, VOIDmode, power, 0, 0); + gimple_call_set_arg (stmt, 1, build_real (TREE_TYPE (arg1), cint)); + return power; + + CASE_FLT_FN (BUILT_IN_POWI): + arg1 = gimple_call_arg (stmt, 1); + power = TREE_INT_CST_LOW (arg1) - 1; + gimple_call_set_arg (stmt, 1, build_int_cst (TREE_TYPE (arg1), power)); + return power; + + default: + gcc_unreachable (); + } +} + +/* Find the single immediate use of STMT's LHS, and replace it + with OP. Remove STMT. If STMT's LHS is the same as *DEF, + replace *DEF with OP as well. */ + +static void +propagate_op_to_single_use (tree op, gimple stmt, tree *def) +{ + tree lhs; + gimple use_stmt; + use_operand_p use; + gimple_stmt_iterator gsi; + + if (is_gimple_call (stmt)) + lhs = gimple_call_lhs (stmt); + else + lhs = gimple_assign_lhs (stmt); + + gcc_assert (has_single_use (lhs)); + single_imm_use (lhs, &use, &use_stmt); + if (lhs == *def) + *def = op; + SET_USE (use, op); + if (TREE_CODE (op) != SSA_NAME) + update_stmt (use_stmt); + gsi = gsi_for_stmt (stmt); + gsi_remove (&gsi, true); + release_defs (stmt); + + if (is_gimple_call (stmt)) + unlink_stmt_vdef (stmt); +} + /* Walks the linear chain with result *DEF searching for an operation with operand OP and code OPCODE removing that from the chain. *DEF is updated if there is only one operand but no operation left. */ @@ -983,7 +1101,17 @@ zero_one_operation (tree *def, enum tree_code opcode, tree op) do { - tree name = gimple_assign_rhs1 (stmt); + tree name; + + if (opcode == MULT_EXPR + && stmt_is_power_of_op (stmt, op)) + { + if (decrement_power (stmt) == 1) + propagate_op_to_single_use (op, stmt, def); + return; + } + + name = gimple_assign_rhs1 (stmt); /* If this is the operation we look for and one of the operands is ours simply propagate the other operand into the stmts @@ -992,24 +1120,27 @@ zero_one_operation (tree *def, enum tree_code opcode, tree op) && (name == op || gimple_assign_rhs2 (stmt) == op)) { - gimple use_stmt; - use_operand_p use; - gimple_stmt_iterator gsi; if (name == op) name = gimple_assign_rhs2 (stmt); - gcc_assert (has_single_use (gimple_assign_lhs (stmt))); - single_imm_use (gimple_assign_lhs (stmt), &use, &use_stmt); - if (gimple_assign_lhs (stmt) == *def) - *def = name; - SET_USE (use, name); - if (TREE_CODE (name) != SSA_NAME) - update_stmt (use_stmt); - gsi = gsi_for_stmt (stmt); - gsi_remove (&gsi, true); - release_defs (stmt); + propagate_op_to_single_use (name, stmt, def); return; } + /* We might have a multiply of two __builtin_pow* calls, and + the operand might be hiding in the rightmost one. */ + if (opcode == MULT_EXPR + && gimple_assign_rhs_code (stmt) == opcode + && TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME) + { + gimple stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt)); + if (stmt_is_power_of_op (stmt2, op)) + { + if (decrement_power (stmt2) == 1) + propagate_op_to_single_use (op, stmt2, def); + return; + } + } + /* Continue walking the chain. */ gcc_assert (name != op && TREE_CODE (name) == SSA_NAME); @@ -2049,6 +2180,32 @@ is_phi_for_stmt (gimple stmt, tree operand) return false; } +/* Remove STMT, unlink its virtual defs, and release its SSA defs. */ + +static inline void +completely_remove_stmt (gimple stmt) +{ + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + gsi_remove (&gsi, true); + unlink_stmt_vdef (stmt); + release_defs (stmt); +} + +/* If OP is defined by a builtin call that has been absorbed by + reassociation, remove its defining statement completely. */ + +static inline void +remove_def_if_absorbed_call (tree op) +{ + gimple stmt; + + if (TREE_CODE (op) == SSA_NAME + && has_zero_uses (op) + && is_gimple_call ((stmt = SSA_NAME_DEF_STMT (op))) + && gimple_visited_p (stmt)) + completely_remove_stmt (stmt); +} + /* Remove def stmt of VAR if VAR has zero uses and recurse on rhs1 operand if so. */ @@ -2057,22 +2214,75 @@ remove_visited_stmt_chain (tree var) { gimple stmt; gimple_stmt_iterator gsi; + tree var2; while (1) { if (TREE_CODE (var) != SSA_NAME || !has_zero_uses (var)) return; stmt = SSA_NAME_DEF_STMT (var); - if (!is_gimple_assign (stmt) - || !gimple_visited_p (stmt)) + if (is_gimple_assign (stmt) && gimple_visited_p (stmt)) + { + var = gimple_assign_rhs1 (stmt); + var2 = gimple_assign_rhs2 (stmt); + gsi = gsi_for_stmt (stmt); + gsi_remove (&gsi, true); + release_defs (stmt); + /* A multiply whose operands are both fed by builtin pow/powi + calls must check whether to remove rhs2 as well. */ + remove_def_if_absorbed_call (var2); + } + else if (is_gimple_call (stmt) && gimple_visited_p (stmt)) + { + completely_remove_stmt (stmt); + return; + } + else return; - var = gimple_assign_rhs1 (stmt); - gsi = gsi_for_stmt (stmt); - gsi_remove (&gsi, true); - release_defs (stmt); } } +/* If OP is an SSA name, find its definition and determine whether it + is a call to __builtin_powi. If so, move the definition prior to + STMT. Only do this during early reassociation. */ + +static void +possibly_move_powi (gimple stmt, tree op) +{ + gimple stmt2; + tree fndecl; + gimple_stmt_iterator gsi1, gsi2; + + if (!first_pass_instance + || !flag_unsafe_math_optimizations + || TREE_CODE (op) != SSA_NAME) + return; + + stmt2 = SSA_NAME_DEF_STMT (op); + + if (!is_gimple_call (stmt2) + || !has_single_use (gimple_call_lhs (stmt2))) + return; + + fndecl = gimple_call_fndecl (stmt2); + + if (!fndecl + || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) + return; + + switch (DECL_FUNCTION_CODE (fndecl)) + { + CASE_FLT_FN (BUILT_IN_POWI): + break; + default: + return; + } + + gsi1 = gsi_for_stmt (stmt); + gsi2 = gsi_for_stmt (stmt2); + gsi_move_before (&gsi2, &gsi1); +} + /* This function checks three consequtive operands in passed operands vector OPS starting from OPINDEX and swaps two operands if it is profitable for binary operation @@ -2178,6 +2388,8 @@ rewrite_expr_tree (gimple stmt, unsigned int opindex, print_gimple_stmt (dump_file, stmt, 0, 0); } + possibly_move_powi (stmt, oe1->op); + possibly_move_powi (stmt, oe2->op); } return; } @@ -2223,6 +2435,8 @@ rewrite_expr_tree (gimple stmt, unsigned int opindex, fprintf (dump_file, " into "); print_gimple_stmt (dump_file, stmt, 0, 0); } + + possibly_move_powi (stmt, oe->op); } /* Recurse on the LHS of the binary operator, which is guaranteed to be the non-leaf side. */ @@ -2396,6 +2610,9 @@ rewrite_expr_tree_parallel (gimple stmt, int width, fprintf (dump_file, " into "); print_gimple_stmt (dump_file, stmts[i], 0, 0); } + + possibly_move_powi (stmts[i], op1); + possibly_move_powi (stmts[i], op2); } remove_visited_stmt_chain (last_rhs1); @@ -2564,6 +2781,75 @@ break_up_subtract (gimple stmt, gimple_stmt_iterator *gsip) update_stmt (stmt); } +/* Determine whether STMT is a builtin call that raises an SSA name + to an integer power and has only one use. If so, and this is early + reassociation and unsafe math optimizations are permitted, place + the SSA name in *BASE and the exponent in *EXPONENT, and return TRUE. + If any of these conditions does not hold, return FALSE. */ + +static bool +acceptable_pow_call (gimple stmt, tree *base, HOST_WIDE_INT *exponent) +{ + tree fndecl, arg1; + REAL_VALUE_TYPE c, cint; + + if (!first_pass_instance + || !flag_unsafe_math_optimizations + || !is_gimple_call (stmt) + || !has_single_use (gimple_call_lhs (stmt))) + return false; + + fndecl = gimple_call_fndecl (stmt); + + if (!fndecl + || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) + return false; + + switch (DECL_FUNCTION_CODE (fndecl)) + { + CASE_FLT_FN (BUILT_IN_POW): + *base = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + + if (TREE_CODE (arg1) != REAL_CST) + return false; + + c = TREE_REAL_CST (arg1); + + if (REAL_EXP (&c) > HOST_BITS_PER_WIDE_INT) + return false; + + *exponent = real_to_integer (&c); + real_from_integer (&cint, VOIDmode, *exponent, + *exponent < 0 ? -1 : 0, 0); + if (!real_identical (&c, &cint)) + return false; + + break; + + CASE_FLT_FN (BUILT_IN_POWI): + *base = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + + if (!host_integerp (arg1, 0)) + return false; + + *exponent = TREE_INT_CST_LOW (arg1); + break; + + default: + return false; + } + + /* Expanding negative exponents is generally unproductive, so we don't + complicate matters with those. Exponents of zero and one should + have been handled by expression folding. */ + if (*exponent < 2 || TREE_CODE (*base) != SSA_NAME) + return false; + + return true; +} + /* Recursively linearize a binary expression that is the RHS of STMT. Place the operands of the expression tree in the vector named OPS. */ @@ -2573,11 +2859,13 @@ linearize_expr_tree (VEC(operand_entry_t, heap) **ops, gimple stmt, { tree binlhs = gimple_assign_rhs1 (stmt); tree binrhs = gimple_assign_rhs2 (stmt); - gimple binlhsdef, binrhsdef; + gimple binlhsdef = NULL, binrhsdef = NULL; bool binlhsisreassoc = false; bool binrhsisreassoc = false; enum tree_code rhscode = gimple_assign_rhs_code (stmt); struct loop *loop = loop_containing_stmt (stmt); + tree base = NULL_TREE; + HOST_WIDE_INT exponent = 0; if (set_visited) gimple_set_visited (stmt, true); @@ -2615,8 +2903,26 @@ linearize_expr_tree (VEC(operand_entry_t, heap) **ops, gimple stmt, if (!binrhsisreassoc) { - add_to_ops_vec (ops, binrhs); - add_to_ops_vec (ops, binlhs); + if (rhscode == MULT_EXPR + && TREE_CODE (binrhs) == SSA_NAME + && acceptable_pow_call (binrhsdef, &base, &exponent)) + { + add_repeat_to_ops_vec (ops, base, exponent); + gimple_set_visited (binrhsdef, true); + } + else + add_to_ops_vec (ops, binrhs); + + if (rhscode == MULT_EXPR + && TREE_CODE (binlhs) == SSA_NAME + && acceptable_pow_call (binlhsdef, &base, &exponent)) + { + add_repeat_to_ops_vec (ops, base, exponent); + gimple_set_visited (binlhsdef, true); + } + else + add_to_ops_vec (ops, binlhs); + return; } @@ -2655,7 +2961,16 @@ linearize_expr_tree (VEC(operand_entry_t, heap) **ops, gimple stmt, rhscode, loop)); linearize_expr_tree (ops, SSA_NAME_DEF_STMT (binlhs), is_associative, set_visited); - add_to_ops_vec (ops, binrhs); + + if (rhscode == MULT_EXPR + && TREE_CODE (binrhs) == SSA_NAME + && acceptable_pow_call (SSA_NAME_DEF_STMT (binrhs), &base, &exponent)) + { + add_repeat_to_ops_vec (ops, base, exponent); + gimple_set_visited (SSA_NAME_DEF_STMT (binrhs), true); + } + else + add_to_ops_vec (ops, binrhs); } /* Repropagate the negates back into subtracts, since no other pass @@ -2815,6 +3130,350 @@ break_up_subtract_bb (basic_block bb) break_up_subtract_bb (son); } +/* Used for repeated factor analysis. */ +struct repeat_factor_d +{ + /* An SSA name that occurs in a multiply chain. */ + tree factor; + + /* Cached rank of the factor. */ + unsigned rank; + + /* Number of occurrences of the factor in the chain. */ + HOST_WIDE_INT count; + + /* An SSA name representing the product of this factor and + all factors appearing later in the repeated factor vector. */ + tree repr; +}; + +typedef struct repeat_factor_d repeat_factor, *repeat_factor_t; +typedef const struct repeat_factor_d *const_repeat_factor_t; + +DEF_VEC_O (repeat_factor); +DEF_VEC_ALLOC_O (repeat_factor, heap); + +static VEC (repeat_factor, heap) *repeat_factor_vec; + +/* Used for sorting the repeat factor vector. Sort primarily by + ascending occurrence count, secondarily by descending rank. */ + +static int +compare_repeat_factors (const void *x1, const void *x2) +{ + const_repeat_factor_t rf1 = (const_repeat_factor_t) x1; + const_repeat_factor_t rf2 = (const_repeat_factor_t) x2; + + if (rf1->count != rf2->count) + return rf1->count - rf2->count; + + return rf2->rank - rf1->rank; +} + +/* Get a new SSA name for register variable *TARGET of type TYPE. + If *TARGET is null or incompatible with TYPE, create the variable + first. */ + +static tree +get_reassoc_pow_ssa_name (tree *target, tree type) +{ + if (!*target || !types_compatible_p (type, TREE_TYPE (*target))) + { + *target = create_tmp_reg (type, "reassocpow"); + add_referenced_var (*target); + } + + return make_ssa_name (*target, NULL); +} + +/* Look for repeated operands in OPS in the multiply tree rooted at + STMT. Replace them with an optimal sequence of multiplies and powi + builtin calls, and remove the used operands from OPS. Push new + SSA names onto OPS that represent the introduced multiplies and + builtin calls. */ + +static void +attempt_builtin_powi (gimple stmt, VEC(operand_entry_t, heap) **ops, + tree *target) +{ + unsigned i, j, vec_len; + int ii; + operand_entry_t oe; + repeat_factor_t rf1, rf2; + repeat_factor rfnew; + tree target_ssa, iter_result; + tree type = TREE_TYPE (gimple_get_lhs (stmt)); + tree powi_fndecl = mathfn_built_in (type, BUILT_IN_POWI); + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + gimple mul_stmt, pow_stmt; + + /* Nothing to do if BUILT_IN_POWI doesn't exist for this type and + target. */ + if (!powi_fndecl) + return; + + /* Allocate the repeated factor vector. */ + repeat_factor_vec = VEC_alloc (repeat_factor, heap, 10); + + /* Scan the OPS vector for all SSA names in the product and build + up a vector of occurrence counts for each factor. */ + FOR_EACH_VEC_ELT (operand_entry_t, *ops, i, oe) + { + if (TREE_CODE (oe->op) == SSA_NAME) + { + FOR_EACH_VEC_ELT (repeat_factor, repeat_factor_vec, j, rf1) + { + if (rf1->factor == oe->op) + { + rf1->count += oe->count; + break; + } + } + + if (j >= VEC_length (repeat_factor, repeat_factor_vec)) + { + rfnew.factor = oe->op; + rfnew.rank = oe->rank; + rfnew.count = oe->count; + rfnew.repr = NULL_TREE; + VEC_safe_push (repeat_factor, heap, repeat_factor_vec, &rfnew); + } + } + } + + /* Sort the repeated factor vector by (a) increasing occurrence count, + and (b) decreasing rank. */ + VEC_qsort (repeat_factor, repeat_factor_vec, compare_repeat_factors); + + /* It is generally best to combine as many base factors as possible + into a product before applying __builtin_powi to the result. + However, the sort order chosen for the repeated factor vector + allows us to cache partial results for the product of the base + factors for subsequent use. When we already have a cached partial + result from a previous iteration, it is best to make use of it + before looking for another __builtin_pow opportunity. + + As an example, consider x * x * y * y * y * z * z * z * z. + We want to first compose the product x * y * z, raise it to the + second power, then multiply this by y * z, and finally multiply + by z. This can be done in 5 multiplies provided we cache y * z + for use in both expressions: + + t1 = y * z + t2 = t1 * x + t3 = t2 * t2 + t4 = t1 * t3 + result = t4 * z + + If we instead ignored the cached y * z and first multiplied by + the __builtin_pow opportunity z * z, we would get the inferior: + + t1 = y * z + t2 = t1 * x + t3 = t2 * t2 + t4 = z * z + t5 = t3 * t4 + result = t5 * y */ + + vec_len = VEC_length (repeat_factor, repeat_factor_vec); + + /* Repeatedly look for opportunities to create a builtin_powi call. */ + while (true) + { + HOST_WIDE_INT power; + + /* First look for the largest cached product of factors from + preceding iterations. If found, create a builtin_powi for + it if the minimum occurrence count for its factors is at + least 2, or just use this cached product as our next + multiplicand if the minimum occurrence count is 1. */ + FOR_EACH_VEC_ELT (repeat_factor, repeat_factor_vec, j, rf1) + { + if (rf1->repr && rf1->count > 0) + break; + } + + if (j < vec_len) + { + power = rf1->count; + + if (power == 1) + { + iter_result = rf1->repr; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + unsigned elt; + repeat_factor_t rf; + fputs ("Multiplying by cached product ", dump_file); + for (elt = j; elt < vec_len; elt++) + { + rf = VEC_index (repeat_factor, repeat_factor_vec, elt); + print_generic_expr (dump_file, rf->factor, 0); + if (elt < vec_len - 1) + fputs (" * ", dump_file); + } + fputs ("\n", dump_file); + } + } + else + { + iter_result = get_reassoc_pow_ssa_name (target, type); + pow_stmt = gimple_build_call (powi_fndecl, 2, rf1->repr, + build_int_cst (integer_type_node, + power)); + gimple_call_set_lhs (pow_stmt, iter_result); + gimple_set_location (pow_stmt, gimple_location (stmt)); + /* Temporarily place the call; we will move it to the + correct place during rewrite_expr. */ + gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + unsigned elt; + repeat_factor_t rf; + fputs ("Building __builtin_pow call for cached product (", + dump_file); + for (elt = j; elt < vec_len; elt++) + { + rf = VEC_index (repeat_factor, repeat_factor_vec, elt); + print_generic_expr (dump_file, rf->factor, 0); + if (elt < vec_len - 1) + fputs (" * ", dump_file); + } + fprintf (dump_file, ")^"HOST_WIDE_INT_PRINT_DEC"\n", + power); + } + } + } + else + { + /* Otherwise, find the first factor in the repeated factor + vector whose occurrence count is at least 2. If no such + factor exists, there are no builtin_powi opportunities + remaining. */ + FOR_EACH_VEC_ELT (repeat_factor, repeat_factor_vec, j, rf1) + { + if (rf1->count >= 2) + break; + } + + if (j >= vec_len) + break; + + power = rf1->count; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + unsigned elt; + repeat_factor_t rf; + fputs ("Building __builtin_pow call for (", dump_file); + for (elt = j; elt < vec_len; elt++) + { + rf = VEC_index (repeat_factor, repeat_factor_vec, elt); + print_generic_expr (dump_file, rf->factor, 0); + if (elt < vec_len - 1) + fputs (" * ", dump_file); + } + fprintf (dump_file, ")^"HOST_WIDE_INT_PRINT_DEC"\n", power); + } + + reassociate_stats.pows_created++; + + /* Visit each element of the vector in reverse order (so that + high-occurrence elements are visited first, and within the + same occurrence count, lower-ranked elements are visited + first). Form a linear product of all elements in this order + whose occurrencce count is at least that of element J. + Record the SSA name representing the product of each element + with all subsequent elements in the vector. */ + if (j == vec_len - 1) + rf1->repr = rf1->factor; + else + { + for (ii = vec_len - 2; ii >= (int)j; ii--) + { + tree op1, op2; + + rf1 = VEC_index (repeat_factor, repeat_factor_vec, ii); + rf2 = VEC_index (repeat_factor, repeat_factor_vec, ii + 1); + + /* Init the last factor's representative to be itself. */ + if (!rf2->repr) + rf2->repr = rf2->factor; + + op1 = rf1->factor; + op2 = rf2->repr; + + target_ssa = get_reassoc_pow_ssa_name (target, type); + mul_stmt = gimple_build_assign_with_ops (MULT_EXPR, + target_ssa, + op1, op2); + gimple_set_location (mul_stmt, gimple_location (stmt)); + gsi_insert_before (&gsi, mul_stmt, GSI_SAME_STMT); + rf1->repr = target_ssa; + + /* Don't reprocess the multiply we just introduced. */ + gimple_set_visited (mul_stmt, true); + } + } + + /* Form a call to __builtin_powi for the maximum product + just formed, raised to the power obtained earlier. */ + rf1 = VEC_index (repeat_factor, repeat_factor_vec, j); + iter_result = get_reassoc_pow_ssa_name (target, type); + pow_stmt = gimple_build_call (powi_fndecl, 2, rf1->repr, + build_int_cst (integer_type_node, + power)); + gimple_call_set_lhs (pow_stmt, iter_result); + gimple_set_location (pow_stmt, gimple_location (stmt)); + gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT); + } + + /* Append the result of this iteration to the ops vector. */ + add_to_ops_vec (ops, iter_result); + + /* Decrement the occurrence count of each element in the product + by the count found above, and remove this many copies of each + factor from OPS. */ + for (i = j; i < vec_len; i++) + { + unsigned k = power; + unsigned n; + + rf1 = VEC_index (repeat_factor, repeat_factor_vec, i); + rf1->count -= power; + + FOR_EACH_VEC_ELT_REVERSE (operand_entry_t, *ops, n, oe) + { + if (oe->op == rf1->factor) + { + if (oe->count <= k) + { + VEC_ordered_remove (operand_entry_t, *ops, n); + k -= oe->count; + + if (k == 0) + break; + } + else + { + oe->count -= k; + break; + } + } + } + } + } + + /* At this point all elements in the repeated factor vector have a + remaining occurrence count of 0 or 1, and those with a count of 1 + don't have cached representatives. Re-sort the ops vector and + clean up. */ + VEC_qsort (operand_entry_t, *ops, sort_by_operand_rank); + VEC_free (repeat_factor, heap, repeat_factor_vec); +} + /* Reassociate expressions in basic block BB and its post-dominator as children. */ @@ -2823,6 +3482,7 @@ reassociate_bb (basic_block bb) { gimple_stmt_iterator gsi; basic_block son; + tree target = NULL_TREE; for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) { @@ -2904,6 +3564,11 @@ reassociate_bb (basic_block bb) if (rhs_code == BIT_IOR_EXPR || rhs_code == BIT_AND_EXPR) optimize_range_tests (rhs_code, &ops); + if (first_pass_instance + && rhs_code == MULT_EXPR + && flag_unsafe_math_optimizations) + attempt_builtin_powi (stmt, &ops, &target); + if (VEC_length (operand_entry_t, ops) == 1) { if (dump_file && (dump_flags & TDF_DETAILS)) @@ -3054,6 +3719,10 @@ fini_reassoc (void) reassociate_stats.ops_eliminated); statistics_counter_event (cfun, "Statements rewritten", reassociate_stats.rewritten); + statistics_counter_event (cfun, "Built-in pow[i] calls encountered", + reassociate_stats.pows_encountered); + statistics_counter_event (cfun, "Built-in powi calls created", + reassociate_stats.pows_created); pointer_map_destroy (operand_rank); free_alloc_pool (operand_entry_pool); diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index b65f5aac02c..09642a03f42 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -2759,7 +2759,7 @@ get_constraint_for_ssa_var (tree t, VEC(ce_s, heap) **results, bool address_p) if (node && node->alias) { node = varpool_variable_node (node, NULL); - t = node->decl; + t = node->symbol.decl; } } @@ -6839,7 +6839,7 @@ static bool associate_varinfo_to_alias (struct cgraph_node *node, void *data) { if (node->alias || node->thunk.thunk_p) - insert_vi_for_tree (node->decl, (varinfo_t)data); + insert_vi_for_tree (node->symbol.decl, (varinfo_t)data); return false; } @@ -6857,12 +6857,12 @@ ipa_pta_execute (void) if (dump_file && (dump_flags & TDF_DETAILS)) { - dump_cgraph (dump_file); + dump_symtab (dump_file); fprintf (dump_file, "\n"); } /* Build the constraints. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { varinfo_t vi; /* Nodes without a body are not interesting. Especially do not @@ -6873,18 +6873,18 @@ ipa_pta_execute (void) gcc_assert (!node->clone_of); - vi = create_function_info_for (node->decl, - alias_get_name (node->decl)); + vi = create_function_info_for (node->symbol.decl, + alias_get_name (node->symbol.decl)); cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, true); } /* Create constraints for global variables and their initializers. */ - for (var = varpool_nodes; var; var = var->next) + FOR_EACH_VARIABLE (var) { if (var->alias) continue; - get_vi_for_tree (var->decl); + get_vi_for_tree (var->symbol.decl); } if (dump_file) @@ -6896,7 +6896,7 @@ ipa_pta_execute (void) } from = VEC_length (constraint_t, constraints); - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { struct function *func; basic_block bb; @@ -6910,33 +6910,34 @@ ipa_pta_execute (void) { fprintf (dump_file, "Generating constraints for %s", cgraph_node_name (node)); - if (DECL_ASSEMBLER_NAME_SET_P (node->decl)) + if (DECL_ASSEMBLER_NAME_SET_P (node->symbol.decl)) fprintf (dump_file, " (%s)", - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))); + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (node->symbol.decl))); fprintf (dump_file, "\n"); } - func = DECL_STRUCT_FUNCTION (node->decl); + func = DECL_STRUCT_FUNCTION (node->symbol.decl); old_func_decl = current_function_decl; push_cfun (func); - current_function_decl = node->decl; + current_function_decl = node->symbol.decl; /* For externally visible or attribute used annotated functions use local constraints for their arguments. For local functions we see all callers and thus do not need initial constraints for parameters. */ - if (node->reachable_from_other_partition - || node->local.externally_visible - || node->needed) + if (node->symbol.used_from_other_partition + || node->symbol.externally_visible + || node->symbol.force_output) { intra_create_variable_infos (); /* We also need to make function return values escape. Nothing escapes by returning from main though. */ - if (!MAIN_NAME_P (DECL_NAME (node->decl))) + if (!MAIN_NAME_P (DECL_NAME (node->symbol.decl))) { varinfo_t fi, rvi; - fi = lookup_vi_for_tree (node->decl); + fi = lookup_vi_for_tree (node->symbol.decl); rvi = first_vi_for_offset (fi, fi_result); if (rvi && rvi->offset == fi_result) { @@ -7003,7 +7004,7 @@ ipa_pta_execute (void) ipa_escaped_pt.ipa_escaped = 0; /* Assign the points-to sets to the SSA names in the unit. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { tree ptr; struct function *fn; @@ -7017,7 +7018,7 @@ ipa_pta_execute (void) if (!cgraph_function_with_gimple_body_p (node)) continue; - fn = DECL_STRUCT_FUNCTION (node->decl); + fn = DECL_STRUCT_FUNCTION (node->symbol.decl); /* Compute the points-to sets for pointer SSA_NAMEs. */ FOR_EACH_VEC_ELT (tree, fn->gimple_df->ssa_names, i, ptr) @@ -7028,7 +7029,7 @@ ipa_pta_execute (void) } /* Compute the call-use and call-clobber sets for all direct calls. */ - fi = lookup_vi_for_tree (node->decl); + fi = lookup_vi_for_tree (node->symbol.decl); gcc_assert (fi->is_fn_info); find_what_var_points_to (first_vi_for_offset (fi, fi_clobbers), &clobbers); diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c index 1f46b10a64e..210cb134624 100644 --- a/gcc/tree-ssa-tail-merge.c +++ b/gcc/tree-ssa-tail-merge.c @@ -269,6 +269,67 @@ struct aux_bb_info #define BB_VOP_AT_EXIT(bb) (((struct aux_bb_info *)bb->aux)->vop_at_exit) #define BB_DEP_BB(bb) (((struct aux_bb_info *)bb->aux)->dep_bb) +/* Returns true if the only effect a statement STMT has, is to define locally + used SSA_NAMEs. */ + +static bool +stmt_local_def (gimple stmt) +{ + basic_block bb, def_bb; + imm_use_iterator iter; + use_operand_p use_p; + tree val; + def_operand_p def_p; + + if (gimple_has_side_effects (stmt)) + return false; + + def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF); + if (def_p == NULL) + return false; + + val = DEF_FROM_PTR (def_p); + if (val == NULL_TREE || TREE_CODE (val) != SSA_NAME) + return false; + + def_bb = gimple_bb (stmt); + + FOR_EACH_IMM_USE_FAST (use_p, iter, val) + { + if (is_gimple_debug (USE_STMT (use_p))) + continue; + bb = gimple_bb (USE_STMT (use_p)); + if (bb == def_bb) + continue; + + if (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI + && EDGE_PRED (bb, PHI_ARG_INDEX_FROM_USE (use_p))->src == def_bb) + continue; + + return false; + } + + return true; +} + +/* Let GSI skip forwards over local defs. */ + +static void +gsi_advance_fw_nondebug_nonlocal (gimple_stmt_iterator *gsi) +{ + gimple stmt; + + while (true) + { + if (gsi_end_p (*gsi)) + return; + stmt = gsi_stmt (*gsi); + if (!stmt_local_def (stmt)) + return; + gsi_next_nondebug (gsi); + } +} + /* VAL1 and VAL2 are either: - uses in BB1 and BB2, or - phi alternatives for BB1 and BB2. @@ -352,39 +413,6 @@ stmt_update_dep_bb (gimple stmt) update_dep_bb (gimple_bb (stmt), USE_FROM_PTR (use)); } -/* Returns whether VAL is used in the same bb as in which it is defined, or - in the phi of a successor bb. */ - -static bool -local_def (tree val) -{ - gimple stmt, def_stmt; - basic_block bb, def_bb; - imm_use_iterator iter; - bool res; - - if (TREE_CODE (val) != SSA_NAME) - return false; - def_stmt = SSA_NAME_DEF_STMT (val); - def_bb = gimple_bb (def_stmt); - - res = true; - FOR_EACH_IMM_USE_STMT (stmt, iter, val) - { - if (is_gimple_debug (stmt)) - continue; - bb = gimple_bb (stmt); - if (bb == def_bb) - continue; - if (gimple_code (stmt) == GIMPLE_PHI - && find_edge (def_bb, bb)) - continue; - res = false; - BREAK_FROM_IMM_USE_STMT (iter); - } - return res; -} - /* Calculates hash value for same_succ VE. */ static hashval_t @@ -408,8 +436,7 @@ same_succ_hash (const void *ve) { stmt = gsi_stmt (gsi); stmt_update_dep_bb (stmt); - if (is_gimple_assign (stmt) && local_def (gimple_get_lhs (stmt)) - && !gimple_has_side_effects (stmt)) + if (stmt_local_def (stmt)) continue; size++; @@ -525,6 +552,8 @@ same_succ_equal (const void *ve1, const void *ve2) gsi1 = gsi_start_nondebug_bb (bb1); gsi2 = gsi_start_nondebug_bb (bb2); + gsi_advance_fw_nondebug_nonlocal (&gsi1); + gsi_advance_fw_nondebug_nonlocal (&gsi2); while (!(gsi_end_p (gsi1) || gsi_end_p (gsi2))) { s1 = gsi_stmt (gsi1); @@ -535,6 +564,8 @@ same_succ_equal (const void *ve1, const void *ve2) return 0; gsi_next_nondebug (&gsi1); gsi_next_nondebug (&gsi2); + gsi_advance_fw_nondebug_nonlocal (&gsi1); + gsi_advance_fw_nondebug_nonlocal (&gsi2); } return 1; @@ -1123,20 +1154,32 @@ gimple_equal_p (same_succ same_succ, gimple s1, gimple s2) } } -/* Let GSI skip backwards over local defs. */ +/* Let GSI skip backwards over local defs. Return the earliest vuse in VUSE. + Return true in VUSE_ESCAPED if the vuse influenced a SSA_OP_DEF of one of the + processed statements. */ static void -gsi_advance_bw_nondebug_nonlocal (gimple_stmt_iterator *gsi) +gsi_advance_bw_nondebug_nonlocal (gimple_stmt_iterator *gsi, tree *vuse, + bool *vuse_escaped) { gimple stmt; + tree lvuse; while (true) { if (gsi_end_p (*gsi)) return; stmt = gsi_stmt (*gsi); - if (!(is_gimple_assign (stmt) && local_def (gimple_get_lhs (stmt)) - && !gimple_has_side_effects (stmt))) + + lvuse = gimple_vuse (stmt); + if (lvuse != NULL_TREE) + { + *vuse = lvuse; + if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_DEF)) + *vuse_escaped = true; + } + + if (!stmt_local_def (stmt)) return; gsi_prev_nondebug (gsi); } @@ -1150,9 +1193,11 @@ find_duplicate (same_succ same_succ, basic_block bb1, basic_block bb2) { gimple_stmt_iterator gsi1 = gsi_last_nondebug_bb (bb1); gimple_stmt_iterator gsi2 = gsi_last_nondebug_bb (bb2); + tree vuse1 = NULL_TREE, vuse2 = NULL_TREE; + bool vuse_escaped = false; - gsi_advance_bw_nondebug_nonlocal (&gsi1); - gsi_advance_bw_nondebug_nonlocal (&gsi2); + gsi_advance_bw_nondebug_nonlocal (&gsi1, &vuse1, &vuse_escaped); + gsi_advance_bw_nondebug_nonlocal (&gsi2, &vuse2, &vuse_escaped); while (!gsi_end_p (gsi1) && !gsi_end_p (gsi2)) { @@ -1161,13 +1206,20 @@ find_duplicate (same_succ same_succ, basic_block bb1, basic_block bb2) gsi_prev_nondebug (&gsi1); gsi_prev_nondebug (&gsi2); - gsi_advance_bw_nondebug_nonlocal (&gsi1); - gsi_advance_bw_nondebug_nonlocal (&gsi2); + gsi_advance_bw_nondebug_nonlocal (&gsi1, &vuse1, &vuse_escaped); + gsi_advance_bw_nondebug_nonlocal (&gsi2, &vuse2, &vuse_escaped); } if (!(gsi_end_p (gsi1) && gsi_end_p (gsi2))) return; + /* If the incoming vuses are not the same, and the vuse escaped into an + SSA_OP_DEF, then merging the 2 blocks will change the value of the def, + which potentially means the semantics of one of the blocks will be changed. + TODO: make this check more precise. */ + if (vuse_escaped && vuse1 != vuse2) + return; + if (dump_file) fprintf (dump_file, "find_duplicates: <bb %d> duplicate of <bb %d>\n", bb1->index, bb2->index); @@ -1592,8 +1644,7 @@ tail_merge_optimize (unsigned int todo) dump_function_to_file (current_function_decl, dump_file, dump_flags); } - todo |= (TODO_verify_ssa | TODO_verify_stmts | TODO_verify_flow - | TODO_dump_func); + todo |= (TODO_verify_ssa | TODO_verify_stmts | TODO_verify_flow); mark_sym_for_renaming (gimple_vop (cfun)); } diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c index 687eee0485a..018092a7a3a 100644 --- a/gcc/tree-ssa-threadupdate.c +++ b/gcc/tree-ssa-threadupdate.c @@ -661,6 +661,13 @@ thread_block (basic_block bb, bool noloop_only) /* We do not update dominance info. */ free_dominance_info (CDI_DOMINATORS); + /* We know we only thread through the loop header to loop exits. + Let the basic block duplication hook know we are not creating + a multiple entry loop. */ + if (noloop_only + && bb == bb->loop_father->header) + set_loop_copy (bb->loop_father, loop_outer (bb->loop_father)); + /* Now create duplicates of BB. Note that for a block with a high outgoing degree we can waste @@ -692,6 +699,10 @@ thread_block (basic_block bb, bool noloop_only) htab_delete (redirection_data); redirection_data = NULL; + if (noloop_only + && bb == bb->loop_father->header) + set_loop_copy (bb->loop_father, NULL); + /* Indicate to our caller whether or not any jumps were threaded. */ return local_info.jumps_threaded; } diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 08f908f6a6c..f399833c546 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -1120,6 +1120,35 @@ init_tree_ssa (struct function *fn) init_phinodes (); } +/* Do the actions required to initialize internal data structures used + in tree-ssa optimization passes. */ + +static unsigned int +execute_init_datastructures (void) +{ + /* Allocate hash tables, arrays and other structures. */ + init_tree_ssa (cfun); + return 0; +} + +struct gimple_opt_pass pass_init_datastructures = +{ + { + GIMPLE_PASS, + "*init_datastructures", /* name */ + NULL, /* gate */ + execute_init_datastructures, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_NONE, /* tv_id */ + PROP_cfg, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + } +}; /* Deallocate memory associated with SSA data structures for FNDECL. */ diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c index 97c78cdf194..a38fb470b1f 100644 --- a/gcc/tree-streamer-in.c +++ b/gcc/tree-streamer-in.c @@ -476,10 +476,7 @@ streamer_alloc_tree (struct lto_input_block *ib, struct data_in *data_in, else if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) { HOST_WIDE_INT len = streamer_read_hwi (ib); - result = ggc_alloc_zone_cleared_tree_node ((len - 1) * sizeof (tree) - + sizeof (struct tree_vector), - &tree_zone); - TREE_SET_CODE (result, VECTOR_CST); + result = make_vector (len); } else if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) { diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c index 4fb3e8a6971..95c8bd805e1 100644 --- a/gcc/tree-switch-conversion.c +++ b/gcc/tree-switch-conversion.c @@ -24,8 +24,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA Switch initialization conversion The following pass changes simple initializations of scalars in a switch -statement into initializations from a static array. Obviously, the values must -be constant and known at compile time and a default branch must be +statement into initializations from a static array. Obviously, the values +must be constant and known at compile time and a default branch must be provided. For example, the following code: int a,b; @@ -162,16 +162,12 @@ struct switch_conv_info basic_block bit_test_bb[2]; }; -/* Global pass info. */ -static struct switch_conv_info info; - - /* Checks whether the range given by individual case statements of the SWTCH switch statement isn't too big and whether the number of branches actually satisfies the size of the new array. */ static bool -check_range (gimple swtch) +check_range (gimple swtch, struct switch_conv_info *info) { tree min_case, max_case; unsigned int branch_num = gimple_switch_num_labels (swtch); @@ -181,7 +177,7 @@ check_range (gimple swtch) is a default label which is the first in the vector. */ min_case = gimple_switch_label (swtch, 1); - info.range_min = CASE_LOW (min_case); + info->range_min = CASE_LOW (min_case); gcc_assert (branch_num > 1); gcc_assert (CASE_LOW (gimple_switch_label (swtch, 0)) == NULL_TREE); @@ -191,22 +187,22 @@ check_range (gimple swtch) else range_max = CASE_LOW (max_case); - gcc_assert (info.range_min); + gcc_assert (info->range_min); gcc_assert (range_max); - info.range_size = int_const_binop (MINUS_EXPR, range_max, info.range_min); + info->range_size = int_const_binop (MINUS_EXPR, range_max, info->range_min); - gcc_assert (info.range_size); - if (!host_integerp (info.range_size, 1)) + gcc_assert (info->range_size); + if (!host_integerp (info->range_size, 1)) { - info.reason = "index range way too large or otherwise unusable.\n"; + info->reason = "index range way too large or otherwise unusable"; return false; } - if ((unsigned HOST_WIDE_INT) tree_low_cst (info.range_size, 1) + if ((unsigned HOST_WIDE_INT) tree_low_cst (info->range_size, 1) > ((unsigned) branch_num * SWITCH_CONVERSION_BRANCH_RATIO)) { - info.reason = "the maximum range-branch ratio exceeded.\n"; + info->reason = "the maximum range-branch ratio exceeded"; return false; } @@ -219,7 +215,7 @@ check_range (gimple swtch) and returns true. Otherwise returns false. */ static bool -check_process_case (tree cs) +check_process_case (tree cs, struct switch_conv_info *info) { tree ldecl; basic_block label_bb, following_bb; @@ -228,48 +224,48 @@ check_process_case (tree cs) ldecl = CASE_LABEL (cs); label_bb = label_to_block (ldecl); - e = find_edge (info.switch_bb, label_bb); + e = find_edge (info->switch_bb, label_bb); gcc_assert (e); if (CASE_LOW (cs) == NULL_TREE) { /* Default branch. */ - info.default_prob = e->probability; - info.default_count = e->count; + info->default_prob = e->probability; + info->default_count = e->count; } else { int i; - info.other_count += e->count; + info->other_count += e->count; for (i = 0; i < 2; i++) - if (info.bit_test_bb[i] == label_bb) + if (info->bit_test_bb[i] == label_bb) break; - else if (info.bit_test_bb[i] == NULL) + else if (info->bit_test_bb[i] == NULL) { - info.bit_test_bb[i] = label_bb; - info.bit_test_uniq++; + info->bit_test_bb[i] = label_bb; + info->bit_test_uniq++; break; } if (i == 2) - info.bit_test_uniq = 3; + info->bit_test_uniq = 3; if (CASE_HIGH (cs) != NULL_TREE && ! tree_int_cst_equal (CASE_LOW (cs), CASE_HIGH (cs))) - info.bit_test_count += 2; + info->bit_test_count += 2; else - info.bit_test_count++; + info->bit_test_count++; } if (!label_bb) { - info.reason = " Bad case - cs BB label is NULL\n"; + info->reason = "bad case - cs BB label is NULL"; return false; } if (!single_pred_p (label_bb)) { - if (info.final_bb && info.final_bb != label_bb) + if (info->final_bb && info->final_bb != label_bb) { - info.reason = " Bad case - a non-final BB has two predecessors\n"; + info->reason = "bad case - a non-final BB has two predecessors"; return false; /* sth complex going on in this branch */ } @@ -279,7 +275,7 @@ check_process_case (tree cs) { if (!empty_block_p (label_bb)) { - info.reason = " Bad case - a non-final BB not empty\n"; + info->reason = "bad case - a non-final BB not empty"; return false; } @@ -287,11 +283,11 @@ check_process_case (tree cs) following_bb = single_succ (label_bb); } - if (!info.final_bb) - info.final_bb = following_bb; - else if (info.final_bb != following_bb) + if (!info->final_bb) + info->final_bb = following_bb; + else if (info->final_bb != following_bb) { - info.reason = " Bad case - different final BB\n"; + info->reason = "bad case - different final BB"; return false; /* the only successor is not common for all the branches */ } @@ -304,31 +300,31 @@ check_process_case (tree cs) phi nodes are OK, otherwise false. */ static bool -check_final_bb (void) +check_final_bb (struct switch_conv_info *info) { gimple_stmt_iterator gsi; - info.phi_count = 0; - for (gsi = gsi_start_phis (info.final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) + info->phi_count = 0; + for (gsi = gsi_start_phis (info->final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple phi = gsi_stmt (gsi); unsigned int i; - info.phi_count++; + info->phi_count++; for (i = 0; i < gimple_phi_num_args (phi); i++) { basic_block bb = gimple_phi_arg_edge (phi, i)->src; - if (bb == info.switch_bb - || (single_pred_p (bb) && single_pred (bb) == info.switch_bb)) + if (bb == info->switch_bb + || (single_pred_p (bb) && single_pred (bb) == info->switch_bb)) { tree reloc, val; val = gimple_phi_arg_def (phi, i); if (!is_gimple_ip_invariant (val)) { - info.reason = " Non-invariant value from a case\n"; + info->reason = "non-invariant value from a case"; return false; /* Non-invariant argument. */ } reloc = initializer_constant_valid_p (val, TREE_TYPE (val)); @@ -336,11 +332,11 @@ check_final_bb (void) || (!flag_pic && reloc == NULL_TREE)) { if (reloc) - info.reason - = " Value from a case would need runtime relocations\n"; + info->reason + = "value from a case would need runtime relocations"; else - info.reason - = " Value from a case is not a valid initializer\n"; + info->reason + = "value from a case is not a valid initializer"; return false; } } @@ -355,17 +351,17 @@ check_final_bb (void) vectors that will become constructors of new arrays. */ static void -create_temp_arrays (void) +create_temp_arrays (struct switch_conv_info *info) { int i; - info.default_values = XCNEWVEC (tree, info.phi_count * 3); - info.constructors = XCNEWVEC (VEC (constructor_elt, gc) *, info.phi_count); - info.target_inbound_names = info.default_values + info.phi_count; - info.target_outbound_names = info.target_inbound_names + info.phi_count; - for (i = 0; i < info.phi_count; i++) - info.constructors[i] - = VEC_alloc (constructor_elt, gc, tree_low_cst (info.range_size, 1) + 1); + info->default_values = XCNEWVEC (tree, info->phi_count * 3); + info->constructors = XCNEWVEC (VEC (constructor_elt, gc) *, info->phi_count); + info->target_inbound_names = info->default_values + info->phi_count; + info->target_outbound_names = info->target_inbound_names + info->phi_count; + for (i = 0; i < info->phi_count; i++) + info->constructors[i] + = VEC_alloc (constructor_elt, gc, tree_low_cst (info->range_size, 1) + 1); } /* Free the arrays created by create_temp_arrays(). The vectors that are @@ -373,17 +369,17 @@ create_temp_arrays (void) already become constructors and must be preserved. */ static void -free_temp_arrays (void) +free_temp_arrays (struct switch_conv_info *info) { - XDELETEVEC (info.constructors); - XDELETEVEC (info.default_values); + XDELETEVEC (info->constructors); + XDELETEVEC (info->default_values); } /* Populate the array of default values in the order of phi nodes. DEFAULT_CASE is the CASE_LABEL_EXPR for the default switch branch. */ static void -gather_default_values (tree default_case) +gather_default_values (tree default_case, struct switch_conv_info *info) { gimple_stmt_iterator gsi; basic_block bb = label_to_block (CASE_LABEL (default_case)); @@ -392,17 +388,17 @@ gather_default_values (tree default_case) gcc_assert (CASE_LOW (default_case) == NULL_TREE); - if (bb == info.final_bb) - e = find_edge (info.switch_bb, bb); + if (bb == info->final_bb) + e = find_edge (info->switch_bb, bb); else e = single_succ_edge (bb); - for (gsi = gsi_start_phis (info.final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) + for (gsi = gsi_start_phis (info->final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple phi = gsi_stmt (gsi); tree val = PHI_ARG_DEF_FROM_EDGE (phi, e); gcc_assert (val); - info.default_values[i++] = val; + info->default_values[i++] = val; } } @@ -411,10 +407,10 @@ gather_default_values (tree default_case) order of phi nodes. SWTCH is the switch statement being converted. */ static void -build_constructors (gimple swtch) +build_constructors (gimple swtch, struct switch_conv_info *info) { unsigned i, branch_num = gimple_switch_num_labels (swtch); - tree pos = info.range_min; + tree pos = info->range_min; for (i = 1; i < branch_num; i++) { @@ -425,8 +421,8 @@ build_constructors (gimple swtch) gimple_stmt_iterator gsi; int j; - if (bb == info.final_bb) - e = find_edge (info.switch_bb, bb); + if (bb == info->final_bb) + e = find_edge (info->switch_bb, bb); else e = single_succ_edge (bb); gcc_assert (e); @@ -434,15 +430,15 @@ build_constructors (gimple swtch) while (tree_int_cst_lt (pos, CASE_LOW (cs))) { int k; - for (k = 0; k < info.phi_count; k++) + for (k = 0; k < info->phi_count; k++) { constructor_elt *elt; elt = VEC_quick_push (constructor_elt, - info.constructors[k], NULL); + info->constructors[k], NULL); elt->index = int_const_binop (MINUS_EXPR, pos, - info.range_min); - elt->value = info.default_values[k]; + info->range_min); + elt->value = info->default_values[k]; } pos = int_const_binop (PLUS_EXPR, pos, integer_one_node); @@ -454,7 +450,7 @@ build_constructors (gimple swtch) high = CASE_HIGH (cs); else high = CASE_LOW (cs); - for (gsi = gsi_start_phis (info.final_bb); + for (gsi = gsi_start_phis (info->final_bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple phi = gsi_stmt (gsi); @@ -467,8 +463,8 @@ build_constructors (gimple swtch) constructor_elt *elt; elt = VEC_quick_push (constructor_elt, - info.constructors[j], NULL); - elt->index = int_const_binop (MINUS_EXPR, pos, info.range_min); + info->constructors[j], NULL); + elt->index = int_const_binop (MINUS_EXPR, pos, info->range_min); elt->value = val; pos = int_const_binop (PLUS_EXPR, pos, integer_one_node); @@ -505,9 +501,10 @@ constructor_contains_same_values_p (VEC (constructor_elt, gc) *vec) all the constants. */ static tree -array_value_type (gimple swtch, tree type, int num) +array_value_type (gimple swtch, tree type, int num, + struct switch_conv_info *info) { - unsigned int i, len = VEC_length (constructor_elt, info.constructors[num]); + unsigned int i, len = VEC_length (constructor_elt, info->constructors[num]); constructor_elt *elt; enum machine_mode mode; int sign = 0; @@ -523,7 +520,7 @@ array_value_type (gimple swtch, tree type, int num) if (len < (optimize_bb_for_size_p (gimple_bb (swtch)) ? 2 : 32)) return type; - FOR_EACH_VEC_ELT (constructor_elt, info.constructors[num], i, elt) + FOR_EACH_VEC_ELT (constructor_elt, info->constructors[num], i, elt) { double_int cst; @@ -585,37 +582,37 @@ array_value_type (gimple swtch, tree type, int num) static void build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi, - tree tidx) + tree tidx, struct switch_conv_info *info) { tree name, cst; gimple load; gimple_stmt_iterator gsi = gsi_for_stmt (swtch); location_t loc = gimple_location (swtch); - gcc_assert (info.default_values[num]); + gcc_assert (info->default_values[num]); name = make_ssa_name (SSA_NAME_VAR (PHI_RESULT (phi)), NULL); - info.target_inbound_names[num] = name; + info->target_inbound_names[num] = name; - cst = constructor_contains_same_values_p (info.constructors[num]); + cst = constructor_contains_same_values_p (info->constructors[num]); if (cst) load = gimple_build_assign (name, cst); else { tree array_type, ctor, decl, value_type, fetch, default_type; - default_type = TREE_TYPE (info.default_values[num]); - value_type = array_value_type (swtch, default_type, num); + default_type = TREE_TYPE (info->default_values[num]); + value_type = array_value_type (swtch, default_type, num, info); array_type = build_array_type (value_type, arr_index_type); if (default_type != value_type) { unsigned int i; constructor_elt *elt; - FOR_EACH_VEC_ELT (constructor_elt, info.constructors[num], i, elt) + FOR_EACH_VEC_ELT (constructor_elt, info->constructors[num], i, elt) elt->value = fold_convert (value_type, elt->value); } - ctor = build_constructor (array_type, info.constructors[num]); + ctor = build_constructor (array_type, info->constructors[num]); TREE_CONSTANT (ctor) = true; TREE_STATIC (ctor) = true; @@ -628,7 +625,6 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi, TREE_CONSTANT (decl) = 1; TREE_READONLY (decl) = 1; add_referenced_var (decl); - varpool_mark_needed_node (varpool_node (decl)); varpool_finalize_decl (decl); fetch = build4 (ARRAY_REF, value_type, decl, tidx, NULL_TREE, @@ -645,7 +641,7 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi, SSA_NAME_DEF_STMT (name) = load; gsi_insert_before (&gsi, load, GSI_SAME_STMT); update_stmt (load); - info.arr_ref_last = load; + info->arr_ref_last = load; } /* Builds and initializes static arrays initialized with values gathered from @@ -653,7 +649,7 @@ build_one_array (gimple swtch, int num, tree arr_index_type, gimple phi, them. */ static void -build_arrays (gimple swtch) +build_arrays (gimple swtch, struct switch_conv_info *info) { tree arr_index_type; tree tidx, sub, tmp, utype; @@ -665,19 +661,19 @@ build_arrays (gimple swtch) gsi = gsi_for_stmt (swtch); /* Make sure we do not generate arithmetics in a subrange. */ - utype = TREE_TYPE (info.index_expr); + utype = TREE_TYPE (info->index_expr); if (TREE_TYPE (utype)) utype = lang_hooks.types.type_for_mode (TYPE_MODE (TREE_TYPE (utype)), 1); else utype = lang_hooks.types.type_for_mode (TYPE_MODE (utype), 1); - arr_index_type = build_index_type (info.range_size); + arr_index_type = build_index_type (info->range_size); tmp = create_tmp_var (utype, "csui"); add_referenced_var (tmp); tidx = make_ssa_name (tmp, NULL); sub = fold_build2_loc (loc, MINUS_EXPR, utype, - fold_convert_loc (loc, utype, info.index_expr), - fold_convert_loc (loc, utype, info.range_min)); + fold_convert_loc (loc, utype, info->index_expr), + fold_convert_loc (loc, utype, info->range_min)); sub = force_gimple_operand_gsi (&gsi, sub, false, NULL, true, GSI_SAME_STMT); stmt = gimple_build_assign (tidx, sub); @@ -685,29 +681,29 @@ build_arrays (gimple swtch) gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); update_stmt (stmt); - info.arr_ref_first = stmt; + info->arr_ref_first = stmt; - for (gsi = gsi_start_phis (info.final_bb), i = 0; + for (gsi = gsi_start_phis (info->final_bb), i = 0; !gsi_end_p (gsi); gsi_next (&gsi), i++) - build_one_array (swtch, i, arr_index_type, gsi_stmt (gsi), tidx); + build_one_array (swtch, i, arr_index_type, gsi_stmt (gsi), tidx, info); } /* Generates and appropriately inserts loads of default values at the position given by BSI. Returns the last inserted statement. */ static gimple -gen_def_assigns (gimple_stmt_iterator *gsi) +gen_def_assigns (gimple_stmt_iterator *gsi, struct switch_conv_info *info) { int i; gimple assign = NULL; - for (i = 0; i < info.phi_count; i++) + for (i = 0; i < info->phi_count; i++) { tree name - = make_ssa_name (SSA_NAME_VAR (info.target_inbound_names[i]), NULL); + = make_ssa_name (SSA_NAME_VAR (info->target_inbound_names[i]), NULL); - info.target_outbound_names[i] = name; - assign = gimple_build_assign (name, info.default_values[i]); + info->target_outbound_names[i] = name; + assign = gimple_build_assign (name, info->default_values[i]); SSA_NAME_DEF_STMT (name) = assign; gsi_insert_before (gsi, assign, GSI_SAME_STMT); update_stmt (assign); @@ -743,7 +739,8 @@ prune_bbs (basic_block bbd, basic_block final) bbf description in the comment below). */ static void -fix_phi_nodes (edge e1f, edge e2f, basic_block bbf) +fix_phi_nodes (edge e1f, edge e2f, basic_block bbf, + struct switch_conv_info *info) { gimple_stmt_iterator gsi; int i; @@ -752,10 +749,9 @@ fix_phi_nodes (edge e1f, edge e2f, basic_block bbf) !gsi_end_p (gsi); gsi_next (&gsi), i++) { gimple phi = gsi_stmt (gsi); - add_phi_arg (phi, info.target_inbound_names[i], e1f, UNKNOWN_LOCATION); - add_phi_arg (phi, info.target_outbound_names[i], e2f, UNKNOWN_LOCATION); + add_phi_arg (phi, info->target_inbound_names[i], e1f, UNKNOWN_LOCATION); + add_phi_arg (phi, info->target_outbound_names[i], e2f, UNKNOWN_LOCATION); } - } /* Creates a check whether the switch expression value actually falls into the @@ -780,7 +776,7 @@ fix_phi_nodes (edge e1f, edge e2f, basic_block bbf) */ static void -gen_inbound_check (gimple swtch) +gen_inbound_check (gimple swtch, struct switch_conv_info *info) { tree label_decl1 = create_artificial_label (UNKNOWN_LOCATION); tree label_decl2 = create_artificial_label (UNKNOWN_LOCATION); @@ -797,17 +793,17 @@ gen_inbound_check (gimple swtch) edge e01, e02, e21, e1d, e1f, e2f; location_t loc = gimple_location (swtch); - gcc_assert (info.default_values); + gcc_assert (info->default_values); bb0 = gimple_bb (swtch); - tidx = gimple_assign_lhs (info.arr_ref_first); + tidx = gimple_assign_lhs (info->arr_ref_first); utype = TREE_TYPE (tidx); /* (end of) block 0 */ - gsi = gsi_for_stmt (info.arr_ref_first); + gsi = gsi_for_stmt (info->arr_ref_first); gsi_next (&gsi); - bound = fold_convert_loc (loc, utype, info.range_size); + bound = fold_convert_loc (loc, utype, info->range_size); cond_stmt = gimple_build_cond (LE_EXPR, tidx, bound, NULL_TREE, NULL_TREE); gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT); update_stmt (cond_stmt); @@ -815,14 +811,14 @@ gen_inbound_check (gimple swtch) /* block 2 */ label2 = gimple_build_label (label_decl2); gsi_insert_before (&gsi, label2, GSI_SAME_STMT); - last_assign = gen_def_assigns (&gsi); + last_assign = gen_def_assigns (&gsi, info); /* block 1 */ label1 = gimple_build_label (label_decl1); gsi_insert_before (&gsi, label1, GSI_SAME_STMT); /* block F */ - gsi = gsi_start_bb (info.final_bb); + gsi = gsi_start_bb (info->final_bb); label3 = gimple_build_label (label_decl3); gsi_insert_before (&gsi, label3, GSI_SAME_STMT); @@ -834,40 +830,40 @@ gen_inbound_check (gimple swtch) bb1 = e21->dest; remove_edge (e21); - e1d = split_block (bb1, info.arr_ref_last); + e1d = split_block (bb1, info->arr_ref_last); bbd = e1d->dest; remove_edge (e1d); /* flags and profiles of the edge for in-range values */ e01 = make_edge (bb0, bb1, EDGE_TRUE_VALUE); - e01->probability = REG_BR_PROB_BASE - info.default_prob; - e01->count = info.other_count; + e01->probability = REG_BR_PROB_BASE - info->default_prob; + e01->count = info->other_count; /* flags and profiles of the edge taking care of out-of-range values */ e02->flags &= ~EDGE_FALLTHRU; e02->flags |= EDGE_FALSE_VALUE; - e02->probability = info.default_prob; - e02->count = info.default_count; + e02->probability = info->default_prob; + e02->count = info->default_count; - bbf = info.final_bb; + bbf = info->final_bb; e1f = make_edge (bb1, bbf, EDGE_FALLTHRU); e1f->probability = REG_BR_PROB_BASE; - e1f->count = info.other_count; + e1f->count = info->other_count; e2f = make_edge (bb2, bbf, EDGE_FALLTHRU); e2f->probability = REG_BR_PROB_BASE; - e2f->count = info.default_count; + e2f->count = info->default_count; /* frequencies of the new BBs */ bb1->frequency = EDGE_FREQUENCY (e01); bb2->frequency = EDGE_FREQUENCY (e02); bbf->frequency = EDGE_FREQUENCY (e1f) + EDGE_FREQUENCY (e2f); - prune_bbs (bbd, info.final_bb); /* To keep calc_dfs_tree() in dominance.c + prune_bbs (bbd, info->final_bb); /* To keep calc_dfs_tree() in dominance.c happy. */ - fix_phi_nodes (e1f, e2f, bbf); + fix_phi_nodes (e1f, e2f, bbf, info); free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS); @@ -875,25 +871,25 @@ gen_inbound_check (gimple swtch) /* The following function is invoked on every switch statement (the current one is given in SWTCH) and runs the individual phases of switch conversion on it - one after another until one fails or the conversion is completed. */ + one after another until one fails or the conversion is completed. + Returns NULL on success, or a pointer to a string with the reason why the + conversion failed. */ -static bool +static const char * process_switch (gimple swtch) { unsigned int i, branch_num = gimple_switch_num_labels (swtch); tree index_type; + struct switch_conv_info info; /* Operand 2 is either NULL_TREE or a vector of cases (stmt.c). */ if (branch_num < 2) - { - info.reason = "switch has no labels\n"; - return false; - } + return "switch has no labels"; + info.reason = NULL; info.final_bb = NULL; info.switch_bb = gimple_bb (swtch); info.index_expr = gimple_switch_index (swtch); - index_type = TREE_TYPE (info.index_expr); info.arr_ref_first = NULL; info.arr_ref_last = NULL; info.default_prob = 0; @@ -906,24 +902,26 @@ process_switch (gimple swtch) /* An ERROR_MARK occurs for various reasons including invalid data type. (comment from stmt.c) */ + index_type = TREE_TYPE (info.index_expr); if (index_type == error_mark_node) - { - info.reason = "index error.\n"; - return false; - } + return "index error\n"; /* Check the case label values are within reasonable range: */ - if (!check_range (swtch)) - return false; + if (!check_range (swtch, &info)) + { + gcc_assert (info.reason); + return info.reason; + } /* For all the cases, see whether they are empty, the assignments they represent constant and so on... */ for (i = 0; i < branch_num; i++) - if (!check_process_case (gimple_switch_label (swtch, i))) + if (!check_process_case (gimple_switch_label (swtch, i), &info)) { + gcc_assert (info.reason); if (dump_file) - fprintf (dump_file, "Processing of case %i failed\n", i); - return false; + fprintf (dump_file, "processing of case %i failed\n\t", i); + return info.reason; } if (info.bit_test_uniq <= 2) @@ -933,27 +931,29 @@ process_switch (gimple swtch) info.range_size, info.bit_test_uniq, info.bit_test_count)) { - info.reason = " Expanding as bit test is preferable\n"; - return false; + return "expanding as bit test is preferable"; } } - if (!check_final_bb ()) - return false; + if (!check_final_bb (&info)) + { + gcc_assert (info.reason); + return info.reason; + } /* At this point all checks have passed and we can proceed with the transformation. */ - create_temp_arrays (); - gather_default_values (gimple_switch_label (swtch, 0)); - build_constructors (swtch); + create_temp_arrays (&info); + gather_default_values (gimple_switch_label (swtch, 0), &info); + build_constructors (swtch, &info); - build_arrays (swtch); /* Build the static arrays and assignments. */ - gen_inbound_check (swtch); /* Build the bounds check. */ + build_arrays (swtch, &info); /* Build the static arrays and assignments. */ + gen_inbound_check (swtch, &info); /* Build the bounds check. */ /* Cleanup: */ - free_temp_arrays (); - return true; + free_temp_arrays (&info); + return NULL; } /* The main function of the pass scans statements for switches and invokes @@ -966,6 +966,7 @@ do_switchconv (void) FOR_EACH_BB (bb) { + const char *failure_reason; gimple stmt = last_stmt (bb); if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) { @@ -980,8 +981,8 @@ do_switchconv (void) putc ('\n', dump_file); } - info.reason = NULL; - if (process_switch (stmt)) + failure_reason = process_switch (stmt); + if (! failure_reason) { if (dump_file) { @@ -993,10 +994,9 @@ do_switchconv (void) { if (dump_file) { - gcc_assert (info.reason); fputs ("Bailing out - ", dump_file); - fputs (info.reason, dump_file); - fputs ("--------------------------------\n", dump_file); + fputs (failure_reason, dump_file); + fputs ("\n--------------------------------\n", dump_file); } } } diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index d9d1abfd480..37df7ab32e9 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -605,7 +605,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, } /* When vectorizing a basic block unknown depnedence can still mean - strided access. */ + grouped access. */ if (vect_check_interleaving (dra, drb)) return false; @@ -1000,9 +1000,9 @@ vect_update_misalignment_for_peel (struct data_reference *dr, /* For interleaved data accesses the step in the loop must be multiplied by the size of the interleaving group. */ - if (STMT_VINFO_STRIDED_ACCESS (stmt_info)) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) dr_size *= GROUP_SIZE (vinfo_for_stmt (GROUP_FIRST_ELEMENT (stmt_info))); - if (STMT_VINFO_STRIDED_ACCESS (peel_stmt_info)) + if (STMT_VINFO_GROUPED_ACCESS (peel_stmt_info)) dr_peel_size *= GROUP_SIZE (peel_stmt_info); /* It can be assumed that the data refs with the same alignment as dr_peel @@ -1062,7 +1062,7 @@ vect_verify_datarefs_alignment (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo) /* For interleaving, only the alignment of the first access matters. Skip statements marked as not vectorizable. */ - if ((STMT_VINFO_STRIDED_ACCESS (stmt_info) + if ((STMT_VINFO_GROUPED_ACCESS (stmt_info) && GROUP_FIRST_ELEMENT (stmt_info) != stmt) || !STMT_VINFO_VECTORIZABLE (stmt_info)) continue; @@ -1103,7 +1103,7 @@ vector_alignment_reachable_p (struct data_reference *dr) stmt_vec_info stmt_info = vinfo_for_stmt (stmt); tree vectype = STMT_VINFO_VECTYPE (stmt_info); - if (STMT_VINFO_STRIDED_ACCESS (stmt_info)) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) { /* For interleaved access we peel only if number of iterations in the prolog loop ({VF - misalignment}), is a multiple of the @@ -1288,7 +1288,7 @@ vect_peeling_hash_get_lowest_cost (void **slot, void *data) stmt_info = vinfo_for_stmt (stmt); /* For interleaving, only the alignment of the first access matters. */ - if (STMT_VINFO_STRIDED_ACCESS (stmt_info) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info) && GROUP_FIRST_ELEMENT (stmt_info) != stmt) continue; @@ -1503,7 +1503,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) /* For interleaving, only the alignment of the first access matters. */ - if (STMT_VINFO_STRIDED_ACCESS (stmt_info) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info) && GROUP_FIRST_ELEMENT (stmt_info) != stmt) continue; @@ -1745,7 +1745,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) members of the group, therefore we divide the number of iterations by the group size. */ stmt_info = vinfo_for_stmt (DR_STMT (dr0)); - if (STMT_VINFO_STRIDED_ACCESS (stmt_info)) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) npeel /= GROUP_SIZE (stmt_info); if (vect_print_dump_info (REPORT_DETAILS)) @@ -1764,7 +1764,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) stmt_info = vinfo_for_stmt (stmt); /* For interleaving, only the alignment of the first access matters. */ - if (STMT_VINFO_STRIDED_ACCESS (stmt_info) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info) && GROUP_FIRST_ELEMENT (stmt_info) != stmt) continue; @@ -1846,7 +1846,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) /* For interleaving, only the alignment of the first access matters. */ if (aligned_access_p (dr) - || (STMT_VINFO_STRIDED_ACCESS (stmt_info) + || (STMT_VINFO_GROUPED_ACCESS (stmt_info) && GROUP_FIRST_ELEMENT (stmt_info) != stmt)) continue; @@ -2041,9 +2041,9 @@ vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo, } -/* Analyze groups of strided accesses: check that DR belongs to a group of - strided accesses of legal size, step, etc. Detect gaps, single element - interleaving, and other special cases. Set strided access info. +/* Analyze groups of accesses: check that DR belongs to a group of + accesses of legal size, step, etc. Detect gaps, single element + interleaving, and other special cases. Set grouped access info. Collect groups of strided stores for further use in SLP analysis. */ static bool @@ -2057,16 +2057,16 @@ vect_analyze_group_access (struct data_reference *dr) loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info); HOST_WIDE_INT dr_step = TREE_INT_CST_LOW (step); - HOST_WIDE_INT stride, last_accessed_element = 1; + HOST_WIDE_INT groupsize, last_accessed_element = 1; bool slp_impossible = false; struct loop *loop = NULL; if (loop_vinfo) loop = LOOP_VINFO_LOOP (loop_vinfo); - /* For interleaving, STRIDE is STEP counted in elements, i.e., the size of the - interleaving group (including gaps). */ - stride = dr_step / type_size; + /* For interleaving, GROUPSIZE is STEP counted in elements, i.e., the + size of the interleaving group (including gaps). */ + groupsize = dr_step / type_size; /* Not consecutive access is possible only if it is a part of interleaving. */ if (!GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt))) @@ -2078,11 +2078,11 @@ vect_analyze_group_access (struct data_reference *dr) size. The size of the group must be a power of 2. */ if (DR_IS_READ (dr) && (dr_step % type_size) == 0 - && stride > 0 - && exact_log2 (stride) != -1) + && groupsize > 0 + && exact_log2 (groupsize) != -1) { GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)) = stmt; - GROUP_SIZE (vinfo_for_stmt (stmt)) = stride; + GROUP_SIZE (vinfo_for_stmt (stmt)) = groupsize; if (vect_print_dump_info (REPORT_DR_DETAILS)) { fprintf (vect_dump, "Detected single element interleaving "); @@ -2239,9 +2239,9 @@ vect_analyze_group_access (struct data_reference *dr) { slp_impossible = true; /* There is a gap after the last load in the group. This gap is a - difference between the stride and the number of elements. When - there is no gap, this difference should be 0. */ - GROUP_GAP (vinfo_for_stmt (stmt)) = stride - count; + difference between the groupsize and the number of elements. + When there is no gap, this difference should be 0. */ + GROUP_GAP (vinfo_for_stmt (stmt)) = groupsize - count; } else { @@ -2265,27 +2265,27 @@ vect_analyze_group_access (struct data_reference *dr) return false; } - if (stride == 0) - stride = count; + if (groupsize == 0) + groupsize = count; - GROUP_SIZE (vinfo_for_stmt (stmt)) = stride; + GROUP_SIZE (vinfo_for_stmt (stmt)) = groupsize; if (vect_print_dump_info (REPORT_DETAILS)) - fprintf (vect_dump, "Detected interleaving of size %d", (int)stride); + fprintf (vect_dump, "Detected interleaving of size %d", (int)groupsize); /* SLP: create an SLP data structure for every interleaving group of stores for further analysis in vect_analyse_slp. */ if (DR_IS_WRITE (dr) && !slp_impossible) { if (loop_vinfo) - VEC_safe_push (gimple, heap, LOOP_VINFO_STRIDED_STORES (loop_vinfo), + VEC_safe_push (gimple, heap, LOOP_VINFO_GROUPED_STORES (loop_vinfo), stmt); if (bb_vinfo) - VEC_safe_push (gimple, heap, BB_VINFO_STRIDED_STORES (bb_vinfo), + VEC_safe_push (gimple, heap, BB_VINFO_GROUPED_STORES (bb_vinfo), stmt); } /* There is a gap in the end of the group. */ - if (stride - last_accessed_element > 0 && loop_vinfo) + if (groupsize - last_accessed_element > 0 && loop_vinfo) { if (vect_print_dump_info (REPORT_DETAILS)) fprintf (vect_dump, "Data access with gaps requires scalar " @@ -2307,7 +2307,7 @@ vect_analyze_group_access (struct data_reference *dr) /* Analyze the access pattern of the data-reference DR. In case of non-consecutive accesses call vect_analyze_group_access() to - analyze groups of strided accesses. */ + analyze groups of accesses. */ static bool vect_analyze_data_ref_access (struct data_reference *dr) @@ -2372,7 +2372,7 @@ vect_analyze_data_ref_access (struct data_reference *dr) if (loop && nested_in_vect_loop_p (loop, stmt)) { if (vect_print_dump_info (REPORT_ALIGNMENT)) - fprintf (vect_dump, "strided access in outer loop."); + fprintf (vect_dump, "grouped access in outer loop."); return false; } @@ -2690,6 +2690,53 @@ vect_check_gather (gimple stmt, loop_vec_info loop_vinfo, tree *basep, return decl; } +/* Check wether a non-affine load in STMT (being in the loop referred to + in LOOP_VINFO) is suitable for handling as strided load. That is the case + if its address is a simple induction variable. If so return the base + of that induction variable in *BASEP and the (loop-invariant) step + in *STEPP, both only when that pointer is non-zero. + + This handles ARRAY_REFs (with variant index) and MEM_REFs (with variant + base pointer) only. */ + +bool +vect_check_strided_load (gimple stmt, loop_vec_info loop_vinfo, tree *basep, + tree *stepp) +{ + struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info); + tree base, off; + affine_iv iv; + + base = DR_REF (dr); + + if (TREE_CODE (base) == ARRAY_REF) + { + off = TREE_OPERAND (base, 1); + base = TREE_OPERAND (base, 0); + } + else if (TREE_CODE (base) == MEM_REF) + { + off = TREE_OPERAND (base, 0); + base = TREE_OPERAND (base, 1); + } + else + return false; + + if (TREE_CODE (off) != SSA_NAME) + return false; + + if (!expr_invariant_in_loop_p (loop, base) + || !simple_iv (loop, loop_containing_stmt (stmt), off, &iv, true)) + return false; + + if (basep) + *basep = iv.base; + if (stepp) + *stepp = iv.step; + return true; +} /* Function vect_analyze_data_refs. @@ -3090,16 +3137,21 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, VEC (ddr_p, heap) *ddrs = LOOP_VINFO_DDRS (loop_vinfo); struct data_dependence_relation *ddr, *newddr; bool bad = false; + bool strided_load = false; tree off; VEC (loop_p, heap) *nest = LOOP_VINFO_LOOP_NEST (loop_vinfo); - if (!vect_check_gather (stmt, loop_vinfo, NULL, &off, NULL) - || get_vectype_for_scalar_type (TREE_TYPE (off)) == NULL_TREE) + strided_load = vect_check_strided_load (stmt, loop_vinfo, NULL, NULL); + gather = 0 != vect_check_gather (stmt, loop_vinfo, NULL, &off, NULL); + if (gather + && get_vectype_for_scalar_type (TREE_TYPE (off)) == NULL_TREE) + gather = false; + if (!gather && !strided_load) { if (vect_print_dump_info (REPORT_UNVECTORIZED_LOCATIONS)) { fprintf (vect_dump, - "not vectorized: not suitable for gather "); + "not vectorized: not suitable for gather/strided load "); print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM); } return false; @@ -3152,13 +3204,16 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo, { fprintf (vect_dump, "not vectorized: data dependence conflict" - " prevents gather"); + " prevents gather/strided load"); print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM); } return false; } - STMT_VINFO_GATHER_P (stmt_info) = true; + if (gather) + STMT_VINFO_GATHER_P (stmt_info) = true; + else if (strided_load) + STMT_VINFO_STRIDE_LOAD_P (stmt_info) = true; } } @@ -3792,13 +3847,13 @@ vect_create_destination_var (tree scalar_dest, tree vectype) return vec_dest; } -/* Function vect_strided_store_supported. +/* Function vect_grouped_store_supported. Returns TRUE if interleave high and interleave low permutations are supported, and FALSE otherwise. */ bool -vect_strided_store_supported (tree vectype, unsigned HOST_WIDE_INT count) +vect_grouped_store_supported (tree vectype, unsigned HOST_WIDE_INT count) { enum machine_mode mode = TYPE_MODE (vectype); @@ -3806,7 +3861,7 @@ vect_strided_store_supported (tree vectype, unsigned HOST_WIDE_INT count) if (exact_log2 (count) == -1) { if (vect_print_dump_info (REPORT_DETAILS)) - fprintf (vect_dump, "the size of the group of strided accesses" + fprintf (vect_dump, "the size of the group of accesses" " is not a power of 2"); return false; } @@ -4243,13 +4298,13 @@ vect_setup_realignment (gimple stmt, gimple_stmt_iterator *gsi, } -/* Function vect_strided_load_supported. +/* Function vect_grouped_load_supported. Returns TRUE if even and odd permutations are supported, and FALSE otherwise. */ bool -vect_strided_load_supported (tree vectype, unsigned HOST_WIDE_INT count) +vect_grouped_load_supported (tree vectype, unsigned HOST_WIDE_INT count) { enum machine_mode mode = TYPE_MODE (vectype); @@ -4257,7 +4312,7 @@ vect_strided_load_supported (tree vectype, unsigned HOST_WIDE_INT count) if (exact_log2 (count) == -1) { if (vect_print_dump_info (REPORT_DETAILS)) - fprintf (vect_dump, "the size of the group of strided accesses" + fprintf (vect_dump, "the size of the group of accesses" " is not a power of 2"); return false; } @@ -4442,7 +4497,7 @@ vect_permute_load_chain (VEC(tree,heap) *dr_chain, } -/* Function vect_transform_strided_load. +/* Function vect_transform_grouped_load. Given a chain of input interleaved data-refs (in DR_CHAIN), build statements to perform their permutation and ascribe the result vectorized statements to @@ -4450,7 +4505,7 @@ vect_permute_load_chain (VEC(tree,heap) *dr_chain, */ void -vect_transform_strided_load (gimple stmt, VEC(tree,heap) *dr_chain, int size, +vect_transform_grouped_load (gimple stmt, VEC(tree,heap) *dr_chain, int size, gimple_stmt_iterator *gsi) { VEC(tree,heap) *result_chain = NULL; @@ -4460,16 +4515,16 @@ vect_transform_strided_load (gimple stmt, VEC(tree,heap) *dr_chain, int size, vectors, that are ready for vector computation. */ result_chain = VEC_alloc (tree, heap, size); vect_permute_load_chain (dr_chain, size, stmt, gsi, &result_chain); - vect_record_strided_load_vectors (stmt, result_chain); + vect_record_grouped_load_vectors (stmt, result_chain); VEC_free (tree, heap, result_chain); } -/* RESULT_CHAIN contains the output of a group of strided loads that were +/* RESULT_CHAIN contains the output of a group of grouped loads that were generated as part of the vectorization of STMT. Assign the statement for each vector to the associated scalar statement. */ void -vect_record_strided_load_vectors (gimple stmt, VEC(tree,heap) *result_chain) +vect_record_grouped_load_vectors (gimple stmt, VEC(tree,heap) *result_chain) { gimple first_stmt = GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt)); gimple next_stmt, new_stmt; diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c index 499dece1dbf..18eef98fc45 100644 --- a/gcc/tree-vect-loop-manip.c +++ b/gcc/tree-vect-loop-manip.c @@ -2167,6 +2167,7 @@ vect_do_peeling_for_alignment (loop_vec_info loop_vinfo) struct loop *new_loop; unsigned int th = 0; int min_profitable_iters; + int max_iter; if (vect_print_dump_info (REPORT_DETAILS)) fprintf (vect_dump, "=== vect_do_peeling_for_alignment ==="); @@ -2192,6 +2193,11 @@ vect_do_peeling_for_alignment (loop_vec_info loop_vinfo) #ifdef ENABLE_CHECKING slpeel_verify_cfg_after_peeling (new_loop, loop); #endif + max_iter = MAX (LOOP_VINFO_VECT_FACTOR (loop_vinfo) - 1, (int) th); + record_niter_bound (new_loop, shwi_to_double_int (max_iter), false, true); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Setting upper bound of nb iterations for prologue " + "loop to %d\n", max_iter); /* Update number of times loop executes. */ n_iters = LOOP_VINFO_NITERS (loop_vinfo); diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 3df0e4b61ba..0c6ed39c123 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -847,7 +847,7 @@ new_loop_vec_info (struct loop *loop) LOOP_VINFO_MAY_ALIAS_DDRS (res) = VEC_alloc (ddr_p, heap, PARAM_VALUE (PARAM_VECT_MAX_VERSION_FOR_ALIAS_CHECKS)); - LOOP_VINFO_STRIDED_STORES (res) = VEC_alloc (gimple, heap, 10); + LOOP_VINFO_GROUPED_STORES (res) = VEC_alloc (gimple, heap, 10); LOOP_VINFO_REDUCTIONS (res) = VEC_alloc (gimple, heap, 10); LOOP_VINFO_REDUCTION_CHAINS (res) = VEC_alloc (gimple, heap, 10); LOOP_VINFO_SLP_INSTANCES (res) = VEC_alloc (slp_instance, heap, 10); @@ -923,7 +923,7 @@ destroy_loop_vec_info (loop_vec_info loop_vinfo, bool clean_stmts) vect_free_slp_instance (instance); VEC_free (slp_instance, heap, LOOP_VINFO_SLP_INSTANCES (loop_vinfo)); - VEC_free (gimple, heap, LOOP_VINFO_STRIDED_STORES (loop_vinfo)); + VEC_free (gimple, heap, LOOP_VINFO_GROUPED_STORES (loop_vinfo)); VEC_free (gimple, heap, LOOP_VINFO_REDUCTIONS (loop_vinfo)); VEC_free (gimple, heap, LOOP_VINFO_REDUCTION_CHAINS (loop_vinfo)); @@ -1235,6 +1235,7 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo, bool slp) int min_scalar_loop_bound; unsigned int th; bool only_slp_in_loop = true, ok; + HOST_WIDE_INT max_niter; if (vect_print_dump_info (REPORT_DETAILS)) fprintf (vect_dump, "=== vect_analyze_loop_operations ==="); @@ -1407,8 +1408,10 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo, bool slp) "vectorization_factor = %d, niters = " HOST_WIDE_INT_PRINT_DEC, vectorization_factor, LOOP_VINFO_INT_NITERS (loop_vinfo)); - if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo) - && (LOOP_VINFO_INT_NITERS (loop_vinfo) < vectorization_factor)) + if ((LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo) + && (LOOP_VINFO_INT_NITERS (loop_vinfo) < vectorization_factor)) + || ((max_niter = max_stmt_executions_int (loop)) != -1 + && max_niter < vectorization_factor)) { if (vect_print_dump_info (REPORT_UNVECTORIZED_LOCATIONS)) fprintf (vect_dump, "not vectorized: iteration count too small."); @@ -5221,7 +5224,7 @@ vect_transform_loop (loop_vec_info loop_vinfo) int i; tree ratio = NULL; int vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo); - bool strided_store; + bool grouped_store; bool slp_scheduled = false; unsigned int nunits; tree cond_expr = NULL_TREE; @@ -5460,11 +5463,11 @@ vect_transform_loop (loop_vec_info loop_vinfo) if (vect_print_dump_info (REPORT_DETAILS)) fprintf (vect_dump, "transform statement."); - strided_store = false; - is_store = vect_transform_stmt (stmt, &si, &strided_store, NULL, NULL); + grouped_store = false; + is_store = vect_transform_stmt (stmt, &si, &grouped_store, NULL, NULL); if (is_store) { - if (STMT_VINFO_STRIDED_ACCESS (stmt_info)) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) { /* Interleaving. If IS_STORE is TRUE, the vectorization of the interleaving chain was completed - free all the stores in diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index b871c0ba361..6372a36b3fd 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -564,6 +564,16 @@ vect_recog_widen_mult_pattern (VEC (gimple, heap) **stmts, VEC (tree, heap) *dummy_vec; bool op1_ok; bool promotion; + loop_vec_info loop_vinfo; + struct loop *loop = NULL; + bb_vec_info bb_vinfo; + stmt_vec_info stmt_vinfo; + + stmt_vinfo = vinfo_for_stmt (last_stmt); + loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo); + bb_vinfo = STMT_VINFO_BB_VINFO (stmt_vinfo); + if (loop_vinfo) + loop = LOOP_VINFO_LOOP (loop_vinfo); if (!is_gimple_assign (last_stmt)) return NULL; @@ -635,6 +645,11 @@ vect_recog_widen_mult_pattern (VEC (gimple, heap) **stmts, || gimple_assign_rhs_code (use_stmt) != NOP_EXPR) return NULL; + if (!gimple_bb (use_stmt) + || (loop && !flow_bb_inside_loop_p (loop, gimple_bb (use_stmt))) + || (!loop && gimple_bb (use_stmt) != BB_VINFO_BB (bb_vinfo))) + return NULL; + use_lhs = gimple_assign_lhs (use_stmt); use_type = TREE_TYPE (use_lhs); if (!INTEGRAL_TYPE_P (use_type) diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c index 014fa988722..e189c5071f0 100644 --- a/gcc/tree-vect-slp.c +++ b/gcc/tree-vect-slp.c @@ -651,7 +651,7 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo, || rhs_code != REALPART_EXPR) && (first_stmt_code != REALPART_EXPR || rhs_code != IMAGPART_EXPR) - && !(STMT_VINFO_STRIDED_ACCESS (vinfo_for_stmt (stmt)) + && !(STMT_VINFO_GROUPED_ACCESS (vinfo_for_stmt (stmt)) && (first_stmt_code == ARRAY_REF || first_stmt_code == INDIRECT_REF || first_stmt_code == COMPONENT_REF @@ -704,8 +704,8 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo, } } - /* Strided store or load. */ - if (STMT_VINFO_STRIDED_ACCESS (vinfo_for_stmt (stmt))) + /* Grouped store or load. */ + if (STMT_VINFO_GROUPED_ACCESS (vinfo_for_stmt (stmt))) { if (REFERENCE_CLASS_P (lhs)) { @@ -729,7 +729,7 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo, { if (vect_print_dump_info (REPORT_SLP)) { - fprintf (vect_dump, "Build SLP failed: strided " + fprintf (vect_dump, "Build SLP failed: grouped " "loads have gaps "); print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM); } @@ -815,19 +815,19 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo, stop_recursion = true; continue; } - } /* Strided access. */ + } /* Grouped access. */ else { if (TREE_CODE_CLASS (rhs_code) == tcc_reference) { - /* Not strided load. */ + /* Not grouped load. */ if (vect_print_dump_info (REPORT_SLP)) { - fprintf (vect_dump, "Build SLP failed: not strided load "); + fprintf (vect_dump, "Build SLP failed: not grouped load "); print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM); } - /* FORNOW: Not strided loads are not supported. */ + /* FORNOW: Not grouped loads are not supported. */ vect_free_oprnd_info (&oprnds_info); return false; } @@ -884,7 +884,7 @@ vect_build_slp_tree (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo, *inside_cost += SLP_TREE_INSIDE_OF_LOOP_COST (*node); *outside_cost += SLP_TREE_OUTSIDE_OF_LOOP_COST (*node); - /* Strided loads were reached - stop the recursion. */ + /* Grouped loads were reached - stop the recursion. */ if (stop_recursion) { VEC_safe_push (slp_tree, heap, *loads, *node); @@ -1109,7 +1109,7 @@ vect_slp_rearrange_stmts (slp_tree node, unsigned int group_size, /* Check if the required load permutation is supported. LOAD_PERMUTATION contains a list of indices of the loads. - In SLP this permutation is relative to the order of strided stores that are + In SLP this permutation is relative to the order of grouped stores that are the base of the SLP instance. */ static bool @@ -1138,7 +1138,7 @@ vect_supported_load_permutation_p (slp_instance slp_instn, int group_size, /* In case of reduction every load permutation is allowed, since the order of the reduction statements is not important (as opposed to the case of - strided stores). The only condition we need to check is that all the + grouped stores). The only condition we need to check is that all the load nodes are of the same size and have the same permutation (and then rearrange all the nodes of the SLP instance according to this permutation). */ @@ -1444,7 +1444,7 @@ vect_find_last_store_in_slp_instance (slp_instance instance) } -/* Analyze an SLP instance starting from a group of strided stores. Call +/* Analyze an SLP instance starting from a group of grouped stores. Call vect_build_slp_tree to build a tree of packed stmts if possible. Return FALSE if it's impossible to SLP any stmt in the loop. */ @@ -1517,7 +1517,7 @@ vect_analyze_slp_instance (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo, return false; } - /* Create a node (a root of the SLP tree) for the packed strided stores. */ + /* Create a node (a root of the SLP tree) for the packed grouped stores. */ scalar_stmts = VEC_alloc (gimple, heap, group_size); next = stmt; if (GROUP_FIRST_ELEMENT (vinfo_for_stmt (stmt))) @@ -1635,7 +1635,7 @@ bool vect_analyze_slp (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo) { unsigned int i; - VEC (gimple, heap) *strided_stores, *reductions = NULL, *reduc_chains = NULL; + VEC (gimple, heap) *grouped_stores, *reductions = NULL, *reduc_chains = NULL; gimple first_element; bool ok = false; @@ -1644,15 +1644,15 @@ vect_analyze_slp (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo) if (loop_vinfo) { - strided_stores = LOOP_VINFO_STRIDED_STORES (loop_vinfo); + grouped_stores = LOOP_VINFO_GROUPED_STORES (loop_vinfo); reduc_chains = LOOP_VINFO_REDUCTION_CHAINS (loop_vinfo); reductions = LOOP_VINFO_REDUCTIONS (loop_vinfo); } else - strided_stores = BB_VINFO_STRIDED_STORES (bb_vinfo); + grouped_stores = BB_VINFO_GROUPED_STORES (bb_vinfo); - /* Find SLP sequences starting from groups of strided stores. */ - FOR_EACH_VEC_ELT (gimple, strided_stores, i, first_element) + /* Find SLP sequences starting from groups of grouped stores. */ + FOR_EACH_VEC_ELT (gimple, grouped_stores, i, first_element) if (vect_analyze_slp_instance (loop_vinfo, bb_vinfo, first_element)) ok = true; @@ -1810,7 +1810,7 @@ new_bb_vec_info (basic_block bb) set_vinfo_for_stmt (stmt, new_stmt_vec_info (stmt, NULL, res)); } - BB_VINFO_STRIDED_STORES (res) = VEC_alloc (gimple, heap, 10); + BB_VINFO_GROUPED_STORES (res) = VEC_alloc (gimple, heap, 10); BB_VINFO_SLP_INSTANCES (res) = VEC_alloc (slp_instance, heap, 2); bb->aux = res; @@ -1844,7 +1844,7 @@ destroy_bb_vec_info (bb_vec_info bb_vinfo) free_data_refs (BB_VINFO_DATAREFS (bb_vinfo)); free_dependence_relations (BB_VINFO_DDRS (bb_vinfo)); - VEC_free (gimple, heap, BB_VINFO_STRIDED_STORES (bb_vinfo)); + VEC_free (gimple, heap, BB_VINFO_GROUPED_STORES (bb_vinfo)); VEC_free (slp_instance, heap, BB_VINFO_SLP_INSTANCES (bb_vinfo)); free (bb_vinfo); bb->aux = NULL; @@ -2859,7 +2859,7 @@ vect_schedule_slp_instance (slp_tree node, slp_instance instance, unsigned int vectorization_factor) { gimple stmt; - bool strided_store, is_store; + bool grouped_store, is_store; gimple_stmt_iterator si; stmt_vec_info stmt_info; unsigned int vec_stmts_size, nunits, group_size; @@ -2919,7 +2919,7 @@ vect_schedule_slp_instance (slp_tree node, slp_instance instance, /* Loads should be inserted before the first load. */ if (SLP_INSTANCE_FIRST_LOAD_STMT (instance) - && STMT_VINFO_STRIDED_ACCESS (stmt_info) + && STMT_VINFO_GROUPED_ACCESS (stmt_info) && !REFERENCE_CLASS_P (gimple_get_lhs (stmt)) && SLP_INSTANCE_LOAD_PERMUTATION (instance)) si = gsi_for_stmt (SLP_INSTANCE_FIRST_LOAD_STMT (instance)); @@ -2929,7 +2929,7 @@ vect_schedule_slp_instance (slp_tree node, slp_instance instance, si = gsi_for_stmt (stmt); /* Stores should be inserted just before the last store. */ - if (STMT_VINFO_STRIDED_ACCESS (stmt_info) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info) && REFERENCE_CLASS_P (gimple_get_lhs (stmt))) { gimple last_store = vect_find_last_store_in_slp_instance (instance); @@ -2941,14 +2941,14 @@ vect_schedule_slp_instance (slp_tree node, slp_instance instance, /* Mark the first element of the reduction chain as reduction to properly transform the node. In the analysis phase only the last element of the chain is marked as reduction. */ - if (GROUP_FIRST_ELEMENT (stmt_info) && !STMT_VINFO_STRIDED_ACCESS (stmt_info) + if (GROUP_FIRST_ELEMENT (stmt_info) && !STMT_VINFO_GROUPED_ACCESS (stmt_info) && GROUP_FIRST_ELEMENT (stmt_info) == stmt) { STMT_VINFO_DEF_TYPE (stmt_info) = vect_reduction_def; STMT_VINFO_TYPE (stmt_info) = reduc_vec_info_type; } - is_store = vect_transform_stmt (stmt, &si, &strided_store, node, instance); + is_store = vect_transform_stmt (stmt, &si, &grouped_store, node, instance); return is_store; } diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index dabb63d7a92..5e6f71a19bf 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -851,14 +851,14 @@ vect_model_promotion_demotion_cost (stmt_vec_info stmt_info, stmt_vinfo_set_outside_of_loop_cost (stmt_info, NULL, outside_cost); } -/* Function vect_cost_strided_group_size +/* Function vect_cost_group_size - For strided load or store, return the group_size only if it is the first + For grouped load or store, return the group_size only if it is the first load or store of a group, else return 1. This ensures that group size is only returned once per group. */ static int -vect_cost_strided_group_size (stmt_vec_info stmt_info) +vect_cost_group_size (stmt_vec_info stmt_info) { gimple first_stmt = GROUP_FIRST_ELEMENT (stmt_info); @@ -871,8 +871,8 @@ vect_cost_strided_group_size (stmt_vec_info stmt_info) /* Function vect_model_store_cost - Models cost for stores. In the case of strided accesses, one access - has the overhead of the strided access attributed to it. */ + Models cost for stores. In the case of grouped accesses, one access + has the overhead of the grouped access attributed to it. */ void vect_model_store_cost (stmt_vec_info stmt_info, int ncopies, @@ -891,8 +891,8 @@ vect_model_store_cost (stmt_vec_info stmt_info, int ncopies, if (dt == vect_constant_def || dt == vect_external_def) outside_cost = vect_get_stmt_cost (scalar_to_vec); - /* Strided access? */ - if (STMT_VINFO_STRIDED_ACCESS (stmt_info)) + /* Grouped access? */ + if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) { if (slp_node) { @@ -902,12 +902,12 @@ vect_model_store_cost (stmt_vec_info stmt_info, int ncopies, else { first_stmt = GROUP_FIRST_ELEMENT (stmt_info); - group_size = vect_cost_strided_group_size (stmt_info); + group_size = vect_cost_group_size (stmt_info); } first_dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt)); } - /* Not a strided access. */ + /* Not a grouped access. */ else { group_size = 1; @@ -915,7 +915,7 @@ vect_model_store_cost (stmt_vec_info stmt_info, int ncopies, } /* We assume that the cost of a single store-lanes instruction is - equivalent to the cost of GROUP_SIZE separate stores. If a strided + equivalent to the cost of GROUP_SIZE separate stores. If a grouped access is instead being provided by a permute-and-store operation, include the cost of the permutes. */ if (!store_lanes_p && group_size > 1) @@ -987,8 +987,8 @@ vect_get_store_cost (struct data_reference *dr, int ncopies, /* Function vect_model_load_cost - Models cost for loads. In the case of strided accesses, the last access - has the overhead of the strided access attributed to it. Since unaligned + Models cost for loads. In the case of grouped accesses, the last access + has the overhead of the grouped access attributed to it. Since unaligned accesses are supported for loads, we also account for the costs of the access scheme chosen. */ @@ -1005,14 +1005,14 @@ vect_model_load_cost (stmt_vec_info stmt_info, int ncopies, bool load_lanes_p, if (PURE_SLP_STMT (stmt_info)) return; - /* Strided accesses? */ + /* Grouped accesses? */ first_stmt = GROUP_FIRST_ELEMENT (stmt_info); - if (STMT_VINFO_STRIDED_ACCESS (stmt_info) && first_stmt && !slp_node) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info) && first_stmt && !slp_node) { - group_size = vect_cost_strided_group_size (stmt_info); + group_size = vect_cost_group_size (stmt_info); first_dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt)); } - /* Not a strided access. */ + /* Not a grouped access. */ else { group_size = 1; @@ -1020,7 +1020,7 @@ vect_model_load_cost (stmt_vec_info stmt_info, int ncopies, bool load_lanes_p, } /* We assume that the cost of a single load-lanes instruction is - equivalent to the cost of GROUP_SIZE separate loads. If a strided + equivalent to the cost of GROUP_SIZE separate loads. If a grouped access is instead being provided by a load-and-permute operation, include the cost of the permutes. */ if (!load_lanes_p && group_size > 1) @@ -1036,7 +1036,7 @@ vect_model_load_cost (stmt_vec_info stmt_info, int ncopies, bool load_lanes_p, /* The loads themselves. */ vect_get_load_cost (first_dr, ncopies, - ((!STMT_VINFO_STRIDED_ACCESS (stmt_info)) || group_size > 1 + ((!STMT_VINFO_GROUPED_ACCESS (stmt_info)) || group_size > 1 || slp_node), &inside_cost, &outside_cost); @@ -1109,7 +1109,7 @@ vect_get_load_cost (struct data_reference *dr, int ncopies, /* Unaligned software pipeline has a load of an address, an initial load, and possibly a mask operation to "prime" the loop. However, - if this is an access in a group of loads, which provide strided + if this is an access in a group of loads, which provide grouped access, then the above cost should only be considered for one access in the group. Inside the loop, there is a load op and a realignment op. */ @@ -3692,7 +3692,7 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, int ncopies; int j; gimple next_stmt, first_stmt = NULL; - bool strided_store = false; + bool grouped_store = false; bool store_lanes_p = false; unsigned int group_size, i; VEC(tree,heap) *dr_chain = NULL, *oprnds = NULL, *result_chain = NULL; @@ -3777,16 +3777,16 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, return false; } - if (STMT_VINFO_STRIDED_ACCESS (stmt_info)) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) { - strided_store = true; + grouped_store = true; first_stmt = GROUP_FIRST_ELEMENT (stmt_info); if (!slp && !PURE_SLP_STMT (stmt_info)) { group_size = GROUP_SIZE (vinfo_for_stmt (first_stmt)); if (vect_store_lanes_supported (vectype, group_size)) store_lanes_p = true; - else if (!vect_strided_store_supported (vectype, group_size)) + else if (!vect_grouped_store_supported (vectype, group_size)) return false; } @@ -3820,7 +3820,7 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, /** Transform. **/ - if (strided_store) + if (grouped_store) { first_dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt)); group_size = GROUP_SIZE (vinfo_for_stmt (first_stmt)); @@ -3842,7 +3842,7 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, if (slp) { - strided_store = false; + grouped_store = false; /* VEC_NUM is the number of vect stmts to be created for this group. */ vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); @@ -3887,7 +3887,7 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, vector stmt by a factor VF/nunits. For more details see documentation in vect_get_vec_def_for_copy_stmt. */ - /* In case of interleaving (non-unit strided access): + /* In case of interleaving (non-unit grouped access): S1: &base + 2 = x2 S2: &base = x0 @@ -3943,7 +3943,7 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, used as an input to vect_permute_store_chain(), and OPRNDS as an input to vect_get_vec_def_for_stmt_copy() for the next copy. - If the store is not strided, GROUP_SIZE is 1, and DR_CHAIN and + If the store is not grouped, GROUP_SIZE is 1, and DR_CHAIN and OPRNDS are of size 1. */ next_stmt = first_stmt; for (i = 0; i < group_size; i++) @@ -3980,7 +3980,7 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, DR_CHAIN is then used as an input to vect_permute_store_chain(), and OPRNDS as an input to vect_get_vec_def_for_stmt_copy() for the next copy. - If the store is not strided, GROUP_SIZE is 1, and DR_CHAIN and + If the store is not grouped, GROUP_SIZE is 1, and DR_CHAIN and OPRNDS are of size 1. */ for (i = 0; i < group_size; i++) { @@ -4018,7 +4018,7 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, else { new_stmt = NULL; - if (strided_store) + if (grouped_store) { result_chain = VEC_alloc (tree, heap, group_size); /* Permute. */ @@ -4038,8 +4038,8 @@ vectorizable_store (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, if (slp) vec_oprnd = VEC_index (tree, vec_oprnds, i); - else if (strided_store) - /* For strided stores vectorized defs are interleaved in + else if (grouped_store) + /* For grouped stores vectorized defs are interleaved in vect_permute_store_chain(). */ vec_oprnd = VEC_index (tree, result_chain, i); @@ -4208,7 +4208,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, tree realignment_token = NULL_TREE; gimple phi = NULL; VEC(tree,heap) *dr_chain = NULL; - bool strided_load = false; + bool grouped_load = false; bool load_lanes_p = false; gimple first_stmt; bool inv_p; @@ -4224,6 +4224,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, tree aggr_type; tree gather_base = NULL_TREE, gather_off = NULL_TREE; tree gather_off_vectype = NULL_TREE, gather_decl = NULL_TREE; + tree stride_base, stride_step; int gather_scale = 1; enum vect_def_type gather_dt = vect_unknown_def_type; @@ -4305,9 +4306,9 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, } /* Check if the load is a part of an interleaving chain. */ - if (STMT_VINFO_STRIDED_ACCESS (stmt_info)) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) { - strided_load = true; + grouped_load = true; /* FORNOW */ gcc_assert (! nested_in_vect_loop && !STMT_VINFO_GATHER_P (stmt_info)); @@ -4317,14 +4318,14 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, group_size = GROUP_SIZE (vinfo_for_stmt (first_stmt)); if (vect_load_lanes_supported (vectype, group_size)) load_lanes_p = true; - else if (!vect_strided_load_supported (vectype, group_size)) + else if (!vect_grouped_load_supported (vectype, group_size)) return false; } } if (negative) { - gcc_assert (!strided_load && !STMT_VINFO_GATHER_P (stmt_info)); + gcc_assert (!grouped_load && !STMT_VINFO_GATHER_P (stmt_info)); alignment_support_scheme = vect_supportable_dr_alignment (dr, false); if (alignment_support_scheme != dr_aligned && alignment_support_scheme != dr_unaligned_supported) @@ -4357,6 +4358,10 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, return false; } } + else if (STMT_VINFO_STRIDE_LOAD_P (stmt_info)) + { + vect_check_strided_load (stmt, loop_vinfo, &stride_base, &stride_step); + } if (!vec_stmt) /* transformation not required. */ { @@ -4524,8 +4529,106 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, } return true; } + else if (STMT_VINFO_STRIDE_LOAD_P (stmt_info)) + { + gimple_stmt_iterator incr_gsi; + bool insert_after; + gimple incr; + tree offvar; + tree ref = DR_REF (dr); + tree ivstep; + tree running_off; + VEC(constructor_elt, gc) *v = NULL; + gimple_seq stmts = NULL; + + gcc_assert (stride_base && stride_step); + + /* For a load with loop-invariant (but other than power-of-2) + stride (i.e. not a grouped access) like so: + + for (i = 0; i < n; i += stride) + ... = array[i]; + + we generate a new induction variable and new accesses to + form a new vector (or vectors, depending on ncopies): + + for (j = 0; ; j += VF*stride) + tmp1 = array[j]; + tmp2 = array[j + stride]; + ... + vectemp = {tmp1, tmp2, ...} + */ + + ivstep = stride_step; + ivstep = fold_build2 (MULT_EXPR, TREE_TYPE (ivstep), ivstep, + build_int_cst (TREE_TYPE (ivstep), vf)); + + standard_iv_increment_position (loop, &incr_gsi, &insert_after); + + create_iv (stride_base, ivstep, NULL, + loop, &incr_gsi, insert_after, + &offvar, NULL); + incr = gsi_stmt (incr_gsi); + set_vinfo_for_stmt (incr, new_stmt_vec_info (incr, loop_vinfo, NULL)); + + stride_step = force_gimple_operand (stride_step, &stmts, true, NULL_TREE); + if (stmts) + gsi_insert_seq_on_edge_immediate (loop_preheader_edge (loop), stmts); + + prev_stmt_info = NULL; + running_off = offvar; + for (j = 0; j < ncopies; j++) + { + tree vec_inv; + + v = VEC_alloc (constructor_elt, gc, nunits); + for (i = 0; i < nunits; i++) + { + tree newref, newoff; + gimple incr; + if (TREE_CODE (ref) == ARRAY_REF) + newref = build4 (ARRAY_REF, TREE_TYPE (ref), + unshare_expr (TREE_OPERAND (ref, 0)), + running_off, + NULL_TREE, NULL_TREE); + else + newref = build2 (MEM_REF, TREE_TYPE (ref), + running_off, + TREE_OPERAND (ref, 1)); + + newref = force_gimple_operand_gsi (gsi, newref, true, + NULL_TREE, true, + GSI_SAME_STMT); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, newref); + newoff = SSA_NAME_VAR (running_off); + if (POINTER_TYPE_P (TREE_TYPE (newoff))) + incr = gimple_build_assign_with_ops (POINTER_PLUS_EXPR, newoff, + running_off, stride_step); + else + incr = gimple_build_assign_with_ops (PLUS_EXPR, newoff, + running_off, stride_step); + newoff = make_ssa_name (newoff, incr); + gimple_assign_set_lhs (incr, newoff); + vect_finish_stmt_generation (stmt, incr, gsi); + + running_off = newoff; + } + + vec_inv = build_constructor (vectype, v); + new_temp = vect_init_vector (stmt, vec_inv, vectype, gsi); + new_stmt = SSA_NAME_DEF_STMT (new_temp); + mark_symbols_for_renaming (new_stmt); + + if (j == 0) + STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt; + else + STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt; + prev_stmt_info = vinfo_for_stmt (new_stmt); + } + return true; + } - if (strided_load) + if (grouped_load) { first_stmt = GROUP_FIRST_ELEMENT (stmt_info); if (slp @@ -4545,7 +4648,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, /* VEC_NUM is the number of vect stmts to be created for this group. */ if (slp) { - strided_load = false; + grouped_load = false; vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); if (SLP_INSTANCE_LOAD_PERMUTATION (slp_node_instance)) slp_perm = true; @@ -4603,7 +4706,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, information we recorded in RELATED_STMT field is used to vectorize stmt S2. */ - /* In case of interleaving (non-unit strided access): + /* In case of interleaving (non-unit grouped access): S1: x2 = &base + 2 S2: x0 = &base @@ -4629,7 +4732,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, corresponds to the order of scalar stmts in the interleaving chain - see the documentation of vect_permute_load_chain()). The generation of permutation stmts and recording them in - STMT_VINFO_VEC_STMT is done in vect_transform_strided_load(). + STMT_VINFO_VEC_STMT is done in vect_transform_grouped_load(). In case of both multiple types and interleaving, the vector loads and permutation stmts above are created for every copy. The result vector @@ -4715,7 +4818,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, gsi, stmt, TYPE_SIZE_UNIT (aggr_type)); - if (strided_load || slp_perm) + if (grouped_load || slp_perm) dr_chain = VEC_alloc (tree, heap, vec_num); if (load_lanes_p) @@ -4741,7 +4844,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, } /* Record the mapping between SSA_NAMEs and statements. */ - vect_record_strided_load_vectors (stmt, dr_chain); + vect_record_grouped_load_vectors (stmt, dr_chain); } else { @@ -4896,7 +4999,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, if (inv_p && !bb_vinfo) { gimple_stmt_iterator gsi2 = *gsi; - gcc_assert (!strided_load); + gcc_assert (!grouped_load); gsi_next (&gsi2); new_temp = vect_init_vector (stmt, scalar_dest, vectype, &gsi2); @@ -4912,8 +5015,8 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, } /* Collect vector loads and later create their permutation in - vect_transform_strided_load (). */ - if (strided_load || slp_perm) + vect_transform_grouped_load (). */ + if (grouped_load || slp_perm) VEC_quick_push (tree, dr_chain, new_temp); /* Store vector loads in the corresponding SLP_NODE. */ @@ -4937,10 +5040,10 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, } else { - if (strided_load) + if (grouped_load) { if (!load_lanes_p) - vect_transform_strided_load (stmt, dr_chain, group_size, gsi); + vect_transform_grouped_load (stmt, dr_chain, group_size, gsi); *vec_stmt = STMT_VINFO_VEC_STMT (stmt_info); } else @@ -5494,7 +5597,7 @@ vect_analyze_stmt (gimple stmt, bool *need_to_vectorize, slp_tree node) bool vect_transform_stmt (gimple stmt, gimple_stmt_iterator *gsi, - bool *strided_store, slp_tree slp_node, + bool *grouped_store, slp_tree slp_node, slp_instance slp_node_instance) { bool is_store = false; @@ -5541,13 +5644,13 @@ vect_transform_stmt (gimple stmt, gimple_stmt_iterator *gsi, case store_vec_info_type: done = vectorizable_store (stmt, gsi, &vec_stmt, slp_node); gcc_assert (done); - if (STMT_VINFO_STRIDED_ACCESS (stmt_info) && !slp_node) + if (STMT_VINFO_GROUPED_ACCESS (stmt_info) && !slp_node) { /* In case of interleaving, the whole chain is vectorized when the last store in the chain is reached. Store stmts before the last one are skipped, and there vec_stmt_info shouldn't be freed meanwhile. */ - *strided_store = true; + *grouped_store = true; if (STMT_VINFO_VEC_STMT (stmt_info)) is_store = true; } diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index d76fe0c3e84..7df31f7c9d2 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -320,11 +320,9 @@ increase_alignment (void) struct varpool_node *vnode; /* Increase the alignment of all global arrays for vectorization. */ - for (vnode = varpool_nodes_queue; - vnode; - vnode = vnode->next_needed) + FOR_EACH_DEFINED_VARIABLE (vnode) { - tree vectype, decl = vnode->decl; + tree vectype, decl = vnode->symbol.decl; tree t; unsigned int alignment; diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 5f031b52f2e..5d996094047 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -253,9 +253,9 @@ typedef struct _loop_vec_info { /* All interleaving chains of stores in the loop, represented by the first stmt in the chain. */ - VEC(gimple, heap) *strided_stores; + VEC(gimple, heap) *grouped_stores; - /* All SLP instances in the loop. This is a subset of the set of STRIDED_STORES + /* All SLP instances in the loop. This is a subset of the set of GROUP_STORES of the loop. */ VEC(slp_instance, heap) *slp_instances; @@ -273,7 +273,7 @@ typedef struct _loop_vec_info { /* Hash table used to choose the best peeling option. */ htab_t peeling_htab; - /* When we have strided data accesses with gaps, we may introduce invalid + /* When we have grouped data accesses with gaps, we may introduce invalid memory accesses. We peel the last iteration of the loop to prevent this. */ bool peeling_for_gaps; @@ -300,7 +300,7 @@ typedef struct _loop_vec_info { #define LOOP_VINFO_MAY_MISALIGN_STMTS(L) (L)->may_misalign_stmts #define LOOP_VINFO_LOC(L) (L)->loop_line_number #define LOOP_VINFO_MAY_ALIAS_DDRS(L) (L)->may_alias_ddrs -#define LOOP_VINFO_STRIDED_STORES(L) (L)->strided_stores +#define LOOP_VINFO_GROUPED_STORES(L) (L)->grouped_stores #define LOOP_VINFO_SLP_INSTANCES(L) (L)->slp_instances #define LOOP_VINFO_SLP_UNROLLING_FACTOR(L) (L)->slp_unrolling_factor #define LOOP_VINFO_REDUCTIONS(L) (L)->reductions @@ -338,10 +338,10 @@ typedef struct _bb_vec_info { basic_block bb; /* All interleaving chains of stores in the basic block, represented by the first stmt in the chain. */ - VEC(gimple, heap) *strided_stores; + VEC(gimple, heap) *grouped_stores; /* All SLP instances in the basic block. This is a subset of the set of - STRIDED_STORES of the basic block. */ + GROUP_STORES of the basic block. */ VEC(slp_instance, heap) *slp_instances; /* All data references in the basic block. */ @@ -352,7 +352,7 @@ typedef struct _bb_vec_info { } *bb_vec_info; #define BB_VINFO_BB(B) (B)->bb -#define BB_VINFO_STRIDED_STORES(B) (B)->strided_stores +#define BB_VINFO_GROUPED_STORES(B) (B)->grouped_stores #define BB_VINFO_SLP_INSTANCES(B) (B)->slp_instances #define BB_VINFO_DATAREFS(B) (B)->datarefs #define BB_VINFO_DDRS(B) (B)->ddrs @@ -545,6 +545,7 @@ typedef struct _stmt_vec_info { /* For loads only, true if this is a gather load. */ bool gather_p; + bool stride_load_p; } *stmt_vec_info; /* Access Functions. */ @@ -559,6 +560,7 @@ typedef struct _stmt_vec_info { #define STMT_VINFO_VECTORIZABLE(S) (S)->vectorizable #define STMT_VINFO_DATA_REF(S) (S)->data_ref_info #define STMT_VINFO_GATHER_P(S) (S)->gather_p +#define STMT_VINFO_STRIDE_LOAD_P(S) (S)->stride_load_p #define STMT_VINFO_DR_BASE_ADDRESS(S) (S)->dr_base_address #define STMT_VINFO_DR_INIT(S) (S)->dr_init @@ -578,7 +580,7 @@ typedef struct _stmt_vec_info { #define STMT_VINFO_GROUP_GAP(S) (S)->gap #define STMT_VINFO_GROUP_SAME_DR_STMT(S) (S)->same_dr_stmt #define STMT_VINFO_GROUP_READ_WRITE_DEPENDENCE(S) (S)->read_write_dep -#define STMT_VINFO_STRIDED_ACCESS(S) ((S)->first_element != NULL && (S)->data_ref_info) +#define STMT_VINFO_GROUPED_ACCESS(S) ((S)->first_element != NULL && (S)->data_ref_info) #define STMT_VINFO_LOOP_PHI_EVOLUTION_PART(S) (S)->loop_phi_evolution_part #define GROUP_FIRST_ELEMENT(S) (S)->first_element @@ -875,24 +877,25 @@ extern bool vect_analyze_data_ref_accesses (loop_vec_info, bb_vec_info); extern bool vect_prune_runtime_alias_test_list (loop_vec_info); extern tree vect_check_gather (gimple, loop_vec_info, tree *, tree *, int *); +extern bool vect_check_strided_load (gimple, loop_vec_info, tree *, tree *); extern bool vect_analyze_data_refs (loop_vec_info, bb_vec_info, int *); extern tree vect_create_data_ref_ptr (gimple, tree, struct loop *, tree, tree *, gimple_stmt_iterator *, gimple *, bool, bool *); extern tree bump_vector_ptr (tree, gimple, gimple_stmt_iterator *, gimple, tree); extern tree vect_create_destination_var (tree, tree); -extern bool vect_strided_store_supported (tree, unsigned HOST_WIDE_INT); +extern bool vect_grouped_store_supported (tree, unsigned HOST_WIDE_INT); extern bool vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT); -extern bool vect_strided_load_supported (tree, unsigned HOST_WIDE_INT); +extern bool vect_grouped_load_supported (tree, unsigned HOST_WIDE_INT); extern bool vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT); extern void vect_permute_store_chain (VEC(tree,heap) *,unsigned int, gimple, gimple_stmt_iterator *, VEC(tree,heap) **); extern tree vect_setup_realignment (gimple, gimple_stmt_iterator *, tree *, enum dr_alignment_support, tree, struct loop **); -extern void vect_transform_strided_load (gimple, VEC(tree,heap) *, int, +extern void vect_transform_grouped_load (gimple, VEC(tree,heap) *, int, gimple_stmt_iterator *); -extern void vect_record_strided_load_vectors (gimple, VEC(tree,heap) *); +extern void vect_record_grouped_load_vectors (gimple, VEC(tree,heap) *); extern int vect_get_place_in_interleaving_chain (gimple, gimple); extern tree vect_get_new_vect_var (tree, enum vect_var_kind, const char *); extern tree vect_create_addr_base_for_vector_ref (gimple, gimple_seq *, diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index ae0ef4dfb29..73b3bb4b926 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -3420,7 +3420,9 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, { double_int nit; - if (estimated_loop_iterations (loop, true, &nit)) + /* We are only entering here for loop header PHI nodes, so using + the number of latch executions is the correct thing to use. */ + if (max_loop_iterations (loop, &nit)) { value_range_t maxvr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }; double_int dtmp; @@ -8272,12 +8274,6 @@ execute_vrp (void) insert_range_assertions (); - /* Estimate number of iterations - but do not use undefined behavior - for this. We can't do this lazily as other functions may compute - this using undefined behavior. */ - free_numbers_of_iterations_estimates (); - estimate_numbers_of_iterations (false); - to_remove_edges = VEC_alloc (edge, heap, 10); to_update_switch_stmts = VEC_alloc (switch_update, heap, 5); threadedge_initialize_values (); diff --git a/gcc/tree.c b/gcc/tree.c index 7c7e43a5a88..b0d52b2e0e9 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -1315,6 +1315,24 @@ cst_and_fits_in_hwi (const_tree x) || TREE_INT_CST_HIGH (x) == -1); } +/* Build a newly constructed TREE_VEC node of length LEN. */ + +tree +make_vector_stat (unsigned len MEM_STAT_DECL) +{ + tree t; + unsigned length = (len - 1) * sizeof (tree) + sizeof (struct tree_vector); + + record_node_allocation_statistics (VECTOR_CST, length); + + t = ggc_alloc_zone_cleared_tree_node_stat (&tree_zone, length PASS_MEM_STAT); + + TREE_SET_CODE (t, VECTOR_CST); + TREE_CONSTANT (t) = 1; + + return t; +} + /* Return a new VECTOR_CST node whose type is TYPE and whose values are in a list pointed to by VALS. */ @@ -1323,16 +1341,7 @@ build_vector_stat (tree type, tree *vals MEM_STAT_DECL) { int over = 0; unsigned cnt = 0; - tree v; - int length = ((TYPE_VECTOR_SUBPARTS (type) - 1) * sizeof (tree) - + sizeof (struct tree_vector)); - - record_node_allocation_statistics (VECTOR_CST, length); - - v = ggc_alloc_zone_cleared_tree_node_stat (&tree_zone, length PASS_MEM_STAT); - - TREE_SET_CODE (v, VECTOR_CST); - TREE_CONSTANT (v) = 1; + tree v = make_vector (TYPE_VECTOR_SUBPARTS (type)); TREE_TYPE (v) = type; /* Iterate through elements and check for overflow. */ @@ -5048,14 +5057,14 @@ find_decls_types_in_node (struct cgraph_node *n, struct free_lang_data_d *fld) unsigned ix; tree t; - find_decls_types (n->decl, fld); + find_decls_types (n->symbol.decl, fld); - if (!gimple_has_body_p (n->decl)) + if (!gimple_has_body_p (n->symbol.decl)) return; gcc_assert (current_function_decl == NULL_TREE && cfun == NULL); - fn = DECL_STRUCT_FUNCTION (n->decl); + fn = DECL_STRUCT_FUNCTION (n->symbol.decl); /* Traverse locals. */ FOR_EACH_LOCAL_DECL (fn, ix, t) @@ -5111,7 +5120,7 @@ find_decls_types_in_node (struct cgraph_node *n, struct free_lang_data_d *fld) static void find_decls_types_in_var (struct varpool_node *v, struct free_lang_data_d *fld) { - find_decls_types (v->decl, fld); + find_decls_types (v->symbol.decl, fld); } /* If T needs an assembler name, have one created for it. */ @@ -5176,14 +5185,14 @@ free_lang_data_in_cgraph (void) fld.types = VEC_alloc (tree, heap, 100); /* Find decls and types in the body of every function in the callgraph. */ - for (n = cgraph_nodes; n; n = n->next) + FOR_EACH_FUNCTION (n) find_decls_types_in_node (n, &fld); FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p) find_decls_types (p->decl, &fld); /* Find decls and types in every varpool symbol. */ - for (v = varpool_nodes; v; v = v->next) + FOR_EACH_VARIABLE (v) find_decls_types_in_var (v, &fld); /* Set the assembler name on every decl found. We need to do this @@ -9388,6 +9397,7 @@ build_common_tree_nodes (bool signed_char, bool short_double) integer_ptr_type_node = build_pointer_type (integer_type_node); /* Fixed size integer types. */ + uint16_type_node = build_nonstandard_integer_type (16, true); uint32_type_node = build_nonstandard_integer_type (32, true); uint64_type_node = build_nonstandard_integer_type (64, true); diff --git a/gcc/tree.def b/gcc/tree.def index fd7cbbd1265..8a3007cd47b 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -876,10 +876,16 @@ DEFTREECODE (LOOP_EXPR, "loop_expr", tcc_statement, 1) of all the cases. */ DEFTREECODE (SWITCH_EXPR, "switch_expr", tcc_statement, 3) -/* Used to represent a case label. The operands are CASE_LOW and - CASE_HIGH, respectively. If CASE_LOW is NULL_TREE, the label is a - 'default' label. If CASE_HIGH is NULL_TREE, the label is a normal case - label. CASE_LABEL is the corresponding LABEL_DECL. */ +/* Used to represent a case label. + + Operand 0 is CASE_LOW. It may be NULL_TREE, in which case the label + is a 'default' label. + Operand 1 is CASE_HIGH. If it is NULL_TREE, the label is a simple + (one-value) case label. If it is non-NULL_TREE, the case is a range. + Operand 2 is CASE_LABEL, which is is the corresponding LABEL_DECL. + Operand 4 is CASE_CHAIN. This operand is only used in tree-cfg.c to + speed up the lookup of case labels which use a particular edge in + the control flow graph. */ DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", tcc_statement, 4) /* Used to represent an inline assembly statement. ASM_STRING returns a diff --git a/gcc/tree.h b/gcc/tree.h index da6be998054..e719be2ed40 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3747,6 +3747,7 @@ enum tree_index TI_UINTDI_TYPE, TI_UINTTI_TYPE, + TI_UINT16_TYPE, TI_UINT32_TYPE, TI_UINT64_TYPE, @@ -3902,6 +3903,7 @@ extern GTY(()) tree global_trees[TI_MAX]; #define unsigned_intDI_type_node global_trees[TI_UINTDI_TYPE] #define unsigned_intTI_type_node global_trees[TI_UINTTI_TYPE] +#define uint16_type_node global_trees[TI_UINT16_TYPE] #define uint32_type_node global_trees[TI_UINT32_TYPE] #define uint64_type_node global_trees[TI_UINT64_TYPE] @@ -4339,6 +4341,8 @@ build_int_cstu (tree type, unsigned HOST_WIDE_INT cst) extern tree build_int_cst (tree, HOST_WIDE_INT); extern tree build_int_cst_type (tree, HOST_WIDE_INT); extern tree build_int_cst_wide (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT); +extern tree make_vector_stat (unsigned MEM_STAT_DECL); +#define make_vector(n) make_vector_stat (n MEM_STAT_INFO) extern tree build_vector_stat (tree, tree * MEM_STAT_DECL); #define build_vector(t,v) build_vector_stat (t, v MEM_STAT_INFO) extern tree build_vector_from_ctor (tree, VEC(constructor_elt,gc) *); @@ -5063,6 +5067,8 @@ extern bool contains_packed_reference (const_tree exp); extern tree array_ref_element_size (tree); +bool array_at_struct_end_p (tree); + /* Return a tree representing the lower bound of the array mentioned in EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ @@ -5211,7 +5217,6 @@ extern tree unshare_expr (tree); /* In stmt.c */ extern void expand_expr_stmt (tree); -extern int warn_if_unused_value (const_tree, location_t); extern void expand_label (tree); extern void expand_goto (tree); diff --git a/gcc/value-prof.c b/gcc/value-prof.c index a6afd5515b5..10a5319d3ec 100644 --- a/gcc/value-prof.c +++ b/gcc/value-prof.c @@ -1073,11 +1073,11 @@ init_node_map (void) VEC_safe_grow_cleared (cgraph_node_ptr, heap, cgraph_node_map, get_last_funcdef_no ()); - for (n = cgraph_nodes; n; n = n->next) + FOR_EACH_FUNCTION (n) { - if (DECL_STRUCT_FUNCTION (n->decl)) + if (DECL_STRUCT_FUNCTION (n->symbol.decl)) VEC_replace (cgraph_node_ptr, cgraph_node_map, - DECL_STRUCT_FUNCTION (n->decl)->funcdef_no, n); + DECL_STRUCT_FUNCTION (n->symbol.decl)->funcdef_no, n); } } @@ -1122,7 +1122,7 @@ static bool check_ic_target (gimple call_stmt, struct cgraph_node *target) { location_t locus; - if (gimple_check_call_matching_types (call_stmt, target->decl)) + if (gimple_check_call_matching_types (call_stmt, target->symbol.decl)) return true; locus = gimple_location (call_stmt); @@ -1162,7 +1162,7 @@ gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call, SSA_NAME_DEF_STMT (tmp0) = load_stmt; gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT); - tmp = fold_convert (optype, build_addr (direct_call->decl, + tmp = fold_convert (optype, build_addr (direct_call->symbol.decl, current_function_decl)); load_stmt = gimple_build_assign (tmp1, tmp); SSA_NAME_DEF_STMT (tmp1) = load_stmt; @@ -1175,8 +1175,8 @@ gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call, gimple_set_vuse (icall_stmt, NULL_TREE); update_stmt (icall_stmt); dcall_stmt = gimple_copy (icall_stmt); - gimple_call_set_fndecl (dcall_stmt, direct_call->decl); - dflags = flags_from_decl_or_type (direct_call->decl); + gimple_call_set_fndecl (dcall_stmt, direct_call->symbol.decl); + dflags = flags_from_decl_or_type (direct_call->symbol.decl); if ((dflags & ECF_NORETURN) != 0) gimple_call_set_lhs (dcall_stmt, NULL_TREE); gsi_insert_before (&gsi, dcall_stmt, GSI_SAME_STMT); @@ -1341,7 +1341,7 @@ gimple_ic_transform (gimple stmt) fprintf (dump_file, "Indirect call -> direct call "); print_generic_expr (dump_file, gimple_call_fn (stmt), TDF_SLIM); fprintf (dump_file, "=> "); - print_generic_expr (dump_file, direct_call->decl, TDF_SLIM); + print_generic_expr (dump_file, direct_call->symbol.decl, TDF_SLIM); fprintf (dump_file, " transformation on insn "); print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); fprintf (dump_file, " to "); diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index c6280e2c1f1..c3fe428ab90 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -320,6 +320,19 @@ typedef struct loc_exp_dep_s DEF_VEC_O (loc_exp_dep); +/* This data structure holds information about the depth of a variable + expansion. */ +typedef struct expand_depth_struct +{ + /* This measures the complexity of the expanded expression. It + grows by one for each level of expansion that adds more than one + operand. */ + int complexity; + /* This counts the number of ENTRY_VALUE expressions in an + expansion. We want to minimize their use. */ + int entryvals; +} expand_depth; + /* This data structure is allocated for one-part variables at the time of emitting notes. */ struct onepart_aux @@ -338,7 +351,7 @@ struct onepart_aux a change notification from any of its active dependencies. */ rtx from; /* The depth of the cur_loc expression. */ - int depth; + expand_depth depth; /* Dependencies actively used when expand FROM into cur_loc. */ VEC (loc_exp_dep, none) deps; }; @@ -7491,7 +7504,7 @@ struct expand_loc_callback_data /* The maximum depth among the sub-expressions under expansion. Zero indicates no expansion so far. */ - int depth; + expand_depth depth; }; /* Allocate the one-part auxiliary data structure for VAR, with enough @@ -7536,7 +7549,8 @@ loc_exp_dep_alloc (variable var, int count) VAR_LOC_1PAUX (var) = XNEWVAR (struct onepart_aux, allocsize); *VAR_LOC_DEP_LSTP (var) = NULL; VAR_LOC_FROM (var) = NULL; - VAR_LOC_DEPTH (var) = 0; + VAR_LOC_DEPTH (var).complexity = 0; + VAR_LOC_DEPTH (var).entryvals = 0; } VEC_embedded_init (loc_exp_dep, VAR_LOC_DEP_VEC (var), count); } @@ -7691,21 +7705,26 @@ static rtx vt_expand_loc_callback (rtx x, bitmap regs, /* Return the combined depth, when one sub-expression evaluated to BEST_DEPTH and the previous known depth was SAVED_DEPTH. */ -static inline int -update_depth (int saved_depth, int best_depth) +static inline expand_depth +update_depth (expand_depth saved_depth, expand_depth best_depth) { /* If we didn't find anything, stick with what we had. */ - if (!best_depth) + if (!best_depth.complexity) return saved_depth; /* If we found hadn't found anything, use the depth of the current expression. Do NOT add one extra level, we want to compute the maximum depth among sub-expressions. We'll increment it later, if appropriate. */ - if (!saved_depth) + if (!saved_depth.complexity) return best_depth; - if (saved_depth < best_depth) + /* Combine the entryval count so that regardless of which one we + return, the entryval count is accurate. */ + best_depth.entryvals = saved_depth.entryvals + = best_depth.entryvals + saved_depth.entryvals; + + if (saved_depth.complexity < best_depth.complexity) return best_depth; else return saved_depth; @@ -7727,12 +7746,14 @@ vt_expand_var_loc_chain (variable var, bitmap regs, void *data, bool *pendrecp) bool pending_recursion; rtx loc_from = NULL; struct elt_loc_list *cloc = NULL; - int depth = 0, saved_depth = elcd->depth; + expand_depth depth = { 0, 0 }, saved_depth = elcd->depth; + int wanted_entryvals, found_entryvals = 0; /* Clear all backlinks pointing at this, so that we're not notified while we're active. */ loc_exp_dep_clear (var); + retry: if (var->onepart == ONEPART_VALUE) { cselib_val *val = CSELIB_VAL_PTR (dv_as_value (var->dv)); @@ -7745,13 +7766,15 @@ vt_expand_var_loc_chain (variable var, bitmap regs, void *data, bool *pendrecp) first_child = result_first_child = last_child = VEC_length (rtx, elcd->expanding); + wanted_entryvals = found_entryvals; + /* Attempt to expand each available location in turn. */ for (next = loc = var->n_var_parts ? var->var_part[0].loc_chain : NULL; loc || cloc; loc = next) { result_first_child = last_child; - if (!loc || (GET_CODE (loc->loc) == ENTRY_VALUE && cloc)) + if (!loc) { loc_from = cloc->loc; next = loc; @@ -7767,7 +7790,7 @@ vt_expand_var_loc_chain (variable var, bitmap regs, void *data, bool *pendrecp) gcc_checking_assert (!unsuitable_loc (loc_from)); - elcd->depth = 0; + elcd->depth.complexity = elcd->depth.entryvals = 0; result = cselib_expand_value_rtx_cb (loc_from, regs, EXPR_DEPTH, vt_expand_loc_callback, data); last_child = VEC_length (rtx, elcd->expanding); @@ -7776,23 +7799,48 @@ vt_expand_var_loc_chain (variable var, bitmap regs, void *data, bool *pendrecp) { depth = elcd->depth; - gcc_checking_assert (depth || result_first_child == last_child); + gcc_checking_assert (depth.complexity + || result_first_child == last_child); if (last_child - result_first_child != 1) - depth++; + { + if (!depth.complexity && GET_CODE (result) == ENTRY_VALUE) + depth.entryvals++; + depth.complexity++; + } - if (depth <= EXPR_USE_DEPTH) - break; + if (depth.complexity <= EXPR_USE_DEPTH) + { + if (depth.entryvals <= wanted_entryvals) + break; + else if (!found_entryvals || depth.entryvals < found_entryvals) + found_entryvals = depth.entryvals; + } result = NULL; } /* Set it up in case we leave the loop. */ - depth = 0; + depth.complexity = depth.entryvals = 0; loc_from = NULL; result_first_child = first_child; } + if (!loc_from && wanted_entryvals < found_entryvals) + { + /* We found entries with ENTRY_VALUEs and skipped them. Since + we could not find any expansions without ENTRY_VALUEs, but we + found at least one with them, go back and get an entry with + the minimum number ENTRY_VALUE count that we found. We could + avoid looping, but since each sub-loc is already resolved, + the re-expansion should be trivial. ??? Should we record all + attempted locs as dependencies, so that we retry the + expansion should any of them change, in the hope it can give + us a new entry without an ENTRY_VALUE? */ + VEC_truncate (rtx, elcd->expanding, first_child); + goto retry; + } + /* Register all encountered dependencies as active. */ pending_recursion = loc_exp_dep_set (var, result, VEC_address (rtx, elcd->expanding) + result_first_child, @@ -7805,7 +7853,7 @@ vt_expand_var_loc_chain (variable var, bitmap regs, void *data, bool *pendrecp) VAR_LOC_FROM (var) = loc_from; VAR_LOC_DEPTH (var) = depth; - gcc_checking_assert (!depth == !result); + gcc_checking_assert (!depth.complexity == !result); elcd->depth = update_depth (saved_depth, depth); @@ -7893,7 +7941,7 @@ vt_expand_loc_callback (rtx x, bitmap regs, gcc_checking_assert (!NO_LOC_P (x)); gcc_checking_assert (var->var_part[0].cur_loc); gcc_checking_assert (VAR_LOC_1PAUX (var)); - gcc_checking_assert (VAR_LOC_1PAUX (var)->depth); + gcc_checking_assert (VAR_LOC_1PAUX (var)->depth.complexity); elcd->depth = update_depth (elcd->depth, VAR_LOC_1PAUX (var)->depth); @@ -7967,7 +8015,7 @@ resolve_expansions_pending_recursion (VEC (rtx, stack) *pending) (d).vars = (v); \ (d).expanding = VEC_alloc (rtx, stack, 4); \ (d).pending = VEC_alloc (rtx, stack, 4); \ - (d).depth = 0; \ + (d).depth.complexity = (d).depth.entryvals = 0; \ } \ while (0) /* Finalize expand_loc_callback_data D, resolved to location L. */ diff --git a/gcc/varasm.c b/gcc/varasm.c index 34ed948cade..c3d289eb91a 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -2249,15 +2249,14 @@ mark_decl_referenced (tree decl) struct cgraph_node *node = cgraph_get_create_node (decl); if (!DECL_EXTERNAL (decl) && !node->local.finalized) - cgraph_mark_needed_node (node); + cgraph_mark_force_output_node (node); } else if (TREE_CODE (decl) == VAR_DECL) { struct varpool_node *node = varpool_node (decl); - varpool_mark_needed_node (node); /* C++ frontend use mark_decl_references to force COMDAT variables to be output that might appear dead otherwise. */ - node->force_output = true; + node->symbol.force_output = true; } /* else do nothing - we can get various sorts of CST nodes here, which do not need to be marked. */ @@ -5271,13 +5270,20 @@ weak_finish_1 (tree decl) #endif } +/* Fiven an assembly name, find the decl it is associated with. */ +static tree +find_decl (tree target) +{ + symtab_node node = symtab_node_for_asm (target); + if (node) + return node->symbol.decl; + return NULL_TREE; +} + /* This TREE_LIST contains weakref targets. */ static GTY(()) tree weakref_targets; -/* Forward declaration. */ -static tree find_decl_and_mark_needed (tree decl, tree target); - /* Emit any pending weak declarations. */ void @@ -5303,7 +5309,7 @@ weak_finish (void) # if defined ASM_WEAKEN_LABEL && ! defined ASM_WEAKEN_DECL ASM_WEAKEN_LABEL (asm_out_file, IDENTIFIER_POINTER (target)); # else - tree decl = find_decl_and_mark_needed (alias_decl, target); + tree decl = find_decl (target); if (! decl) { @@ -5406,43 +5412,6 @@ globalize_decl (tree decl) VEC(alias_pair,gc) *alias_pairs; -/* Given an assembly name, find the decl it is associated with. At the - same time, mark it needed for cgraph. */ - -static tree -find_decl_and_mark_needed (tree decl, tree target) -{ - struct cgraph_node *fnode = NULL; - struct varpool_node *vnode = NULL; - - if (TREE_CODE (decl) == FUNCTION_DECL) - { - fnode = cgraph_node_for_asm (target); - if (fnode == NULL) - vnode = varpool_node_for_asm (target); - } - else - { - vnode = varpool_node_for_asm (target); - if (vnode == NULL) - fnode = cgraph_node_for_asm (target); - } - - if (fnode) - { - cgraph_mark_needed_node (fnode); - return fnode->decl; - } - else if (vnode) - { - varpool_mark_needed_node (vnode); - vnode->force_output = 1; - return vnode->decl; - } - else - return NULL_TREE; -} - /* Output the assembler code for a define (equate) using ASM_OUTPUT_DEF or ASM_OUTPUT_DEF_FROM_DECLS. The function defines the symbol whose tree node is DECL to have the value of the tree node TARGET. */ @@ -5748,7 +5717,7 @@ finish_aliases_1 (void) { tree target_decl; - target_decl = find_decl_and_mark_needed (p->decl, p->target); + target_decl = find_decl (p->target); if (target_decl == NULL) { if (symbol_alias_set_contains (defined, p->target)) @@ -5854,7 +5823,7 @@ assemble_alias (tree decl, tree target) /* If the target has already been emitted, we don't have to queue the alias. This saves a tad of memory. */ if (cgraph_global_info_ready) - target_decl = find_decl_and_mark_needed (decl, target); + target_decl = find_decl (target); else target_decl= NULL; if (target_decl && TREE_ASM_WRITTEN (target_decl)) @@ -5960,12 +5929,12 @@ dump_tm_clone_pairs (VEC(tm_alias_pair,heap) *tm_alias_pairs) TM_GETTMCLONE. If neither of these are true, we didn't generate a clone, and we didn't call it indirectly... no sense keeping it in the clone table. */ - if (!dst_n || !dst_n->needed) + if (!dst_n || !dst_n->analyzed) continue; /* This covers the case where we have optimized the original function away, and only access the transactional clone. */ - if (!src_n || !src_n->needed) + if (!src_n || !src_n->analyzed) continue; if (!switched) @@ -6900,20 +6869,20 @@ default_binds_local_p_1 (const_tree exp, int shlib) && (TREE_STATIC (exp) || DECL_EXTERNAL (exp))) { struct varpool_node *vnode = varpool_get_node (exp); - if (vnode && resolution_local_p (vnode->resolution)) + if (vnode && resolution_local_p (vnode->symbol.resolution)) resolved_locally = true; if (vnode - && resolution_to_local_definition_p (vnode->resolution)) + && resolution_to_local_definition_p (vnode->symbol.resolution)) resolved_to_local_def = true; } else if (TREE_CODE (exp) == FUNCTION_DECL && TREE_PUBLIC (exp)) { struct cgraph_node *node = cgraph_get_node (exp); if (node - && resolution_local_p (node->resolution)) + && resolution_local_p (node->symbol.resolution)) resolved_locally = true; if (node - && resolution_to_local_definition_p (node->resolution)) + && resolution_to_local_definition_p (node->symbol.resolution)) resolved_to_local_def = true; } @@ -6994,15 +6963,15 @@ decl_binds_to_current_def_p (tree decl) { struct varpool_node *vnode = varpool_get_node (decl); if (vnode - && vnode->resolution != LDPR_UNKNOWN) - return resolution_to_local_definition_p (vnode->resolution); + && vnode->symbol.resolution != LDPR_UNKNOWN) + return resolution_to_local_definition_p (vnode->symbol.resolution); } else if (TREE_CODE (decl) == FUNCTION_DECL) { struct cgraph_node *node = cgraph_get_node (decl); if (node - && node->resolution != LDPR_UNKNOWN) - return resolution_to_local_definition_p (node->resolution); + && node->symbol.resolution != LDPR_UNKNOWN) + return resolution_to_local_definition_p (node->symbol.resolution); } /* Otherwise we have to assume the worst for DECL_WEAK (hidden weaks binds locally but still can be overwritten). diff --git a/gcc/varpool.c b/gcc/varpool.c index e064f7bd648..7c8d1fd8c9f 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -1,5 +1,5 @@ /* Callgraph handling code. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012 Free Software Foundation, Inc. Contributed by Jan Hubicka @@ -48,108 +48,20 @@ along with GCC; see the file COPYING3. If not see All variables supposed to be output into final file needs to be explicitly marked by frontend via VARPOOL_FINALIZE_DECL function. */ -/* Hash table used to convert declarations into nodes. */ -static GTY((param_is (struct varpool_node))) htab_t varpool_hash; - -/* The linked list of cgraph varpool nodes. - Linked via node->next pointer. */ -struct varpool_node *varpool_nodes; - -/* Queue of cgraph nodes scheduled to be lowered and output. - The queue is maintained via mark_needed_node, linked via node->next_needed - pointer. - - LAST_NEEDED_NODE points to the end of queue, so it can be - maintained in forward order. GTY is needed to make it friendly to - PCH. - - During compilation we construct the queue of needed variables - twice: first time it is during cgraph construction, second time it is at the - end of compilation in VARPOOL_REMOVE_UNREFERENCED_DECLS so we can avoid - optimized out variables being output. - - Each variable is thus first analyzed and then later possibly output. - FIRST_UNANALYZED_NODE points to first node in queue that was not analyzed - yet and is moved via VARPOOL_ANALYZE_PENDING_DECLS. */ - -struct varpool_node *varpool_nodes_queue; -static GTY(()) struct varpool_node *varpool_last_needed_node; -static GTY(()) struct varpool_node *varpool_first_unanalyzed_node; - -/* Lists all assembled variables to be sent to debugger output later on. */ -static GTY(()) struct varpool_node *varpool_assembled_nodes_queue; - -/* Return name of the node used in debug output. */ -const char * -varpool_node_name (struct varpool_node *node) -{ - return lang_hooks.decl_printable_name (node->decl, 2); -} - -/* Returns a hash code for P. */ -static hashval_t -hash_varpool_node (const void *p) -{ - const struct varpool_node *n = (const struct varpool_node *) p; - return (hashval_t) DECL_UID (n->decl); -} - -/* Returns nonzero if P1 and P2 are equal. */ -static int -eq_varpool_node (const void *p1, const void *p2) -{ - const struct varpool_node *n1 = - (const struct varpool_node *) p1; - const struct varpool_node *n2 = - (const struct varpool_node *) p2; - return DECL_UID (n1->decl) == DECL_UID (n2->decl); -} - -/* Return varpool node assigned to DECL without creating new one. */ -struct varpool_node * -varpool_get_node (const_tree decl) -{ - struct varpool_node key, **slot; - - gcc_assert (TREE_CODE (decl) == VAR_DECL - && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))); - - if (!varpool_hash) - return NULL; - key.decl = CONST_CAST2 (tree, const_tree, decl); - slot = (struct varpool_node **) - htab_find_slot (varpool_hash, &key, NO_INSERT); - if (!slot) - return NULL; - return *slot; -} - /* Return varpool node assigned to DECL. Create new one when needed. */ struct varpool_node * varpool_node (tree decl) { - struct varpool_node key, *node, **slot; - + struct varpool_node *node = varpool_get_node (decl); gcc_assert (TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p)); + if (node) + return node; - if (!varpool_hash) - varpool_hash = htab_create_ggc (10, hash_varpool_node, - eq_varpool_node, NULL); - key.decl = decl; - slot = (struct varpool_node **) - htab_find_slot (varpool_hash, &key, INSERT); - if (*slot) - return *slot; node = ggc_alloc_cleared_varpool_node (); - node->decl = decl; - node->order = cgraph_order++; - node->next = varpool_nodes; - ipa_empty_ref_list (&node->ref_list); - if (varpool_nodes) - varpool_nodes->prev = node; - varpool_nodes = node; - *slot = node; + node->symbol.type = SYMTAB_VARIABLE; + node->symbol.decl = decl; + symtab_register_node ((symtab_node)node); return node; } @@ -157,51 +69,7 @@ varpool_node (tree decl) void varpool_remove_node (struct varpool_node *node) { - void **slot; - slot = htab_find_slot (varpool_hash, node, NO_INSERT); - gcc_assert (*slot == node); - htab_clear_slot (varpool_hash, slot); - gcc_assert (!varpool_assembled_nodes_queue); - if (node->next) - node->next->prev = node->prev; - if (node->prev) - node->prev->next = node->next; - else - { - gcc_assert (varpool_nodes == node); - varpool_nodes = node->next; - } - if (varpool_first_unanalyzed_node == node) - varpool_first_unanalyzed_node = node->next_needed; - if (node->next_needed) - node->next_needed->prev_needed = node->prev_needed; - else if (node->prev_needed) - { - gcc_assert (varpool_last_needed_node); - varpool_last_needed_node = node->prev_needed; - } - if (node->prev_needed) - node->prev_needed->next_needed = node->next_needed; - else if (node->next_needed) - { - gcc_assert (varpool_nodes_queue == node); - varpool_nodes_queue = node->next_needed; - } - if (node->same_comdat_group) - { - struct varpool_node *prev; - for (prev = node->same_comdat_group; - prev->same_comdat_group != node; - prev = prev->same_comdat_group) - ; - if (node->same_comdat_group == prev) - prev->same_comdat_group = NULL; - else - prev->same_comdat_group = node->same_comdat_group; - node->same_comdat_group = NULL; - } - ipa_remove_all_references (&node->ref_list); - ipa_remove_all_refering (&node->ref_list); + symtab_unregister_node ((symtab_node)node); ggc_free (node); } @@ -209,39 +77,21 @@ varpool_remove_node (struct varpool_node *node) void dump_varpool_node (FILE *f, struct varpool_node *node) { - fprintf (f, "%s:", varpool_node_name (node)); - fprintf (f, " availability:%s", + dump_symtab_base (f, (symtab_node)node); + fprintf (f, " Availability: %s\n", cgraph_function_flags_ready ? cgraph_availability_names[cgraph_variable_initializer_availability (node)] : "not-ready"); - if (DECL_ASSEMBLER_NAME_SET_P (node->decl)) - fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))); - if (DECL_INITIAL (node->decl)) + fprintf (f, " Varpool flags:"); + if (DECL_INITIAL (node->symbol.decl)) fprintf (f, " initialized"); - if (TREE_ASM_WRITTEN (node->decl)) - fprintf (f, " (asm written)"); - if (node->needed) - fprintf (f, " needed"); if (node->analyzed) fprintf (f, " analyzed"); if (node->finalized) fprintf (f, " finalized"); if (node->output) fprintf (f, " output"); - if (node->externally_visible) - fprintf (f, " externally_visible"); - if (node->resolution != LDPR_UNKNOWN) - fprintf (f, " %s", - ld_plugin_symbol_resolution_names[(int)node->resolution]); - if (node->in_other_partition) - fprintf (f, " in_other_partition"); - else if (node->used_from_other_partition) - fprintf (f, " used_from_other_partition"); fprintf (f, "\n"); - fprintf (f, " References: "); - ipa_dump_references (f, &node->ref_list); - fprintf (f, " Refering this var: "); - ipa_dump_refering (f, &node->ref_list); } /* Dump the variable pool. */ @@ -251,7 +101,7 @@ dump_varpool (FILE *f) struct varpool_node *node; fprintf (f, "variable pool:\n\n"); - for (node = varpool_nodes; node; node = node->next) + FOR_EACH_VARIABLE (node) dump_varpool_node (f, node); } @@ -267,54 +117,12 @@ debug_varpool (void) struct varpool_node * varpool_node_for_asm (tree asmname) { - struct varpool_node *node; - - for (node = varpool_nodes; node ; node = node->next) - if (decl_assembler_name_equal (node->decl, asmname)) - return node; - + symtab_node node = symtab_node_for_asm (asmname); + if (node && symtab_variable_p (node)) + return varpool (node); return NULL; } -/* Helper function for finalization code - add node into lists so it will - be analyzed and compiled. */ -static void -varpool_enqueue_needed_node (struct varpool_node *node) -{ - if (varpool_last_needed_node) - { - varpool_last_needed_node->next_needed = node; - node->prev_needed = varpool_last_needed_node; - } - varpool_last_needed_node = node; - node->next_needed = NULL; - if (!varpool_nodes_queue) - varpool_nodes_queue = node; - if (!varpool_first_unanalyzed_node) - varpool_first_unanalyzed_node = node; - notice_global_symbol (node->decl); -} - -/* Notify finalize_compilation_unit that given node is reachable - or needed. */ -void -varpool_mark_needed_node (struct varpool_node *node) -{ - if (!node->needed && node->finalized - && !TREE_ASM_WRITTEN (node->decl)) - varpool_enqueue_needed_node (node); - node->needed = 1; -} - -/* Reset the queue of needed nodes. */ -void -varpool_reset_queue (void) -{ - varpool_last_needed_node = NULL; - varpool_nodes_queue = NULL; - varpool_first_unanalyzed_node = NULL; -} - /* Determine if variable DECL is needed. That is, visible to something either outside this translation unit, something magic in the system configury */ @@ -322,7 +130,7 @@ bool decide_is_variable_needed (struct varpool_node *node, tree decl) { /* If the user told us it is used, then it must be so. */ - if (node->force_output) + if (node->symbol.force_output) return true; gcc_assert (!DECL_EXTERNAL (decl)); @@ -378,42 +186,6 @@ const_value_known_p (tree decl) return true; } -/* Mark DECL as finalized. By finalizing the declaration, frontend instruct the - middle end to output the variable to asm file, if needed or externally - visible. */ -void -varpool_finalize_decl (tree decl) -{ - struct varpool_node *node = varpool_node (decl); - - gcc_assert (TREE_STATIC (decl)); - - /* The first declaration of a variable that comes through this function - decides whether it is global (in C, has external linkage) - or local (in C, has internal linkage). So do nothing more - if this function has already run. */ - if (node->finalized) - { - if (cgraph_global_info_ready) - varpool_assemble_pending_decls (); - return; - } - if (node->needed) - varpool_enqueue_needed_node (node); - node->finalized = true; - if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl) - /* Traditionally we do not eliminate static variables when not - optimizing and when not doing toplevel reoder. */ - || (!flag_toplevel_reorder && !DECL_COMDAT (node->decl) - && !DECL_ARTIFICIAL (node->decl))) - node->force_output = true; - - if (decide_is_variable_needed (node, decl)) - varpool_mark_needed_node (node); - if (cgraph_global_info_ready) - varpool_assemble_pending_decls (); -} - /* Add the variable DECL to the varpool. Unlike varpool_finalize_decl function is intended to be used by middle end and allows insertion of new variable at arbitrary point @@ -425,7 +197,7 @@ varpool_add_new_variable (tree decl) varpool_finalize_decl (decl); node = varpool_node (decl); if (varpool_externally_visible_p (node, false)) - node->externally_visible = true; + node->symbol.externally_visible = true; } /* Return variable availability. See cgraph.h for description of individual @@ -436,101 +208,79 @@ cgraph_variable_initializer_availability (struct varpool_node *node) gcc_assert (cgraph_function_flags_ready); if (!node->finalized) return AVAIL_NOT_AVAILABLE; - if (!TREE_PUBLIC (node->decl)) + if (!TREE_PUBLIC (node->symbol.decl)) return AVAIL_AVAILABLE; /* If the variable can be overwritten, return OVERWRITABLE. Takes care of at least two notable extensions - the COMDAT variables used to share template instantiations in C++. */ - if (!decl_replaceable_p (node->decl)) + if (!decl_replaceable_p (node->symbol.decl)) return AVAIL_OVERWRITABLE; return AVAIL_AVAILABLE; } -/* Walk the decls we marked as necessary and see if they reference new - variables or functions and add them into the worklists. */ -bool -varpool_analyze_pending_decls (void) +void +varpool_analyze_node (struct varpool_node *node) { - bool changed = false; + tree decl = node->symbol.decl; - timevar_push (TV_VARPOOL); - while (varpool_first_unanalyzed_node) + /* When reading back varpool at LTO time, we re-construct the queue in order + to have "needed" list right by inserting all needed nodes into varpool. + We however don't want to re-analyze already analyzed nodes. */ + if (!node->analyzed) { - struct varpool_node *node = varpool_first_unanalyzed_node, *next; - tree decl = node->decl; - bool analyzed = node->analyzed; - - varpool_first_unanalyzed_node->analyzed = true; - - varpool_first_unanalyzed_node = varpool_first_unanalyzed_node->next_needed; - - /* When reading back varpool at LTO time, we re-construct the queue in order - to have "needed" list right by inserting all needed nodes into varpool. - We however don't want to re-analyze already analyzed nodes. */ - if (!analyzed) - { - gcc_assert (!in_lto_p || cgraph_function_flags_ready); - /* Compute the alignment early so function body expanders are - already informed about increased alignment. */ - align_variable (decl, 0); - } - if (node->alias && node->alias_of) + gcc_assert (!in_lto_p || cgraph_function_flags_ready); + /* Compute the alignment early so function body expanders are + already informed about increased alignment. */ + align_variable (decl, 0); + } + if (node->alias && node->alias_of) + { + struct varpool_node *tgt = varpool_node (node->alias_of); + struct varpool_node *n; + + for (n = tgt; n && n->alias; + n = n->analyzed ? varpool_alias_aliased_node (n) : NULL) + if (n == node) + { + error ("variable %q+D part of alias cycle", node->symbol.decl); + node->alias = false; + continue; + } + if (!VEC_length (ipa_ref_t, node->symbol.ref_list.references)) + ipa_record_reference ((symtab_node)node, (symtab_node)tgt, IPA_REF_ALIAS, NULL); + /* C++ FE sometimes change linkage flags after producing same body aliases. */ + if (node->extra_name_alias) { - struct varpool_node *tgt = varpool_node (node->alias_of); - struct varpool_node *n; - - for (n = tgt; n && n->alias; - n = n->analyzed ? varpool_alias_aliased_node (n) : NULL) - if (n == node) - { - error ("variable %q+D part of alias cycle", node->decl); - node->alias = false; - continue; - } - if (!VEC_length (ipa_ref_t, node->ref_list.references)) - ipa_record_reference (NULL, node, NULL, tgt, IPA_REF_ALIAS, NULL); - /* C++ FE sometimes change linkage flags after producing same body aliases. */ - if (node->extra_name_alias) + DECL_WEAK (node->symbol.decl) = DECL_WEAK (node->alias_of); + TREE_PUBLIC (node->symbol.decl) = TREE_PUBLIC (node->alias_of); + DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (node->alias_of); + DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (node->alias_of); + if (TREE_PUBLIC (node->symbol.decl)) { - DECL_WEAK (node->decl) = DECL_WEAK (node->alias_of); - TREE_PUBLIC (node->decl) = TREE_PUBLIC (node->alias_of); - DECL_EXTERNAL (node->decl) = DECL_EXTERNAL (node->alias_of); - DECL_VISIBILITY (node->decl) = DECL_VISIBILITY (node->alias_of); - if (TREE_PUBLIC (node->decl)) + DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (node->alias_of); + DECL_COMDAT_GROUP (node->symbol.decl) = DECL_COMDAT_GROUP (node->alias_of); + if (DECL_ONE_ONLY (node->alias_of) + && !node->symbol.same_comdat_group) { - DECL_COMDAT (node->decl) = DECL_COMDAT (node->alias_of); - DECL_COMDAT_GROUP (node->decl) = DECL_COMDAT_GROUP (node->alias_of); - if (DECL_ONE_ONLY (node->alias_of) && !node->same_comdat_group) + node->symbol.same_comdat_group = (symtab_node)tgt; + if (!tgt->symbol.same_comdat_group) + tgt->symbol.same_comdat_group = (symtab_node)node; + else { - node->same_comdat_group = tgt; - if (!tgt->same_comdat_group) - tgt->same_comdat_group = node; - else - { - struct varpool_node *n; - for (n = tgt->same_comdat_group; - n->same_comdat_group != tgt; - n = n->same_comdat_group) - ; - n->same_comdat_group = node; - } + symtab_node n; + for (n = tgt->symbol.same_comdat_group; + n->symbol.same_comdat_group != (symtab_node)tgt; + n = n->symbol.same_comdat_group) + ; + n->symbol.same_comdat_group = (symtab_node)node; } } } } - else if (DECL_INITIAL (decl)) - record_references_in_initializer (decl, analyzed); - if (node->same_comdat_group) - { - for (next = node->same_comdat_group; - next != node; - next = next->same_comdat_group) - varpool_mark_needed_node (next); - } - changed = true; } - timevar_pop (TV_VARPOOL); - return changed; + else if (DECL_INITIAL (decl)) + record_references_in_initializer (decl, node->analyzed); + node->analyzed = true; } /* Assemble thunks and aliases asociated to NODE. */ @@ -540,11 +290,11 @@ assemble_aliases (struct varpool_node *node) { int i; struct ipa_ref *ref; - for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); i++) if (ref->use == IPA_REF_ALIAS) { - struct varpool_node *alias = ipa_ref_refering_varpool_node (ref); - assemble_alias (alias->decl, + struct varpool_node *alias = ipa_ref_referring_varpool_node (ref); + assemble_alias (alias->symbol.decl, DECL_ASSEMBLER_NAME (alias->alias_of)); assemble_aliases (alias); } @@ -554,22 +304,17 @@ assemble_aliases (struct varpool_node *node) bool varpool_assemble_decl (struct varpool_node *node) { - tree decl = node->decl; + tree decl = node->symbol.decl; if (!TREE_ASM_WRITTEN (decl) && !node->alias - && !node->in_other_partition + && !node->symbol.in_other_partition && !DECL_EXTERNAL (decl) && (TREE_CODE (decl) != VAR_DECL || !DECL_HAS_VALUE_EXPR_P (decl))) { assemble_variable (decl, 0, 1, 0); if (TREE_ASM_WRITTEN (decl)) { - node->next_needed = varpool_assembled_nodes_queue; - node->prev_needed = NULL; - if (varpool_assembled_nodes_queue) - varpool_assembled_nodes_queue->prev_needed = node; - varpool_assembled_nodes_queue = node; node->finalized = 1; assemble_aliases (node); return true; @@ -579,40 +324,85 @@ varpool_assemble_decl (struct varpool_node *node) return false; } +/* Add NODE to queue starting at FIRST. + The queue is linked via AUX pointers and terminated by pointer to 1. */ + +static void +enqueue_node (struct varpool_node *node, struct varpool_node **first) +{ + if (node->symbol.aux) + return; + gcc_checking_assert (*first); + node->symbol.aux = *first; + *first = node; +} + /* Optimization of function bodies might've rendered some variables as - unnecessary so we want to avoid these from being compiled. + unnecessary so we want to avoid these from being compiled. Re-do + reachability starting from variables that are either externally visible + or was referred from the asm output routines. */ - This is done by pruning the queue and keeping only the variables that - really appear needed (ie they are either externally visible or referenced - by compiled function). Re-doing the reachability analysis on variables - brings back the remaining variables referenced by these. */ void varpool_remove_unreferenced_decls (void) { - struct varpool_node *next, *node = varpool_nodes_queue; - - varpool_reset_queue (); + struct varpool_node *next, *node; + struct varpool_node *first = (struct varpool_node *)(void *)1; + int i; + struct ipa_ref *ref; if (seen_error ()) return; - while (node) + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Trivially needed variables:"); + finish_aliases_1 (); + FOR_EACH_DEFINED_VARIABLE (node) { - next = node->next_needed; - node->needed = 0; - if (node->analyzed && (!varpool_can_remove_if_no_refs (node) /* We just expanded all function bodies. See if any of them needed the variable. */ - || DECL_RTL_SET_P (node->decl))) - varpool_mark_needed_node (node); + || DECL_RTL_SET_P (node->symbol.decl))) + { + enqueue_node (node, &first); + if (cgraph_dump_file) + fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node)); + } + } + while (first != (struct varpool_node *)(void *)1) + { + node = first; + first = (struct varpool_node *)first->symbol.aux; - node = next; + if (node->symbol.same_comdat_group) + { + symtab_node next; + for (next = node->symbol.same_comdat_group; + next != (symtab_node)node; + next = next->symbol.same_comdat_group) + if (symtab_variable_p (next) + && varpool (next)->analyzed) + enqueue_node (varpool (next), &first); + } + for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++) + if (symtab_variable_p (ref->referred) + && varpool (ref->referred)->analyzed) + enqueue_node (varpool (ref->referred), &first); } - /* Make sure we mark alias targets as used targets. */ - finish_aliases_1 (); - varpool_analyze_pending_decls (); + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "\nRemoving variables:"); + for (node = varpool_first_defined_variable (); node; node = next) + { + next = varpool_next_defined_variable (node); + if (!node->symbol.aux) + { + if (cgraph_dump_file) + fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node)); + varpool_remove_node (node); + } + } + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "\n"); } /* For variables in named sections make sure get_variable_section @@ -622,14 +412,14 @@ varpool_remove_unreferenced_decls (void) void varpool_finalize_named_section_flags (struct varpool_node *node) { - if (!TREE_ASM_WRITTEN (node->decl) + if (!TREE_ASM_WRITTEN (node->symbol.decl) && !node->alias - && !node->in_other_partition - && !DECL_EXTERNAL (node->decl) - && TREE_CODE (node->decl) == VAR_DECL - && !DECL_HAS_VALUE_EXPR_P (node->decl) - && DECL_SECTION_NAME (node->decl)) - get_variable_section (node->decl, false); + && !node->symbol.in_other_partition + && !DECL_EXTERNAL (node->symbol.decl) + && TREE_CODE (node->symbol.decl) == VAR_DECL + && !DECL_HAS_VALUE_EXPR_P (node->symbol.decl) + && DECL_SECTION_NAME (node->symbol.decl)) + get_variable_section (node->symbol.decl, false); } /* Output all variables enqueued to be assembled. */ @@ -643,55 +433,17 @@ varpool_assemble_pending_decls (void) return false; timevar_push (TV_VAROUT); - /* EH might mark decls as needed during expansion. This should be safe since - we don't create references to new function, but it should not be used - elsewhere. */ - varpool_analyze_pending_decls (); - for (node = varpool_nodes_queue; node; node = node->next_needed) + FOR_EACH_DEFINED_VARIABLE (node) varpool_finalize_named_section_flags (node); - while (varpool_nodes_queue) - { - struct varpool_node *node = varpool_nodes_queue; - - varpool_nodes_queue = varpool_nodes_queue->next_needed; - if (varpool_assemble_decl (node)) - changed = true; - else - { - node->prev_needed = NULL; - node->next_needed = NULL; - } - } - /* varpool_nodes_queue is now empty, clear the pointer to the last element - in the queue. */ - varpool_last_needed_node = NULL; + FOR_EACH_DEFINED_VARIABLE (node) + if (varpool_assemble_decl (node)) + changed = true; timevar_pop (TV_VAROUT); return changed; } -/* Remove all elements from the queue so we can re-use it for debug output. */ -void -varpool_empty_needed_queue (void) -{ - /* EH might mark decls as needed during expansion. This should be safe since - we don't create references to new function, but it should not be used - elsewhere. */ - varpool_analyze_pending_decls (); - - while (varpool_nodes_queue) - { - struct varpool_node *node = varpool_nodes_queue; - varpool_nodes_queue = varpool_nodes_queue->next_needed; - node->next_needed = NULL; - node->prev_needed = NULL; - } - /* varpool_nodes_queue is now empty, clear the pointer to the last element - in the queue. */ - varpool_last_needed_node = NULL; -} - /* Create a new global variable of type TYPE. */ tree add_new_static_var (tree type) @@ -709,11 +461,10 @@ add_new_static_var (tree type) lang_hooks.dup_lang_specific_decl (new_decl); create_var_ann (new_decl); new_node = varpool_node (new_decl); - varpool_mark_needed_node (new_node); add_referenced_var (new_decl); varpool_finalize_decl (new_decl); - return new_node->decl; + return new_node->symbol.decl; } /* Attempt to mark ALIAS as an alias to DECL. Return TRUE if successful. @@ -728,13 +479,19 @@ varpool_create_variable_alias (tree alias, tree decl) gcc_assert (TREE_CODE (alias) == VAR_DECL); alias_node = varpool_node (alias); alias_node->alias = 1; - if (!DECL_EXTERNAL (alias)) - alias_node->finalized = 1; + alias_node->finalized = 1; alias_node->alias_of = decl; - if ((!DECL_EXTERNAL (alias) - && decide_is_variable_needed (alias_node, alias)) - || alias_node->needed) - varpool_mark_needed_node (alias_node); + + /* Extra name alias mechanizm creates aliases really late + via DECL_ASSEMBLER_NAME mechanizm. + This is unfortunate because they are not going through the + standard channels. Ensure they get output. */ + if (cgraph_state >= CGRAPH_STATE_IPA) + { + varpool_analyze_node (alias_node); + if (TREE_PUBLIC (alias)) + alias_node->symbol.externally_visible = true; + } return alias_node; } @@ -761,9 +518,9 @@ varpool_extra_name_alias (tree alias, tree decl) bool varpool_used_from_object_file_p (struct varpool_node *node) { - if (!TREE_PUBLIC (node->decl)) + if (!TREE_PUBLIC (node->symbol.decl)) return false; - if (resolution_used_from_other_file_p (node->resolution)) + if (resolution_used_from_other_file_p (node->symbol.resolution)) return true; return false; } @@ -783,10 +540,10 @@ varpool_for_node_and_aliases (struct varpool_node *node, if (callback (node, data)) return true; - for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); i++) if (ref->use == IPA_REF_ALIAS) { - struct varpool_node *alias = ipa_ref_refering_varpool_node (ref); + struct varpool_node *alias = ipa_ref_referring_varpool_node (ref); if (include_overwritable || cgraph_variable_initializer_availability (alias) > AVAIL_OVERWRITABLE) if (varpool_for_node_and_aliases (alias, callback, data, @@ -795,4 +552,3 @@ varpool_for_node_and_aliases (struct varpool_node *node, } return false; } -#include "gt-varpool.h" diff --git a/include/ChangeLog b/include/ChangeLog index b9e81e31f40..4e0ee9a0c1c 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2012-04-10 Tristan Gingold <gingold@adacore.com> + + * splay-tree.h: Conditionnaly includes stdint.h and inttypes.h + (libi_uhostptr_t, libi_shostptr_t): Remove, replaced by uintptr_t. + 2012-01-26 Cary Coutant <ccoutant@google.com> * dwarf2.h (enum dwarf_form): Add Fission extensions. diff --git a/include/splay-tree.h b/include/splay-tree.h index 480b2c43e7d..a26135a099d 100644 --- a/include/splay-tree.h +++ b/include/splay-tree.h @@ -37,18 +37,11 @@ extern "C" { #include "ansidecl.h" -#ifndef _WIN64 - typedef unsigned long int libi_uhostptr_t; - typedef long int libi_shostptr_t; -#else -#ifdef __GNUC__ - __extension__ +#ifdef HAVE_STDINT_H +#include <stdint.h> #endif - typedef unsigned long long libi_uhostptr_t; -#ifdef __GNUC__ - __extension__ -#endif - typedef long long libi_shostptr_t; +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> #endif #ifndef GTY @@ -59,8 +52,8 @@ extern "C" { these types, if necessary. These types should be sufficiently wide that any pointer or scalar can be cast to these types, and then cast back, without loss of precision. */ -typedef libi_uhostptr_t splay_tree_key; -typedef libi_uhostptr_t splay_tree_value; +typedef uintptr_t splay_tree_key; +typedef uintptr_t splay_tree_value; /* Forward declaration for a node in the tree. */ typedef struct splay_tree_node_s *splay_tree_node; diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 354b3ceedf8..401fc6222de 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,20 @@ +2012-04-20 Thomas Schwinge <thomas@codesourcery.com> + + struct siginfo vs. siginfo_t + + * config/alpha/linux-unwind.h (alpha_fallback_frame_state): Use + siginfo_t instead of struct siginfo. + * config/bfin/linux-unwind.h (bfin_fallback_frame_state): Likewise. + * config/i386/linux-unwind.h (x86_fallback_frame_state): Likewise. + * config/ia64/linux-unwind.h (ia64_fallback_frame_state) + (ia64_handle_unwabi): Likewise. + * config/mips/linux-unwind.h (mips_fallback_frame_state): Likewise. + * config/pa/linux-unwind.h (pa32_fallback_frame_state): Likewise. + * config/sh/linux-unwind.h (shmedia_fallback_frame_state) + (sh_fallback_frame_state): Likewise. + * config/tilepro/linux-unwind.h (tile_fallback_frame_state): Likewise. + * config/xtensa/linux-unwind.h (xtensa_fallback_frame_state): Likewise. + 2012-04-02 H.J. Lu <hongjiu.lu@intel.com> * config/i386/linux-unwind.h (RT_SIGRETURN_SYSCALL): Update x32 diff --git a/libgcc/config/alpha/linux-unwind.h b/libgcc/config/alpha/linux-unwind.h index 4c811dca4bf..8c04b3b415f 100644 --- a/libgcc/config/alpha/linux-unwind.h +++ b/libgcc/config/alpha/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for Alpha Linux. - Copyright (C) 2004, 2005, 2009, 2011 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2009, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -49,7 +49,7 @@ alpha_fallback_frame_state (struct _Unwind_Context *context, else if (pc[1] == 0x201f015f) /* lda $0,NR_rt_sigreturn */ { struct rt_sigframe { - struct siginfo info; + siginfo_t info; struct ucontext uc; } *rt_ = context->cfa; sc = &rt_->uc.uc_mcontext; diff --git a/libgcc/config/bfin/linux-unwind.h b/libgcc/config/bfin/linux-unwind.h index 88c8285632d..15bb2f12b69 100644 --- a/libgcc/config/bfin/linux-unwind.h +++ b/libgcc/config/bfin/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for Blackfin. - Copyright (C) 2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2007, 2009, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -48,10 +48,10 @@ bfin_fallback_frame_state (struct _Unwind_Context *context, { struct rt_sigframe { int sig; - struct siginfo *pinfo; + siginfo_t *pinfo; void *puc; char retcode[8]; - struct siginfo info; + siginfo_t info; struct ucontext uc; } *rt_ = context->cfa; diff --git a/libgcc/config/i386/linux-unwind.h b/libgcc/config/i386/linux-unwind.h index ad0ccfa0be7..02b1897f039 100644 --- a/libgcc/config/i386/linux-unwind.h +++ b/libgcc/config/i386/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for AMD x86-64 and x86. - Copyright (C) 2004, 2005, 2006, 2009, 2010, 2011 + Copyright (C) 2004, 2005, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -136,9 +136,9 @@ x86_fallback_frame_state (struct _Unwind_Context *context, { struct rt_sigframe { int sig; - struct siginfo *pinfo; + siginfo_t *pinfo; void *puc; - struct siginfo info; + siginfo_t info; struct ucontext uc; } *rt_ = context->cfa; /* The void * cast is necessary to avoid an aliasing warning. diff --git a/libgcc/config/ia64/linux-unwind.h b/libgcc/config/ia64/linux-unwind.h index 93f762de573..da31259782b 100644 --- a/libgcc/config/ia64/linux-unwind.h +++ b/libgcc/config/ia64/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for IA64 Linux. - Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2009, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -47,7 +47,7 @@ ia64_fallback_frame_state (struct _Unwind_Context *context, struct sigframe { char scratch[16]; unsigned long sig_number; - struct siginfo *info; + siginfo_t *info; struct sigcontext *sc; } *frame_ = (struct sigframe *)context->psp; struct sigcontext *sc = frame_->sc; @@ -137,7 +137,7 @@ ia64_handle_unwabi (struct _Unwind_Context *context, _Unwind_FrameState *fs) struct sigframe { char scratch[16]; unsigned long sig_number; - struct siginfo *info; + siginfo_t *info; struct sigcontext *sc; } *frame = (struct sigframe *)context->psp; struct sigcontext *sc = frame->sc; diff --git a/libgcc/config/mips/linux-unwind.h b/libgcc/config/mips/linux-unwind.h index 02f7cd54c5a..094ff58cb03 100644 --- a/libgcc/config/mips/linux-unwind.h +++ b/libgcc/config/mips/linux-unwind.h @@ -1,5 +1,6 @@ /* DWARF2 EH unwinding support for MIPS Linux. - Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2012 Free Software + Foundation, Inc. This file is part of GCC. @@ -75,7 +76,7 @@ mips_fallback_frame_state (struct _Unwind_Context *context, struct rt_sigframe { u_int32_t ass[4]; /* Argument save space for o32. */ u_int32_t trampoline[2]; - struct siginfo info; + siginfo_t info; _sig_ucontext_t uc; } *rt_ = context->cfa; sc = &rt_->uc.uc_mcontext; diff --git a/libgcc/config/pa/linux-unwind.h b/libgcc/config/pa/linux-unwind.h index a0560e97445..38b4eda7aee 100644 --- a/libgcc/config/pa/linux-unwind.h +++ b/libgcc/config/pa/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for PA Linux. - Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2009, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -63,7 +63,7 @@ pa32_fallback_frame_state (struct _Unwind_Context *context, int i; struct sigcontext *sc; struct rt_sigframe { - struct siginfo info; + siginfo_t info; struct ucontext uc; } *frame; diff --git a/libgcc/config/sh/linux-unwind.h b/libgcc/config/sh/linux-unwind.h index 94ed95d55e1..5a78e3172aa 100644 --- a/libgcc/config/sh/linux-unwind.h +++ b/libgcc/config/sh/linux-unwind.h @@ -1,5 +1,6 @@ /* DWARF2 EH unwinding support for SH Linux. - Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2009, 2012 Free Software Foundation, + Inc. This file is part of GCC. @@ -80,9 +81,9 @@ shmedia_fallback_frame_state (struct _Unwind_Context *context, && (*(unsigned long *) (pc+11) == 0x6ff0fff0)) { struct rt_sigframe { - struct siginfo *pinfo; + siginfo_t *pinfo; void *puc; - struct siginfo info; + siginfo_t info; struct ucontext uc; } *rt_ = context->cfa; /* The void * cast is necessary to avoid an aliasing warning. @@ -179,7 +180,7 @@ sh_fallback_frame_state (struct _Unwind_Context *context, && (*(unsigned short *) (pc+14) == 0x00ad)))) { struct rt_sigframe { - struct siginfo info; + siginfo_t info; struct ucontext uc; } *rt_ = context->cfa; /* The void * cast is necessary to avoid an aliasing warning. diff --git a/libgcc/config/tilepro/linux-unwind.h b/libgcc/config/tilepro/linux-unwind.h index 0ed662c6598..27a6c4351eb 100644 --- a/libgcc/config/tilepro/linux-unwind.h +++ b/libgcc/config/tilepro/linux-unwind.h @@ -61,7 +61,7 @@ tile_fallback_frame_state (struct _Unwind_Context *context, struct rt_sigframe { unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; - struct siginfo info; + siginfo_t info; struct ucontext uc; } *rt_; diff --git a/libgcc/config/xtensa/linux-unwind.h b/libgcc/config/xtensa/linux-unwind.h index 32e93497287..24564972820 100644 --- a/libgcc/config/xtensa/linux-unwind.h +++ b/libgcc/config/xtensa/linux-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for Xtensa. - Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2008, 2009, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -62,7 +62,7 @@ xtensa_fallback_frame_state (struct _Unwind_Context *context, struct sigcontext *sc; struct rt_sigframe { - struct siginfo info; + siginfo_t info; struct ucontext uc; } *rt_; diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 93e9117d956..ec662841ee2 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,47 @@ +2012-04-22 Tobias Burnus <burnus@net-b.de> + + PR fortran/53051 + * io/list_read.c (parse_real): Support "q" for the + exponential. + * io/read.c (read_f): Ditto. + +2012-04-17 Tobias Burnus <burnus@net-b.de> + + PR libfortran/38199 + PR libfortran/50673 + * io/unit.c (get_internal_unit): Properly check for the presence + of the format string. + +2012-04-15 Thomas Koenig <tkoenig@gcc.gnu.org> + + PR libfortran/38199 + PR libfortran/50673 + * intrinsics/string_intriniscs_inc.c (string_len_trim): + Remove prototypes for string_len_trim and move to... + * libgfortran.h (string_len_trim): ... here and + (string_len_trim_char4): ...here. + * io/unit.c: For non-array internal arrays where we do reading, + adjust the record length to the last non-blank character. + * io/unix.c: Fix typo. + +2012-04-10 Michael Matz <matz@suse.de> + + * m4/cshift0.m4 (cshift0_'rtype_code`): Guard use of modulo. + + * generated/cshift0_c10.c: Regenerated. + * generated/cshift0_c16.c: Regenerated. + * generated/cshift0_c4.c: Regenerated. + * generated/cshift0_c8.c: Regenerated. + * generated/cshift0_i16.c: Regenerated. + * generated/cshift0_i1.c: Regenerated. + * generated/cshift0_i2.c: Regenerated. + * generated/cshift0_i4.c: Regenerated. + * generated/cshift0_i8.c: Regenerated. + * generated/cshift0_r10.c: Regenerated. + * generated/cshift0_r16.c: Regenerated. + * generated/cshift0_r4.c: Regenerated. + * generated/cshift0_r8.c: Regenerated. + 2012-04-04 Tristan Gingold <gingold@adacore.com> * libgfortran.h: Include complex.h before math.h diff --git a/libgfortran/generated/cshift0_c10.c b/libgfortran/generated/cshift0_c10.c index 43e173bf417..ba27a9ed4ae 100644 --- a/libgfortran/generated/cshift0_c10.c +++ b/libgfortran/generated/cshift0_c10.c @@ -97,9 +97,13 @@ cshift0_c10 (gfc_array_c10 *ret, const gfc_array_c10 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_c16.c b/libgfortran/generated/cshift0_c16.c index f1f2539bc77..0cdc6dc31e9 100644 --- a/libgfortran/generated/cshift0_c16.c +++ b/libgfortran/generated/cshift0_c16.c @@ -97,9 +97,13 @@ cshift0_c16 (gfc_array_c16 *ret, const gfc_array_c16 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_c4.c b/libgfortran/generated/cshift0_c4.c index bf8554e1abe..17613777046 100644 --- a/libgfortran/generated/cshift0_c4.c +++ b/libgfortran/generated/cshift0_c4.c @@ -97,9 +97,13 @@ cshift0_c4 (gfc_array_c4 *ret, const gfc_array_c4 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_c8.c b/libgfortran/generated/cshift0_c8.c index e3fd5b66e22..e4534885d1b 100644 --- a/libgfortran/generated/cshift0_c8.c +++ b/libgfortran/generated/cshift0_c8.c @@ -97,9 +97,13 @@ cshift0_c8 (gfc_array_c8 *ret, const gfc_array_c8 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_i1.c b/libgfortran/generated/cshift0_i1.c index f2315de95fa..76c30efbd58 100644 --- a/libgfortran/generated/cshift0_i1.c +++ b/libgfortran/generated/cshift0_i1.c @@ -97,9 +97,13 @@ cshift0_i1 (gfc_array_i1 *ret, const gfc_array_i1 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_i16.c b/libgfortran/generated/cshift0_i16.c index 7566042c8fb..b1143032021 100644 --- a/libgfortran/generated/cshift0_i16.c +++ b/libgfortran/generated/cshift0_i16.c @@ -97,9 +97,13 @@ cshift0_i16 (gfc_array_i16 *ret, const gfc_array_i16 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_i2.c b/libgfortran/generated/cshift0_i2.c index 4a8154c4c55..0f510f854c9 100644 --- a/libgfortran/generated/cshift0_i2.c +++ b/libgfortran/generated/cshift0_i2.c @@ -97,9 +97,13 @@ cshift0_i2 (gfc_array_i2 *ret, const gfc_array_i2 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_i4.c b/libgfortran/generated/cshift0_i4.c index 7d25b7b0200..d75b4d6b475 100644 --- a/libgfortran/generated/cshift0_i4.c +++ b/libgfortran/generated/cshift0_i4.c @@ -97,9 +97,13 @@ cshift0_i4 (gfc_array_i4 *ret, const gfc_array_i4 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_i8.c b/libgfortran/generated/cshift0_i8.c index 2f565caeede..4154eb29ef3 100644 --- a/libgfortran/generated/cshift0_i8.c +++ b/libgfortran/generated/cshift0_i8.c @@ -97,9 +97,13 @@ cshift0_i8 (gfc_array_i8 *ret, const gfc_array_i8 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_r10.c b/libgfortran/generated/cshift0_r10.c index b7f21caffb2..14be6832123 100644 --- a/libgfortran/generated/cshift0_r10.c +++ b/libgfortran/generated/cshift0_r10.c @@ -97,9 +97,13 @@ cshift0_r10 (gfc_array_r10 *ret, const gfc_array_r10 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_r16.c b/libgfortran/generated/cshift0_r16.c index 320b705f382..6d351f7bfdd 100644 --- a/libgfortran/generated/cshift0_r16.c +++ b/libgfortran/generated/cshift0_r16.c @@ -97,9 +97,13 @@ cshift0_r16 (gfc_array_r16 *ret, const gfc_array_r16 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_r4.c b/libgfortran/generated/cshift0_r4.c index 93ccf529b6d..939ba6e12cc 100644 --- a/libgfortran/generated/cshift0_r4.c +++ b/libgfortran/generated/cshift0_r4.c @@ -97,9 +97,13 @@ cshift0_r4 (gfc_array_r4 *ret, const gfc_array_r4 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/generated/cshift0_r8.c b/libgfortran/generated/cshift0_r8.c index a3f747993c9..73afb8a43e0 100644 --- a/libgfortran/generated/cshift0_r8.c +++ b/libgfortran/generated/cshift0_r8.c @@ -97,9 +97,13 @@ cshift0_r8 (gfc_array_r8 *ret, const gfc_array_r8 *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgfortran/intrinsics/string_intrinsics_inc.c b/libgfortran/intrinsics/string_intrinsics_inc.c index b20483da2c4..a1f86b558c8 100644 --- a/libgfortran/intrinsics/string_intrinsics_inc.c +++ b/libgfortran/intrinsics/string_intrinsics_inc.c @@ -44,9 +44,6 @@ extern void concat_string (gfc_charlen_type, CHARTYPE *, gfc_charlen_type, const CHARTYPE *); export_proto(concat_string); -extern gfc_charlen_type string_len_trim (gfc_charlen_type, const CHARTYPE *); -export_proto(string_len_trim); - extern void adjustl (CHARTYPE *, gfc_charlen_type, const CHARTYPE *); export_proto(adjustl); diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c index 2024fcd9b6c..4d2ce794120 100644 --- a/libgfortran/io/list_read.c +++ b/libgfortran/io/list_read.c @@ -1136,6 +1136,8 @@ parse_real (st_parameter_dt *dtp, void *buffer, int length) case 'E': case 'd': case 'D': + case 'q': + case 'Q': push_char (dtp, 'e'); goto exp1; @@ -1449,6 +1451,8 @@ read_real (st_parameter_dt *dtp, void * dest, int length) case 'e': case 'D': case 'd': + case 'Q': + case 'q': goto exp1; case '+': @@ -1546,6 +1550,8 @@ read_real (st_parameter_dt *dtp, void * dest, int length) case 'e': case 'D': case 'd': + case 'Q': + case 'q': goto exp1; case '+': diff --git a/libgfortran/io/read.c b/libgfortran/io/read.c index aa41bc7b9d2..32c8b3250f8 100644 --- a/libgfortran/io/read.c +++ b/libgfortran/io/read.c @@ -1026,6 +1026,8 @@ found_digit: case 'E': case 'd': case 'D': + case 'q': + case 'Q': ++p; --w; goto exponent; diff --git a/libgfortran/io/unit.c b/libgfortran/io/unit.c index d5029dcac27..911521d5df7 100644 --- a/libgfortran/io/unit.c +++ b/libgfortran/io/unit.c @@ -397,7 +397,7 @@ get_internal_unit (st_parameter_dt *dtp) __gthread_mutex_lock (&iunit->lock); iunit->recl = dtp->internal_unit_len; - + /* For internal units we set the unit number to -1. Otherwise internal units can be mistaken for a pre-connected unit or some other file I/O unit. */ @@ -415,6 +415,26 @@ get_internal_unit (st_parameter_dt *dtp) start_record *= iunit->recl; } + else + { + /* If we are not processing an array, adjust the unit record length not + to include trailing blanks for list-formatted reads. */ + if (dtp->u.p.mode == READING && !(dtp->common.flags & IOPARM_DT_HAS_FORMAT)) + { + if (dtp->common.unit == 0) + { + dtp->internal_unit_len = + string_len_trim (dtp->internal_unit_len, dtp->internal_unit); + iunit->recl = dtp->internal_unit_len; + } + else + { + dtp->internal_unit_len = + string_len_trim_char4 (dtp->internal_unit_len, dtp->internal_unit); + iunit->recl = dtp->internal_unit_len; + } + } + } /* Set initial values for unit parameters. */ if (dtp->common.unit) diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c index 278decd6775..185936f109d 100644 --- a/libgfortran/io/unix.c +++ b/libgfortran/io/unix.c @@ -736,7 +736,7 @@ mem_alloc_w4 (stream * strm, int * len) } -/* Stream read function for character(kine=1) internal units. */ +/* Stream read function for character(kind=1) internal units. */ static ssize_t mem_read (stream * s, void * buf, ssize_t nbytes) diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index ea20e140c46..e7f5b711a51 100644 --- a/libgfortran/libgfortran.h +++ b/libgfortran/libgfortran.h @@ -791,6 +791,13 @@ internal_proto(fstrcpy); extern gfc_charlen_type cf_strcpy (char *, gfc_charlen_type, const char *); internal_proto(cf_strcpy); +extern gfc_charlen_type string_len_trim (gfc_charlen_type, const char *); +export_proto(string_len_trim); + +extern gfc_charlen_type string_len_trim_char4 (gfc_charlen_type, + const gfc_char4_t *); +export_proto(string_len_trim_char4); + /* io/intrinsics.c */ extern void flush_all_units (void); diff --git a/libgfortran/m4/cshift0.m4 b/libgfortran/m4/cshift0.m4 index 567222b7146..b1966aa5556 100644 --- a/libgfortran/m4/cshift0.m4 +++ b/libgfortran/m4/cshift0.m4 @@ -98,9 +98,13 @@ cshift0_'rtype_code` ('rtype` *ret, const 'rtype` *array, ptrdiff_t shift, rptr = ret->base_addr; sptr = array->base_addr; - shift = len == 0 ? 0 : shift % (ptrdiff_t)len; - if (shift < 0) - shift += len; + /* Avoid the costly modulo for trivially in-bound shifts. */ + if (shift < 0 || shift >= len) + { + shift = len == 0 ? 0 : shift % (ptrdiff_t)len; + if (shift < 0) + shift += len; + } while (rptr) { diff --git a/libgo/Makefile.am b/libgo/Makefile.am index e19cdf0a36d..11a650be689 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -1559,7 +1559,6 @@ s-syscall_arch: Makefile echo "package syscall" > syscall_arch.go.tmp echo 'const ARCH = "'$(GOARCH)'"' >> syscall_arch.go.tmp echo 'const OS = "'$(GOOS)'"' >> syscall_arch.go.tmp - echo 'const BigEndian = $(GO_BIGENDIAN)' >> syscall_arch.go.tmp $(SHELL) $(srcdir)/../move-if-change syscall_arch.go.tmp syscall_arch.go $(STAMP) $@ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 4695a4e20da..62cdf6dba78 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -379,7 +379,6 @@ GOARCH = @GOARCH@ GOC = @GOC@ GOCFLAGS = $(CFLAGS) GOOS = @GOOS@ -GO_BIGENDIAN = @GO_BIGENDIAN@ GO_LIBCALL_OS_ARCH_FILE = @GO_LIBCALL_OS_ARCH_FILE@ GO_LIBCALL_OS_FILE = @GO_LIBCALL_OS_FILE@ GO_SYSCALL_OS_ARCH_FILE = @GO_SYSCALL_OS_ARCH_FILE@ @@ -4332,7 +4331,6 @@ s-syscall_arch: Makefile echo "package syscall" > syscall_arch.go.tmp echo 'const ARCH = "'$(GOARCH)'"' >> syscall_arch.go.tmp echo 'const OS = "'$(GOOS)'"' >> syscall_arch.go.tmp - echo 'const BigEndian = $(GO_BIGENDIAN)' >> syscall_arch.go.tmp $(SHELL) $(srcdir)/../move-if-change syscall_arch.go.tmp syscall_arch.go $(STAMP) $@ diff --git a/libgo/config.h.in b/libgo/config.h.in index 270a4ae37fa..91b91bfb0a9 100644 --- a/libgo/config.h.in +++ b/libgo/config.h.in @@ -48,6 +48,18 @@ /* Define to 1 if you have the <linux/filter.h> header file. */ #undef HAVE_LINUX_FILTER_H +/* Define to 1 if you have the <linux/fs.h> header file. */ +#undef HAVE_LINUX_FS_H + +/* Define to 1 if you have the <linux/if_addr.h> header file. */ +#undef HAVE_LINUX_IF_ADDR_H + +/* Define to 1 if you have the <linux/if_ether.h> header file. */ +#undef HAVE_LINUX_IF_ETHER_H + +/* Define to 1 if you have the <linux/if_tun.h> header file. */ +#undef HAVE_LINUX_IF_TUN_H + /* Define to 1 if you have the <linux/netlink.h> header file. */ #undef HAVE_LINUX_NETLINK_H @@ -75,12 +87,30 @@ /* Define to 1 if you have the `mknodat' function. */ #undef HAVE_MKNODAT +/* Define to 1 if you have the <netinet/if_ether.h> header file. */ +#undef HAVE_NETINET_IF_ETHER_H + +/* Define to 1 if you have the <netinet/in_syst.h> header file. */ +#undef HAVE_NETINET_IN_SYST_H + +/* Define to 1 if you have the <netinet/ip.h> header file. */ +#undef HAVE_NETINET_IP_H + +/* Define to 1 if you have the <netinet/ip_mroute.h> header file. */ +#undef HAVE_NETINET_IP_MROUTE_H + +/* Define to 1 if you have the <netpacket/packet.h> header file. */ +#undef HAVE_NETPACKET_PACKET_H + /* Define to 1 if you have the <net/if_arp.h> header file. */ #undef HAVE_NET_IF_ARP_H /* Define to 1 if you have the <net/if.h> header file. */ #undef HAVE_NET_IF_H +/* Define to 1 if you have the <net/route.h> header file. */ +#undef HAVE_NET_ROUTE_H + /* Define to 1 if the system has the type `off64_t'. */ #undef HAVE_OFF64_T @@ -145,6 +175,12 @@ /* Define to 1 if you have the <sys/epoll.h> header file. */ #undef HAVE_SYS_EPOLL_H +/* Define to 1 if you have the <sys/file.h> header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the <sys/inotify.h> header file. */ +#undef HAVE_SYS_INOTIFY_H + /* Define to 1 if you have the <sys/mman.h> header file. */ #undef HAVE_SYS_MMAN_H diff --git a/libgo/configure b/libgo/configure index e58b238cd0f..24b05b9271b 100755 --- a/libgo/configure +++ b/libgo/configure @@ -612,7 +612,6 @@ HAVE_STRERROR_R_FALSE HAVE_STRERROR_R_TRUE HAVE_SYS_MMAN_H_FALSE HAVE_SYS_MMAN_H_TRUE -GO_BIGENDIAN PTHREAD_LIBS PTHREAD_CFLAGS NET_LIBS @@ -11101,7 +11100,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11104 "configure" +#line 11103 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11207,7 +11206,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11210 "configure" +#line 11209 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -14409,12 +14408,6 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac -case $ac_cv_c_bigendian in - yes) GO_BIGENDIAN=true ;; - no) GO_BIGENDIAN=false ;; - *) as_fn_error "unknown endianness" "$LINENO" 5 ;; -esac - @@ -14515,7 +14508,7 @@ no) ;; esac -for ac_header in sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/reboot.h +for ac_header in sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -14530,7 +14523,7 @@ fi done -for ac_header in linux/filter.h linux/netlink.h linux/rtnetlink.h +for ac_header in linux/filter.h linux/if_addr.h linux/if_ether.h linux/if_tun.h linux/netlink.h linux/rtnetlink.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_SYS_SOCKET_H diff --git a/libgo/configure.ac b/libgo/configure.ac index f1d0bfc8b32..7da76191404 100644 --- a/libgo/configure.ac +++ b/libgo/configure.ac @@ -400,12 +400,6 @@ dnl Test if -lrt is required for sched_yield. AC_SEARCH_LIBS([sched_yield], [rt]) AC_C_BIGENDIAN -case $ac_cv_c_bigendian in - yes) GO_BIGENDIAN=true ;; - no) GO_BIGENDIAN=false ;; - *) AC_MSG_ERROR([unknown endianness]) ;; -esac -AC_SUBST(GO_BIGENDIAN) GCC_CHECK_UNWIND_GETIPINFO @@ -459,9 +453,9 @@ no) ;; esac -AC_CHECK_HEADERS(sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/reboot.h) +AC_CHECK_HEADERS(sys/file.h sys/mman.h syscall.h sys/epoll.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/reboot.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h) -AC_CHECK_HEADERS([linux/filter.h linux/netlink.h linux/rtnetlink.h], [], [], +AC_CHECK_HEADERS([linux/filter.h linux/if_addr.h linux/if_ether.h linux/if_tun.h linux/netlink.h linux/rtnetlink.h], [], [], [#ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif diff --git a/libgo/go/debug/dwarf/line.go b/libgo/go/debug/dwarf/line.go index f9c77cc87e4..52c3b114da3 100644 --- a/libgo/go/debug/dwarf/line.go +++ b/libgo/go/debug/dwarf/line.go @@ -415,6 +415,10 @@ func (d *Data) addLine(lines []mapLineInfo, lineInfo Line, address uint64, line if newLineInfo { if len(lines) > 0 { sort.Sort(lines[len(lines)-1].addrs) + p := &lines[len(lines)-1] + if len(p.addrs) > 0 && address > p.addrs[len(p.addrs)-1].pc { + p.addrs = append(p.addrs, oneLineInfo{address, p.addrs[len(p.addrs)-1].line}) + } } lines = append(lines, mapLineInfo{line: lineInfo}) } diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go index 5aa93ce5837..ffba6a7bcb7 100644 --- a/libgo/go/net/http/fs_test.go +++ b/libgo/go/net/http/fs_test.go @@ -396,7 +396,7 @@ func TestLinuxSendfile(t *testing.T) { defer ln.Close() var buf bytes.Buffer - child := exec.Command("strace", "-f", os.Args[0], "-test.run=TestLinuxSendfileChild") + child := exec.Command("strace", "-f", "-e!sigaltstack", os.Args[0], "-test.run=TestLinuxSendfileChild") child.ExtraFiles = append(child.ExtraFiles, lnf) child.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...) child.Stdout = &buf diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go index 0d7017f301e..ce2e921e865 100644 --- a/libgo/go/net/interface_linux.go +++ b/libgo/go/net/interface_linux.go @@ -64,11 +64,7 @@ func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interfac case syscall.IFLA_IFNAME: ifi.Name = string(a.Value[:len(a.Value)-1]) case syscall.IFLA_MTU: - if syscall.BigEndian { - ifi.MTU = int(uint32(a.Value[0])<<24 | uint32(a.Value[1])<<16 | uint32(a.Value[2])<<8 | uint32(a.Value[3])) - } else { - ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0])) - } + ifi.MTU = int(*(*uint32)(unsafe.Pointer(&a.Value[:4][0]))) } } return ifi @@ -197,15 +193,14 @@ func parseProcNetIGMP(path string, ifi *Interface) []Addr { name = f[1] case len(f[0]) == 8: if ifi == nil || name == ifi.Name { + // The Linux kernel puts the IP + // address in /proc/net/igmp in native + // endianness. for i := 0; i+1 < len(f[0]); i += 2 { b[i/2], _ = xtoi2(f[0][i:i+2], 0) } - var ifma IPAddr - if syscall.BigEndian { - ifma = IPAddr{IP: IPv4(b[0], b[1], b[2], b[3])} - } else { - ifma = IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])} - } + i := *(*uint32)(unsafe.Pointer(&b[:4][0])) + ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))} ifmat = append(ifmat, ifma.toAddr()) } } diff --git a/libgo/go/os/stat.go b/libgo/go/os/stat.go index 789007206fa..01afa39e0f8 100644 --- a/libgo/go/os/stat.go +++ b/libgo/go/os/stat.go @@ -19,7 +19,7 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo { fs := &fileStat{ name: basename(name), size: int64(st.Size), - modTime: timespecToTime(st.Mtime), + modTime: timespecToTime(st.Mtim), sys: st, } fs.mode = FileMode(st.Mode & 0777) @@ -52,5 +52,5 @@ func timespecToTime(ts syscall.Timespec) time.Time { // For testing. func atime(fi FileInfo) time.Time { - return timespecToTime(fi.Sys().(*syscall.Stat_t).Atime) + return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim) } diff --git a/libgo/go/os/stat_solaris.go b/libgo/go/os/stat_solaris.go index 93b698c3c4c..51a2f71e1be 100644 --- a/libgo/go/os/stat_solaris.go +++ b/libgo/go/os/stat_solaris.go @@ -19,7 +19,7 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo { fs := &fileStat{ name: basename(name), size: int64(st.Size), - modTime: timestrucToTime(st.Mtime), + modTime: timestrucToTime(st.Mtim), sys: st, } fs.mode = FileMode(st.Mode & 0777) @@ -52,5 +52,5 @@ func timestrucToTime(ts syscall.Timestruc) time.Time { // For testing. func atime(fi FileInfo) time.Time { - return timestrucToTime(fi.(*fileStat).Sys().(*syscall.Stat_t).Atime) + return timestrucToTime(fi.(*fileStat).Sys().(*syscall.Stat_t).Atim) } diff --git a/libgo/go/runtime/gc_test.go b/libgo/go/runtime/gc_test.go index 65894a6fd01..7770e499ad3 100644 --- a/libgo/go/runtime/gc_test.go +++ b/libgo/go/runtime/gc_test.go @@ -15,6 +15,8 @@ func TestGcSys(t *testing.T) { runtime.ReadMemStats(memstats) sys := memstats.Sys + runtime.MemProfileRate = 0 // disable profiler + itercount := 1000000 if testing.Short() { itercount = 100000 diff --git a/libgo/go/syscall/libcall_linux.go b/libgo/go/syscall/libcall_linux.go index f5358f53d9b..7c9f05e8d52 100644 --- a/libgo/go/syscall/libcall_linux.go +++ b/libgo/go/syscall/libcall_linux.go @@ -335,7 +335,7 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i //sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error) //tee(rfd int, wfd int, len Size_t, flags uint) Ssize_t -func Tgkill(tgid, tid, sig Signal) error { +func Tgkill(tgid int, tid int, sig Signal) error { r1, _, errno := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig)) if r1 < 0 { return errno diff --git a/libgo/go/syscall/libcall_posix.go b/libgo/go/syscall/libcall_posix.go index 9961ba8ff2d..4f25b82649a 100644 --- a/libgo/go/syscall/libcall_posix.go +++ b/libgo/go/syscall/libcall_posix.go @@ -268,7 +268,7 @@ func Gettimeofday(tv *Timeval) (err error) { //sys Mknod(path string, mode uint32, dev int) (err error) //mknod(path *byte, mode Mode_t, dev _dev_t) int -//sys Mount(source string, target string, fstype string, flags int, data string) (err error) +//sys Mount(source string, target string, fstype string, flags uintptr, data string) (err error) //mount(source *byte, target *byte, fstype *byte, flags _C_long, data *byte) int //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) diff --git a/libgo/go/syscall/netlink_linux.go b/libgo/go/syscall/netlink_linux.go index 1c99a81785f..d535713069b 100644 --- a/libgo/go/syscall/netlink_linux.go +++ b/libgo/go/syscall/netlink_linux.go @@ -30,43 +30,12 @@ type NetlinkRouteRequest struct { func (rr *NetlinkRouteRequest) toWireFormat() []byte { b := make([]byte, rr.Header.Len) - if BigEndian { - b[0] = byte(rr.Header.Len >> 24) - b[1] = byte(rr.Header.Len >> 16) - b[2] = byte(rr.Header.Len >> 8) - b[3] = byte(rr.Header.Len) - b[4] = byte(rr.Header.Type >> 8) - b[5] = byte(rr.Header.Type) - b[6] = byte(rr.Header.Flags >> 8) - b[7] = byte(rr.Header.Flags) - b[8] = byte(rr.Header.Seq >> 24) - b[9] = byte(rr.Header.Seq >> 16) - b[10] = byte(rr.Header.Seq >> 8) - b[11] = byte(rr.Header.Seq) - b[12] = byte(rr.Header.Pid >> 24) - b[13] = byte(rr.Header.Pid >> 16) - b[14] = byte(rr.Header.Pid >> 8) - b[15] = byte(rr.Header.Pid) - b[16] = byte(rr.Data.Family) - } else { - b[0] = byte(rr.Header.Len) - b[1] = byte(rr.Header.Len >> 8) - b[2] = byte(rr.Header.Len >> 16) - b[3] = byte(rr.Header.Len >> 24) - b[4] = byte(rr.Header.Type) - b[5] = byte(rr.Header.Type >> 8) - b[6] = byte(rr.Header.Flags) - b[7] = byte(rr.Header.Flags >> 8) - b[8] = byte(rr.Header.Seq) - b[9] = byte(rr.Header.Seq >> 8) - b[10] = byte(rr.Header.Seq >> 16) - b[11] = byte(rr.Header.Seq >> 24) - b[12] = byte(rr.Header.Pid) - b[13] = byte(rr.Header.Pid >> 8) - b[14] = byte(rr.Header.Pid >> 16) - b[15] = byte(rr.Header.Pid >> 24) - b[16] = byte(rr.Data.Family) - } + *(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len + *(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type + *(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags + *(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq + *(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid + b[16] = byte(rr.Data.Family) return b } diff --git a/libgo/go/syscall/sockcmsg_unix.go b/libgo/go/syscall/sockcmsg_unix.go index 1faac84f4a6..943ebdd7209 100644 --- a/libgo/go/syscall/sockcmsg_unix.go +++ b/libgo/go/syscall/sockcmsg_unix.go @@ -39,7 +39,7 @@ func CmsgSpace(datalen int) int { } func cmsgData(cmsg *Cmsghdr) unsafe.Pointer { - return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + uintptr(SizeofCmsghdr)) + return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + SizeofCmsghdr) } type SocketControlMessage struct { @@ -72,7 +72,7 @@ func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, error) { func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, error) { h := (*Cmsghdr)(unsafe.Pointer(&buf[0])) - if int(h.Len) < SizeofCmsghdr || int(h.Len) > len(buf) { + if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) { return nil, nil, EINVAL } return h, buf[cmsgAlignOf(SizeofCmsghdr):], nil diff --git a/libgo/go/syscall/socket.go b/libgo/go/syscall/socket.go index 6d36e3985f3..973759086ce 100644 --- a/libgo/go/syscall/socket.go +++ b/libgo/go/syscall/socket.go @@ -22,7 +22,7 @@ type Sockaddr interface { type RawSockaddrAny struct { Addr RawSockaddr - Pad [12]int8 + Pad [96]int8 } const SizeofSockaddrAny = 0x1c diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh index 291fbb52cc0..487965bf3bf 100755 --- a/libgo/mksysinfo.sh +++ b/libgo/mksysinfo.sh @@ -40,6 +40,18 @@ cat > sysinfo.c <<EOF #include <sys/ttold.h> #endif #include <netinet/tcp.h> +#if defined(HAVE_NETINET_IN_SYSTM_H) +#include <netinet/in_systm.h> +#endif +#if defined(HAVE_NETINET_IP_H) +#include <netinet/ip.h> +#endif +#if defined(HAVE_NETINET_IP_MROUTE_H) +#include <netinet/ip_mroute.h> +#endif +#if defined(HAVE_NETINET_IF_ETHER_H) +#include <netinet/if_ether.h> +#endif #include <signal.h> #include <sys/ioctl.h> #include <termios.h> @@ -52,6 +64,9 @@ cat > sysinfo.c <<EOF #if defined(HAVE_SYS_EPOLL_H) #include <sys/epoll.h> #endif +#if defined(HAVE_SYS_FILE_H) +#include <sys/file.h> +#endif #if defined(HAVE_SYS_MMAN_H) #include <sys/mman.h> #endif @@ -85,6 +100,15 @@ cat > sysinfo.c <<EOF #if defined(HAVE_LINUX_FILTER_H) #include <linux/filter.h> #endif +#if defined(HAVE_LINUX_IF_ADDR_H) +#include <linux/if_addr.h> +#endif +#if defined(HAVE_LINUX_IF_ETHER_H) +#include <linux/if_ether.h> +#endif +#if defined(HAVE_LINUX_IF_TUN_H) +#include <linux/if_tun.h> +#endif #if defined(HAVE_LINUX_NETLINK_H) #include <linux/netlink.h> #endif @@ -97,6 +121,12 @@ cat > sysinfo.c <<EOF #if defined(HAVE_NET_IF_ARP_H) #include <net/if_arp.h> #endif +#if defined(HAVE_NET_ROUTE_H) +#include <net/route.h> +#endif +#if defined (HAVE_NETPACKET_PACKET_H) +#include <netpacket/packet.h> +#endif #if defined(HAVE_SYS_MOUNT_H) #include <sys/mount.h> #endif @@ -121,9 +151,15 @@ cat > sysinfo.c <<EOF #if defined(HAVE_LINUX_ETHER_H) #include <linux/ether.h> #endif +#if defined(HAVE_LINUX_FS_H) +#include <linux/fs.h> +#endif #if defined(HAVE_LINUX_REBOOT_H) #include <linux/reboot.h> #endif +#if defined(HAVE_SYS_INOTIFY_H) +#include <sys/inotify.h> +#endif /* Constants that may only be defined as expressions on some systems, expressions too complex for -fdump-go-spec to handle. These are @@ -199,6 +235,8 @@ grep '^const _MAP_' gen-sysinfo.go | \ sed -e 's/^\(const \)_\(MAP_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} grep '^const _MADV_' gen-sysinfo.go | \ sed -e 's/^\(const \)_\(MADV_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} +grep '^const _MCL_' gen-sysinfo.go | \ + sed -e 's/^\(const \)_\(MCL_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} # Process status constants. grep '^const _W' gen-sysinfo.go | @@ -236,6 +274,10 @@ done grep '^const __PC' gen-sysinfo.go | sed -e 's/^\(const \)__\(PC[^= ]*\)\(.*\)$/\1\2 = __\2/' >> ${OUT} +# The PATH_MAX constant. +grep '^const _PATH_MAX ' gen-sysinfo.go | + echo 'const PathMax = _PATH_MAX' >> ${OUT} + # epoll constants. grep '^const _EPOLL' gen-sysinfo.go | sed -e 's/^\(const \)_\(EPOLL[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} @@ -435,9 +477,9 @@ fi | sed -e 's/type _stat64/type Stat_t/' \ -e 's/st_size/Size/' \ -e 's/st_blksize/Blksize/' \ -e 's/st_blocks/Blocks/' \ - -e 's/st_atim/Atime/' \ - -e 's/st_mtim/Mtime/' \ - -e 's/st_ctim/Ctime/' \ + -e 's/st_atim/Atim/' \ + -e 's/st_mtim/Mtim/' \ + -e 's/st_ctim/Ctim/' \ -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1Timeval\2/g' \ -e 's/\([^a-zA-Z0-9_]\)_timespec_t\([^a-zA-Z0-9_]\)/\1Timespec\2/g' \ -e 's/\([^a-zA-Z0-9_]\)_timespec\([^a-zA-Z0-9_]\)/\1Timespec\2/g' \ @@ -551,9 +593,6 @@ if test -n "$cmsghdr"; then -e 's/cmsg_type/Type/' \ -e 's/\[\]/[0]/' \ >> ${OUT} - - # The size of the cmsghdr struct. - echo 'var SizeofCmsghdr = int(unsafe.Sizeof(Cmsghdr{}))' >> ${OUT} fi # The SCM_ flags for Cmsghdr. @@ -568,11 +607,6 @@ grep '^type _ucred ' gen-sysinfo.go | \ -e 's/gid/Gid/' \ >> ${OUT} -# The size of the ucred struct. -if grep 'type Ucred ' ${OUT} >/dev/null 2>&1; then - echo 'var SizeofUcred = int(unsafe.Sizeof(Ucred{}))' >> ${OUT} -fi - # The ip_mreq struct. grep '^type _ip_mreq ' gen-sysinfo.go | \ sed -e 's/_ip_mreq/IPMreq/' \ @@ -586,9 +620,6 @@ if ! grep 'type IPMreq ' ${OUT} >/dev/null 2>&1; then echo 'type IPMreq struct { Multiaddr [4]byte; Interface [4]byte; }' >> ${OUT} fi -# The size of the ip_mreq struct. -echo 'var SizeofIPMreq = int(unsafe.Sizeof(IPMreq{}))' >> ${OUT} - # The ipv6_mreq struct. grep '^type _ipv6_mreq ' gen-sysinfo.go | \ sed -e 's/_ipv6_mreq/IPv6Mreq/' \ @@ -602,9 +633,6 @@ if ! grep 'type IPv6Mreq ' ${OUT} >/dev/null 2>&1; then echo 'type IPv6Mreq struct { Multiaddr [16]byte; Interface uint32; }' >> ${OUT} fi -# The size of the ipv6_mreq struct. -echo 'var SizeofIPv6Mreq = int(unsafe.Sizeof(IPv6Mreq{}))' >> ${OUT} - # The ip_mreqn struct. grep '^type _ip_mreqn ' gen-sysinfo.go | \ sed -e 's/_ip_mreqn/IPMreqn/' \ @@ -619,9 +647,6 @@ if ! grep 'type IPMreqn ' ${OUT} >/dev/null 2>&1; then echo 'type IPMreqn struct { Multiaddr [4]byte; Interface [4]byte; Ifindex int32 }' >> ${OUT} fi -# The size of the ip_mreqn struct. -echo 'var SizeofIPMreqn = int(unsafe.Sizeof(IPMreqn{}))' >> ${OUT} - # Try to guess the type to use for fd_set. fd_set=`grep '^type _fd_set ' gen-sysinfo.go || true` fds_bits_type="_C_long" @@ -687,8 +712,8 @@ grep '^const _NLM' gen-sysinfo.go | \ # NLMSG_HDRLEN is defined as an expression using sizeof. if ! grep '^const NLMSG_HDRLEN' ${OUT} > /dev/null 2>&1; then - if grep '^type NlMsghdr ' ${OUT} > /dev/null 2>&1; then - echo 'var NLMSG_HDRLEN = int((unsafe.Sizeof(NlMsghdr{}) + (NLMSG_ALIGNTO-1)) &^ (NLMSG_ALIGNTO-1))' >> ${OUT} + if grep '^const _sizeof_nlmsghdr ' ${OUT} > /dev/null 2>&1; then + echo 'const NLMSG_HDRLEN = (_sizeof_nlmsghdr + (NLMSG_ALIGNTO-1)) &^ (NLMSG_ALIGNTO-1)' >> ${OUT} fi fi @@ -700,17 +725,12 @@ grep '^type _rtmsg ' gen-sysinfo.go | \ -e 's/rtm_src_len/Src_len/' \ -e 's/rtm_tos/Tos/' \ -e 's/rtm_table/Table/' \ - -e 's/rtm_protocol/Procotol/' \ + -e 's/rtm_protocol/Protocol/' \ -e 's/rtm_scope/Scope/' \ -e 's/rtm_type/Type/' \ -e 's/rtm_flags/Flags/' \ >> ${OUT} -# The size of the rtmsg struct. -if grep 'type RtMsg ' ${OUT} > /dev/null 2>&1; then - echo 'var SizeofRtMsg = int(unsafe.Sizeof(RtMsg{}))' >> ${OUT} -fi - # The rtgenmsg struct. grep '^type _rtgenmsg ' gen-sysinfo.go | \ sed -e 's/_rtgenmsg/RtGenmsg/' \ @@ -718,6 +738,8 @@ grep '^type _rtgenmsg ' gen-sysinfo.go | \ >> ${OUT} # The routing message flags. +grep '^const _RT_' gen-sysinfo.go | \ + sed -e 's/^\(const \)_\(RT_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} grep '^const _RTA' gen-sysinfo.go | \ sed -e 's/^\(const \)_\(RTA[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} grep '^const _RTF' gen-sysinfo.go | \ @@ -726,11 +748,10 @@ grep '^const _RTCF' gen-sysinfo.go | \ sed -e 's/^\(const \)_\(RTCF[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} grep '^const _RTM' gen-sysinfo.go | \ sed -e 's/^\(const \)_\(RTM[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} - -# The size of the rtgenmsg struct. -if grep 'type RtGenmsg ' ${OUT} > /dev/null 2>&1; then - echo 'var SizeofRtGenmsg = int(unsafe.Sizeof(RtGenmsg{}))' >> ${OUT} -fi +grep '^const _RTN' gen-sysinfo.go | \ + sed -e 's/^\(const \)_\(RTN[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} +grep '^const _RTPROT' gen-sysinfo.go | \ + sed -e 's/^\(const \)_\(RTPROT[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} # The ifinfomsg struct. grep '^type _ifinfomsg ' gen-sysinfo.go | \ @@ -754,11 +775,6 @@ grep '^const _IFNAMSIZ' gen-sysinfo.go | \ grep '^const _SIOC' gen-sysinfo.go | sed -e 's/^\(const \)_\(SIOC[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} -# The size of the ifinfomsg struct. -if grep 'type IfInfomsg ' ${OUT} > /dev/null 2>&1; then - echo 'var SizeofIfInfomsg = int(unsafe.Sizeof(IfInfomsg{}))' >> ${OUT} -fi - # The ifaddrmsg struct. grep '^type _ifaddrmsg ' gen-sysinfo.go | \ sed -e 's/_ifaddrmsg/IfAddrmsg/' \ @@ -769,11 +785,6 @@ grep '^type _ifaddrmsg ' gen-sysinfo.go | \ -e 's/ifa_index/Index/' \ >> ${OUT} -# The size of the ifaddrmsg struct. -if grep 'type IfAddrmsg ' ${OUT} > /dev/null 2>&1; then - echo 'var SizeofIfAddrmsg = int(unsafe.Sizeof(IfAddrmsg{}))' >> ${OUT} -fi - # The rtattr struct. grep '^type _rtattr ' gen-sysinfo.go | \ sed -e 's/_rtattr/RtAttr/' \ @@ -781,10 +792,22 @@ grep '^type _rtattr ' gen-sysinfo.go | \ -e 's/rta_type/Type/' \ >> ${OUT} -# The size of the rtattr struct. -if grep 'type RtAttr ' ${OUT} > /dev/null 2>&1; then - echo 'var SizeofRtAttr = int(unsafe.Sizeof(RtAttr{}))' >> ${OUT} -fi +# The in_pktinfo struct. +grep '^type _in_pktinfo ' gen-sysinfo.go | \ + sed -e 's/_in_pktinfo/Inet4Pktinfo/' \ + -e 's/ipi_ifindex/Ifindex/' \ + -e 's/ipi_spec_dst/Spec_dst/' \ + -e 's/ipi_addr/Addr/' \ + -e 's/_in_addr/[4]byte/g' \ + >> ${OUT} + +# The in6_pktinfo struct. +grep '^type _in6_pktinfo ' gen-sysinfo.go | \ + sed -e 's/_in6_pktinfo/Inet6Pktinfo/' \ + -e 's/ipi6_addr/Addr/' \ + -e 's/ipi6_ifindex/Ifindex/' \ + -e 's/_in6_addr/[16]byte/' \ + >> ${OUT} # The termios struct. grep '^type _termios ' gen-sysinfo.go | \ @@ -811,13 +834,15 @@ for n in IGNBRK BRKINT IGNPAR PARMRK INPCK ISTRIP INLCR IGNCR ICRNL IUCLC \ TCSAFLUSH TCIFLUSH TCOFLUSH TCIOFLUSH TCOOFF TCOON TCIOFF TCION B0 B50 \ B75 B110 B134 B150 B200 B300 B600 B1200 B1800 B2400 B4800 B9600 B19200 \ B38400 B57600 B115200 B230400 B460800 B500000 B576000 B921600 B1000000 \ - B1152000 B1500000 B2000000 B2500000 B3000000 B4000000; do + B1152000 B1500000 B2000000 B2500000 B3000000 B3500000 B4000000; do grep "^const _$n " gen-sysinfo.go | \ sed -e 's/^\(const \)_\([^=]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} done # The mount flags +grep '^const _MNT_' gen-sysinfo.go | + sed -e 's/^\(const \)_\(MNT_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} grep '^const _MS_' gen-sysinfo.go | sed -e 's/^\(const \)_\(MS_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} @@ -893,6 +918,8 @@ grep '^type _rlimit ' gen-sysinfo.go | \ # The RLIMIT constants. grep '^const _RLIMIT_' gen-sysinfo.go | sed -e 's/^\(const \)_\(RLIMIT_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} +grep '^const _RLIM_' gen-sysinfo.go | + sed -e 's/^\(const \)_\(RLIM_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} # The sysinfo struct. grep '^type _sysinfo ' gen-sysinfo.go | \ @@ -932,6 +959,10 @@ grep '^type _utimbuf ' gen-sysinfo.go | \ -e 's/modtime/Modtime/' \ >> ${OUT} +# The LOCK flags for flock. +grep '^const _LOCK_' gen-sysinfo.go | + sed -e 's/^\(const \)_\(LOCK_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} + # The GNU/Linux LINUX_REBOOT flags. grep '^const _LINUX_REBOOT_' gen-sysinfo.go | sed -e 's/^\(const \)_\(LINUX_REBOOT_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} @@ -957,9 +988,84 @@ grep '^type _sock_fprog ' gen-sysinfo.go | \ grep '^const _BPF_' gen-sysinfo.go | \ sed -e 's/^\(const \)_\(BPF_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} +# The GNU/Linux nlattr struct. +grep '^type _nlattr ' gen-sysinfo.go | \ + sed -e 's/_nlattr/NlAttr/' \ + -e 's/nla_len/Len/' \ + -e 's/nla_type/Type/' \ + >> ${OUT} + +# The GNU/Linux nlmsgerr struct. +grep '^type _nlmsgerr ' gen-sysinfo.go | \ + sed -e 's/_nlmsgerr/NlMsgerr/' \ + -e 's/error/Error/' \ + -e 's/msg/Msg/' \ + -e 's/_nlmsghdr/NlMsghdr/' \ + >> ${OUT} + +# The GNU/Linux rtnexthop struct. +grep '^type _rtnexthop ' gen-sysinfo.go | \ + sed -e 's/_rtnexthop/RtNexthop/' \ + -e 's/rtnh_len/Len/' \ + -e 's/rtnh_flags/Flags/' \ + -e 's/rtnh_hops/Hops/' \ + -e 's/rtnh_ifindex/Ifindex/' \ + >> ${OUT} + +# The GNU/Linux netlink flags. +grep '^const _NETLINK_' gen-sysinfo.go | \ + sed -e 's/^\(const \)_\(NETLINK_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} +grep '^const _NLA_' gen-sysinfo.go | \ + sed -e 's/^\(const \)_\(NLA_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} + +# The GNU/Linux packet socket flags. +grep '^const _PACKET_' gen-sysinfo.go | \ + sed -e 's/^\(const \)_\(PACKET_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} + +# The GNU/Linux inotify_event struct. +grep '^type _inotify_event ' gen-sysinfo.go | \ + sed -e 's/_inotify_event/InotifyEvent/' \ + -e 's/wd/Wd/' \ + -e 's/mask/Mask/' \ + -e 's/cookie/Cookie/' \ + -e 's/len/Len/' \ + -e 's/name/Name/' \ + -e 's/\[\]/[0]/' \ + -e 's/\[0\]byte/[0]int8/' \ + >> ${OUT} + # The Solaris 11 Update 1 _zone_net_addr_t struct. grep '^type _zone_net_addr_t ' gen-sysinfo.go | \ sed -e 's/_in6_addr/[16]byte/' \ >> ${OUT} +# Struct sizes. +set cmsghdr Cmsghdr ip_mreq IPMreq ip_mreqn IPMreqn ipv6_mreq IPv6Mreq \ + ifaddrmsg IfAddrmsg ifinfomsg IfInfomsg in_pktinfo Inet4Pktinfo \ + in6_pktinfo Inet6Pktinfo inotify_event InotifyEvent linger Linger \ + msghdr Msghdr nlattr NlAttr nlmsgerr NlMsgerr nlmsghdr NlMsghdr \ + rtattr RtAttr rtgenmsg RtGenmsg rtmsg RtMsg rtnexthop RtNexthop \ + sock_filter SockFilter sock_fprog SockFprog ucred Ucred +while test $# != 0; do + nc=$1 + ngo=$2 + shift + shift + if grep "^const _sizeof_$nc =" gen-sysinfo.go >/dev/null 2>&1; then + echo "const Sizeof$ngo = _sizeof_$nc" >> ${OUT} + fi +done + +# In order to compile the net package, we need some sizes to exist +# even if the types do not. +if ! grep 'const SizeofIPMreq ' ${OUT} >/dev/null 2>&1; then + echo 'const SizeofIPMreq = 8' >> ${OUT} +fi +if ! grep 'const SizeofIPv6Mreq ' ${OUT} >/dev/null 2>&1; then + echo 'const SizeofIPv6Mreq = 20' >> ${OUT} +fi +if ! grep 'const SizeofIPMreqn ' ${OUT} >/dev/null 2>&1; then + echo 'const SizeofIPMreqn = 12' >> ${OUT} +fi + exit $? diff --git a/libgo/runtime/go-runtime-error.c b/libgo/runtime/go-runtime-error.c index f732e7f017f..68db8acd8b1 100644 --- a/libgo/runtime/go-runtime-error.c +++ b/libgo/runtime/go-runtime-error.c @@ -46,7 +46,10 @@ enum MAKE_MAP_OUT_OF_BOUNDS = 8, /* Channel capacity out of bounds in make: negative or overflow. */ - MAKE_CHAN_OUT_OF_BOUNDS = 9 + MAKE_CHAN_OUT_OF_BOUNDS = 9, + + /* Integer division by zero. */ + DIVISION_BY_ZERO = 10 }; extern void __go_runtime_error () __attribute__ ((noreturn)); @@ -78,6 +81,9 @@ __go_runtime_error (int i) case MAKE_CHAN_OUT_OF_BOUNDS: runtime_panicstring ("make chan len out of range"); + case DIVISION_BY_ZERO: + runtime_panicstring ("integer divide by zero"); + default: runtime_panicstring ("unknown runtime error"); } diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc index 97cfabe040a..253fdbe0ccb 100644 --- a/libgo/runtime/malloc.goc +++ b/libgo/runtime/malloc.goc @@ -72,7 +72,7 @@ runtime_mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed) npages = size >> PageShift; if((size & PageMask) != 0) npages++; - s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, !(flag & FlagNoGC)); + s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1); if(s == nil) runtime_throw("out of memory"); size = npages<<PageShift; diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c index 4aa7c45dcb3..7e68535ebfd 100644 --- a/libgo/runtime/mgc0.c +++ b/libgo/runtime/mgc0.c @@ -4,6 +4,8 @@ // Garbage collector. +#include <unistd.h> + #include "runtime.h" #include "arch.h" #include "malloc.h" @@ -918,7 +920,7 @@ cachestats(void) uint64 stacks_sys; stacks_inuse = 0; - stacks_sys = 0; + stacks_sys = runtime_stacks_sys; for(m=runtime_allm; m; m=m->alllink) { runtime_purgecachedstats(m); // stacks_inuse += m->stackalloc->inuse; @@ -1020,7 +1022,7 @@ runtime_gc(int32 force) stealcache(); cachestats(); - mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100; + mstats.next_gc = mstats.heap_alloc+(mstats.heap_alloc-runtime_stacks_sys)*gcpercent/100; m->gcing = 0; m->locks++; // disable gc during the mallocs in newproc @@ -1329,6 +1331,8 @@ runtime_setblockspecial(void *v, bool s) void runtime_MHeap_MapBits(MHeap *h) { + size_t page_size; + // Caller has added extra mappings to the arena. // Add extra mappings of bitmap words as needed. // We allocate extra bitmap pieces in chunks of bitmapChunk. @@ -1342,6 +1346,9 @@ runtime_MHeap_MapBits(MHeap *h) if(h->bitmap_mapped >= n) return; + page_size = getpagesize(); + n = (n+page_size-1) & ~(page_size-1); + runtime_SysMap(h->arena_start - n, n - h->bitmap_mapped); h->bitmap_mapped = n; } diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index 9ad9f9659b9..660c69fc03c 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -46,6 +46,8 @@ extern void __splitstack_block_signals_context (void *context[10], int *, # define StackMin 2 * 1024 * 1024 #endif +uintptr runtime_stacks_sys; + static void schedule(G*); typedef struct Sched Sched; @@ -1091,6 +1093,7 @@ schedule(G *gp) m->lockedg = nil; } gp->idlem = nil; + runtime_memclr(&gp->context, sizeof gp->context); gfput(gp); if(--runtime_sched.gcount == 0) runtime_exit(0); @@ -1288,6 +1291,7 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) *ret_stacksize = stacksize; newg->gcinitial_sp = *ret_stack; newg->gcstack_size = stacksize; + runtime_xadd(&runtime_stacks_sys, stacksize); #endif } return newg; diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index a81c210a2b8..d379f99f8da 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -463,3 +463,8 @@ struct root_list { }; void __go_register_gc_roots(struct root_list*); + +// Size of stack space allocated using Go's allocator. +// This will be 0 when using split stacks, as in that case +// the stacks are allocated by the splitstack library. +extern uintptr runtime_stacks_sys; diff --git a/libgo/testsuite/Makefile.in b/libgo/testsuite/Makefile.in index 92defa60b52..1d1e05e7ae3 100644 --- a/libgo/testsuite/Makefile.in +++ b/libgo/testsuite/Makefile.in @@ -86,7 +86,6 @@ GOARCH = @GOARCH@ GOC = @GOC@ GOCFLAGS = @GOCFLAGS@ GOOS = @GOOS@ -GO_BIGENDIAN = @GO_BIGENDIAN@ GO_LIBCALL_OS_ARCH_FILE = @GO_LIBCALL_OS_ARCH_FILE@ GO_LIBCALL_OS_FILE = @GO_LIBCALL_OS_FILE@ GO_SYSCALL_OS_ARCH_FILE = @GO_SYSCALL_OS_ARCH_FILE@ diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest index aac67bfbcfb..c6966fa7d4c 100755 --- a/libgo/testsuite/gotest +++ b/libgo/testsuite/gotest @@ -347,18 +347,18 @@ localname() { pattern='Test([^a-z].*)?' # The -p option tells GNU nm not to sort. # The -v option tells Solaris nm to sort by value. - tests=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/') + tests=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | fgrep -v ' __go_' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/') if [ "x$tests" = x ]; then echo 'gotest: warning: no tests matching '$pattern in _gotest_.o $xofile 1>&2 exit 2 fi # benchmarks are named BenchmarkFoo. pattern='Benchmark([^a-z].*)?' - benchmarks=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/') + benchmarks=$($NM -p -v _gotest_.o $xofile | egrep " $test .*\."$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | fgrep -v ' __go_' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/') # examples are named ExampleFoo pattern='Example([^a-z].*)?' - examples=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/') + examples=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | fgrep -v ' __go_' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/') # package spec echo 'package main' diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 66321424d45..bc6d5c47792 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,7 @@ +2012-04-11 Manuel López-Ibáñez <manu@gcc.gnu.org> + + * testsuite/lib/libgomp.exp: Add -fno-diagnostics-show-caret. + 2012-03-31 H.J. Lu <hongjiu.lu@intel.com> PR bootstrap/52812 diff --git a/libgomp/testsuite/lib/libgomp.exp b/libgomp/testsuite/lib/libgomp.exp index 02909f8f2d7..cd561bf1576 100644 --- a/libgomp/testsuite/lib/libgomp.exp +++ b/libgomp/testsuite/lib/libgomp.exp @@ -161,6 +161,9 @@ proc libgomp_init { args } { # error-message parsing machinery. lappend ALWAYS_CFLAGS "additional_flags=-fmessage-length=0" + # Disable caret + lappend ALWAYS_CFLAGS "additional_flags=-fno-diagnostics-show-caret" + # And, gee, turn on OpenMP. lappend ALWAYS_CFLAGS "additional_flags=-fopenmp" } diff --git a/libmudflap/ChangeLog b/libmudflap/ChangeLog index 3d3e5af21a9..9fb1cac7758 100644 --- a/libmudflap/ChangeLog +++ b/libmudflap/ChangeLog @@ -1,3 +1,8 @@ +2012-04-11 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR 24985 + * testsuite/lib/libmudflap.exp: Handle caret. + 2012-01-19 Jakub Jelinek <jakub@redhat.com> PR libmudflap/40778 diff --git a/libmudflap/testsuite/lib/libmudflap.exp b/libmudflap/testsuite/lib/libmudflap.exp index f9603553199..00699e87b75 100644 --- a/libmudflap/testsuite/lib/libmudflap.exp +++ b/libmudflap/testsuite/lib/libmudflap.exp @@ -298,6 +298,9 @@ proc libmudflap-dg-prune { system text } { proc prune_gcc_output { text } { + # Ignore caret diagnostics. Unfortunately dejaGNU trims leading + # spaces, so one cannot rely on them being present. + regsub -all "(^|\n)\[^\n\]+\n *\\^\n" $text "\n" text regsub -all {(^|\n)[^\n]*ld: warning: libgcc_s[^\n]*not found[^\n]*try using[^\n]*} $text "" text regsub -all {(^|\n)[^\n]*In function.*pthread_create[^\n]*} $text "" text regsub -all {(^|\n)[^\n]*the use of .pthread.*is deprecated[^\n]*} $text "" text diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 9bd426812e7..6ad664509b3 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,246 @@ +2012-04-22 Paolo Carlini <paolo.carlini@oracle.com> + + PR libstdc++/53067 + * include/bits/hashtable_policy.h: Change inheritances to public. + * testsuite/23_containers/unordered_map/requirements/53067.cc: New. + * testsuite/23_containers/unordered_set/requirements/53067.cc: Likewise. + +2012-04-22 Jonathan Wakely <jwakely.gcc@gmail.com> + + * include/ext/alloc_traits.h (__alloc_traits::difference_type): + Define. + +2012-04-22 Jonathan Wakely <jwakely.gcc@gmail.com> + + PR libstdc++/53027 + * include/bits/ptr_traits.h (pointer_traits::rebind): Make public. + * testsuite/20_util/pointer_traits/requirements/typedefs.cc: Check + rebind works. + +2012-04-22 Jonathan Wakely <jwakely.gcc@gmail.com> + + * include/debug/forward_list (forward_list::splice_after): Check + allocators are equal. + * src/c++11/debug.cc: Fix spelling. + * testsuite/23_containers/forward_list/debug/splice_after5_neg.cc: + New. + * testsuite/23_containers/forward_list/debug/splice_after6_neg.cc: + Likewise. + * testsuite/23_containers/forward_list/debug/splice_after7_neg.cc: + Likewise. + +2012-04-20 Paolo Carlini <paolo.carlini@oracle.com> + + PR libstdc++/53052 + * include/std/type_traits (is_explicitly_convertible): Remove. + * testsuite/20_util/is_explicitly_convertible: Likewise. + * testsuite/20_util/make_signed/requirements/typedefs_neg.cc: + Adjust dg-error line numbers. + * testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: + Likewise. + * testsuite/20_util/declval/requirements/1_neg.cc: Likewise. + +2012-04-17 Benjamin Kosnik <bkoz@redhat.com> + + * testsuite/20_util/specialized_algorithms/uninitialized_copy/ + 808590.cc: New. + +2012-04-17 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * testsuite/util/testsuite_abi.cc (compare_symbols): Change + summary header to avoid confusion with DejaGnu header. + +2012-04-15 Paolo Carlini <paolo.carlini@oracle.com> + + PR libstdc++/52702 + * include/std/type_traits (is_trivially_destructible): Add. + (has_trivial_destructor): Remove. + * testsuite/util/testsuite_common_types.h: Adjust. + * testsuite/20_util/tuple/requirements/dr801.cc: Likewise. + * testsuite/20_util/pair/requirements/dr801.cc: Likewise. + * testsuite/20_util/is_trivially_destructible/value.cc: New. + * testsuite/20_util/is_trivially_destructible/requirements/ + typedefs.cc: Likewise. + * testsuite/20_util/is_trivially_destructible/requirements/ + explicit_instantiation.cc: Likewise. + * testsuite/20_util/make_signed/requirements/typedefs_neg.cc: + Adjust dg-error line numbers. + * testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: + Likewise. + * testsuite/20_util/declval/requirements/1_neg.cc: Likewise. + +2012-04-14 Paolo Carlini <paolo.carlini@oracle.com> + + PR libstdc++/52699 + * include/bits/random.tcc (independent_bits_engine<>::operator()()) + Avoid various overflows; use common_type on result_type and + _RandomNumberEngine::result_type; avoid floating point computations; + other smaller tweaks. + + * include/bits/random.tcc (uniform_int_distribution<>::operator()) + Use common_type; assume _UniformRandomNumberGenerator::result_type + unsigned; tidy. + + * include/bits/stl_algobase.h (__lg(unsigned), __lg(unsigned long), + __lg(unsigned long long)): Add. + +2012-04-14 Alan Modra <amodra@gmail.com> + + PR libstdc++/52839 + * acinclude.m4 (_GLIBCXX_ATOMIC_BUILTINS): Do not depend on + glibcxx_cv_atomic_long_long. + * configure: Regenerate. + +2012-04-13 Paolo Carlini <paolo.carlini@oracle.com> + + * testsuite/26_numerics/cmath/51083.cc: Move... + * testsuite/26_numerics/headers/cmath/51083.cc: ... here. + +2012-04-13 Laurent Alfonsi <laurent.alfonsi@st.com> + + PR libstdc++/52604 + * src/c++98/mt_allocator.cc: (__freelist::~__freelist): Reset pointer. + +2012-04-13 Paolo Carlini <paolo.carlini@oracle.com> + + * include/debug/safe_iterator.h (_BeforeBeginHelper<>:: + _S_Is_Beginnest): Add. + * include/debug/forward_list (_BeforeBeginHelper<>:: + _S_Is_Beginnest): Likewise. + (_Safe_iterator<>::_M_is_beginnest): Add. + * include/debug/safe_iterator.tcc (_Safe_iterator<>::_M_valid_range): + Use the latter. + * testsuite/23_containers/forward_list/debug/splice_after.cc: + Add test. + +2012-04-12 Benjamin Kosnik <bkoz@redhat.com> + + * include/bits/unordered_map.h (__unordered_map): Remove. + (__unordered_multimap): Remove. + Add aliases for __umap_traits, __umap_hashtable, __ummap_traits, + __ummap_hashtable. + (unordered_map): Derive from __umap_hashtable. + (unordered_multimap): Derive from __ummap_hashtable. + * include/bits/unordered_set.h (__unordered_set): Remove. + (__unordered_multiset): Remove. + Add aliases for __uset_traits, __uset_hashtable, __umset_traits, + __umset_hashtable. + (unordered_set): Derive from __uset_hashtable. + (unordered_multiset): Derive from __umset_hashtable. + * include/bits/hashtable.h (__cache_default): New, consolidated + cache defaults for _Hashtable. Adjust comments for doxygen. + (_Hashtable): Consolidate bool template parameters into new, + _Traits class. Inherited base classes synthesize _Hashtable in + CRTP via original 10 parameters. Prefer using declarations to + typedefs, add __node_type, __bucket_type, etc. Push many nested + types down hierarchy to _Hashtable_base. Add constructors + necessary for top-level unordered_containers. Consolidate insert + member functions and logic in new base class, __detail::_Insert + and __detail::_Insert_base. + (_Hashtable::operator=(initializer_list)): Add. + * include/bits/hashtable_policy.h: Convert to doxygen markup. + (_Hashtable_traits) New. Consolidate bool template parameters here. + (_Insert, _Insert_base): New, consolidated insert member functions. + (_Map_base, _Equality, _Rehash_base): Adjust template parameters, + use base types. + (_Hashtable_base): Move type declarations useful to other base + classes into this class. + * python/libstdcxx/v6/printers.py (Tr1HashtableIterator): Update. + * testsuite/23_containers/unordered_set/instantiation_neg.cc: + Adjust traits, line numbers. + +2012-04-12 Jeffrey Yasskin <jyasskin@google.com> + + PR libstdc++/52822 + * include/bits/stl_algo.h (__find_if_not): Expose in C++98 mode. + (__find_if_not_n): Like __find_if_not, but works on and updates a + counted range instead of a bounded range. + (stable_partition): Guarantee !__pred(*__first) in call to + __stable_partition_adaptive() or __inplace_stable_partition(). + (__stable_partition_adaptive): Use new precondition to avoid + moving/copying objects onto themselves. Guarantee new + precondition to recursive calls. + (__inplace_stable_partition): Use new precondition to simplify + base case, remove __last parameter. Guarantee new precondition to + recursive calls. + * testsuite/25_algorithms/stable_partition/moveable.cc (test02): + Test a sequence that starts with a value matching the predicate. + * testsuite/25_algorithms/stable_partition/pr52822.cc: Test + vectors, which have a destructive self-move-assignment. + +2012-04-12 Andreas Schwab <schwab@linux-m68k.org> + + * testsuite/Makefile.am (check_DEJAGNUnormal0): Run + prettyprinters.exp. + * testsuite/Makefile.in: Regenerated. + +2012-04-12 Paolo Carlini <paolo.carlini@oracle.com> + + PR libstdc++/52942 + * include/bits/stl_function.h (_Identity, _Select1st, _Select2nd): + In C++11 mode do not derive from std::unary_function. + * include/ext/functional (identity, select1st, select2nd): Adjust. + * testsuite/23_containers/unordered_map/requirements/52942.cc: New. + * testsuite/23_containers/unordered_set/requirements/52942.cc: Likewise. + +2012-04-11 Jonathan Wakely <jwakely.gcc@gmail.com> + + PR libstdc++/52924 + * include/bits/shared_ptr_base.h (_Sp_counted_deleter): Add + user-defined destructor. + (_Sp_counted_inplace): Likewise. + * testsuite/20_util/shared_ptr/cons/52924.cc: New. + * testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust dg-error + line numbers. + +2012-04-11 Jonathan Wakely <jwakely.gcc@gmail.com> + + * doc/xml/manual/debug.xml (Debug Versions of Library Binary Files): + Re-arrange text slightly. + +2012-04-11 Jonathan Wakely <jwakely.gcc@gmail.com> + + * testsuite/performance/30_threads/future/polling.cc: Adjust. + +2012-04-11 Paolo Carlini <paolo.carlini@oracle.com> + + * include/bits/forward_list.h (splice_after(const_iterator, + forward_list&), splice_after(const_iterator, forward_list&, + const_iterator), splice_after(const_iterator, forward_list&, + const_iterator, const_iterator), merge(forward_list&), + merge(forward_list&, _Comp)): Add per C++11 as published (and + LWG 1310). + * include/debug/forward_list: Adjust. + + * include/bits/forward_list.h (splice_after(const_iterator, + forward_list&&, const_iterator)): Only declare. + (_M_transfer_after): Remove. + (_M_splice_after(const_iterator, forward_list&&)): Change signature. + (splice_after(const_iterator, forward_list&&, const_iterator, + const_iterator)): Use the latter. + * include/bits/forward_list.tcc (splice_after(const_iterator, + forward_list&&, const_iterator)): Define here. + (_M_splice_after): Define, use throughout. + + * include/bits/forward_list.h (insert_after(const_iterator, + std::initializer_list<_Tp>)): Forward to insert_after(const_iterator, + _InputIterator, _InputIterator). + * include/bits/forward_list.tcc: Remove definition. + + * testsuite/23_containers/forward_list/modifiers/6.cc: New. + * testsuite/23_containers/forward_list/operations/1.cc: Adjust. + +2012-04-11 Paolo Carlini <paolo.carlini@oracle.com> + + PR libstdc++/52931 + * include/bits/functional_hash.h (struct hash): Remove definition. + * testsuite/20_util/hash/52931.cc: New. + +2012-04-11 Manuel López-Ibáñez <manu@gcc.gnu.org> + + PR 24985 + * testsuite/lib/prune.exp: Handle caret. + 2012-04-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> Partially revert: diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 01b06e490d7..6632725b7ec 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -2861,11 +2861,10 @@ EOF CXXFLAGS="$old_CXXFLAGS" AC_LANG_RESTORE - # Set atomicity_dir to builtins if all of above tests pass. + # Set atomicity_dir to builtins if all but the long long test above passes. if test $glibcxx_cv_atomic_bool = yes \ && test $glibcxx_cv_atomic_short = yes \ - && test $glibcxx_cv_atomic_int = yes \ - && test $glibcxx_cv_atomic_long_long = yes ; then + && test $glibcxx_cv_atomic_int = yes; then AC_DEFINE(_GLIBCXX_ATOMIC_BUILTINS, 1, [Define if the compiler supports C++11 atomics.]) atomicity_dir=cpu/generic/atomicity_builtins diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index e8fb5d37b22..a545eda2eec 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -15446,11 +15446,10 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu - # Set atomicity_dir to builtins if all of above tests pass. + # Set atomicity_dir to builtins if all but the long long test above passes. if test $glibcxx_cv_atomic_bool = yes \ && test $glibcxx_cv_atomic_short = yes \ - && test $glibcxx_cv_atomic_int = yes \ - && test $glibcxx_cv_atomic_long_long = yes ; then + && test $glibcxx_cv_atomic_int = yes; then $as_echo "#define _GLIBCXX_ATOMIC_BUILTINS 1" >>confdefs.h @@ -15482,7 +15481,7 @@ $as_echo "$as_me: WARNING: Performance of certain classes will degrade as a resu # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 15485 "configure" +#line 15484 "configure" int main() { _Decimal32 d1; @@ -15524,7 +15523,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 15527 "configure" +#line 15526 "configure" template<typename T1, typename T2> struct same { typedef T2 type; }; @@ -15558,7 +15557,7 @@ $as_echo "$enable_int128" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 15561 "configure" +#line 15560 "configure" template<typename T1, typename T2> struct same { typedef T2 type; }; diff --git a/libstdc++-v3/doc/xml/manual/debug.xml b/libstdc++-v3/doc/xml/manual/debug.xml index 7ee2abf6988..0a24c960211 100644 --- a/libstdc++-v3/doc/xml/manual/debug.xml +++ b/libstdc++-v3/doc/xml/manual/debug.xml @@ -64,8 +64,9 @@ <para> If you would like debug symbols in libstdc++, there are two ways to - build libstdc++ with debug flags. The first is to run make from the - toplevel in a freshly-configured tree with + build libstdc++ with debug flags. The first is to create a separate + debug build by running make from the top-level of a tree + freshly-configured with </para> <programlisting> --enable-libstdcxx-debug @@ -75,11 +76,11 @@ --enable-libstdcxx-debug-flags='...' </programlisting> <para> - to create a separate debug build. Both the normal build and the - debug build will persist, without having to specify - <code>CXXFLAGS</code>, and the debug library will be installed in a - separate directory tree, in <code>(prefix)/lib/debug</code>. For - more information, look at the <link linkend="manual.intro.setup.configure">configuration</link> section. + Both the normal build and the debug build will persist, without + having to specify <code>CXXFLAGS</code>, and the debug library will + be installed in a separate directory tree, in <code>(prefix)/lib/debug</code>. + For more information, look at the + <link linkend="manual.intro.setup.configure">configuration</link> section. </para> <para> diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h index 01020c5e933..76c3e3303cc 100644 --- a/libstdc++-v3/include/bits/forward_list.h +++ b/libstdc++-v3/include/bits/forward_list.h @@ -53,15 +53,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _Fwd_list_node_base* _M_next; _Fwd_list_node_base* - _M_transfer_after(_Fwd_list_node_base* __begin) - { - _Fwd_list_node_base* __end = __begin; - while (__end && __end->_M_next) - __end = __end->_M_next; - return _M_transfer_after(__begin, __end); - } - - _Fwd_list_node_base* _M_transfer_after(_Fwd_list_node_base* __begin, _Fwd_list_node_base* __end) { @@ -925,7 +916,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * does not invalidate iterators and references. */ iterator - insert_after(const_iterator __pos, std::initializer_list<_Tp> __il); + insert_after(const_iterator __pos, std::initializer_list<_Tp> __il) + { return insert_after(__pos, __il.begin(), __il.end()); } /** * @brief Removes the element pointed to by the iterator following @@ -1047,9 +1039,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER splice_after(const_iterator __pos, forward_list&& __list) { if (!__list.empty()) - _M_splice_after(__pos, std::move(__list)); + _M_splice_after(__pos, __list.before_begin(), __list.end()); } + void + splice_after(const_iterator __pos, forward_list& __list) + { splice_after(__pos, std::move(__list)); } + /** * @brief Insert element from another %forward_list. * @param __pos Iterator referencing the element to insert after. @@ -1062,15 +1058,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ void splice_after(const_iterator __pos, forward_list&& __list, - const_iterator __i) - { - const_iterator __j = __i; - ++__j; - if (__pos == __i || __pos == __j) - return; + const_iterator __i); - splice_after(__pos, std::move(__list), __i, __j); - } + void + splice_after(const_iterator __pos, forward_list& __list, + const_iterator __i) + { splice_after(__pos, std::move(__list), __i); } /** * @brief Insert range from another %forward_list. @@ -1086,8 +1079,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Undefined if @a __pos is in (__before,__last). */ void - splice_after(const_iterator __pos, forward_list&& __list, - const_iterator __before, const_iterator __last); + splice_after(const_iterator __pos, forward_list&&, + const_iterator __before, const_iterator __last) + { _M_splice_after(__pos, __before, __last); } + + void + splice_after(const_iterator __pos, forward_list&, + const_iterator __before, const_iterator __last) + { _M_splice_after(__pos, __before, __last); } /** * @brief Remove all elements equal to value. @@ -1130,7 +1129,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ void unique() - { this->unique(std::equal_to<_Tp>()); } + { unique(std::equal_to<_Tp>()); } /** * @brief Remove consecutive elements satisfying a predicate. @@ -1159,7 +1158,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ void merge(forward_list&& __list) - { this->merge(std::move(__list), std::less<_Tp>()); } + { merge(std::move(__list), std::less<_Tp>()); } + + void + merge(forward_list& __list) + { merge(std::move(__list)); } /** * @brief Merge sorted lists according to comparison function. @@ -1176,6 +1179,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER void merge(forward_list&& __list, _Comp __comp); + template<typename _Comp> + void + merge(forward_list& __list, _Comp __comp) + { merge(std::move(__list), __comp); } + /** * @brief Sort the elements of the list. * @@ -1184,7 +1192,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ void sort() - { this->sort(std::less<_Tp>()); } + { sort(std::less<_Tp>()); } /** * @brief Sort the forward_list using a comparison function. @@ -1218,7 +1226,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Called by splice_after and insert_after. iterator - _M_splice_after(const_iterator __pos, forward_list&& __list); + _M_splice_after(const_iterator __pos, const_iterator __before, + const_iterator __last); // Called by forward_list(n). void diff --git a/libstdc++-v3/include/bits/forward_list.tcc b/libstdc++-v3/include/bits/forward_list.tcc index 99fa3a01609..3c9f2380b27 100644 --- a/libstdc++-v3/include/bits/forward_list.tcc +++ b/libstdc++-v3/include/bits/forward_list.tcc @@ -223,22 +223,37 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template<typename _Tp, typename _Alloc> typename forward_list<_Tp, _Alloc>::iterator forward_list<_Tp, _Alloc>:: - _M_splice_after(const_iterator __pos, forward_list&& __list) + _M_splice_after(const_iterator __pos, + const_iterator __before, const_iterator __last) { _Node_base* __tmp = const_cast<_Node_base*>(__pos._M_node); - iterator __before = __list.before_begin(); - return iterator(__tmp->_M_transfer_after(__before._M_node)); + _Node_base* __b = const_cast<_Node_base*>(__before._M_node); + _Node_base* __end = __b; + + while (__end && __end->_M_next != __last._M_node) + __end = __end->_M_next; + + if (__b != __end) + return iterator(__tmp->_M_transfer_after(__b, __end)); + else + return iterator(__tmp); } template<typename _Tp, typename _Alloc> void forward_list<_Tp, _Alloc>:: splice_after(const_iterator __pos, forward_list&&, - const_iterator __before, const_iterator __last) + const_iterator __i) { + const_iterator __j = __i; + ++__j; + + if (__pos == __i || __pos == __j) + return; + _Node_base* __tmp = const_cast<_Node_base*>(__pos._M_node); - __tmp->_M_transfer_after(const_cast<_Node_base*>(__before._M_node), - const_cast<_Node_base*>(__last._M_node)); + __tmp->_M_transfer_after(const_cast<_Node_base*>(__i._M_node), + const_cast<_Node_base*>(__j._M_node)); } template<typename _Tp, typename _Alloc> @@ -249,7 +264,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if (__n) { forward_list __tmp(__n, __val, get_allocator()); - return _M_splice_after(__pos, std::move(__tmp)); + return _M_splice_after(__pos, __tmp.before_begin(), __tmp.end()); } else return iterator(const_cast<_Node_base*>(__pos._M_node)); @@ -264,26 +279,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { forward_list __tmp(__first, __last, get_allocator()); if (!__tmp.empty()) - return _M_splice_after(__pos, std::move(__tmp)); + return _M_splice_after(__pos, __tmp.before_begin(), __tmp.end()); else return iterator(const_cast<_Node_base*>(__pos._M_node)); } template<typename _Tp, typename _Alloc> - typename forward_list<_Tp, _Alloc>::iterator - forward_list<_Tp, _Alloc>:: - insert_after(const_iterator __pos, std::initializer_list<_Tp> __il) - { - if (__il.size()) - { - forward_list __tmp(__il, get_allocator()); - return _M_splice_after(__pos, std::move(__tmp)); - } - else - return iterator(const_cast<_Node_base*>(__pos._M_node)); - } - - template<typename _Tp, typename _Alloc> void forward_list<_Tp, _Alloc>:: remove(const _Tp& __val) diff --git a/libstdc++-v3/include/bits/functional_hash.h b/libstdc++-v3/include/bits/functional_hash.h index e892159d449..69c186c5795 100644 --- a/libstdc++-v3/include/bits/functional_hash.h +++ b/libstdc++-v3/include/bits/functional_hash.h @@ -1,6 +1,7 @@ // functional_hash.h header -*- C++ -*- -// Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 +// Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -55,12 +56,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Primary class template hash. template<typename _Tp> - struct hash : public __hash_base<size_t, _Tp> - { - static_assert(sizeof(_Tp) < 0, - "std::hash is not specialized for this type"); - size_t operator()(const _Tp&) const noexcept; - }; + struct hash; /// Partial specializations for pointer types. template<typename _Tp> diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h index 41418a8a509..8c17035b5c8 100644 --- a/libstdc++-v3/include/bits/hashtable.h +++ b/libstdc++-v3/include/bits/hashtable.h @@ -1,6 +1,7 @@ // hashtable.h header -*- C++ -*- -// Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 +// Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -38,254 +39,305 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - // Class template _Hashtable, class definition. + template<typename _Tp, typename _Hash> + using __cache_default = __not_<__and_<is_integral<_Tp>, + is_empty<_Hash>, + integral_constant<bool, !__is_final(_Hash)>, + __detail::__is_noexcept_hash<_Tp, _Hash> >>; - // Meaning of class template _Hashtable's template parameters - - // _Key and _Value: arbitrary CopyConstructible types. - - // _Allocator: an allocator type ([lib.allocator.requirements]) whose - // value type is Value. As a conforming extension, we allow for - // value type != Value. - - // _ExtractKey: function object that takes an object of type Value - // and returns a value of type _Key. - - // _Equal: function object that takes two objects of type k and returns - // a bool-like value that is true if the two objects are considered equal. - - // _H1: the hash function. A unary function object with argument type - // Key and result type size_t. Return values should be distributed - // over the entire range [0, numeric_limits<size_t>:::max()]. - - // _H2: the range-hashing function (in the terminology of Tavori and - // Dreizin). A binary function object whose argument types and result - // type are all size_t. Given arguments r and N, the return value is - // in the range [0, N). - - // _Hash: the ranged hash function (Tavori and Dreizin). A binary function - // whose argument types are _Key and size_t and whose result type is - // size_t. Given arguments k and N, the return value is in the range - // [0, N). Default: hash(k, N) = h2(h1(k), N). If _Hash is anything other - // than the default, _H1 and _H2 are ignored. - - // _RehashPolicy: Policy class with three members, all of which govern - // the bucket count. _M_next_bkt(n) returns a bucket count no smaller - // than n. _M_bkt_for_elements(n) returns a bucket count appropriate - // for an element count of n. _M_need_rehash(n_bkt, n_elt, n_ins) - // determines whether, if the current bucket count is n_bkt and the - // current element count is n_elt, we need to increase the bucket - // count. If so, returns make_pair(true, n), where n is the new - // bucket count. If not, returns make_pair(false, <anything>). - - // __cache_hash_code: bool. true if we store the value of the hash - // function along with the value. This is a time-space tradeoff. - // Storing it may improve lookup speed by reducing the number of times - // we need to call the Equal function. - - // __constant_iterators: bool. true if iterator and const_iterator are - // both constant iterator types. This is true for unordered_set and - // unordered_multiset, false for unordered_map and unordered_multimap. - - // __unique_keys: bool. true if the return value of _Hashtable::count(k) - // is always at most one, false if it may be an arbitrary number. This - // true for unordered_set and unordered_map, false for unordered_multiset - // and unordered_multimap. /** - * Here's _Hashtable data structure, each _Hashtable has: - * - _Bucket[] _M_buckets - * - _Hash_node_base _M_before_begin - * - size_type _M_bucket_count - * - size_type _M_element_count + * Primary class template _Hashtable. + * + * @ingroup hashtable-detail + * + * @tparam _Value CopyConstructible type. + * + * @tparam _Key CopyConstructible type. + * + * @tparam _Alloc An allocator type + * ([lib.allocator.requirements]) whose _Alloc::value_type is + * _Value. As a conforming extension, we allow for + * _Alloc::value_type != _Value. + * + * @tparam _ExtractKey Function object that takes an object of type + * _Value and returns a value of type _Key. + * + * @tparam _Equal Function object that takes two objects of type k + * and returns a bool-like value that is true if the two objects + * are considered equal. + * + * @tparam _H1 The hash function. A unary function object with + * argument type _Key and result type size_t. Return values should + * be distributed over the entire range [0, numeric_limits<size_t>:::max()]. + * + * @tparam _H2 The range-hashing function (in the terminology of + * Tavori and Dreizin). A binary function object whose argument + * types and result type are all size_t. Given arguments r and N, + * the return value is in the range [0, N). + * + * @tparam _Hash The ranged hash function (Tavori and Dreizin). A + * binary function whose argument types are _Key and size_t and + * whose result type is size_t. Given arguments k and N, the + * return value is in the range [0, N). Default: hash(k, N) = + * h2(h1(k), N). If _Hash is anything other than the default, _H1 + * and _H2 are ignored. + * + * @tparam _RehashPolicy Policy class with three members, all of + * which govern the bucket count. _M_next_bkt(n) returns a bucket + * count no smaller than n. _M_bkt_for_elements(n) returns a + * bucket count appropriate for an element count of n. + * _M_need_rehash(n_bkt, n_elt, n_ins) determines whether, if the + * current bucket count is n_bkt and the current element count is + * n_elt, we need to increase the bucket count. If so, returns + * make_pair(true, n), where n is the new bucket count. If not, + * returns make_pair(false, <anything>) + * + * @tparam _Traits Compile-time class with three boolean + * std::integral_constant members: __cache_hash_code, __constant_iterators, + * __unique_keys. * - * with _Bucket being _Hash_node* and _Hash_node constaining: - * - _Hash_node* _M_next - * - Tp _M_value - * - size_t _M_code if cache_hash_code is true + * Each _Hashtable data structure has: * - * In terms of Standard containers the hastable is like the aggregation of: - * - std::forward_list<_Node> containing the elements - * - std::vector<std::forward_list<_Node>::iterator> representing the buckets + * - _Bucket[] _M_buckets + * - _Hash_node_base _M_before_begin + * - size_type _M_bucket_count + * - size_type _M_element_count * - * The non-empty buckets contain the node before the first bucket node. This - * design allow to implement something like a std::forward_list::insert_after - * on container insertion and std::forward_list::erase_after on container - * erase calls. _M_before_begin is equivalent to - * std::foward_list::before_begin. Empty buckets are containing nullptr. - * Note that one of the non-empty bucket contains &_M_before_begin which is - * not a derefenrenceable node so the node pointers in buckets shall never be - * derefenrenced, only its next node can be. - * - * Walk through a bucket nodes require a check on the hash code to see if the - * node is still in the bucket. Such a design impose a quite efficient hash - * functor and is one of the reasons it is highly advise to set - * __cache_hash_code to true. + * with _Bucket being _Hash_node* and _Hash_node constaining: * - * The container iterators are simply built from nodes. This way incrementing - * the iterator is perfectly efficient independent of how many empty buckets - * there are in the container. + * - _Hash_node* _M_next + * - Tp _M_value + * - size_t _M_code if cache_hash_code is true * - * On insert we compute element hash code and thanks to it find the bucket - * index. If the element must be inserted on an empty bucket we add it at the - * beginning of the singly linked list and make the bucket point to - * _M_before_begin. The bucket that used to point to _M_before_begin, if any, - * is updated to point to its new before begin node. + * In terms of Standard containers the hastable is like the aggregation of: * - * On erase, the simple iterator design impose to use the hash functor to get - * the index of the bucket to update. For this reason, when __cache_hash_code - * is set to false, there is a static assertion that the hash functor cannot - * throw. + * - std::forward_list<_Node> containing the elements + * - std::vector<std::forward_list<_Node>::iterator> representing the buckets + * + * The non-empty buckets contain the node before the first bucket + * node. This design allow to implement something like a + * std::forward_list::insert_after on container insertion and + * std::forward_list::erase_after on container erase + * calls. _M_before_begin is equivalent to + * std::foward_list::before_begin. Empty buckets are containing + * nullptr. Note that one of the non-empty bucket contains + * &_M_before_begin which is not a derefenrenceable node so the + * node pointers in buckets shall never be derefenrenced, only its + * next node can be. + * + * Walk through a bucket nodes require a check on the hash code to + * see if the node is still in the bucket. Such a design impose a + * quite efficient hash functor and is one of the reasons it is + * highly advise to set __cache_hash_code to true. + * + * The container iterators are simply built from nodes. This way + * incrementing the iterator is perfectly efficient independent of + * how many empty buckets there are in the container. + * + * On insert we compute element hash code and thanks to it find the + * bucket index. If the element must be inserted on an empty bucket + * we add it at the beginning of the singly linked list and make the + * bucket point to _M_before_begin. The bucket that used to point to + * _M_before_begin, if any, is updated to point to its new before + * begin node. + * + * On erase, the simple iterator design impose to use the hash + * functor to get the index of the bucket to update. For this + * reason, when __cache_hash_code is set to false, there is a static + * assertion that the hash functor cannot throw. + * + * Functionality is implemented by decomposition into base classes, + * where the derived _Hashtable class is used in _Map_base, + * _Insert, _Rehash_base, and _Equality base classes to access the + * "this" pointer. _Hashtable_base is used in the base classes as a + * non-recursive, fully-completed-type so that detailed nested type + * information, such as iterator type and node type, can be + * used. This is similar to the "Curiously Recurring Template + * Pattern" (CRTP) technique, but uses a reconstructed, not + * explicitly passed, template pattern. + * + * Base class templates are: + * __detail::_Hashtable_base + * __detail::_Map_base + * __detail::_Insert + * __detail::_Rehash_base + * __detail::_Equality */ - - template<typename _Key, typename _Value, typename _Allocator, + template<typename _Key, typename _Value, typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, - typename _RehashPolicy, - bool __cache_hash_code, - bool __constant_iterators, - bool __unique_keys> + typename _RehashPolicy, typename _Traits> class _Hashtable - : public __detail::_Rehash_base<_RehashPolicy, - _Hashtable<_Key, _Value, _Allocator, - _ExtractKey, - _Equal, _H1, _H2, _Hash, - _RehashPolicy, - __cache_hash_code, - __constant_iterators, - __unique_keys> >, - public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, - _H1, _H2, _Hash, __cache_hash_code>, - public __detail::_Map_base<_Key, _Value, _ExtractKey, __unique_keys, - _Hashtable<_Key, _Value, _Allocator, - _ExtractKey, - _Equal, _H1, _H2, _Hash, - _RehashPolicy, - __cache_hash_code, - __constant_iterators, - __unique_keys> >, - public __detail::_Equality_base<_ExtractKey, __unique_keys, - _Hashtable<_Key, _Value, _Allocator, - _ExtractKey, - _Equal, _H1, _H2, _Hash, - _RehashPolicy, - __cache_hash_code, - __constant_iterators, - __unique_keys> > + : public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, + _H1, _H2, _Hash, _Traits>, + public __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>, + public __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>, + public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>, + public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits> { + public: + typedef _Key key_type; + typedef _Value value_type; + typedef _Alloc allocator_type; + typedef _Equal key_equal; + + // mapped_type, if present, comes from _Map_base. + // hasher, if present, comes from _Hash_code_base/_Hashtable_base. + typedef typename _Alloc::pointer pointer; + typedef typename _Alloc::const_pointer const_pointer; + typedef typename _Alloc::reference reference; + typedef typename _Alloc::const_reference const_reference; + + private: + using __rehash_type = _RehashPolicy; + using __rehash_state = typename __rehash_type::_State; + + using __traits_type = _Traits; + using __hash_cached = typename __traits_type::__hash_cached; + using __constant_iterators = typename __traits_type::__constant_iterators; + using __unique_keys = typename __traits_type::__unique_keys; + + using __key_extract = typename std::conditional< + __constant_iterators::value, + std::_Identity<value_type>, + std::_Select1st<value_type>>::type; + + using __hashtable_base = __detail:: + _Hashtable_base<_Key, _Value, _ExtractKey, + _Equal, _H1, _H2, _Hash, _Traits>; + + using __hash_code_base = typename __hashtable_base::__hash_code_base; + using __hash_code = typename __hashtable_base::__hash_code; + using __node_type = typename __hashtable_base::__node_type; + using __node_base = typename __hashtable_base::__node_base; + using __bucket_type = typename __hashtable_base::__bucket_type; + using __ireturn_type = typename __hashtable_base::__ireturn_type; + using __iconv_type = typename __hashtable_base::__iconv_type; + + using __map_base = __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, + _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits>; + + using __rehash_base = __detail::_Rehash_base<_Key, _Value, _Alloc, + _ExtractKey, _Equal, + _H1, _H2, _Hash, + _RehashPolicy, _Traits>; + + using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, + _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits>; + + // Metaprogramming for picking apart hash caching. + using __hash_noexcept = __detail::__is_noexcept_hash<_Key, _H1>; + template<typename _Cond> - using __if_hash_code_cached - = __or_<__not_<integral_constant<bool, __cache_hash_code>>, _Cond>; + using __if_hash_cached = __or_<__not_<__hash_cached>, _Cond>; template<typename _Cond> - using __if_hash_code_not_cached - = __or_<integral_constant<bool, __cache_hash_code>, _Cond>; - - // When hash codes are not cached the hash functor shall not throw - // because it is used in methods (erase, swap...) that shall not throw. - static_assert(__if_hash_code_not_cached<__detail::__is_noexcept_hash<_Key, - _H1>>::value, - "Cache the hash code or qualify your hash functor with noexcept"); - - // Following two static assertions are necessary to guarantee that - // swapping two hashtable instances won't invalidate associated local - // iterators. - - // When hash codes are cached local iterator only uses H2 which must then - // be empty. - static_assert(__if_hash_code_cached<is_empty<_H2>>::value, - "Functor used to map hash code to bucket index must be empty"); - - typedef __detail::_Hash_code_base<_Key, _Value, _ExtractKey, - _H1, _H2, _Hash, - __cache_hash_code> _HCBase; - - // When hash codes are not cached local iterator is going to use _HCBase - // above to compute node bucket index so it has to be empty. - static_assert(__if_hash_code_not_cached<is_empty<_HCBase>>::value, - "Cache the hash code or make functors involved in hash code" - " and bucket index computation empty"); + using __if_hash_not_cached = __or_<__hash_cached, _Cond>; + + // Compile-time diagnostics. + + // When hash codes are not cached the hash functor shall not + // throw because it is used in methods (erase, swap...) that + // shall not throw. + static_assert(__if_hash_not_cached<__hash_noexcept>::value, + "Cache the hash code" + " or qualify your hash functor with noexcept"); + + // Following two static assertions are necessary to guarantee + // that swapping two hashtable instances won't invalidate + // associated local iterators. + + // When hash codes are cached local iterator only uses H2 which + // must then be empty. + static_assert(__if_hash_cached<is_empty<_H2>>::value, + "Functor used to map hash code to bucket index" + " must be empty"); + + // When hash codes are not cached local iterator is going to use + // __hash_code_base above to compute node bucket index so it has + // to be empty. + static_assert(__if_hash_not_cached<is_empty<__hash_code_base>>::value, + "Cache the hash code or make functors involved in hash code" + " and bucket index computation empty"); public: - typedef _Allocator allocator_type; - typedef _Value value_type; - typedef _Key key_type; - typedef _Equal key_equal; - // mapped_type, if present, comes from _Map_base. - // hasher, if present, comes from _Hash_code_base. - typedef typename _Allocator::pointer pointer; - typedef typename _Allocator::const_pointer const_pointer; - typedef typename _Allocator::reference reference; - typedef typename _Allocator::const_reference const_reference; - - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - typedef __detail::_Local_iterator<key_type, value_type, _ExtractKey, - _H1, _H2, _Hash, - __constant_iterators, - __cache_hash_code> - local_iterator; - typedef __detail::_Local_const_iterator<key_type, value_type, _ExtractKey, - _H1, _H2, _Hash, - __constant_iterators, - __cache_hash_code> - const_local_iterator; - typedef __detail::_Node_iterator<value_type, __constant_iterators, - __cache_hash_code> - iterator; - typedef __detail::_Node_const_iterator<value_type, - __constant_iterators, - __cache_hash_code> - const_iterator; - - template<typename _Key2, typename _Value2, typename _Ex2, bool __unique2, - typename _Hashtable2> + template<typename _Keya, typename _Valuea, typename _Alloca, + typename _ExtractKeya, typename _Equala, + typename _H1a, typename _H2a, typename _Hasha, + typename _RehashPolicya, typename _Traitsa, + bool _Unique_keysa> friend struct __detail::_Map_base; + template<typename _Keya, typename _Valuea, typename _Alloca, + typename _ExtractKeya, typename _Equala, + typename _H1a, typename _H2a, typename _Hasha, + typename _RehashPolicya, typename _Traitsa> + friend struct __detail::_Insert_base; + + template<typename _Keya, typename _Valuea, typename _Alloca, + typename _ExtractKeya, typename _Equala, + typename _H1a, typename _H2a, typename _Hasha, + typename _RehashPolicya, typename _Traitsa, + bool _Constant_iteratorsa, bool _Unique_keysa> + friend struct __detail::_Insert; + + using size_type = typename __hashtable_base::size_type; + using difference_type = typename __hashtable_base::difference_type; + + using iterator = typename __hashtable_base::iterator; + using const_iterator = typename __hashtable_base::const_iterator; + + using local_iterator = typename __hashtable_base::local_iterator; + using const_local_iterator = typename __hashtable_base:: + const_local_iterator; + private: - typedef typename _RehashPolicy::_State _RehashPolicyState; - typedef __detail::_Hash_node<_Value, __cache_hash_code> _Node; - typedef typename _Allocator::template rebind<_Node>::other + typedef typename _Alloc::template rebind<__node_type>::other _Node_allocator_type; - typedef __detail::_Hash_node_base _BaseNode; - typedef _BaseNode* _Bucket; - typedef typename _Allocator::template rebind<_Bucket>::other + typedef typename _Alloc::template rebind<__bucket_type>::other _Bucket_allocator_type; - - typedef typename _Allocator::template rebind<_Value>::other + typedef typename _Alloc::template rebind<value_type>::other _Value_allocator_type; + _Node_allocator_type _M_node_allocator; - _Bucket* _M_buckets; + __bucket_type* _M_buckets; size_type _M_bucket_count; - _BaseNode _M_before_begin; + __node_base _M_before_begin; size_type _M_element_count; _RehashPolicy _M_rehash_policy; template<typename... _Args> - _Node* + __node_type* _M_allocate_node(_Args&&... __args); void - _M_deallocate_node(_Node* __n); + _M_deallocate_node(__node_type* __n); // Deallocate the linked list of nodes pointed to by __n void - _M_deallocate_nodes(_Node* __n); + _M_deallocate_nodes(__node_type* __n); - _Bucket* + __bucket_type* _M_allocate_buckets(size_type __n); void - _M_deallocate_buckets(_Bucket*, size_type __n); + _M_deallocate_buckets(__bucket_type*, size_type __n); // Gets bucket begin, deals with the fact that non-empty buckets contain // their before begin node. - _Node* + __node_type* _M_bucket_begin(size_type __bkt) const; - _Node* + __node_type* _M_begin() const - { return static_cast<_Node*>(_M_before_begin._M_nxt); } + { return static_cast<__node_type*>(_M_before_begin._M_nxt); } public: // Constructor, destructor, assignment, swap @@ -305,6 +357,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Hashtable(_Hashtable&&); + // Use delegating construtors. + explicit + _Hashtable(size_type __n = 10, + const _H1& __hf = _H1(), + const key_equal& __eql = key_equal(), + const allocator_type& __a = allocator_type()) + : _Hashtable(__n, __hf, __detail::_Mod_range_hashing(), + __detail::_Default_ranged_hash(), __eql, + __key_extract(), __a) + { } + + template<typename _InputIterator> + _Hashtable(_InputIterator __f, _InputIterator __l, + size_type __n = 0, + const _H1& __hf = _H1(), + const key_equal& __eql = key_equal(), + const allocator_type& __a = allocator_type()) + : _Hashtable(__f, __l, __n, __hf, __detail::_Mod_range_hashing(), + __detail::_Default_ranged_hash(), __eql, + __key_extract(), __a) + { } + + _Hashtable(initializer_list<value_type> __l, + size_type __n = 0, + const _H1& __hf = _H1(), + const key_equal& __eql = key_equal(), + const allocator_type& __a = allocator_type()) + : _Hashtable(__l.begin(), __l.end(), __n, __hf, + __detail::_Mod_range_hashing(), + __detail::_Default_ranged_hash(), __eql, + __key_extract(), __a) + { } + _Hashtable& operator=(const _Hashtable& __ht) { @@ -323,6 +408,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } + _Hashtable& + operator=(initializer_list<value_type> __l) + { + this->clear(); + this->insert(__l.begin(), __l.end()); + return *this; + } + ~_Hashtable() noexcept; void swap(_Hashtable&); @@ -394,8 +487,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION local_iterator begin(size_type __n) - { return local_iterator(_M_bucket_begin(__n), __n, - _M_bucket_count); } + { return local_iterator(_M_bucket_begin(__n), __n, _M_bucket_count); } local_iterator end(size_type __n) @@ -428,8 +520,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // max_load_factor, if present, comes from _Rehash_base. - // Generalization of max_load_factor. Extension, not found in TR1. Only - // useful if _RehashPolicy is something other than the default. + // Generalization of max_load_factor. Extension, not found in + // TR1. Only useful if _RehashPolicy is something other than + // the default. const _RehashPolicy& __rehash_policy() const { return _M_rehash_policy; } @@ -453,63 +546,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::pair<const_iterator, const_iterator> equal_range(const key_type& __k) const; - private: + protected: // Bucket index computation helpers. size_type - _M_bucket_index(_Node* __n) const - { return _HCBase::_M_bucket_index(__n, _M_bucket_count); } + _M_bucket_index(__node_type* __n) const + { return __hash_code_base::_M_bucket_index(__n, _M_bucket_count); } size_type - _M_bucket_index(const key_type& __k, - typename _Hashtable::_Hash_code_type __c) const - { return _HCBase::_M_bucket_index(__k, __c, _M_bucket_count); } + _M_bucket_index(const key_type& __k, __hash_code __c) const + { return __hash_code_base::_M_bucket_index(__k, __c, _M_bucket_count); } // Find and insert helper functions and types // Find the node before the one matching the criteria. - _BaseNode* - _M_find_before_node(size_type, const key_type&, - typename _Hashtable::_Hash_code_type) const; + __node_base* + _M_find_before_node(size_type, const key_type&, __hash_code) const; - _Node* + __node_type* _M_find_node(size_type __bkt, const key_type& __key, - typename _Hashtable::_Hash_code_type __c) const + __hash_code __c) const { - _BaseNode* __before_n = _M_find_before_node(__bkt, __key, __c); + __node_base* __before_n = _M_find_before_node(__bkt, __key, __c); if (__before_n) - return static_cast<_Node*>(__before_n->_M_nxt); + return static_cast<__node_type*>(__before_n->_M_nxt); return nullptr; } // Insert a node at the beginning of a bucket. void - _M_insert_bucket_begin(size_type, _Node*); + _M_insert_bucket_begin(size_type, __node_type*); // Remove the bucket first node void - _M_remove_bucket_begin(size_type __bkt, _Node* __next_n, + _M_remove_bucket_begin(size_type __bkt, __node_type* __next_n, size_type __next_bkt); // Get the node before __n in the bucket __bkt - _BaseNode* - _M_get_previous_node(size_type __bkt, _BaseNode* __n); + __node_base* + _M_get_previous_node(size_type __bkt, __node_base* __n); template<typename _Arg> iterator - _M_insert_bucket(_Arg&&, size_type, - typename _Hashtable::_Hash_code_type); + _M_insert_bucket(_Arg&&, size_type, __hash_code); - typedef typename std::conditional<__unique_keys, - std::pair<iterator, bool>, - iterator>::type - _Insert_Return_Type; - typedef typename std::conditional<__unique_keys, - std::_Select1st<_Insert_Return_Type>, - std::_Identity<_Insert_Return_Type> - >::type - _Insert_Conv_Type; - - protected: template<typename... _Args> std::pair<iterator, bool> _M_emplace(std::true_type, _Args&&... __args); @@ -527,51 +606,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_insert(_Arg&&, std::false_type); public: - // Emplace, insert and erase + // Emplace template<typename... _Args> - _Insert_Return_Type + __ireturn_type emplace(_Args&&... __args) - { return _M_emplace(integral_constant<bool, __unique_keys>(), - std::forward<_Args>(__args)...); } + { return _M_emplace(__unique_keys(), std::forward<_Args>(__args)...); } template<typename... _Args> iterator emplace_hint(const_iterator, _Args&&... __args) - { return _Insert_Conv_Type()(emplace(std::forward<_Args>(__args)...)); } + { return __iconv_type()(emplace(std::forward<_Args>(__args)...)); } - _Insert_Return_Type - insert(const value_type& __v) - { return _M_insert(__v, integral_constant<bool, __unique_keys>()); } - - iterator - insert(const_iterator, const value_type& __v) - { return _Insert_Conv_Type()(insert(__v)); } - - template<typename _Pair, typename = typename - std::enable_if<__and_<integral_constant<bool, !__constant_iterators>, - std::is_convertible<_Pair, - value_type>>::value>::type> - _Insert_Return_Type - insert(_Pair&& __v) - { return _M_insert(std::forward<_Pair>(__v), - integral_constant<bool, __unique_keys>()); } - - template<typename _Pair, typename = typename - std::enable_if<__and_<integral_constant<bool, !__constant_iterators>, - std::is_convertible<_Pair, - value_type>>::value>::type> - iterator - insert(const_iterator, _Pair&& __v) - { return _Insert_Conv_Type()(insert(std::forward<_Pair>(__v))); } - - template<typename _InputIterator> - void - insert(_InputIterator __first, _InputIterator __last); - - void - insert(initializer_list<value_type> __l) - { this->insert(__l.begin(), __l.end()); } + // Insert member functions via inheritance. + // Erase iterator erase(const_iterator); @@ -602,26 +650,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Helper rehash method used when keys can be non-unique. void _M_rehash_aux(size_type __n, std::false_type); - // Unconditionally change size of bucket array to n, restore hash policy - // state to __state on exception. - void _M_rehash(size_type __n, const _RehashPolicyState& __state); + // Unconditionally change size of bucket array to n, restore + // hash policy state to __state on exception. + void _M_rehash(size_type __n, const __rehash_state& __state); }; // Definitions of class template _Hashtable's out-of-line member functions. template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> template<typename... _Args> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::_Node* - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type* + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_allocate_node(_Args&&... __args) { - _Node* __n = _M_node_allocator.allocate(1); + __node_type* __n = _M_node_allocator.allocate(1); __try { _M_node_allocator.construct(__n, std::forward<_Args>(__args)...); @@ -635,125 +682,122 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: - _M_deallocate_node(_Node* __n) + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: + _M_deallocate_node(__node_type* __n) { _M_node_allocator.destroy(__n); _M_node_allocator.deallocate(__n, 1); } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: - _M_deallocate_nodes(_Node* __n) + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: + _M_deallocate_nodes(__node_type* __n) { while (__n) { - _Node* __tmp = __n; + __node_type* __tmp = __n; __n = __n->_M_next(); _M_deallocate_node(__tmp); } } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::_Bucket* - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>::__bucket_type* + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_allocate_buckets(size_type __n) { _Bucket_allocator_type __alloc(_M_node_allocator); - _Bucket* __p = __alloc.allocate(__n); - __builtin_memset(__p, 0, __n * sizeof(_Bucket)); + __bucket_type* __p = __alloc.allocate(__n); + __builtin_memset(__p, 0, __n * sizeof(__bucket_type)); return __p; } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: - _M_deallocate_buckets(_Bucket* __p, size_type __n) + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: + _M_deallocate_buckets(__bucket_type* __p, size_type __n) { _Bucket_allocator_type __alloc(_M_node_allocator); __alloc.deallocate(__p, __n); } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::_Node* - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::__node_type* + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_bucket_begin(size_type __bkt) const { - _BaseNode* __n = _M_buckets[__bkt]; - return __n ? static_cast<_Node*>(__n->_M_nxt) : nullptr; + __node_base* __n = _M_buckets[__bkt]; + return __n ? static_cast<__node_type*>(__n->_M_nxt) : nullptr; } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + typename _Traits> + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _Hashtable(size_type __bucket_hint, const _H1& __h1, const _H2& __h2, const _Hash& __h, const _Equal& __eq, const _ExtractKey& __exk, const allocator_type& __a) - : __detail::_Rehash_base<_RehashPolicy, _Hashtable>(), - __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, - _H1, _H2, _Hash, __chc>(__exk, __h1, __h2, __h, - __eq), - __detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(), + : __hashtable_base(__exk, __h1, __h2, __h, __eq), + __map_base(), + __rehash_base(), _M_node_allocator(__a), _M_bucket_count(0), _M_element_count(0), _M_rehash_policy() { _M_bucket_count = _M_rehash_policy._M_next_bkt(__bucket_hint); - // We don't want the rehash policy to ask for the hashtable to shrink - // on the first insertion so we need to reset its previous resize level. + + // We don't want the rehash policy to ask for the hashtable to + // shrink on the first insertion so we need to reset its + // previous resize level. _M_rehash_policy._M_prev_resize = 0; _M_buckets = _M_allocate_buckets(_M_bucket_count); } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> template<typename _InputIterator> - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _Hashtable(_InputIterator __f, _InputIterator __l, size_type __bucket_hint, const _H1& __h1, const _H2& __h2, const _Hash& __h, const _Equal& __eq, const _ExtractKey& __exk, const allocator_type& __a) - : __detail::_Rehash_base<_RehashPolicy, _Hashtable>(), - __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, - _H1, _H2, _Hash, __chc>(__exk, __h1, __h2, __h, - __eq), - __detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(), + : __hashtable_base(__exk, __h1, __h2, __h, __eq), + __map_base(), + __rehash_base(), _M_node_allocator(__a), _M_bucket_count(0), _M_element_count(0), @@ -764,9 +808,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_bkt_for_elements(__detail:: __distance_fw(__f, __l))); - // We don't want the rehash policy to ask for the hashtable to shrink - // on the first insertion so we need to reset its previous resize - // level. + + // We don't want the rehash policy to ask for the hashtable to + // shrink on the first insertion so we need to reset its + // previous resize level. _M_rehash_policy._M_prev_resize = 0; _M_buckets = _M_allocate_buckets(_M_bucket_count); __try @@ -783,16 +828,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + typename _Traits> + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _Hashtable(const _Hashtable& __ht) - : __detail::_Rehash_base<_RehashPolicy, _Hashtable>(__ht), - __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, - _H1, _H2, _Hash, __chc>(__ht), - __detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(__ht), + : __hashtable_base(__ht), + __map_base(__ht), + __rehash_base(__ht), _M_node_allocator(__ht._M_node_allocator), _M_bucket_count(__ht._M_bucket_count), _M_element_count(__ht._M_element_count), @@ -806,14 +850,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // First deal with the special first node pointed to by // _M_before_begin. - const _Node* __ht_n = __ht._M_begin(); - _Node* __this_n = _M_allocate_node(__ht_n->_M_v); + const __node_type* __ht_n = __ht._M_begin(); + __node_type* __this_n = _M_allocate_node(__ht_n->_M_v); this->_M_copy_code(__this_n, __ht_n); _M_before_begin._M_nxt = __this_n; _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin; // Then deal with other nodes. - _BaseNode* __prev_n = __this_n; + __node_base* __prev_n = __this_n; for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next()) { __this_n = _M_allocate_node(__ht_n->_M_v); @@ -834,16 +878,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + typename _Traits> + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _Hashtable(_Hashtable&& __ht) - : __detail::_Rehash_base<_RehashPolicy, _Hashtable>(__ht), - __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, - _H1, _H2, _Hash, __chc>(__ht), - __detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(__ht), + : __hashtable_base(__ht), + __map_base(__ht), + __rehash_base(__ht), _M_node_allocator(std::move(__ht._M_node_allocator)), _M_buckets(__ht._M_buckets), _M_bucket_count(__ht._M_bucket_count), @@ -862,11 +905,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + typename _Traits> + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: ~_Hashtable() noexcept { clear(); @@ -874,17 +917,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: swap(_Hashtable& __x) { - // The only base class with member variables is hash_code_base. We - // define _Hash_code_base::_M_swap because different specializations - // have different members. + // The only base class with member variables is hash_code_base. + // We define _Hash_code_base::_M_swap because different + // specializations have different members. this->_M_swap(__x); // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -897,8 +940,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::swap(_M_bucket_count, __x._M_bucket_count); std::swap(_M_before_begin._M_nxt, __x._M_before_begin._M_nxt); std::swap(_M_element_count, __x._M_element_count); - // Fix buckets containing the _M_before_begin pointers that can't be - // swapped. + + // Fix buckets containing the _M_before_begin pointers that + // can't be swapped. if (_M_begin()) _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; if (__x._M_begin()) @@ -907,12 +951,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: __rehash_policy(const _RehashPolicy& __pol) { size_type __n_bkt = __pol._M_bkt_for_elements(_M_element_count); @@ -922,53 +966,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::iterator + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: find(const key_type& __k) { - typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k); + __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); - _Node* __p = _M_find_node(__n, __k, __code); + __node_type* __p = _M_find_node(__n, __k, __code); return __p ? iterator(__p) : this->end(); } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::const_iterator - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::const_iterator + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: find(const key_type& __k) const { - typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k); + __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); - _Node* __p = _M_find_node(__n, __k, __code); + __node_type* __p = _M_find_node(__n, __k, __code); return __p ? const_iterator(__p) : this->end(); } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::size_type - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::size_type + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: count(const key_type& __k) const { - typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k); + __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); - _Node* __p = _M_bucket_begin(__n); + __node_type* __p = _M_bucket_begin(__n); if (!__p) return 0; @@ -978,9 +1022,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (this->_M_equals(__k, __code, __p)) ++__result; else if (__result) - // All equivalent values are next to each other, if we found a not - // equivalent value after an equivalent one it means that we won't - // find anymore an equivalent value. + // All equivalent values are next to each other, if we + // found a not equivalent value after an equivalent one it + // means that we won't find anymore an equivalent value. break; if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) break; @@ -989,28 +1033,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - std::pair<typename _Hashtable<_Key, _Value, _Allocator, + typename _Traits> + std::pair<typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator, - typename _Hashtable<_Key, _Value, _Allocator, + _Traits>::iterator, + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator> - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::iterator> + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: equal_range(const key_type& __k) { - typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k); + __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); - _Node* __p = _M_find_node(__n, __k, __code); + __node_type* __p = _M_find_node(__n, __k, __code); if (__p) { - _Node* __p1 = __p->_M_next(); + __node_type* __p1 = __p->_M_next(); while (__p1 && _M_bucket_index(__p1) == __n && this->_M_equals(__k, __code, __p1)) __p1 = __p1->_M_next(); @@ -1022,28 +1066,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - std::pair<typename _Hashtable<_Key, _Value, _Allocator, + typename _Traits> + std::pair<typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::const_iterator, - typename _Hashtable<_Key, _Value, _Allocator, + _Traits>::const_iterator, + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::const_iterator> - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::const_iterator> + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: equal_range(const key_type& __k) const { - typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k); + __hash_code __code = this->_M_hash_code(__k); std::size_t __n = _M_bucket_index(__k, __code); - _Node* __p = _M_find_node(__n, __k, __code); + __node_type* __p = _M_find_node(__n, __k, __code); if (__p) { - _Node* __p1 = __p->_M_next(); + __node_type* __p1 = __p->_M_next(); while (__p1 && _M_bucket_index(__p1) == __n && this->_M_equals(__k, __code, __p1)) __p1 = __p1->_M_next(); @@ -1054,24 +1098,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return std::make_pair(this->end(), this->end()); } - // Find the node whose key compares equal to k in the bucket n. Return nullptr - // if no node is found. + // Find the node whose key compares equal to k in the bucket n. + // Return nullptr if no node is found. template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::_BaseNode* - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::__node_base* + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_find_before_node(size_type __n, const key_type& __k, - typename _Hashtable::_Hash_code_type __code) const + __hash_code __code) const { - _BaseNode* __prev_p = _M_buckets[__n]; + __node_base* __prev_p = _M_buckets[__n]; if (!__prev_p) return nullptr; - _Node* __p = static_cast<_Node*>(__prev_p->_M_nxt); + __node_type* __p = static_cast<__node_type*>(__prev_p->_M_nxt); for (;; __p = __p->_M_next()) { if (this->_M_equals(__k, __code, __p)) @@ -1084,44 +1128,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: - _M_insert_bucket_begin(size_type __bkt, _Node* __new_node) + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: + _M_insert_bucket_begin(size_type __bkt, __node_type* __node) { if (_M_buckets[__bkt]) { - // Bucket is not empty, we just need to insert the new node after the - // bucket before begin. - __new_node->_M_nxt = _M_buckets[__bkt]->_M_nxt; - _M_buckets[__bkt]->_M_nxt = __new_node; + // Bucket is not empty, we just need to insert the new node + // after the bucket before begin. + __node->_M_nxt = _M_buckets[__bkt]->_M_nxt; + _M_buckets[__bkt]->_M_nxt = __node; } else { - // The bucket is empty, the new node is inserted at the beginning of - // the singly linked list and the bucket will contain _M_before_begin - // pointer. - __new_node->_M_nxt = _M_before_begin._M_nxt; - _M_before_begin._M_nxt = __new_node; - if (__new_node->_M_nxt) + // The bucket is empty, the new node is inserted at the + // beginning of the singly linked list and the bucket will + // contain _M_before_begin pointer. + __node->_M_nxt = _M_before_begin._M_nxt; + _M_before_begin._M_nxt = __node; + if (__node->_M_nxt) // We must update former begin bucket that is pointing to // _M_before_begin. - _M_buckets[_M_bucket_index(__new_node->_M_next())] = __new_node; + _M_buckets[_M_bucket_index(__node->_M_next())] = __node; _M_buckets[__bkt] = &_M_before_begin; } } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: - _M_remove_bucket_begin(size_type __bkt, _Node* __next, size_type __next_bkt) + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: + _M_remove_bucket_begin(size_type __bkt, __node_type* __next, + size_type __next_bkt) { if (!__next || __next_bkt != __bkt) { @@ -1129,6 +1174,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // First update next bucket if any if (__next) _M_buckets[__next_bkt] = _M_buckets[__bkt]; + // Second update before begin node if necessary if (&_M_before_begin == _M_buckets[__bkt]) _M_before_begin._M_nxt = __next; @@ -1137,54 +1183,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::_BaseNode* - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: - _M_get_previous_node(size_type __bkt, _BaseNode* __n) + _Traits>::__node_base* + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: + _M_get_previous_node(size_type __bkt, __node_base* __n) { - _BaseNode* __prev_n = _M_buckets[__bkt]; + __node_base* __prev_n = _M_buckets[__bkt]; while (__prev_n->_M_nxt != __n) __prev_n = __prev_n->_M_nxt; return __prev_n; } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> template<typename... _Args> - std::pair<typename _Hashtable<_Key, _Value, _Allocator, + std::pair<typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator, bool> - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::iterator, bool> + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_emplace(std::true_type, _Args&&... __args) { // First build the node to get access to the hash code - _Node* __new_node = _M_allocate_node(std::forward<_Args>(__args)...); + __node_type* __node = _M_allocate_node(std::forward<_Args>(__args)...); __try { - const key_type& __k = this->_M_extract()(__new_node->_M_v); - typename _Hashtable::_Hash_code_type __code - = this->_M_hash_code(__k); + const key_type& __k = this->_M_extract()(__node->_M_v); + __hash_code __code = this->_M_hash_code(__k); size_type __bkt = _M_bucket_index(__k, __code); - if (_Node* __p = _M_find_node(__bkt, __k, __code)) + if (__node_type* __p = _M_find_node(__bkt, __k, __code)) { // There is already an equivalent node, no insertion - _M_deallocate_node(__new_node); + _M_deallocate_node(__node); return std::make_pair(iterator(__p), false); } // We are going to insert this node - this->_M_store_code(__new_node, __code); - const _RehashPolicyState& __saved_state + this->_M_store_code(__node, __code); + const __rehash_state& __saved_state = _M_rehash_policy._M_state(); std::pair<bool, std::size_t> __do_rehash = _M_rehash_policy._M_need_rehash(_M_bucket_count, @@ -1196,42 +1241,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __bkt = _M_bucket_index(__k, __code); } - _M_insert_bucket_begin(__bkt, __new_node); + _M_insert_bucket_begin(__bkt, __node); ++_M_element_count; - return std::make_pair(iterator(__new_node), true); + return std::make_pair(iterator(__node), true); } __catch(...) { - _M_deallocate_node(__new_node); + _M_deallocate_node(__node); __throw_exception_again; } } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> template<typename... _Args> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::iterator + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_emplace(std::false_type, _Args&&... __args) { - const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state(); + const __rehash_state& __saved_state = _M_rehash_policy._M_state(); std::pair<bool, std::size_t> __do_rehash = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1); // First build the node to get its hash code. - _Node* __new_node = _M_allocate_node(std::forward<_Args>(__args)...); + __node_type* __node = _M_allocate_node(std::forward<_Args>(__args)...); __try { - const key_type& __k = this->_M_extract()(__new_node->_M_v); - typename _Hashtable::_Hash_code_type __code - = this->_M_hash_code(__k); - this->_M_store_code(__new_node, __code); + const key_type& __k = this->_M_extract()(__node->_M_v); + __hash_code __code = this->_M_hash_code(__k); + this->_M_store_code(__node, __code); // Second, do rehash if necessary. if (__do_rehash.first) @@ -1239,44 +1283,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Third, find the node before an equivalent one. size_type __bkt = _M_bucket_index(__k, __code); - _BaseNode* __prev = _M_find_before_node(__bkt, __k, __code); - + __node_base* __prev = _M_find_before_node(__bkt, __k, __code); + if (__prev) { // Insert after the node before the equivalent one. - __new_node->_M_nxt = __prev->_M_nxt; - __prev->_M_nxt = __new_node; + __node->_M_nxt = __prev->_M_nxt; + __prev->_M_nxt = __node; } else - // The inserted node has no equivalent in the hashtable. We must - // insert the new node at the beginning of the bucket to preserve - // equivalent elements relative positions. - _M_insert_bucket_begin(__bkt, __new_node); + // The inserted node has no equivalent in the + // hashtable. We must insert the new node at the + // beginning of the bucket to preserve equivalent + // elements relative positions. + _M_insert_bucket_begin(__bkt, __node); ++_M_element_count; - return iterator(__new_node); + return iterator(__node); } __catch(...) { - _M_deallocate_node(__new_node); + _M_deallocate_node(__node); __throw_exception_again; } } // Insert v in bucket n (assumes no element with its key already present). template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> template<typename _Arg> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: - _M_insert_bucket(_Arg&& __v, size_type __n, - typename _Hashtable::_Hash_code_type __code) + _Traits>::iterator + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: + _M_insert_bucket(_Arg&& __v, size_type __n, __hash_code __code) { - const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state(); + const __rehash_state& __saved_state = _M_rehash_policy._M_state(); std::pair<bool, std::size_t> __do_rehash = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1); @@ -1284,52 +1328,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__do_rehash.first) { const key_type& __k = this->_M_extract()(__v); - __n = _HCBase::_M_bucket_index(__k, __code, __do_rehash.second); + __n = __hash_code_base::_M_bucket_index(__k, __code, + __do_rehash.second); } - _Node* __new_node = nullptr; + __node_type* __node = nullptr; __try { // Allocate the new node before doing the rehash so that we // don't do a rehash if the allocation throws. - __new_node = _M_allocate_node(std::forward<_Arg>(__v)); - this->_M_store_code(__new_node, __code); + __node = _M_allocate_node(std::forward<_Arg>(__v)); + this->_M_store_code(__node, __code); if (__do_rehash.first) _M_rehash(__do_rehash.second, __saved_state); - _M_insert_bucket_begin(__n, __new_node); + _M_insert_bucket_begin(__n, __node); ++_M_element_count; - return iterator(__new_node); + return iterator(__node); } __catch(...) { - if (!__new_node) + if (!__node) _M_rehash_policy._M_reset(__saved_state); else - _M_deallocate_node(__new_node); + _M_deallocate_node(__node); __throw_exception_again; } } // Insert v if no element with its key is already present. template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> template<typename _Arg> - std::pair<typename _Hashtable<_Key, _Value, _Allocator, + std::pair<typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator, bool> - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::iterator, bool> + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_insert(_Arg&& __v, std::true_type) { const key_type& __k = this->_M_extract()(__v); - typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k); + __hash_code __code = this->_M_hash_code(__k); size_type __n = _M_bucket_index(__k, __code); - if (_Node* __p = _M_find_node(__n, __k, __code)) + if (__node_type* __p = _M_find_node(__n, __k, __code)) return std::make_pair(iterator(__p), false); return std::make_pair(_M_insert_bucket(std::forward<_Arg>(__v), __n, __code), true); @@ -1337,103 +1382,84 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Insert v unconditionally. template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> template<typename _Arg> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::iterator + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_insert(_Arg&& __v, std::false_type) { - const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state(); + const __rehash_state& __saved_state = _M_rehash_policy._M_state(); std::pair<bool, std::size_t> __do_rehash = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1); - // First compute the hash code so that we don't do anything if it throws. - typename _Hashtable::_Hash_code_type __code - = this->_M_hash_code(this->_M_extract()(__v)); + // First compute the hash code so that we don't do anything if + // it throws. + __hash_code __code = this->_M_hash_code(this->_M_extract()(__v)); - _Node* __new_node = nullptr; + __node_type* __node = nullptr; __try { // Second allocate new node so that we don't rehash if it throws. - __new_node = _M_allocate_node(std::forward<_Arg>(__v)); - this->_M_store_code(__new_node, __code); + __node = _M_allocate_node(std::forward<_Arg>(__v)); + this->_M_store_code(__node, __code); if (__do_rehash.first) _M_rehash(__do_rehash.second, __saved_state); // Third, find the node before an equivalent one. - size_type __bkt = _M_bucket_index(__new_node); - _BaseNode* __prev - = _M_find_before_node(__bkt, this->_M_extract()(__new_node->_M_v), + size_type __bkt = _M_bucket_index(__node); + __node_base* __prev + = _M_find_before_node(__bkt, this->_M_extract()(__node->_M_v), __code); if (__prev) { // Insert after the node before the equivalent one. - __new_node->_M_nxt = __prev->_M_nxt; - __prev->_M_nxt = __new_node; + __node->_M_nxt = __prev->_M_nxt; + __prev->_M_nxt = __node; } else - // The inserted node has no equivalent in the hashtable. We must - // insert the new node at the beginning of the bucket to preserve - // equivalent elements relative positions. - _M_insert_bucket_begin(__bkt, __new_node); + // The inserted node has no equivalent in the + // hashtable. We must insert the new node at the + // beginning of the bucket to preserve equivalent + // elements relative positions. + _M_insert_bucket_begin(__bkt, __node); ++_M_element_count; - return iterator(__new_node); + return iterator(__node); } __catch(...) { - if (!__new_node) + if (!__node) _M_rehash_policy._M_reset(__saved_state); else - _M_deallocate_node(__new_node); + _M_deallocate_node(__node); __throw_exception_again; } } - template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, - typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - template<typename _InputIterator> - void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: - insert(_InputIterator __first, _InputIterator __last) - { - size_type __n_elt = __detail::__distance_fw(__first, __last); - const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state(); - std::pair<bool, std::size_t> __do_rehash - = _M_rehash_policy._M_need_rehash(_M_bucket_count, - _M_element_count, __n_elt); - if (__do_rehash.first) - _M_rehash(__do_rehash.second, __saved_state); - - for (; __first != __last; ++__first) - this->insert(*__first); - } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::iterator + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: erase(const_iterator __it) { - _Node* __n = __it._M_cur; + __node_type* __n = __it._M_cur; std::size_t __bkt = _M_bucket_index(__n); - // Look for previous node to unlink it from the erased one, this is why - // we need buckets to contain the before begin to make this research fast. - _BaseNode* __prev_n = _M_get_previous_node(__bkt, __n); + // Look for previous node to unlink it from the erased one, this + // is why we need buckets to contain the before begin to make + // this research fast. + __node_base* __prev_n = _M_get_previous_node(__bkt, __n); if (__n == _M_bucket_begin(__bkt)) _M_remove_bucket_begin(__bkt, __n->_M_next(), __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0); @@ -1453,34 +1479,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::size_type - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::size_type + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: erase(const key_type& __k) { - typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k); + __hash_code __code = this->_M_hash_code(__k); std::size_t __bkt = _M_bucket_index(__k, __code); + // Look for the node before the first matching node. - _BaseNode* __prev_n = _M_find_before_node(__bkt, __k, __code); + __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code); if (!__prev_n) return 0; - _Node* __n = static_cast<_Node*>(__prev_n->_M_nxt); + __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt); bool __is_bucket_begin = _M_buckets[__bkt] == __prev_n; // We found a matching node, start deallocation loop from it std::size_t __next_bkt = __bkt; - _Node* __next_n = __n; + __node_type* __next_n = __n; size_type __result = 0; - _Node* __saved_n = nullptr; + __node_type* __saved_n = nullptr; do { - _Node* __p = __next_n; + __node_type* __p = __next_n; __next_n = __p->_M_next(); + // _GLIBCXX_RESOLVE_LIB_DEFECTS // 526. Is it undefined if a function in the standard changes // in parameters? @@ -1509,31 +1537,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> - typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, + typename _Traits> + typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, - __chc, __cit, __uk>::iterator - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Traits>::iterator + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: erase(const_iterator __first, const_iterator __last) { - _Node* __n = __first._M_cur; - _Node* __last_n = __last._M_cur; + __node_type* __n = __first._M_cur; + __node_type* __last_n = __last._M_cur; if (__n == __last_n) return iterator(__n); std::size_t __bkt = _M_bucket_index(__n); - _BaseNode* __prev_n = _M_get_previous_node(__bkt, __n); + __node_base* __prev_n = _M_get_previous_node(__bkt, __n); bool __is_bucket_begin = __n == _M_bucket_begin(__bkt); std::size_t __n_bkt = __bkt; for (;;) { do { - _Node* __tmp = __n; + __node_type* __tmp = __n; __n = __n->_M_next(); _M_deallocate_node(__tmp); --_M_element_count; @@ -1557,30 +1585,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: clear() noexcept { _M_deallocate_nodes(_M_begin()); - __builtin_memset(_M_buckets, 0, _M_bucket_count * sizeof(_Bucket)); + __builtin_memset(_M_buckets, 0, _M_bucket_count * sizeof(__bucket_type)); _M_element_count = 0; _M_before_begin._M_nxt = nullptr; } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: rehash(size_type __n) { - const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state(); + const __rehash_state& __saved_state = _M_rehash_policy._M_state(); _M_rehash(std::max(_M_rehash_policy._M_next_bkt(__n), _M_rehash_policy._M_bkt_for_elements(_M_element_count + 1)), @@ -1588,17 +1616,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: - _M_rehash(size_type __n, const _RehashPolicyState& __state) + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: + _M_rehash(size_type __n, const __rehash_state& __state) { __try { - _M_rehash_aux(__n, integral_constant<bool, __uk>()); + _M_rehash_aux(__n, __unique_keys()); } __catch(...) { @@ -1611,22 +1639,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Rehash when there is no equivalent elements. template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_rehash_aux(size_type __n, std::true_type) { - _Bucket* __new_buckets = _M_allocate_buckets(__n); - _Node* __p = _M_begin(); + __bucket_type* __new_buckets = _M_allocate_buckets(__n); + __node_type* __p = _M_begin(); _M_before_begin._M_nxt = nullptr; std::size_t __bbegin_bkt; while (__p) { - _Node* __next = __p->_M_next(); - std::size_t __bkt = _HCBase::_M_bucket_index(__p, __n); + __node_type* __next = __p->_M_next(); + std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); if (!__new_buckets[__bkt]) { __p->_M_nxt = _M_before_begin._M_nxt; @@ -1651,28 +1679,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Rehash when there can be equivalent elements, preserve their relative // order. template<typename _Key, typename _Value, - typename _Allocator, typename _ExtractKey, typename _Equal, + typename _Alloc, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, - bool __chc, bool __cit, bool __uk> + typename _Traits> void - _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, - _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>:: _M_rehash_aux(size_type __n, std::false_type) { - _Bucket* __new_buckets = _M_allocate_buckets(__n); + __bucket_type* __new_buckets = _M_allocate_buckets(__n); - _Node* __p = _M_begin(); + __node_type* __p = _M_begin(); _M_before_begin._M_nxt = nullptr; std::size_t __bbegin_bkt; std::size_t __prev_bkt; - _Node* __prev_p = nullptr; + __node_type* __prev_p = nullptr; bool __check_bucket = false; while (__p) { bool __check_now = true; - _Node* __next = __p->_M_next(); - std::size_t __bkt = _HCBase::_M_bucket_index(__p, __n); + __node_type* __next = __p->_M_next(); + std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); if (!__new_buckets[__bkt]) { @@ -1707,7 +1735,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __new_buckets[__bkt]->_M_nxt = __p; } } - + if (__check_now && __check_bucket) { // Check if we shall update the next bucket because of insertions @@ -1715,7 +1743,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__prev_p->_M_nxt) { std::size_t __next_bkt - = _HCBase::_M_bucket_index(__prev_p->_M_next(), __n); + = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), + __n); if (__next_bkt != __prev_bkt) __new_buckets[__next_bkt] = __prev_p; } @@ -1729,7 +1758,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__check_bucket && __prev_p->_M_nxt) { std::size_t __next_bkt - = _HCBase::_M_bucket_index(__prev_p->_M_next(), __n); + = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), __n); if (__next_bkt != __prev_bkt) __new_buckets[__next_bkt] = __prev_p; } diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h index b585d23a970..160a6ce1724 100644 --- a/libstdc++-v3/include/bits/hashtable_policy.h +++ b/libstdc++-v3/include/bits/hashtable_policy.h @@ -33,10 +33,26 @@ namespace std _GLIBCXX_VISIBILITY(default) { + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + class _Hashtable; + namespace __detail { _GLIBCXX_BEGIN_NAMESPACE_VERSION + /** + * @defgroup hashtable-detail Base and Implementation Classes + * @ingroup unordered_associative_containers + * @{ + */ + template<typename _Key, typename _Value, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, typename _Traits> + struct _Hashtable_base; + // Helper function: return distance(first, last) for forward // iterators, or 0 for input iterators. template<class _Iterator> @@ -64,28 +80,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Key, typename _Hash> struct __is_noexcept_hash : std::integral_constant<bool, noexcept(declval<const _Hash&>()(declval<const _Key&>()))> - {}; + { }; - // Auxiliary types used for all instantiations of _Hashtable: nodes + // Auxiliary types used for all instantiations of _Hashtable nodes // and iterators. - // Nodes, used to wrap elements stored in the hash table. A policy - // template parameter of class template _Hashtable controls whether - // nodes also store a hash code. In some cases (e.g. strings) this - // may be a performance win. + /** + * struct _Hashtable_traits + * + * Important traits for hash tables. + * + * @tparam __cache_hash_code Boolean value. True if the value of + * the hash function is stored along with the value. This is a + * time-space tradeoff. Storing it may improve lookup speed by + * reducing the number of times we need to call the _Equal + * function. + * + * @tparam __constant_iterators Boolean value. True if iterator and + * const_iterator are both constant iterator types. This is true + * for unordered_set and unordered_multiset, false for + * unordered_map and unordered_multimap. + * + * @tparam __unique_keys Boolean value. True if the return value + * of _Hashtable::count(k) is always at most one, false if it may + * be an arbitrary number. This true for unordered_set and + * unordered_map, false for unordered_multiset and + * unordered_multimap. + */ + template<bool _Cache_hash_code, bool _Constant_iterators, bool _Unique_keys> + struct _Hashtable_traits + { + template<bool _Cond> + using __bool_constant = integral_constant<bool, _Cond>; + + using __hash_cached = __bool_constant<_Cache_hash_code>; + using __constant_iterators = __bool_constant<_Constant_iterators>; + using __unique_keys = __bool_constant<_Unique_keys>; + }; + + /** + * struct _Hash_node_base + * + * Nodes, used to wrap elements stored in the hash table. A policy + * template parameter of class template _Hashtable controls whether + * nodes also store a hash code. In some cases (e.g. strings) this + * may be a performance win. + */ struct _Hash_node_base { _Hash_node_base* _M_nxt; - _Hash_node_base() - : _M_nxt() { } - _Hash_node_base(_Hash_node_base* __next) - : _M_nxt(__next) { } + _Hash_node_base() : _M_nxt() { } + + _Hash_node_base(_Hash_node_base* __next) : _M_nxt(__next) { } }; - template<typename _Value, bool __cache_hash_code> + /** + * Primary template struct _Hash_node. + */ + template<typename _Value, bool _Cache_hash_code> struct _Hash_node; + /// Specialization. template<typename _Value> struct _Hash_node<_Value, true> : _Hash_node_base { @@ -96,10 +152,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Hash_node(_Args&&... __args) : _M_v(std::forward<_Args>(__args)...), _M_hash_code() { } - _Hash_node* _M_next() const - { return static_cast<_Hash_node*>(_M_nxt); } + _Hash_node* + _M_next() const { return static_cast<_Hash_node*>(_M_nxt); } }; + /// Specialization. template<typename _Value> struct _Hash_node<_Value, false> : _Hash_node_base { @@ -109,56 +166,64 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Hash_node(_Args&&... __args) : _M_v(std::forward<_Args>(__args)...) { } - _Hash_node* _M_next() const - { return static_cast<_Hash_node*>(_M_nxt); } + _Hash_node* + _M_next() const { return static_cast<_Hash_node*>(_M_nxt); } }; - // Node iterators, used to iterate through all the hashtable. - template<typename _Value, bool __cache> + /// Base class for node iterators. + template<typename _Value, bool _Cache_hash_code> struct _Node_iterator_base { - _Node_iterator_base(_Hash_node<_Value, __cache>* __p) + typedef _Hash_node<_Value, _Cache_hash_code> __node_type; + + __node_type* _M_cur; + + _Node_iterator_base(__node_type* __p) : _M_cur(__p) { } void _M_incr() { _M_cur = _M_cur->_M_next(); } - - _Hash_node<_Value, __cache>* _M_cur; }; - template<typename _Value, bool __cache> + template<typename _Value, bool _Cache_hash_code> inline bool - operator==(const _Node_iterator_base<_Value, __cache>& __x, - const _Node_iterator_base<_Value, __cache>& __y) + operator==(const _Node_iterator_base<_Value, _Cache_hash_code>& __x, + const _Node_iterator_base<_Value, _Cache_hash_code >& __y) { return __x._M_cur == __y._M_cur; } - template<typename _Value, bool __cache> + template<typename _Value, bool _Cache_hash_code> inline bool - operator!=(const _Node_iterator_base<_Value, __cache>& __x, - const _Node_iterator_base<_Value, __cache>& __y) + operator!=(const _Node_iterator_base<_Value, _Cache_hash_code>& __x, + const _Node_iterator_base<_Value, _Cache_hash_code>& __y) { return __x._M_cur != __y._M_cur; } + /// Node iterators, used to iterate through all the hashtable. template<typename _Value, bool __constant_iterators, bool __cache> struct _Node_iterator : public _Node_iterator_base<_Value, __cache> { + private: + using __base_type = _Node_iterator_base<_Value, __cache>; + using __node_type = typename __base_type::__node_type; + + public: typedef _Value value_type; - typedef typename std::conditional<__constant_iterators, - const _Value*, _Value*>::type - pointer; - typedef typename std::conditional<__constant_iterators, - const _Value&, _Value&>::type - reference; typedef std::ptrdiff_t difference_type; typedef std::forward_iterator_tag iterator_category; + using pointer = typename std::conditional<__constant_iterators, + const _Value*, _Value*>::type; + + using reference = typename std::conditional<__constant_iterators, + const _Value&, _Value&>::type; + _Node_iterator() - : _Node_iterator_base<_Value, __cache>(0) { } + : __base_type(0) { } explicit - _Node_iterator(_Hash_node<_Value, __cache>* __p) - : _Node_iterator_base<_Value, __cache>(__p) { } + _Node_iterator(__node_type* __p) + : __base_type(__p) { } reference operator*() const @@ -184,26 +249,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + /// Node const_iterators, used to iterate through all the hashtable. template<typename _Value, bool __constant_iterators, bool __cache> struct _Node_const_iterator : public _Node_iterator_base<_Value, __cache> { + private: + using __base_type = _Node_iterator_base<_Value, __cache>; + using __node_type = typename __base_type::__node_type; + + public: typedef _Value value_type; - typedef const _Value* pointer; - typedef const _Value& reference; typedef std::ptrdiff_t difference_type; typedef std::forward_iterator_tag iterator_category; + typedef const _Value* pointer; + typedef const _Value& reference; + _Node_const_iterator() - : _Node_iterator_base<_Value, __cache>(0) { } + : __base_type(0) { } explicit - _Node_const_iterator(_Hash_node<_Value, __cache>* __p) - : _Node_iterator_base<_Value, __cache>(__p) { } + _Node_const_iterator(__node_type* __p) + : __base_type(__p) { } _Node_const_iterator(const _Node_iterator<_Value, __constant_iterators, __cache>& __x) - : _Node_iterator_base<_Value, __cache>(__x._M_cur) { } + : __base_type(__x._M_cur) { } reference operator*() const @@ -232,8 +304,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Many of class template _Hashtable's template parameters are policy // classes. These are defaults for the policies. - // Default range hashing function: use division to fold a large number - // into the range [0, N). + /// Default range hashing function: use division to fold a large number + /// into the range [0, N). struct _Mod_range_hashing { typedef std::size_t first_argument_type; @@ -245,15 +317,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __num % __den; } }; - // Default ranged hash function H. In principle it should be a - // function object composed from objects of type H1 and H2 such that - // h(k, N) = h2(h1(k), N), but that would mean making extra copies of - // h1 and h2. So instead we'll just use a tag to tell class template - // hashtable to do that composition. + /// Default ranged hash function H. In principle it should be a + /// function object composed from objects of type H1 and H2 such that + /// h(k, N) = h2(h1(k), N), but that would mean making extra copies of + /// h1 and h2. So instead we'll just use a tag to tell class template + /// hashtable to do that composition. struct _Default_ranged_hash { }; - // Default value for rehash policy. Bucket size is (usually) the - // smallest prime that keeps the load factor small enough. + /// Default value for rehash policy. Bucket size is (usually) the + /// smallest prime that keeps the load factor small enough. struct _Prime_rehash_policy { _Prime_rehash_policy(float __z = 1.0) @@ -385,77 +457,116 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } // Base classes for std::_Hashtable. We define these base classes - // because in some cases we want to do different things depending - // on the value of a policy class. In some cases the policy class + // because in some cases we want to do different things depending on + // the value of a policy class. In some cases the policy class // affects which member functions and nested typedefs are defined; // we handle that by specializing base class templates. Several of // the base class templates need to access other members of class - // template _Hashtable, so we use the "curiously recurring template - // pattern" for them. - - // class template _Map_base. If the hashtable has a value type of - // the form pair<T1, T2> and a key extraction policy that returns the - // first part of the pair, the hashtable gets a mapped_type typedef. - // If it satisfies those criteria and also has unique keys, then it - // also gets an operator[]. - template<typename _Key, typename _Value, typename _Ex, bool __unique, - typename _Hashtable> + // template _Hashtable, so we use a variant of the "Curiously + // Recurring Template Pattern" (CRTP) technique. + + /** + * Primary class template _Map_base. + * + * If the hashtable has a value type of the form pair<T1, T2> and a + * key extraction policy (_ExtractKey) that returns the first part + * of the pair, the hashtable gets a mapped_type typedef. If it + * satisfies those criteria and also has unique keys, then it also + * gets an operator[]. + */ + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits, + bool _Unique_keys = _Traits::__unique_keys::value> struct _Map_base { }; - template<typename _Key, typename _Pair, typename _Hashtable> - struct _Map_base<_Key, _Pair, std::_Select1st<_Pair>, false, _Hashtable> + /// Partial specialization, __unique_keys set to false. + template<typename _Key, typename _Pair, typename _Alloc, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + struct _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, false> { - typedef typename _Pair::second_type mapped_type; + using mapped_type = typename _Pair::second_type; }; - template<typename _Key, typename _Pair, typename _Hashtable> - struct _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable> + /// Partial specialization, __unique_keys set to true. + template<typename _Key, typename _Pair, typename _Alloc, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + struct _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true> { - typedef typename _Pair::second_type mapped_type; + private: + using __hashtable_base = __detail::_Hashtable_base<_Key, _Pair, + std::_Select1st<_Pair>, + _Equal, _H1, _H2, _Hash, + _Traits>; + + using __hashtable = _Hashtable<_Key, _Pair, _Alloc, + std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>; + + using __hash_code = typename __hashtable_base::__hash_code; + using __node_type = typename __hashtable_base::__node_type; + + public: + using key_type = typename __hashtable_base::key_type; + using iterator = typename __hashtable_base::iterator; + using mapped_type = typename _Pair::second_type; mapped_type& - operator[](const _Key& __k); + operator[](const key_type& __k); mapped_type& - operator[](_Key&& __k); + operator[](key_type&& __k); // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 761. unordered_map needs an at() member function. mapped_type& - at(const _Key& __k); + at(const key_type& __k); const mapped_type& - at(const _Key& __k) const; + at(const key_type& __k) const; }; - template<typename _Key, typename _Pair, typename _Hashtable> - typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>, - true, _Hashtable>::mapped_type& - _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>:: - operator[](const _Key& __k) + template<typename _Key, typename _Pair, typename _Alloc, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + typename _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true> + ::mapped_type& + _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true>:: + operator[](const key_type& __k) { - _Hashtable* __h = static_cast<_Hashtable*>(this); - typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k); + __hashtable* __h = static_cast<__hashtable*>(this); + __hash_code __code = __h->_M_hash_code(__k); std::size_t __n = __h->_M_bucket_index(__k, __code); + __node_type* __p = __h->_M_find_node(__n, __k, __code); - typename _Hashtable::_Node* __p = __h->_M_find_node(__n, __k, __code); if (!__p) return __h->_M_insert_bucket(std::make_pair(__k, mapped_type()), __n, __code)->second; return (__p->_M_v).second; } - template<typename _Key, typename _Pair, typename _Hashtable> - typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>, - true, _Hashtable>::mapped_type& - _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>:: - operator[](_Key&& __k) + template<typename _Key, typename _Pair, typename _Alloc, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + typename _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true> + ::mapped_type& + _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true>:: + operator[](key_type&& __k) { - _Hashtable* __h = static_cast<_Hashtable*>(this); - typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k); + __hashtable* __h = static_cast<__hashtable*>(this); + __hash_code __code = __h->_M_hash_code(__k); std::size_t __n = __h->_M_bucket_index(__k, __code); + __node_type* __p = __h->_M_find_node(__n, __k, __code); - typename _Hashtable::_Node* __p = __h->_M_find_node(__n, __k, __code); if (!__p) return __h->_M_insert_bucket(std::make_pair(std::move(__k), mapped_type()), @@ -463,79 +574,320 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return (__p->_M_v).second; } - template<typename _Key, typename _Pair, typename _Hashtable> - typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>, - true, _Hashtable>::mapped_type& - _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>:: - at(const _Key& __k) + template<typename _Key, typename _Pair, typename _Alloc, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + typename _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true> + ::mapped_type& + _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true>:: + at(const key_type& __k) { - _Hashtable* __h = static_cast<_Hashtable*>(this); - typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k); + __hashtable* __h = static_cast<__hashtable*>(this); + __hash_code __code = __h->_M_hash_code(__k); std::size_t __n = __h->_M_bucket_index(__k, __code); + __node_type* __p = __h->_M_find_node(__n, __k, __code); - typename _Hashtable::_Node* __p = __h->_M_find_node(__n, __k, __code); if (!__p) __throw_out_of_range(__N("_Map_base::at")); return (__p->_M_v).second; } - template<typename _Key, typename _Pair, typename _Hashtable> - const typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>, - true, _Hashtable>::mapped_type& - _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>:: - at(const _Key& __k) const + template<typename _Key, typename _Pair, typename _Alloc, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + const typename _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, + _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true> + ::mapped_type& + _Map_base<_Key, _Pair, _Alloc, std::_Select1st<_Pair>, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true>:: + at(const key_type& __k) const { - const _Hashtable* __h = static_cast<const _Hashtable*>(this); - typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k); + const __hashtable* __h = static_cast<const __hashtable*>(this); + __hash_code __code = __h->_M_hash_code(__k); std::size_t __n = __h->_M_bucket_index(__k, __code); + __node_type* __p = __h->_M_find_node(__n, __k, __code); - typename _Hashtable::_Node* __p = __h->_M_find_node(__n, __k, __code); if (!__p) __throw_out_of_range(__N("_Map_base::at")); return (__p->_M_v).second; } - // class template _Rehash_base. Give hashtable the max_load_factor - // functions and reserve iff the rehash policy is _Prime_rehash_policy. - template<typename _RehashPolicy, typename _Hashtable> - struct _Rehash_base { }; + /** + * Primary class template _Insert_base. + * + * insert member functions appropriate to all _Hashtables. + */ + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + struct _Insert_base + { + using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey, + _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits>; + + using __hashtable_base = _Hashtable_base<_Key, _Value, _ExtractKey, + _Equal, _H1, _H2, _Hash, + _Traits>; + + using value_type = typename __hashtable_base::value_type; + using iterator = typename __hashtable_base::iterator; + using const_iterator = typename __hashtable_base::const_iterator; + using size_type = typename __hashtable_base::size_type; + + using __unique_keys = typename __hashtable_base::__unique_keys; + using __ireturn_type = typename __hashtable_base::__ireturn_type; + using __iconv_type = typename __hashtable_base::__iconv_type; + + __hashtable& + _M_conjure_hashtable() + { return *(static_cast<__hashtable*>(this)); } + + __ireturn_type + insert(const value_type& __v) + { + __hashtable& __h = _M_conjure_hashtable(); + return __h._M_insert(__v, __unique_keys()); + } + + iterator + insert(const_iterator, const value_type& __v) + { return __iconv_type()(insert(__v)); } + + void + insert(initializer_list<value_type> __l) + { this->insert(__l.begin(), __l.end()); } + + template<typename _InputIterator> + void + insert(_InputIterator __first, _InputIterator __last); + }; + + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + template<typename _InputIterator> + void + _Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits>:: + insert(_InputIterator __first, _InputIterator __last) + { + using __rehash_type = typename __hashtable::__rehash_type; + using __rehash_state = typename __hashtable::__rehash_state; + using pair_type = std::pair<bool, std::size_t>; + + size_type __n_elt = __detail::__distance_fw(__first, __last); + + __hashtable& __h = _M_conjure_hashtable(); + __rehash_type& __rehash = __h._M_rehash_policy; + const __rehash_state& __saved_state = __rehash._M_state(); + pair_type __do_rehash = __rehash._M_need_rehash(__h._M_bucket_count, + __h._M_element_count, + __n_elt); + + if (__do_rehash.first) + __h._M_rehash(__do_rehash.second, __saved_state); + + for (; __first != __last; ++__first) + this->insert(*__first); + } + + /** + * Primary class template _Insert. + * + * Select insert member functions appropriate to _Hashtable policy choices. + */ + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits, + bool _Constant_iterators = _Traits::__constant_iterators::value, + bool _Unique_keys = _Traits::__unique_keys::value> + struct _Insert; + + /// Specialization. + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + struct _Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits, true, true> + : public _Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits> + { + using __base_type = _Insert_base<_Key, _Value, _Alloc, _ExtractKey, + _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits>; + using value_type = typename __base_type::value_type; + using iterator = typename __base_type::iterator; + using const_iterator = typename __base_type::const_iterator; + + using __unique_keys = typename __base_type::__unique_keys; + using __hashtable = typename __base_type::__hashtable; + + using __base_type::insert; - template<typename _Hashtable> - struct _Rehash_base<_Prime_rehash_policy, _Hashtable> + std::pair<iterator, bool> + insert(value_type&& __v) + { + __hashtable& __h = this->_M_conjure_hashtable(); + return __h._M_insert(std::move(__v), __unique_keys()); + } + + iterator + insert(const_iterator, value_type&& __v) + { return insert(std::move(__v)).first; } + }; + + /// Specialization. + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + struct _Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits, true, false> + : public _Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits> { + using __base_type = _Insert_base<_Key, _Value, _Alloc, _ExtractKey, + _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits>; + using value_type = typename __base_type::value_type; + using iterator = typename __base_type::iterator; + using const_iterator = typename __base_type::const_iterator; + + using __unique_keys = typename __base_type::__unique_keys; + using __hashtable = typename __base_type::__hashtable; + + using __base_type::insert; + + iterator + insert(value_type&& __v) + { + __hashtable& __h = this->_M_conjure_hashtable(); + return __h._M_insert(std::move(__v), __unique_keys()); + } + + iterator + insert(const_iterator, value_type&& __v) + { return insert(std::move(__v)); } + }; + + /// Specialization. + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits, bool _Unique_keys> + struct _Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits, false, _Unique_keys> + : public _Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits> + { + using __base_type = _Insert_base<_Key, _Value, _Alloc, _ExtractKey, + _Equal, _H1, _H2, _Hash, + _RehashPolicy, _Traits>; + using value_type = typename __base_type::value_type; + using iterator = typename __base_type::iterator; + using const_iterator = typename __base_type::const_iterator; + + using __unique_keys = typename __base_type::__unique_keys; + using __hashtable = typename __base_type::__hashtable; + using __ireturn_type = typename __base_type::__ireturn_type; + using __iconv_type = typename __base_type::__iconv_type; + + using __base_type::insert; + + template<typename _Pair> + using __is_convertible = std::is_convertible<_Pair, value_type>; + + template<typename _Pair> + using _IFconv = std::enable_if<__is_convertible<_Pair>::value>; + + template<typename _Pair> + using _IFconvp = typename _IFconv<_Pair>::type; + + template<typename _Pair, typename = _IFconvp<_Pair>> + __ireturn_type + insert(_Pair&& __v) + { + __hashtable& __h = this->_M_conjure_hashtable(); + return __h._M_insert(std::forward<_Pair>(__v), __unique_keys()); + } + + template<typename _Pair, typename = _IFconvp<_Pair>> + iterator + insert(const_iterator, _Pair&& __v) + { return __iconv_type()(insert(std::forward<_Pair>(__v))); } + }; + + /** + * Primary class template _Rehash_base. + * + * Give hashtable the max_load_factor functions and reserve iff the + * rehash policy is _Prime_rehash_policy. + */ + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + struct _Rehash_base; + + /// Specialization. + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, typename _Traits> + struct _Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _Prime_rehash_policy, _Traits> + { + using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey, + _Equal, _H1, _H2, _Hash, + _Prime_rehash_policy, _Traits>; + float max_load_factor() const noexcept { - const _Hashtable* __this = static_cast<const _Hashtable*>(this); + const __hashtable* __this = static_cast<const __hashtable*>(this); return __this->__rehash_policy().max_load_factor(); } void max_load_factor(float __z) { - _Hashtable* __this = static_cast<_Hashtable*>(this); + __hashtable* __this = static_cast<__hashtable*>(this); __this->__rehash_policy(_Prime_rehash_policy(__z)); } void reserve(std::size_t __n) { - _Hashtable* __this = static_cast<_Hashtable*>(this); + __hashtable* __this = static_cast<__hashtable*>(this); __this->rehash(__builtin_ceil(__n / max_load_factor())); } }; - // Helper class using EBO when it is not forbidden, type is not final, - // and when it worth it, type is empty. + /** + * Primary class template _Hashtable_ebo_helper. + * + * Helper class using EBO when it is not forbidden, type is not + * final, and when it worth it, type is empty. + */ template<int _Nm, typename _Tp, bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)> struct _Hashtable_ebo_helper; - // Specialization using EBO. + /// Specialization using EBO. template<int _Nm, typename _Tp> - struct _Hashtable_ebo_helper<_Nm, _Tp, true> : private _Tp + struct _Hashtable_ebo_helper<_Nm, _Tp, true> + // See PR53067. + : public _Tp { _Hashtable_ebo_helper() = default; + _Hashtable_ebo_helper(const _Tp& __tp) : _Tp(__tp) { } @@ -548,11 +900,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return static_cast<_Tp&>(__eboh); } }; - // Specialization not using EBO. + /// Specialization not using EBO. template<int _Nm, typename _Tp> struct _Hashtable_ebo_helper<_Nm, _Tp, false> { _Hashtable_ebo_helper() = default; + _Hashtable_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { } @@ -568,70 +921,73 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Tp _M_tp; }; - // Class template _Hash_code_base. Encapsulates two policy issues that - // aren't quite orthogonal. - // (1) the difference between using a ranged hash function and using - // the combination of a hash function and a range-hashing function. - // In the former case we don't have such things as hash codes, so - // we have a dummy type as placeholder. - // (2) Whether or not we cache hash codes. Caching hash codes is - // meaningless if we have a ranged hash function. - // We also put the key extraction objects here, for convenience. - // - // Each specialization derives from one or more of the template parameters to - // benefit from Ebo. This is important as this type is inherited in some cases - // by the _Local_iterator_base type used to implement local_iterator and - // const_local_iterator. As with any iterator type we prefer to make it as - // small as possible. - - // Primary template: unused except as a hook for specializations. + /** + * Primary class template _Hash_code_base. + * + * Encapsulates two policy issues that aren't quite orthogonal. + * (1) the difference between using a ranged hash function and using + * the combination of a hash function and a range-hashing function. + * In the former case we don't have such things as hash codes, so + * we have a dummy type as placeholder. + * (2) Whether or not we cache hash codes. Caching hash codes is + * meaningless if we have a ranged hash function. + * + * We also put the key extraction objects here, for convenience. + * Each specialization derives from one or more of the template + * parameters to benefit from Ebo. This is important as this type + * is inherited in some cases by the _Local_iterator_base type used + * to implement local_iterator and const_local_iterator. As with + * any iterator type we prefer to make it as small as possible. + * + * Primary template is unused except as a hook for specializations. + */ template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2, typename _Hash, bool __cache_hash_code> struct _Hash_code_base; - // Specialization: ranged hash function, no caching hash codes. H1 - // and H2 are provided but ignored. We define a dummy hash code type. - template<typename _Key, typename _Value, typename _ExtractKey, + /// Specialization: ranged hash function, no caching hash codes. H1 + /// and H2 are provided but ignored. We define a dummy hash code type. + template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2, typename _Hash> struct _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash, false> - : private _Hashtable_ebo_helper<0, _ExtractKey>, - private _Hashtable_ebo_helper<1, _Hash> + // See PR53067. + : public _Hashtable_ebo_helper<0, _ExtractKey>, + public _Hashtable_ebo_helper<1, _Hash> { private: - typedef _Hashtable_ebo_helper<0, _ExtractKey> _EboExtractKey; - typedef _Hashtable_ebo_helper<1, _Hash> _EboHash; + typedef _Hashtable_ebo_helper<0, _ExtractKey> _EboExtractKey; + typedef _Hashtable_ebo_helper<1, _Hash> _EboHash; protected: + typedef void* __hash_code; + typedef _Hash_node<_Value, false> __node_type; + // We need the default constructor for the local iterators. _Hash_code_base() = default; - _Hash_code_base(const _ExtractKey& __ex, - const _H1&, const _H2&, const _Hash& __h) - : _EboExtractKey(__ex), _EboHash(__h) { } - typedef void* _Hash_code_type; + _Hash_code_base(const _ExtractKey& __ex, const _H1&, const _H2&, + const _Hash& __h) + : _EboExtractKey(__ex), _EboHash(__h) { } - _Hash_code_type + __hash_code _M_hash_code(const _Key& __key) const { return 0; } std::size_t - _M_bucket_index(const _Key& __k, _Hash_code_type, - std::size_t __n) const + _M_bucket_index(const _Key& __k, __hash_code, std::size_t __n) const { return _M_ranged_hash()(__k, __n); } std::size_t - _M_bucket_index(const _Hash_node<_Value, false>* __p, - std::size_t __n) const + _M_bucket_index(const __node_type* __p, std::size_t __n) const { return _M_ranged_hash()(_M_extract()(__p->_M_v), __n); } void - _M_store_code(_Hash_node<_Value, false>*, _Hash_code_type) const + _M_store_code(__node_type*, __hash_code) const { } void - _M_copy_code(_Hash_node<_Value, false>*, - const _Hash_node<_Value, false>*) const + _M_copy_code(__node_type*, const __node_type*) const { } void @@ -644,10 +1000,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION protected: const _ExtractKey& _M_extract() const { return _EboExtractKey::_S_cget(*this); } + _ExtractKey& _M_extract() { return _EboExtractKey::_S_get(*this); } + const _Hash& _M_ranged_hash() const { return _EboHash::_S_cget(*this); } + _Hash& _M_ranged_hash() { return _EboHash::_S_get(*this); } }; @@ -655,67 +1014,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // No specialization for ranged hash function while caching hash codes. // That combination is meaningless, and trying to do it is an error. - // Specialization: ranged hash function, cache hash codes. This - // combination is meaningless, so we provide only a declaration - // and no definition. + /// Specialization: ranged hash function, cache hash codes. This + /// combination is meaningless, so we provide only a declaration + /// and no definition. template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2, typename _Hash> struct _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash, true>; - // Specialization: hash function and range-hashing function, no - // caching of hash codes. - // Provides typedef and accessor required by TR1. + /// Specialization: hash function and range-hashing function, no + /// caching of hash codes. + /// Provides typedef and accessor required by TR1. template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2> struct _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Default_ranged_hash, false> - : private _Hashtable_ebo_helper<0, _ExtractKey>, - private _Hashtable_ebo_helper<1, _H1>, - private _Hashtable_ebo_helper<2, _H2> + // See PR53067. + : public _Hashtable_ebo_helper<0, _ExtractKey>, + public _Hashtable_ebo_helper<1, _H1>, + public _Hashtable_ebo_helper<2, _H2> { private: - typedef _Hashtable_ebo_helper<0, _ExtractKey> _EboExtractKey; - typedef _Hashtable_ebo_helper<1, _H1> _EboH1; - typedef _Hashtable_ebo_helper<2, _H2> _EboH2; + typedef _Hashtable_ebo_helper<0, _ExtractKey> _EboExtractKey; + typedef _Hashtable_ebo_helper<1, _H1> _EboH1; + typedef _Hashtable_ebo_helper<2, _H2> _EboH2; public: - typedef _H1 hasher; + typedef _H1 hasher; hasher hash_function() const { return _M_h1(); } + typedef std::size_t __hash_code; + typedef _Hash_node<_Value, false> __node_type; + protected: // We need the default constructor for the local iterators. _Hash_code_base() = default; + _Hash_code_base(const _ExtractKey& __ex, const _H1& __h1, const _H2& __h2, const _Default_ranged_hash&) : _EboExtractKey(__ex), _EboH1(__h1), _EboH2(__h2) { } - typedef std::size_t _Hash_code_type; - - _Hash_code_type + __hash_code _M_hash_code(const _Key& __k) const { return _M_h1()(__k); } std::size_t - _M_bucket_index(const _Key&, _Hash_code_type __c, - std::size_t __n) const + _M_bucket_index(const _Key&, __hash_code __c, std::size_t __n) const { return _M_h2()(__c, __n); } std::size_t - _M_bucket_index(const _Hash_node<_Value, false>* __p, + _M_bucket_index(const __node_type* __p, std::size_t __n) const { return _M_h2()(_M_h1()(_M_extract()(__p->_M_v)), __n); } void - _M_store_code(_Hash_node<_Value, false>*, _Hash_code_type) const + _M_store_code(__node_type*, __hash_code) const { } void - _M_copy_code(_Hash_node<_Value, false>*, - const _Hash_node<_Value, false>*) const + _M_copy_code(__node_type*, const __node_type*) const { } void @@ -726,73 +1086,77 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::swap(_M_h2(), __x._M_h2()); } - protected: const _ExtractKey& _M_extract() const { return _EboExtractKey::_S_cget(*this); } + _ExtractKey& _M_extract() { return _EboExtractKey::_S_get(*this); } + const _H1& _M_h1() const { return _EboH1::_S_cget(*this); } + _H1& _M_h1() { return _EboH1::_S_get(*this); } + const _H2& _M_h2() const { return _EboH2::_S_cget(*this); } + _H2& _M_h2() { return _EboH2::_S_get(*this); } }; - // Specialization: hash function and range-hashing function, - // caching hash codes. H is provided but ignored. Provides - // typedef and accessor required by TR1. + /// Specialization: hash function and range-hashing function, + /// caching hash codes. H is provided but ignored. Provides + /// typedef and accessor required by TR1. template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2> struct _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Default_ranged_hash, true> - : private _Hashtable_ebo_helper<0, _ExtractKey>, - private _Hashtable_ebo_helper<1, _H1>, - private _Hashtable_ebo_helper<2, _H2> + // See PR53067. + : public _Hashtable_ebo_helper<0, _ExtractKey>, + public _Hashtable_ebo_helper<1, _H1>, + public _Hashtable_ebo_helper<2, _H2> { private: - typedef _Hashtable_ebo_helper<0, _ExtractKey> _EboExtractKey; - typedef _Hashtable_ebo_helper<1, _H1> _EboH1; - typedef _Hashtable_ebo_helper<2, _H2> _EboH2; + typedef _Hashtable_ebo_helper<0, _ExtractKey> _EboExtractKey; + typedef _Hashtable_ebo_helper<1, _H1> _EboH1; + typedef _Hashtable_ebo_helper<2, _H2> _EboH2; public: - typedef _H1 hasher; + typedef _H1 hasher; hasher hash_function() const { return _M_h1(); } + typedef std::size_t __hash_code; + typedef _Hash_node<_Value, true> __node_type; + protected: _Hash_code_base(const _ExtractKey& __ex, const _H1& __h1, const _H2& __h2, const _Default_ranged_hash&) : _EboExtractKey(__ex), _EboH1(__h1), _EboH2(__h2) { } - typedef std::size_t _Hash_code_type; - - _Hash_code_type + __hash_code _M_hash_code(const _Key& __k) const { return _M_h1()(__k); } std::size_t - _M_bucket_index(const _Key&, _Hash_code_type __c, + _M_bucket_index(const _Key&, __hash_code __c, std::size_t __n) const { return _M_h2()(__c, __n); } std::size_t - _M_bucket_index(const _Hash_node<_Value, true>* __p, - std::size_t __n) const + _M_bucket_index(const __node_type* __p, std::size_t __n) const { return _M_h2()(__p->_M_hash_code, __n); } void - _M_store_code(_Hash_node<_Value, true>* __n, _Hash_code_type __c) const + _M_store_code(__node_type* __n, __hash_code __c) const { __n->_M_hash_code = __c; } void - _M_copy_code(_Hash_node<_Value, true>* __to, - const _Hash_node<_Value, true>* __from) const + _M_copy_code(__node_type* __to, const __node_type* __from) const { __to->_M_hash_code = __from->_M_hash_code; } void @@ -803,110 +1167,75 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::swap(_M_h2(), __x._M_h2()); } - protected: const _ExtractKey& _M_extract() const { return _EboExtractKey::_S_cget(*this); } + _ExtractKey& _M_extract() { return _EboExtractKey::_S_get(*this); } + const _H1& _M_h1() const { return _EboH1::_S_cget(*this); } + _H1& _M_h1() { return _EboH1::_S_get(*this); } + const _H2& _M_h2() const { return _EboH2::_S_cget(*this); } + _H2& _M_h2() { return _EboH2::_S_get(*this); } }; + /** + * Primary class template _Equal_helper. + * + */ template <typename _Key, typename _Value, typename _ExtractKey, typename _Equal, typename _HashCodeType, bool __cache_hash_code> struct _Equal_helper; + /// Specialization. template<typename _Key, typename _Value, typename _ExtractKey, typename _Equal, typename _HashCodeType> struct _Equal_helper<_Key, _Value, _ExtractKey, _Equal, _HashCodeType, true> { static bool _S_equals(const _Equal& __eq, const _ExtractKey& __extract, - const _Key& __k, _HashCodeType __c, - _Hash_node<_Value, true>* __n) - { return __c == __n->_M_hash_code - && __eq(__k, __extract(__n->_M_v)); } + const _Key& __k, _HashCodeType __c, _Hash_node<_Value, true>* __n) + { return __c == __n->_M_hash_code && __eq(__k, __extract(__n->_M_v)); } }; + /// Specialization. template<typename _Key, typename _Value, typename _ExtractKey, typename _Equal, typename _HashCodeType> struct _Equal_helper<_Key, _Value, _ExtractKey, _Equal, _HashCodeType, false> { static bool _S_equals(const _Equal& __eq, const _ExtractKey& __extract, - const _Key& __k, _HashCodeType, - _Hash_node<_Value, false>* __n) + const _Key& __k, _HashCodeType, _Hash_node<_Value, false>* __n) { return __eq(__k, __extract(__n->_M_v)); } }; - // Helper class adding management of _Equal functor to _Hash_code_base - // type. - template<typename _Key, typename _Value, - typename _ExtractKey, typename _Equal, - typename _H1, typename _H2, typename _Hash, - bool __cache_hash_code> - struct _Hashtable_base - : public _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash, - __cache_hash_code>, - private _Hashtable_ebo_helper<0, _Equal> - { - private: - typedef _Hashtable_ebo_helper<0, _Equal> _EboEqual; - - protected: - typedef _Hash_code_base<_Key, _Value, _ExtractKey, - _H1, _H2, _Hash, __cache_hash_code> _HCBase; - typedef typename _HCBase::_Hash_code_type _Hash_code_type; - - _Hashtable_base(const _ExtractKey& __ex, - const _H1& __h1, const _H2& __h2, - const _Hash& __hash, const _Equal& __eq) - : _HCBase(__ex, __h1, __h2, __hash), _EboEqual(__eq) { } - - bool - _M_equals(const _Key& __k, _Hash_code_type __c, - _Hash_node<_Value, __cache_hash_code>* __n) const - { - typedef _Equal_helper<_Key, _Value, _ExtractKey, - _Equal, _Hash_code_type, - __cache_hash_code> _EqualHelper; - return _EqualHelper::_S_equals(_M_eq(), this->_M_extract(), - __k, __c, __n); - } - void - _M_swap(_Hashtable_base& __x) - { - _HCBase::_M_swap(__x); - std::swap(_M_eq(), __x._M_eq()); - } - - protected: - const _Equal& - _M_eq() const { return _EboEqual::_S_cget(*this); } - _Equal& - _M_eq() { return _EboEqual::_S_get(*this); } - }; - - // Local iterators, used to iterate within a bucket but not between - // buckets. + /** + * Primary class template _Local_iterator_base. + * + * Base class for local iterators, used to iterate within a bucket + * but not between buckets. + */ template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2, typename _Hash, bool __cache_hash_code> struct _Local_iterator_base; + /// Specialization. template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2, typename _Hash> struct _Local_iterator_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash, true> - : private _H2 + // See PR53067. + : public _H2 { _Local_iterator_base() = default; _Local_iterator_base(_Hash_node<_Value, true>* __p, @@ -933,12 +1262,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::size_t _M_bucket_count; }; + /// Specialization. template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2, typename _Hash> struct _Local_iterator_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash, false> - : private _Hash_code_base<_Key, _Value, _ExtractKey, - _H1, _H2, _Hash, false> + // See PR53067. + : public _Hash_code_base<_Key, _Value, _ExtractKey, + _H1, _H2, _Hash, false> { _Local_iterator_base() = default; _Local_iterator_base(_Hash_node<_Value, false>* __p, @@ -980,6 +1311,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _H1, _H2, _Hash, __cache>& __y) { return __x._M_cur != __y._M_cur; } + /// local iterators template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2, typename _Hash, bool __constant_iterators, bool __cache> @@ -1030,6 +1362,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + /// local const_iterators template<typename _Key, typename _Value, typename _ExtractKey, typename _H1, typename _H2, typename _Hash, bool __constant_iterators, bool __cache> @@ -1085,27 +1418,201 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + /** + * Primary class template _Hashtable_base. + * + * Base class for _Hashtable. Helper class adding management of + * _Equal functor to _Hash_code_base type. + */ + template<typename _Key, typename _Value, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, typename _Traits> + struct _Hashtable_base + // See PR53067. + : public _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash, + _Traits::__hash_cached::value>, + public _Hashtable_ebo_helper<0, _Equal> + { + public: + typedef _Key key_type; + typedef _Value value_type; + typedef _Equal key_equal; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + using __traits_type = _Traits; + using __hash_cached = typename __traits_type::__hash_cached; + using __constant_iterators = typename __traits_type::__constant_iterators; + using __unique_keys = typename __traits_type::__unique_keys; + + using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey, + _H1, _H2, _Hash, + __hash_cached::value>; + + using __hash_code = typename __hash_code_base::__hash_code; + using __node_type = typename __hash_code_base::__node_type; + + using iterator = __detail::_Node_iterator<value_type, + __constant_iterators::value, + __hash_cached::value>; + + using const_iterator = __detail::_Node_const_iterator<value_type, + __constant_iterators::value, + __hash_cached::value>; + + using local_iterator = __detail::_Local_iterator<key_type, value_type, + _ExtractKey, _H1, _H2, _Hash, + __constant_iterators::value, + __hash_cached::value>; + + using const_local_iterator = __detail::_Local_const_iterator<key_type, + value_type, + _ExtractKey, _H1, _H2, _Hash, + __constant_iterators::value, + __hash_cached::value>; + + using __ireturn_type = typename std::conditional<__unique_keys::value, + std::pair<iterator, bool>, + iterator>::type; + + using __iconv_type = typename std::conditional<__unique_keys::value, + std::_Select1st<__ireturn_type>, + std::_Identity<__ireturn_type> + >::type; + private: + using _EqualEBO = _Hashtable_ebo_helper<0, _Equal>; + using _EqualHelper = _Equal_helper<_Key, _Value, _ExtractKey, _Equal, + __hash_code, __hash_cached::value>; + + protected: + using __node_base = __detail::_Hash_node_base; + using __bucket_type = __node_base*; + + _Hashtable_base(const _ExtractKey& __ex, const _H1& __h1, const _H2& __h2, + const _Hash& __hash, const _Equal& __eq) + : __hash_code_base(__ex, __h1, __h2, __hash), _EqualEBO(__eq) + { } + + bool + _M_equals(const _Key& __k, __hash_code __c, __node_type* __n) const + { + return _EqualHelper::_S_equals(_M_eq(), this->_M_extract(), + __k, __c, __n); + } + + void + _M_swap(_Hashtable_base& __x) + { + __hash_code_base::_M_swap(__x); + std::swap(_M_eq(), __x._M_eq()); + } + + const _Equal& + _M_eq() const { return _EqualEBO::_S_cget(*this); } + + _Equal& + _M_eq() { return _EqualEBO::_S_get(*this); } + }; - // Class template _Equality_base. This is for implementing equality - // comparison for unordered containers, per N3068, by John Lakos and - // Pablo Halpern. Algorithmically, we follow closely the reference - // implementations therein. - template<typename _ExtractKey, bool __unique_keys, - typename _Hashtable> - struct _Equality_base; + /** + * struct _Equality_base. + * + * Common types and functions for class _Equality. + */ + struct _Equality_base + { + protected: + template<typename _Uiterator> + static bool + _S_is_permutation(_Uiterator, _Uiterator, _Uiterator); + }; - template<typename _ExtractKey, typename _Hashtable> - struct _Equality_base<_ExtractKey, true, _Hashtable> + // See std::is_permutation in N3068. + template<typename _Uiterator> + bool + _Equality_base:: + _S_is_permutation(_Uiterator __first1, _Uiterator __last1, + _Uiterator __first2) { - bool _M_equal(const _Hashtable&) const; + for (; __first1 != __last1; ++__first1, ++__first2) + if (!(*__first1 == *__first2)) + break; + + if (__first1 == __last1) + return true; + + _Uiterator __last2 = __first2; + std::advance(__last2, std::distance(__first1, __last1)); + + for (_Uiterator __it1 = __first1; __it1 != __last1; ++__it1) + { + _Uiterator __tmp = __first1; + while (__tmp != __it1 && !bool(*__tmp == *__it1)) + ++__tmp; + + // We've seen this one before. + if (__tmp != __it1) + continue; + + std::ptrdiff_t __n2 = 0; + for (__tmp = __first2; __tmp != __last2; ++__tmp) + if (*__tmp == *__it1) + ++__n2; + + if (!__n2) + return false; + + std::ptrdiff_t __n1 = 0; + for (__tmp = __it1; __tmp != __last1; ++__tmp) + if (*__tmp == *__it1) + ++__n1; + + if (__n1 != __n2) + return false; + } + return true; + } + + /** + * Primary class template _Equality. + * + * This is for implementing equality comparison for unordered + * containers, per N3068, by John Lakos and Pablo Halpern. + * Algorithmically, we follow closely the reference implementations + * therein. + */ + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits, + bool _Unique_keys = _Traits::__unique_keys::value> + struct _Equality; + + /// Specialization. + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + struct _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true> + { + using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>; + + bool + _M_equal(const __hashtable&) const; }; - template<typename _ExtractKey, typename _Hashtable> + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> bool - _Equality_base<_ExtractKey, true, _Hashtable>:: - _M_equal(const _Hashtable& __other) const + _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, true>:: + _M_equal(const __hashtable& __other) const { - const _Hashtable* __this = static_cast<const _Hashtable*>(this); + const __hashtable* __this = static_cast<const __hashtable*>(this); if (__this->size() != __other.size()) return false; @@ -1119,70 +1626,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return true; } - template<typename _ExtractKey, typename _Hashtable> - struct _Equality_base<_ExtractKey, false, _Hashtable> + /// Specialization. + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> + struct _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, false> + : public _Equality_base { - bool _M_equal(const _Hashtable&) const; - - private: - template<typename _Uiterator> - static bool - _S_is_permutation(_Uiterator, _Uiterator, _Uiterator); - }; + using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits>; - // See std::is_permutation in N3068. - template<typename _ExtractKey, typename _Hashtable> - template<typename _Uiterator> bool - _Equality_base<_ExtractKey, false, _Hashtable>:: - _S_is_permutation(_Uiterator __first1, _Uiterator __last1, - _Uiterator __first2) - { - for (; __first1 != __last1; ++__first1, ++__first2) - if (!(*__first1 == *__first2)) - break; - - if (__first1 == __last1) - return true; - - _Uiterator __last2 = __first2; - std::advance(__last2, std::distance(__first1, __last1)); - - for (_Uiterator __it1 = __first1; __it1 != __last1; ++__it1) - { - _Uiterator __tmp = __first1; - while (__tmp != __it1 && !bool(*__tmp == *__it1)) - ++__tmp; - - // We've seen this one before. - if (__tmp != __it1) - continue; - - std::ptrdiff_t __n2 = 0; - for (__tmp = __first2; __tmp != __last2; ++__tmp) - if (*__tmp == *__it1) - ++__n2; - - if (!__n2) - return false; - - std::ptrdiff_t __n1 = 0; - for (__tmp = __it1; __tmp != __last1; ++__tmp) - if (*__tmp == *__it1) - ++__n1; - - if (__n1 != __n2) - return false; - } - return true; - } + _M_equal(const __hashtable&) const; + }; - template<typename _ExtractKey, typename _Hashtable> + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _H1, typename _H2, typename _Hash, + typename _RehashPolicy, typename _Traits> bool - _Equality_base<_ExtractKey, false, _Hashtable>:: - _M_equal(const _Hashtable& __other) const + _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _H1, _H2, _Hash, _RehashPolicy, _Traits, false>:: + _M_equal(const __hashtable& __other) const { - const _Hashtable* __this = static_cast<const _Hashtable*>(this); + const __hashtable* __this = static_cast<const __hashtable*>(this); if (__this->size() != __other.size()) return false; @@ -1196,8 +1665,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION != std::distance(__yrange.first, __yrange.second)) return false; - if (!_S_is_permutation(__xrange.first, - __xrange.second, + if (!_S_is_permutation(__xrange.first, __xrange.second, __yrange.first)) return false; @@ -1206,6 +1674,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return true; } + //@} hashtable-detail _GLIBCXX_END_NAMESPACE_VERSION } // namespace __detail } // namespace std diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h index 7f120b1f8ac..bba9b49bfc6 100644 --- a/libstdc++-v3/include/bits/ptr_traits.h +++ b/libstdc++-v3/include/bits/ptr_traits.h @@ -140,14 +140,8 @@ _GLIBCXX_HAS_NESTED_TYPE(difference_type) /// Type used to represent the difference between two pointers typedef typename __ptrtr_diff_type<_Ptr>::__type difference_type; - private: template<typename _Up> using rebind = typename __ptrtr_rebind<_Ptr, _Up>::__type; - - // allocator_traits needs to use __rebind - template<typename> friend struct allocator_traits; - template<typename> friend struct pointer_traits; - template<typename, typename> friend class __ptrtr_rebind_helper2; }; /** diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc index d55b51838b8..5da353f8bd4 100644 --- a/libstdc++-v3/include/bits/random.tcc +++ b/libstdc++-v3/include/bits/random.tcc @@ -730,40 +730,65 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION independent_bits_engine<_RandomNumberEngine, __w, _UIntType>:: operator()() { - const long double __r = static_cast<long double>(_M_b.max()) - - static_cast<long double>(_M_b.min()) + 1.0L; - const result_type __m = std::log(__r) / std::log(2.0L); - result_type __n, __n0, __y0, __y1, __s0, __s1; + typedef typename _RandomNumberEngine::result_type _Eresult_type; + const _Eresult_type __r + = (_M_b.max() - _M_b.min() < std::numeric_limits<_Eresult_type>::max() + ? _M_b.max() - _M_b.min() + 1 : 0); + const unsigned __edig = std::numeric_limits<_Eresult_type>::digits; + const unsigned __m = __r ? std::__lg(__r) : __edig; + + typedef typename std::common_type<_Eresult_type, result_type>::type + __ctype; + const unsigned __cdig = std::numeric_limits<__ctype>::digits; + + unsigned __n, __n0; + __ctype __s0, __s1, __y0, __y1; + for (size_t __i = 0; __i < 2; ++__i) { __n = (__w + __m - 1) / __m + __i; __n0 = __n - __w % __n; - const result_type __w0 = __w / __n; - const result_type __w1 = __w0 + 1; - __s0 = result_type(1) << __w0; - __s1 = result_type(1) << __w1; - __y0 = __s0 * (__r / __s0); - __y1 = __s1 * (__r / __s1); - if (__r - __y0 <= __y0 / __n) + const unsigned __w0 = __w / __n; // __w0 <= __m + + __s0 = 0; + __s1 = 0; + if (__w0 < __cdig) + { + __s0 = __ctype(1) << __w0; + __s1 = __s0 << 1; + } + + __y0 = 0; + __y1 = 0; + if (__r) + { + __y0 = __s0 * (__r / __s0); + if (__s1) + __y1 = __s1 * (__r / __s1); + + if (__r - __y0 <= __y0 / __n) + break; + } + else break; } result_type __sum = 0; for (size_t __k = 0; __k < __n0; ++__k) { - result_type __u; + __ctype __u; do __u = _M_b() - _M_b.min(); - while (__u >= __y0); - __sum = __s0 * __sum + __u % __s0; + while (__y0 && __u >= __y0); + __sum = __s0 * __sum + (__s0 ? __u % __s0 : __u); } for (size_t __k = __n0; __k < __n; ++__k) { - result_type __u; + __ctype __u; do __u = _M_b() - _M_b.min(); - while (__u >= __y1); - __sum = __s1 * __sum + __u % __s1; + while (__y1 && __u >= __y1); + __sum = __s1 * __sum + (__s1 ? __u % __s1 : __u); } return __sum; } @@ -840,12 +865,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator()(_UniformRandomNumberGenerator& __urng, const param_type& __param) { - typedef typename std::make_unsigned<typename - _UniformRandomNumberGenerator::result_type>::type __urngtype; + typedef typename _UniformRandomNumberGenerator::result_type + _Gresult_type; typedef typename std::make_unsigned<result_type>::type __utype; - typedef typename std::conditional<(sizeof(__urngtype) - > sizeof(__utype)), - __urngtype, __utype>::type __uctype; + typedef typename std::common_type<_Gresult_type, __utype>::type + __uctype; const __uctype __urngmin = __urng.min(); const __uctype __urngmax = __urng.max(); diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index c48c18eaee9..39449f1b4bb 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -343,6 +343,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) : _M_ptr(__p), _M_del(__d, __a) { } + ~_Sp_counted_deleter() noexcept { } + virtual void _M_dispose() noexcept { _M_del._M_del(_M_ptr); } @@ -401,6 +403,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_Args>(__args)...); // might throw } + ~_Sp_counted_ptr_inplace() noexcept { } + virtual void _M_dispose() noexcept { allocator_traits<_Alloc>::destroy(_M_impl, _M_impl._M_ptr); } diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index c517a1963d1..f337e0c07a6 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -244,7 +244,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } -#ifdef __GXX_EXPERIMENTAL_CXX0X__ /// This is an overload used by find_if_not() for the Input Iterator case. template<typename _InputIterator, typename _Predicate> inline _InputIterator @@ -303,7 +302,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __last; } } -#endif + + /// Provided for stable_partition to use. + template<typename _InputIterator, typename _Predicate> + inline _InputIterator + __find_if_not(_InputIterator __first, _InputIterator __last, + _Predicate __pred) + { + return std::__find_if_not(__first, __last, __pred, + std::__iterator_category(__first)); + } + + /// Like find_if_not(), but uses and updates a count of the + /// remaining range length instead of comparing against an end + /// iterator. + template<typename _InputIterator, typename _Predicate, typename _Distance> + _InputIterator + __find_if_not_n(_InputIterator __first, _Distance& __len, _Predicate __pred) + { + for (; __len; --__len, ++__first) + if (!bool(__pred(*__first))) + break; + return __first; + } // set_difference // set_intersection @@ -789,8 +810,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, typename iterator_traits<_InputIterator>::value_type>) __glibcxx_requires_valid_range(__first, __last); - return std::__find_if_not(__first, __last, __pred, - std::__iterator_category(__first)); + return std::__find_if_not(__first, __last, __pred); } /** @@ -1784,30 +1804,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // partition /// This is a helper function... + /// Requires __len != 0 and !__pred(*__first), + /// same as __stable_partition_adaptive. template<typename _ForwardIterator, typename _Predicate, typename _Distance> _ForwardIterator __inplace_stable_partition(_ForwardIterator __first, - _ForwardIterator __last, _Predicate __pred, _Distance __len) { if (__len == 1) - return __pred(*__first) ? __last : __first; + return __first; _ForwardIterator __middle = __first; std::advance(__middle, __len / 2); - _ForwardIterator __begin = std::__inplace_stable_partition(__first, - __middle, - __pred, - __len / 2); - _ForwardIterator __end = std::__inplace_stable_partition(__middle, __last, - __pred, - __len - - __len / 2); - std::rotate(__begin, __middle, __end); - std::advance(__begin, std::distance(__middle, __end)); - return __begin; + _ForwardIterator __left_split = + std::__inplace_stable_partition(__first, __pred, __len / 2); + // Advance past true-predicate values to satisfy this + // function's preconditions. + _Distance __right_len = __len - __len / 2; + _ForwardIterator __right_split = + std::__find_if_not_n(__middle, __right_len, __pred); + if (__right_len) + __right_split = std::__inplace_stable_partition(__middle, + __pred, + __right_len); + std::rotate(__left_split, __middle, __right_split); + std::advance(__left_split, std::distance(__middle, __right_split)); + return __left_split; } /// This is a helper function... + /// Requires __first != __last and !__pred(*__first) + /// and __len == distance(__first, __last). + /// + /// !__pred(*__first) allows us to guarantee that we don't + /// move-assign an element onto itself. template<typename _ForwardIterator, typename _Pointer, typename _Predicate, typename _Distance> _ForwardIterator @@ -1821,6 +1850,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _ForwardIterator __result1 = __first; _Pointer __result2 = __buffer; + // The precondition guarantees that !__pred(*__first), so + // move that element to the buffer before starting the loop. + // This ensures that we only call __pred once per element. + *__result2 = _GLIBCXX_MOVE(*__first); + ++__result2; + ++__first; for (; __first != __last; ++__first) if (__pred(*__first)) { @@ -1839,17 +1874,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _ForwardIterator __middle = __first; std::advance(__middle, __len / 2); - _ForwardIterator __begin = + _ForwardIterator __left_split = std::__stable_partition_adaptive(__first, __middle, __pred, __len / 2, __buffer, __buffer_size); - _ForwardIterator __end = - std::__stable_partition_adaptive(__middle, __last, __pred, - __len - __len / 2, - __buffer, __buffer_size); - std::rotate(__begin, __middle, __end); - std::advance(__begin, std::distance(__middle, __end)); - return __begin; + // Advance past true-predicate values to satisfy this + // function's preconditions. + _Distance __right_len = __len - __len / 2; + _ForwardIterator __right_split = + std::__find_if_not_n(__middle, __right_len, __pred); + if (__right_len) + __right_split = + std::__stable_partition_adaptive(__right_split, __last, __pred, + __right_len, + __buffer, __buffer_size); + std::rotate(__left_split, __middle, __right_split); + std::advance(__left_split, std::distance(__middle, __right_split)); + return __left_split; } } @@ -1882,6 +1923,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename iterator_traits<_ForwardIterator>::value_type>) __glibcxx_requires_valid_range(__first, __last); + __first = std::__find_if_not(__first, __last, __pred); + if (__first == __last) return __first; else @@ -1901,7 +1944,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _DistanceType(__buf.size())); else return - std::__inplace_stable_partition(__first, __last, __pred, + std::__inplace_stable_partition(__first, __pred, _DistanceType(__buf.requested_size())); } } diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 4e6e0f49c5b..1ccf8604f5f 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -989,14 +989,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __lg(int __n) { return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); } + inline unsigned + __lg(unsigned __n) + { return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); } + inline long __lg(long __n) { return sizeof(long) * __CHAR_BIT__ - 1 - __builtin_clzl(__n); } + inline unsigned long + __lg(unsigned long __n) + { return sizeof(long) * __CHAR_BIT__ - 1 - __builtin_clzl(__n); } + inline long long __lg(long long __n) { return sizeof(long long) * __CHAR_BIT__ - 1 - __builtin_clzll(__n); } + inline unsigned long long + __lg(unsigned long long __n) + { return sizeof(long long) * __CHAR_BIT__ - 1 - __builtin_clzll(__n); } + _GLIBCXX_END_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_ALGO diff --git a/libstdc++-v3/include/bits/stl_function.h b/libstdc++-v3/include/bits/stl_function.h index 88655fc55c3..33d5e709628 100644 --- a/libstdc++-v3/include/bits/stl_function.h +++ b/libstdc++-v3/include/bits/stl_function.h @@ -1,6 +1,7 @@ // Functor implementations -*- C++ -*- -// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011 +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, +// 2011, 2012 // Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free @@ -471,7 +472,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /** @} */ template<typename _Tp> - struct _Identity : public unary_function<_Tp,_Tp> + struct _Identity +#ifndef __GXX_EXPERIMENTAL_CXX0X__ + // unary_function itself is deprecated in C++11 and deriving from + // it can even be a nuisance (see PR 52942). + : public unary_function<_Tp,_Tp> +#endif { _Tp& operator()(_Tp& __x) const @@ -483,8 +489,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template<typename _Pair> - struct _Select1st : public unary_function<_Pair, - typename _Pair::first_type> + struct _Select1st +#ifndef __GXX_EXPERIMENTAL_CXX0X__ + : public unary_function<_Pair, typename _Pair::first_type> +#endif { typename _Pair::first_type& operator()(_Pair& __x) const @@ -508,8 +516,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template<typename _Pair> - struct _Select2nd : public unary_function<_Pair, - typename _Pair::second_type> + struct _Select2nd +#ifndef __GXX_EXPERIMENTAL_CXX0X__ + : public unary_function<_Pair, typename _Pair::second_type> +#endif { typename _Pair::second_type& operator()(_Pair& __x) const diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h index 95f5657762a..dd08b2645c1 100644 --- a/libstdc++-v3/include/bits/unordered_map.h +++ b/libstdc++-v3/include/bits/unordered_map.h @@ -1,6 +1,6 @@ // unordered_map implementation -*- C++ -*- -// Copyright (C) 2010, 2011 Free Software Foundation, Inc. +// Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -34,208 +34,41 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_CONTAINER - // NB: When we get typedef templates these class definitions - // will be unnecessary. - template<class _Key, class _Tp, - class _Hash = hash<_Key>, - class _Pred = std::equal_to<_Key>, - class _Alloc = std::allocator<std::pair<const _Key, _Tp> >, - bool __cache_hash_code = - __not_<__and_<is_integral<_Key>, is_empty<_Hash>, - integral_constant<bool, !__is_final(_Hash)>, - __detail::__is_noexcept_hash<_Key, _Hash>>>::value> - class __unordered_map - : public _Hashtable<_Key, std::pair<const _Key, _Tp>, _Alloc, - std::_Select1st<std::pair<const _Key, _Tp> >, _Pred, - _Hash, __detail::_Mod_range_hashing, - __detail::_Default_ranged_hash, - __detail::_Prime_rehash_policy, - __cache_hash_code, false, true> - { - typedef _Hashtable<_Key, std::pair<const _Key, _Tp>, _Alloc, - std::_Select1st<std::pair<const _Key, _Tp> >, _Pred, - _Hash, __detail::_Mod_range_hashing, - __detail::_Default_ranged_hash, - __detail::_Prime_rehash_policy, - __cache_hash_code, false, true> - _Base; - - public: - typedef typename _Base::value_type value_type; - typedef typename _Base::size_type size_type; - typedef typename _Base::hasher hasher; - typedef typename _Base::key_equal key_equal; - typedef typename _Base::allocator_type allocator_type; - - explicit - __unordered_map(size_type __n = 10, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__n, __hf, __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), - __eql, std::_Select1st<std::pair<const _Key, _Tp> >(), __a) - { } - - template<typename _InputIterator> - __unordered_map(_InputIterator __f, _InputIterator __l, - size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__f, __l, __n, __hf, __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), - __eql, std::_Select1st<std::pair<const _Key, _Tp> >(), __a) - { } - - __unordered_map(initializer_list<value_type> __l, - size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__l.begin(), __l.end(), __n, __hf, - __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), - __eql, std::_Select1st<std::pair<const _Key, _Tp> >(), __a) - { } - - __unordered_map& - operator=(initializer_list<value_type> __l) - { - this->clear(); - this->insert(__l.begin(), __l.end()); - return *this; - } - }; - - template<class _Key, class _Tp, - class _Hash = hash<_Key>, - class _Pred = std::equal_to<_Key>, - class _Alloc = std::allocator<std::pair<const _Key, _Tp> >, - bool __cache_hash_code = - __not_<__and_<is_integral<_Key>, is_empty<_Hash>, - integral_constant<bool, !__is_final(_Hash)>, - __detail::__is_noexcept_hash<_Key, _Hash>>>::value> - class __unordered_multimap - : public _Hashtable<_Key, std::pair<const _Key, _Tp>, - _Alloc, - std::_Select1st<std::pair<const _Key, _Tp> >, _Pred, - _Hash, __detail::_Mod_range_hashing, - __detail::_Default_ranged_hash, - __detail::_Prime_rehash_policy, - __cache_hash_code, false, false> - { - typedef _Hashtable<_Key, std::pair<const _Key, _Tp>, - _Alloc, - std::_Select1st<std::pair<const _Key, _Tp> >, _Pred, - _Hash, __detail::_Mod_range_hashing, - __detail::_Default_ranged_hash, - __detail::_Prime_rehash_policy, - __cache_hash_code, false, false> - _Base; - - public: - typedef typename _Base::value_type value_type; - typedef typename _Base::size_type size_type; - typedef typename _Base::hasher hasher; - typedef typename _Base::key_equal key_equal; - typedef typename _Base::allocator_type allocator_type; - - explicit - __unordered_multimap(size_type __n = 10, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__n, __hf, __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), - __eql, std::_Select1st<std::pair<const _Key, _Tp> >(), __a) - { } - - - template<typename _InputIterator> - __unordered_multimap(_InputIterator __f, _InputIterator __l, - size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__f, __l, __n, __hf, __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), - __eql, std::_Select1st<std::pair<const _Key, _Tp> >(), __a) - { } - - __unordered_multimap(initializer_list<value_type> __l, - size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__l.begin(), __l.end(), __n, __hf, - __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), - __eql, std::_Select1st<std::pair<const _Key, _Tp> >(), __a) - { } - - __unordered_multimap& - operator=(initializer_list<value_type> __l) - { - this->clear(); - this->insert(__l.begin(), __l.end()); - return *this; - } - }; - - template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline void - swap(__unordered_map<_Key, _Tp, _Hash, _Pred, - _Alloc, __cache_hash_code>& __x, - __unordered_map<_Key, _Tp, _Hash, _Pred, - _Alloc, __cache_hash_code>& __y) - { __x.swap(__y); } - - template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline void - swap(__unordered_multimap<_Key, _Tp, _Hash, _Pred, - _Alloc, __cache_hash_code>& __x, - __unordered_multimap<_Key, _Tp, _Hash, _Pred, - _Alloc, __cache_hash_code>& __y) - { __x.swap(__y); } - - template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline bool - operator==(const __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc, - __cache_hash_code>& __x, - const __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc, - __cache_hash_code>& __y) - { return __x._M_equal(__y); } - - template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline bool - operator!=(const __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc, - __cache_hash_code>& __x, - const __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc, - __cache_hash_code>& __y) - { return !(__x == __y); } - - template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline bool - operator==(const __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc, - __cache_hash_code>& __x, - const __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc, - __cache_hash_code>& __y) - { return __x._M_equal(__y); } - - template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline bool - operator!=(const __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc, - __cache_hash_code>& __x, - const __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc, - __cache_hash_code>& __y) - { return !(__x == __y); } + /// Base types for unordered_map. + template<bool _Cache> + using __umap_traits = __detail::_Hashtable_traits<_Cache, false, true>; + + template<typename _Key, + typename _Tp, + typename _Hash = hash<_Key>, + typename _Pred = std::equal_to<_Key>, + typename _Alloc = std::allocator<std::pair<const _Key, _Tp> >, + typename _Tr = __umap_traits<__cache_default<_Key, _Hash>::value>> + using __umap_hashtable = _Hashtable<_Key, std::pair<const _Key, _Tp>, + _Alloc, + std::_Select1st<std::pair<const _Key, _Tp>>, + _Pred, _Hash, + __detail::_Mod_range_hashing, + __detail::_Default_ranged_hash, + __detail::_Prime_rehash_policy, _Tr>; + + /// Base types for unordered_multimap. + template<bool _Cache> + using __ummap_traits = __detail::_Hashtable_traits<_Cache, false, false>; + + template<typename _Key, + typename _Tp, + typename _Hash = hash<_Key>, + typename _Pred = std::equal_to<_Key>, + typename _Alloc = std::allocator<std::pair<const _Key, _Tp> >, + typename _Tr = __ummap_traits<__cache_default<_Key, _Hash>::value>> + using __ummap_hashtable = _Hashtable<_Key, std::pair<const _Key, _Tp>, + _Alloc, + std::_Select1st<std::pair<const _Key, _Tp>>, + _Pred, _Hash, + __detail::_Mod_range_hashing, + __detail::_Default_ranged_hash, + __detail::_Prime_rehash_policy, _Tr>; /** * @brief A standard container composed of unique keys (containing @@ -247,22 +80,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Meets the requirements of a <a href="tables.html#65">container</a>, and * <a href="tables.html#xx">unordered associative container</a> * - * @param Key Type of key objects. - * @param Tp Type of mapped objects. - * @param Hash Hashing function object type, defaults to hash<Value>. - * @param Pred Predicate function object type, defaults to equal_to<Value>. - * @param Alloc Allocator type, defaults to allocator<Key>. + * @tparam _Key Type of key objects. + * @tparam _Tp Type of mapped objects. + * @tparam _Hash Hashing function object type, defaults to hash<_Value>. + * @tparam _Pred Predicate function object type, defaults + * to equal_to<_Value>. + * @tparam _Alloc Allocator type, defaults to allocator<_Key>. * - * The resulting value type of the container is std::pair<const Key, Tp>. + * The resulting value type of the container is std::pair<const _Key, _Tp>. + * + * Base is _Hashtable, dispatched at compile time via template + * alias __umap_hashtable. */ template<class _Key, class _Tp, class _Hash = hash<_Key>, class _Pred = std::equal_to<_Key>, class _Alloc = std::allocator<std::pair<const _Key, _Tp> > > class unordered_map - : public __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc> + : public __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc> { - typedef __unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc> _Base; + typedef __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc> _Base; public: typedef typename _Base::value_type value_type; @@ -280,13 +117,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { } template<typename _InputIterator> - unordered_map(_InputIterator __f, _InputIterator __l, + unordered_map(_InputIterator __f, _InputIterator __l, size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), + const hasher& __hf = hasher(), + const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _Base(__f, __l, __n, __hf, __eql, __a) - { } + { } unordered_map(initializer_list<value_type> __l, size_type __n = 0, @@ -295,16 +132,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER const allocator_type& __a = allocator_type()) : _Base(__l.begin(), __l.end(), __n, __hf, __eql, __a) { } - - unordered_map& - operator=(initializer_list<value_type> __l) - { - this->clear(); - this->insert(__l.begin(), __l.end()); - return *this; - } }; - + /** * @brief A standard container composed of equivalent keys * (possibly containing multiple of each key value) that associates @@ -315,22 +144,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Meets the requirements of a <a href="tables.html#65">container</a>, and * <a href="tables.html#xx">unordered associative container</a> * - * @param Key Type of key objects. - * @param Tp Type of mapped objects. - * @param Hash Hashing function object type, defaults to hash<Value>. - * @param Pred Predicate function object type, defaults to equal_to<Value>. - * @param Alloc Allocator type, defaults to allocator<Key>. + * @tparam _Key Type of key objects. + * @tparam _Tp Type of mapped objects. + * @tparam _Hash Hashing function object type, defaults to hash<_Value>. + * @tparam _Pred Predicate function object type, defaults + * to equal_to<_Value>. + * @tparam _Alloc Allocator type, defaults to allocator<_Key>. + * + * The resulting value type of the container is std::pair<const _Key, _Tp>. * - * The resulting value type of the container is std::pair<const Key, Tp>. + * Base is _Hashtable, dispatched at compile time via template + * alias __ummap_hashtable. */ template<class _Key, class _Tp, class _Hash = hash<_Key>, class _Pred = std::equal_to<_Key>, class _Alloc = std::allocator<std::pair<const _Key, _Tp> > > class unordered_multimap - : public __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc> + : public __ummap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc> { - typedef __unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc> _Base; + typedef __ummap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc> _Base; public: typedef typename _Base::value_type value_type; @@ -338,7 +171,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef typename _Base::hasher hasher; typedef typename _Base::key_equal key_equal; typedef typename _Base::allocator_type allocator_type; - + explicit unordered_multimap(size_type __n = 10, const hasher& __hf = hasher(), @@ -348,13 +181,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { } template<typename _InputIterator> - unordered_multimap(_InputIterator __f, _InputIterator __l, + unordered_multimap(_InputIterator __f, _InputIterator __l, size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), + const hasher& __hf = hasher(), + const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _Base(__f, __l, __n, __hf, __eql, __a) - { } + { } unordered_multimap(initializer_list<value_type> __l, size_type __n = 0, @@ -363,14 +196,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER const allocator_type& __a = allocator_type()) : _Base(__l.begin(), __l.end(), __n, __hf, __eql, __a) { } - - unordered_multimap& - operator=(initializer_list<value_type> __l) - { - this->clear(); - this->insert(__l.begin(), __l.end()); - return *this; - } }; template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h index 3d5361d4266..bd0deb0717c 100644 --- a/libstdc++-v3/include/bits/unordered_set.h +++ b/libstdc++-v3/include/bits/unordered_set.h @@ -1,6 +1,6 @@ // unordered_set implementation -*- C++ -*- -// Copyright (C) 2010, 2011 Free Software Foundation, Inc. +// Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -34,228 +34,36 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_CONTAINER - // NB: When we get typedef templates these class definitions - // will be unnecessary. - template<class _Value, - class _Hash = hash<_Value>, - class _Pred = std::equal_to<_Value>, - class _Alloc = std::allocator<_Value>, - bool __cache_hash_code = - __not_<__and_<is_integral<_Value>, is_empty<_Hash>, - integral_constant<bool, !__is_final(_Hash)>, - __detail::__is_noexcept_hash<_Value, _Hash>>>::value> - class __unordered_set - : public _Hashtable<_Value, _Value, _Alloc, - std::_Identity<_Value>, _Pred, - _Hash, __detail::_Mod_range_hashing, - __detail::_Default_ranged_hash, - __detail::_Prime_rehash_policy, - __cache_hash_code, true, true> - { - typedef _Hashtable<_Value, _Value, _Alloc, - std::_Identity<_Value>, _Pred, - _Hash, __detail::_Mod_range_hashing, - __detail::_Default_ranged_hash, - __detail::_Prime_rehash_policy, - __cache_hash_code, true, true> - _Base; - - public: - typedef typename _Base::value_type value_type; - typedef typename _Base::size_type size_type; - typedef typename _Base::hasher hasher; - typedef typename _Base::key_equal key_equal; - typedef typename _Base::allocator_type allocator_type; - typedef typename _Base::iterator iterator; - typedef typename _Base::const_iterator const_iterator; - - explicit - __unordered_set(size_type __n = 10, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__n, __hf, __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), __eql, - std::_Identity<value_type>(), __a) - { } - - template<typename _InputIterator> - __unordered_set(_InputIterator __f, _InputIterator __l, - size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__f, __l, __n, __hf, __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), __eql, - std::_Identity<value_type>(), __a) - { } - - __unordered_set(initializer_list<value_type> __l, - size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__l.begin(), __l.end(), __n, __hf, - __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), __eql, - std::_Identity<value_type>(), __a) - { } - - __unordered_set& - operator=(initializer_list<value_type> __l) - { - this->clear(); - this->insert(__l.begin(), __l.end()); - return *this; - } - - using _Base::insert; - - std::pair<iterator, bool> - insert(value_type&& __v) - { return this->_M_insert(std::move(__v), std::true_type()); } - - iterator - insert(const_iterator, value_type&& __v) - { return insert(std::move(__v)).first; } - }; - - template<class _Value, - class _Hash = hash<_Value>, - class _Pred = std::equal_to<_Value>, - class _Alloc = std::allocator<_Value>, - bool __cache_hash_code = - __not_<__and_<is_integral<_Value>, is_empty<_Hash>, - integral_constant<bool, !__is_final(_Hash)>, - __detail::__is_noexcept_hash<_Value, _Hash>>>::value> - class __unordered_multiset - : public _Hashtable<_Value, _Value, _Alloc, - std::_Identity<_Value>, _Pred, - _Hash, __detail::_Mod_range_hashing, - __detail::_Default_ranged_hash, - __detail::_Prime_rehash_policy, - __cache_hash_code, true, false> - { - typedef _Hashtable<_Value, _Value, _Alloc, - std::_Identity<_Value>, _Pred, - _Hash, __detail::_Mod_range_hashing, - __detail::_Default_ranged_hash, - __detail::_Prime_rehash_policy, - __cache_hash_code, true, false> - _Base; - - public: - typedef typename _Base::value_type value_type; - typedef typename _Base::size_type size_type; - typedef typename _Base::hasher hasher; - typedef typename _Base::key_equal key_equal; - typedef typename _Base::allocator_type allocator_type; - typedef typename _Base::iterator iterator; - typedef typename _Base::const_iterator const_iterator; - - explicit - __unordered_multiset(size_type __n = 10, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__n, __hf, __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), __eql, - std::_Identity<value_type>(), __a) - { } - - - template<typename _InputIterator> - __unordered_multiset(_InputIterator __f, _InputIterator __l, - size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__f, __l, __n, __hf, __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), __eql, - std::_Identity<value_type>(), __a) - { } - - __unordered_multiset(initializer_list<value_type> __l, - size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), - const allocator_type& __a = allocator_type()) - : _Base(__l.begin(), __l.end(), __n, __hf, - __detail::_Mod_range_hashing(), - __detail::_Default_ranged_hash(), __eql, - std::_Identity<value_type>(), __a) - { } - - __unordered_multiset& - operator=(initializer_list<value_type> __l) - { - this->clear(); - this->insert(__l.begin(), __l.end()); - return *this; - } - - using _Base::insert; - - iterator - insert(value_type&& __v) - { return this->_M_insert(std::move(__v), std::false_type()); } - - iterator - insert(const_iterator, value_type&& __v) - { return insert(std::move(__v)); } - }; - - template<class _Value, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline void - swap(__unordered_set<_Value, _Hash, _Pred, _Alloc, __cache_hash_code>& __x, - __unordered_set<_Value, _Hash, _Pred, _Alloc, __cache_hash_code>& __y) - { __x.swap(__y); } - - template<class _Value, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline void - swap(__unordered_multiset<_Value, _Hash, _Pred, - _Alloc, __cache_hash_code>& __x, - __unordered_multiset<_Value, _Hash, _Pred, - _Alloc, __cache_hash_code>& __y) - { __x.swap(__y); } - - template<class _Value, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline bool - operator==(const __unordered_set<_Value, _Hash, _Pred, _Alloc, - __cache_hash_code>& __x, - const __unordered_set<_Value, _Hash, _Pred, _Alloc, - __cache_hash_code>& __y) - { return __x._M_equal(__y); } - - template<class _Value, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline bool - operator!=(const __unordered_set<_Value, _Hash, _Pred, _Alloc, - __cache_hash_code>& __x, - const __unordered_set<_Value, _Hash, _Pred, _Alloc, - __cache_hash_code>& __y) - { return !(__x == __y); } - - template<class _Value, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline bool - operator==(const __unordered_multiset<_Value, _Hash, _Pred, _Alloc, - __cache_hash_code>& __x, - const __unordered_multiset<_Value, _Hash, _Pred, _Alloc, - __cache_hash_code>& __y) - { return __x._M_equal(__y); } - - template<class _Value, class _Hash, class _Pred, class _Alloc, - bool __cache_hash_code> - inline bool - operator!=(const __unordered_multiset<_Value, _Hash, _Pred, _Alloc, - __cache_hash_code>& __x, - const __unordered_multiset<_Value, _Hash, _Pred, _Alloc, - __cache_hash_code>& __y) - { return !(__x == __y); } + /// Base types for unordered_set. + template<bool _Cache> + using __uset_traits = __detail::_Hashtable_traits<_Cache, true, true>; + + template<typename _Value, + typename _Hash = hash<_Value>, + typename _Pred = std::equal_to<_Value>, + typename _Alloc = std::allocator<_Value>, + typename _Tr = __uset_traits<__cache_default<_Value, _Hash>::value>> + using __uset_hashtable = _Hashtable<_Value, _Value, _Alloc, + std::_Identity<_Value>, _Pred, _Hash, + __detail::_Mod_range_hashing, + __detail::_Default_ranged_hash, + __detail::_Prime_rehash_policy, _Tr>; + + /// Base types for unordered_multiset. + template<bool _Cache> + using __umset_traits = __detail::_Hashtable_traits<_Cache, true, false>; + + template<typename _Value, + typename _Hash = hash<_Value>, + typename _Pred = std::equal_to<_Value>, + typename _Alloc = std::allocator<_Value>, + typename _Tr = __umset_traits<__cache_default<_Value, _Hash>::value>> + using __umset_hashtable = _Hashtable<_Value, _Value, _Alloc, + std::_Identity<_Value>, + _Pred, _Hash, + __detail::_Mod_range_hashing, + __detail::_Default_ranged_hash, + __detail::_Prime_rehash_policy, _Tr>; /** * @brief A standard container composed of unique keys (containing @@ -267,19 +75,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Meets the requirements of a <a href="tables.html#65">container</a>, and * <a href="tables.html#xx">unordered associative container</a> * - * @param Value Type of key objects. - * @param Hash Hashing function object type, defaults to hash<Value>. - * @param Pred Predicate function object type, defaults to equal_to<Value>. - * @param Alloc Allocator type, defaults to allocator<Key>. + * @tparam _Value Type of key objects. + * @tparam _Hash Hashing function object type, defaults to hash<_Value>. + + * @tparam _Pred Predicate function object type, defaults to + * equal_to<_Value>. + * + * @tparam _Alloc Allocator type, defaults to allocator<_Key>. + * + * Base is _Hashtable, dispatched at compile time via template + * alias __uset_hashtable. */ template<class _Value, class _Hash = hash<_Value>, class _Pred = std::equal_to<_Value>, class _Alloc = std::allocator<_Value> > class unordered_set - : public __unordered_set<_Value, _Hash, _Pred, _Alloc> + : public __uset_hashtable<_Value, _Hash, _Pred, _Alloc> { - typedef __unordered_set<_Value, _Hash, _Pred, _Alloc> _Base; + typedef __uset_hashtable<_Value, _Hash, _Pred, _Alloc> _Base; public: typedef typename _Base::value_type value_type; @@ -287,7 +101,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef typename _Base::hasher hasher; typedef typename _Base::key_equal key_equal; typedef typename _Base::allocator_type allocator_type; - + explicit unordered_set(size_type __n = 10, const hasher& __hf = hasher(), @@ -297,13 +111,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { } template<typename _InputIterator> - unordered_set(_InputIterator __f, _InputIterator __l, + unordered_set(_InputIterator __f, _InputIterator __l, size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), + const hasher& __hf = hasher(), + const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _Base(__f, __l, __n, __hf, __eql, __a) - { } + { } unordered_set(initializer_list<value_type> __l, size_type __n = 0, @@ -312,14 +126,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER const allocator_type& __a = allocator_type()) : _Base(__l.begin(), __l.end(), __n, __hf, __eql, __a) { } - - unordered_set& - operator=(initializer_list<value_type> __l) - { - this->clear(); - this->insert(__l.begin(), __l.end()); - return *this; - } }; /** @@ -332,19 +138,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Meets the requirements of a <a href="tables.html#65">container</a>, and * <a href="tables.html#xx">unordered associative container</a> * - * @param Value Type of key objects. - * @param Hash Hashing function object type, defaults to hash<Value>. - * @param Pred Predicate function object type, defaults to equal_to<Value>. - * @param Alloc Allocator type, defaults to allocator<Key>. + * @tparam _Value Type of key objects. + * @tparam _Hash Hashing function object type, defaults to hash<_Value>. + * @tparam _Pred Predicate function object type, defaults + * to equal_to<_Value>. + * @tparam _Alloc Allocator type, defaults to allocator<_Key>. + * + * Base is _Hashtable, dispatched at compile time via template + * alias __umset_hashtable. */ template<class _Value, class _Hash = hash<_Value>, class _Pred = std::equal_to<_Value>, class _Alloc = std::allocator<_Value> > class unordered_multiset - : public __unordered_multiset<_Value, _Hash, _Pred, _Alloc> + : public __umset_hashtable<_Value, _Hash, _Pred, _Alloc> { - typedef __unordered_multiset<_Value, _Hash, _Pred, _Alloc> _Base; + typedef __umset_hashtable<_Value, _Hash, _Pred, _Alloc> _Base; public: typedef typename _Base::value_type value_type; @@ -352,7 +162,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef typename _Base::hasher hasher; typedef typename _Base::key_equal key_equal; typedef typename _Base::allocator_type allocator_type; - + explicit unordered_multiset(size_type __n = 10, const hasher& __hf = hasher(), @@ -363,13 +173,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template<typename _InputIterator> - unordered_multiset(_InputIterator __f, _InputIterator __l, + unordered_multiset(_InputIterator __f, _InputIterator __l, size_type __n = 0, - const hasher& __hf = hasher(), - const key_equal& __eql = key_equal(), + const hasher& __hf = hasher(), + const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _Base(__f, __l, __n, __hf, __eql, __a) - { } + { } unordered_multiset(initializer_list<value_type> __l, size_type __n = 0, @@ -378,14 +188,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER const allocator_type& __a = allocator_type()) : _Base(__l.begin(), __l.end(), __n, __hf, __eql, __a) { } - - unordered_multiset& - operator=(initializer_list<value_type> __l) - { - this->clear(); - this->insert(__l.begin(), __l.end()); - return *this; - } }; template<class _Value, class _Hash, class _Pred, class _Alloc> @@ -428,4 +230,3 @@ _GLIBCXX_END_NAMESPACE_CONTAINER } // namespace std #endif /* _UNORDERED_SET_H */ - diff --git a/libstdc++-v3/include/debug/forward_list b/libstdc++-v3/include/debug/forward_list index 1f887da432c..8ad4336663e 100644 --- a/libstdc++-v3/include/debug/forward_list +++ b/libstdc++-v3/include/debug/forward_list @@ -409,6 +409,10 @@ namespace __debug _GLIBCXX_DEBUG_VERIFY(&__list != this, _M_message(__gnu_debug::__msg_self_splice) ._M_sequence(*this, "this")); + _GLIBCXX_DEBUG_VERIFY(__list.get_allocator() == this->get_allocator(), + _M_message(__gnu_debug::__msg_splice_alloc) + ._M_sequence(*this) + ._M_sequence(__list, "__list")); this->_M_transfer_from_if(__list, [&__list](_Base_const_iterator __it) { return __it != __list._M_base().cbefore_begin() @@ -418,6 +422,10 @@ namespace __debug } void + splice_after(const_iterator __pos, forward_list& __list) + { splice_after(__pos, std::move(__list)); } + + void splice_after(const_iterator __pos, forward_list&& __list, const_iterator __i) { @@ -429,6 +437,10 @@ namespace __debug _M_message(__gnu_debug::__msg_splice_other) ._M_iterator(__i, "__i") ._M_sequence(__list, "__list")); + _GLIBCXX_DEBUG_VERIFY(__list.get_allocator() == this->get_allocator(), + _M_message(__gnu_debug::__msg_splice_alloc) + ._M_sequence(*this) + ._M_sequence(__list, "__list")); // _GLIBCXX_RESOLVE_LIB_DEFECTS // 250. splicing invalidates iterators @@ -440,6 +452,11 @@ namespace __debug } void + splice_after(const_iterator __pos, forward_list& __list, + const_iterator __i) + { splice_after(__pos, std::move(__list), __i); } + + void splice_after(const_iterator __pos, forward_list&& __list, const_iterator __before, const_iterator __last) { @@ -460,6 +477,10 @@ namespace __debug ._M_sequence(__list, "list") ._M_iterator(__before, "before") ._M_iterator(__last, "last")); + _GLIBCXX_DEBUG_VERIFY(__list.get_allocator() == this->get_allocator(), + _M_message(__gnu_debug::__msg_splice_alloc) + ._M_sequence(*this) + ._M_sequence(__list, "__list")); for (_Base_const_iterator __tmp = std::next(__before.base()); __tmp != __last.base(); ++__tmp) @@ -485,6 +506,11 @@ namespace __debug } void + splice_after(const_iterator __pos, forward_list& __list, + const_iterator __before, const_iterator __last) + { splice_after(__pos, std::move(__list), __before, __last); } + + void remove(const _Tp& __val) { _Base_iterator __x = _Base::before_begin(); @@ -565,6 +591,10 @@ namespace __debug } } + void + merge(forward_list& __list) + { merge(std::move(__list)); } + template<typename _Comp> void merge(forward_list&& __list, _Comp __comp) @@ -584,6 +614,11 @@ namespace __debug } } + template<typename _Comp> + void + merge(forward_list& __list, _Comp __comp) + { merge(std::move(__list), __comp); } + using _Base::sort; using _Base::reverse; @@ -737,8 +772,12 @@ namespace __gnu_debug typedef typename _It::iterator_type _BaseIt; static bool - _M_Is(_BaseIt __it, const _Sequence* __seq) + _S_Is(_BaseIt __it, const _Sequence* __seq) { return __it == __seq->_M_base().cbefore_begin(); } + + static bool + _S_Is_Beginnest(_BaseIt __it, const _Sequence* __seq) + { return _S_Is(__it, __seq); } }; } diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h index b02fa7ab8ff..3cab2d7d8a2 100644 --- a/libstdc++-v3/include/debug/safe_iterator.h +++ b/libstdc++-v3/include/debug/safe_iterator.h @@ -50,8 +50,12 @@ namespace __gnu_debug typedef typename _It::iterator_type _BaseIt; static bool - _M_Is(_BaseIt __it, const _Sequence* __seq) + _S_Is(_BaseIt, const _Sequence*) { return false; } + + static bool + _S_Is_Beginnest(_BaseIt __it, const _Sequence* __seq) + { return __it == __seq->_M_base().begin(); } }; /** Iterators that derive from _Safe_iterator_base but that aren't @@ -465,7 +469,15 @@ namespace __gnu_debug /// any? bool _M_is_before_begin() const { - return _BeforeBeginHelper<_Sequence>::_M_Is(base(), _M_get_sequence()); + return _BeforeBeginHelper<_Sequence>::_S_Is(base(), _M_get_sequence()); + } + + /// Is this iterator equal to the sequence's before_begin() iterator if + /// any or begin() otherwise? + bool _M_is_beginnest() const + { + return _BeforeBeginHelper<_Sequence>::_S_Is_Beginnest(base(), + _M_get_sequence()); } }; diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc b/libstdc++-v3/include/debug/safe_iterator.tcc index 777a707e7f3..f01252bf6c2 100644 --- a/libstdc++-v3/include/debug/safe_iterator.tcc +++ b/libstdc++-v3/include/debug/safe_iterator.tcc @@ -1,6 +1,6 @@ // Debugging iterator implementation (out of line) -*- C++ -*- -// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011 +// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2012 // Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free @@ -91,10 +91,11 @@ namespace __gnu_debug /* We can only test for equality, but check if one of the iterators is at an extreme. */ /* Optim for classic [begin, it) or [it, end) ranges, limit checks - * when code is valid. */ - if (_M_is_begin() || __rhs._M_is_end()) + * when code is valid. Note, for the special case of forward_list, + * before_begin replaces the role of begin. */ + if (_M_is_beginnest() || __rhs._M_is_end()) return true; - if (_M_is_end() || __rhs._M_is_begin()) + if (_M_is_end() || __rhs._M_is_beginnest()) return false; // Assume that this is a valid range; we can't check anything else diff --git a/libstdc++-v3/include/ext/alloc_traits.h b/libstdc++-v3/include/ext/alloc_traits.h index 4862636645e..b3e3af663a6 100644 --- a/libstdc++-v3/include/ext/alloc_traits.h +++ b/libstdc++-v3/include/ext/alloc_traits.h @@ -99,6 +99,7 @@ template<typename _Alloc> typedef typename _Base_type::pointer pointer; typedef typename _Base_type::const_pointer const_pointer; typedef typename _Base_type::size_type size_type; + typedef typename _Base_type::difference_type difference_type; // C++0x allocators do not define reference or const_reference typedef value_type& reference; typedef const value_type& const_reference; @@ -170,6 +171,7 @@ template<typename _Alloc> typedef typename _Alloc::reference reference; typedef typename _Alloc::const_reference const_reference; typedef typename _Alloc::size_type size_type; + typedef typename _Alloc::difference_type difference_type; static pointer allocate(_Alloc& __a, size_type __n) diff --git a/libstdc++-v3/include/ext/functional b/libstdc++-v3/include/ext/functional index 85b944bf61d..f8402c16dc6 100644 --- a/libstdc++-v3/include/ext/functional +++ b/libstdc++-v3/include/ext/functional @@ -1,6 +1,6 @@ // Functional extensions -*- C++ -*- -// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 +// Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2012 // Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free @@ -183,7 +183,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @addtogroup SGIextensions */ template <class _Tp> - struct identity : public std::_Identity<_Tp> {}; + struct identity +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + : public std::unary_function<_Tp,_Tp>, + public std::_Identity<_Tp> {}; +#else + : public std::_Identity<_Tp> {}; +#endif /** @c select1st and @c select2nd are extensions provided by SGI. Their * @c operator()s @@ -197,11 +203,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ /// An \link SGIextensions SGI extension \endlink. template <class _Pair> - struct select1st : public std::_Select1st<_Pair> {}; + struct select1st +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + : public std::unary_function<_Pair, typename _Pair::first_type>, + public std::_Select1st<_Pair> {}; +#else + : public std::_Select1st<_Pair> {}; +#endif /// An \link SGIextensions SGI extension \endlink. template <class _Pair> - struct select2nd : public std::_Select2nd<_Pair> {}; + struct select2nd +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + : public std::unary_function<_Pair, typename _Pair::second_type>, + public std::_Select2nd<_Pair> {}; +#else + : public std::_Select2nd<_Pair> {}; +#endif /** @} */ // extension documented next diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 41022630837..c03b7bd64bb 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -1147,30 +1147,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public __is_nt_move_assignable_impl<_Tp> { }; - /// has_trivial_default_constructor + /// is_trivially_constructible (still unimplemented) + + /// is_trivially_default_constructible (still unimplemented) + + /// is_trivially_copy_constructible (still unimplemented) + + /// is_trivially_move_constructible (still unimplemented) + + /// is_trivially_assignable (still unimplemented) + + /// is_trivially_copy_assignable (still unimplemented) + + /// is_trivially_move_assignable (still unimplemented) + + /// is_trivially_destructible + template<typename _Tp> + struct is_trivially_destructible + : public __and_<is_destructible<_Tp>, integral_constant<bool, + __has_trivial_destructor(_Tp)>>::type + { }; + + /// has_trivial_default_constructor (temporary legacy) template<typename _Tp> struct has_trivial_default_constructor : public integral_constant<bool, __has_trivial_constructor(_Tp)> { }; - /// has_trivial_copy_constructor + /// has_trivial_copy_constructor (temporary legacy) template<typename _Tp> struct has_trivial_copy_constructor : public integral_constant<bool, __has_trivial_copy(_Tp)> { }; - /// has_trivial_copy_assign + /// has_trivial_copy_assign (temporary legacy) template<typename _Tp> struct has_trivial_copy_assign : public integral_constant<bool, __has_trivial_assign(_Tp)> { }; - /// has_trivial_destructor - template<typename _Tp> - struct has_trivial_destructor - : public integral_constant<bool, __has_trivial_destructor(_Tp)> - { }; - /// has_virtual_destructor template<typename _Tp> struct has_virtual_destructor @@ -1266,12 +1281,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __is_convertible_helper<_From, _To>::value> { }; - /// is_explicitly_convertible - template<typename _From, typename _To> - struct is_explicitly_convertible - : public is_constructible<_To, _From> - { }; - // const-volatile modifications. diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py index 76c54b1598e..4520f32ac13 100644 --- a/libstdc++-v3/python/libstdcxx/v6/printers.py +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py @@ -611,7 +611,7 @@ class StdStringPrinter: class Tr1HashtableIterator: def __init__ (self, hash): self.node = hash['_M_before_begin']['_M_nxt'] - self.node_type = find_type(hash.type, '_Node').pointer() + self.node_type = find_type(hash.type, '__node_type').pointer() def __iter__ (self): return self diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc index 0c746c1fc37..f0ab4bc4ec6 100644 --- a/libstdc++-v3/src/c++11/debug.cc +++ b/libstdc++-v3/src/c++11/debug.cc @@ -131,7 +131,7 @@ namespace __gnu_debug "attempt to flip a singular bitset reference", // std::list checks "attempt to splice a list into itself", - "attempt to splice lists with inequal allocators", + "attempt to splice lists with unequal allocators", "attempt to splice elements referenced by a %1.state; iterator", "attempt to splice an iterator from a different container", "splice destination %1.name;" diff --git a/libstdc++-v3/src/c++98/mt_allocator.cc b/libstdc++-v3/src/c++98/mt_allocator.cc index 16c2fb8063e..92f252be79b 100644 --- a/libstdc++-v3/src/c++98/mt_allocator.cc +++ b/libstdc++-v3/src/c++98/mt_allocator.cc @@ -1,6 +1,7 @@ // Allocator details. -// Copyright (C) 2004, 2005, 2006, 2009, 2010 Free Software Foundation, Inc. +// Copyright (C) 2004, 2005, 2006, 2009, 2010, 2012 +// Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -48,6 +49,7 @@ namespace { __gthread_key_delete(_M_key); ::operator delete(static_cast<void*>(_M_thread_freelist_array)); + _M_thread_freelist = 0; } } }; diff --git a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc index eafbe5f6666..0839e246df3 100644 --- a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc +++ b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc @@ -2,7 +2,7 @@ // { dg-do compile } // 2009-11-12 Paolo Carlini <paolo.carlini@oracle.com> // -// Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. +// Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -19,7 +19,7 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// { dg-error "static assertion failed" "" { target *-*-* } 1777 } +// { dg-error "static assertion failed" "" { target *-*-* } 1786 } #include <utility> diff --git a/libstdc++-v3/testsuite/20_util/hash/52931.cc b/libstdc++-v3/testsuite/20_util/hash/52931.cc new file mode 100644 index 00000000000..f30a3e7d17a --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/hash/52931.cc @@ -0,0 +1,32 @@ +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. +// +// This library 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <type_traits> +#include <functional> + +class S{}; // No hash specialization + +template<class T> +auto f(int) -> decltype(std::hash<T>(), std::true_type()); + +template<class T> +auto f(...) -> decltype(std::false_type()); + +static_assert(!decltype(f<S>(0))::value, ""); diff --git a/libstdc++-v3/testsuite/20_util/is_explicitly_convertible/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/20_util/is_trivially_destructible/requirements/explicit_instantiation.cc index 87dd950b27d..c6ab0b2c54e 100644 --- a/libstdc++-v3/testsuite/20_util/is_explicitly_convertible/requirements/explicit_instantiation.cc +++ b/libstdc++-v3/testsuite/20_util/is_trivially_destructible/requirements/explicit_instantiation.cc @@ -1,9 +1,9 @@ -// { dg-options "-std=gnu++0x" } +// { dg-options "-std=gnu++11" } // { dg-do compile } - -// 2009-12-30 Paolo Carlini <paolo.carlini@oracle.com> - -// Copyright (C) 2009 Free Software Foundation, Inc. +// +// 2012-04-15 Paolo Carlini <paolo.carlini@oracle.com> +// +// Copyright (C) 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -27,5 +27,5 @@ namespace std { typedef short test_type; - template struct is_explicitly_convertible<test_type, test_type>; + template struct is_trivially_destructible<test_type>; } diff --git a/libstdc++-v3/testsuite/20_util/is_explicitly_convertible/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/is_trivially_destructible/requirements/typedefs.cc index 52ba964b1fd..66b3f7bd920 100644 --- a/libstdc++-v3/testsuite/20_util/is_explicitly_convertible/requirements/typedefs.cc +++ b/libstdc++-v3/testsuite/20_util/is_trivially_destructible/requirements/typedefs.cc @@ -1,9 +1,8 @@ -// { dg-options "-std=gnu++0x" } -// { dg-do compile } - -// 2009-12-30 Paolo Carlini <paolo.carlini@oracle.com> +// { dg-options "-std=gnu++11" } +// +// 2012-04-15 Paolo Carlini <paolo.carlini@oracle.com> // -// Copyright (C) 2009 Free Software Foundation, Inc. +// Copyright (C) 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -25,12 +24,14 @@ #include <type_traits> +// { dg-do compile } + void test01() { // Check for required typedefs - typedef std::is_explicitly_convertible<int, int> test_type; - typedef test_type::value_type value_type; - typedef test_type::type type; - typedef test_type::type::value_type type_value_type; - typedef test_type::type::type type_type; + typedef std::is_trivially_destructible<int> test_type; + typedef test_type::value_type value_type; + typedef test_type::type type; + typedef test_type::type::value_type type_value_type; + typedef test_type::type::type type_type; } diff --git a/libstdc++-v3/testsuite/20_util/is_explicitly_convertible/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_destructible/value.cc index 7e704873275..cfba8aeba9e 100644 --- a/libstdc++-v3/testsuite/20_util/is_explicitly_convertible/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_trivially_destructible/value.cc @@ -1,6 +1,8 @@ -// { dg-options "-std=gnu++0x" } - -// Copyright (C) 2009 Free Software Foundation, Inc. +// { dg-options "-std=gnu++11" } +// +// 2012-04-15 Paolo Carlini <paolo.carlini@oracle.com> +// +// Copyright (C) 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -24,18 +26,15 @@ void test01() { bool test __attribute__((unused)) = true; - using std::is_explicitly_convertible; + using std::is_trivially_destructible; using namespace __gnu_test; - // Positive tests. - VERIFY( (test_relationship<is_explicitly_convertible, double&, - ExplicitClass>(true)) ); - VERIFY( (test_relationship<is_explicitly_convertible, int&, - ExplicitClass>(true)) ); + VERIFY( (test_category<is_trivially_destructible, int>(true)) ); + VERIFY( (test_category<is_trivially_destructible, TType>(true)) ); + VERIFY( (test_category<is_trivially_destructible, PODType>(true)) ); - // Negative tests. - VERIFY( (test_relationship<is_explicitly_convertible, void*, - ExplicitClass>(false)) ); + VERIFY( (test_category<is_trivially_destructible, NType>(false)) ); + VERIFY( (test_category<is_trivially_destructible, SLType>(false)) ); } int main() diff --git a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc index 6358d72c4a5..09ab111b796 100644 --- a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc +++ b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc @@ -3,7 +3,8 @@ // 2007-05-03 Benjamin Kosnik <bkoz@redhat.com> // -// Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 +// Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -42,11 +43,11 @@ void test01() typedef make_signed<float>::type test5_type; } -// { dg-error "does not name a type" "" { target *-*-* } 33 } -// { dg-error "required from here" "" { target *-*-* } 35 } -// { dg-error "required from here" "" { target *-*-* } 37 } -// { dg-error "required from here" "" { target *-*-* } 40 } -// { dg-error "required from here" "" { target *-*-* } 42 } +// { dg-error "does not name a type" "" { target *-*-* } 34 } +// { dg-error "required from here" "" { target *-*-* } 36 } +// { dg-error "required from here" "" { target *-*-* } 38 } +// { dg-error "required from here" "" { target *-*-* } 41 } +// { dg-error "required from here" "" { target *-*-* } 43 } -// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1566 } -// { dg-error "declaration of" "" { target *-*-* } 1530 } +// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1575 } +// { dg-error "declaration of" "" { target *-*-* } 1539 } diff --git a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc index d9a0f178f6c..574a9bb05ca 100644 --- a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc +++ b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc @@ -3,7 +3,8 @@ // 2007-05-03 Benjamin Kosnik <bkoz@redhat.com> // -// Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 +// Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -42,11 +43,11 @@ void test01() typedef make_unsigned<float>::type test5_type; } -// { dg-error "does not name a type" "" { target *-*-* } 33 } -// { dg-error "required from here" "" { target *-*-* } 35 } -// { dg-error "required from here" "" { target *-*-* } 37 } -// { dg-error "required from here" "" { target *-*-* } 40 } -// { dg-error "required from here" "" { target *-*-* } 42 } +// { dg-error "does not name a type" "" { target *-*-* } 34 } +// { dg-error "required from here" "" { target *-*-* } 36 } +// { dg-error "required from here" "" { target *-*-* } 38 } +// { dg-error "required from here" "" { target *-*-* } 41 } +// { dg-error "required from here" "" { target *-*-* } 43 } -// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1484 } -// { dg-error "declaration of" "" { target *-*-* } 1448 } +// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1493 } +// { dg-error "declaration of" "" { target *-*-* } 1457 } diff --git a/libstdc++-v3/testsuite/20_util/pair/requirements/dr801.cc b/libstdc++-v3/testsuite/20_util/pair/requirements/dr801.cc index 36d380dcf87..e7d6626becd 100644 --- a/libstdc++-v3/testsuite/20_util/pair/requirements/dr801.cc +++ b/libstdc++-v3/testsuite/20_util/pair/requirements/dr801.cc @@ -1,7 +1,7 @@ // { dg-do compile } // { dg-options "-std=gnu++0x" } -// Copyright (C) 2010 Free Software Foundation, Inc. +// Copyright (C) 2010, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -29,7 +29,7 @@ void test_trivial() // static_assert(std::is_literal_type<pair_type>::value, "! literal"); static_assert(std::has_trivial_copy_constructor<pair_type>::value, "! triv copy"); - static_assert(std::has_trivial_destructor<pair_type>::value, + static_assert(std::is_trivially_destructible<pair_type>::value, "! triv destructor"); // static_assert(std::is_standard_layout<pair_type>::value, // "! standard layout"); diff --git a/libstdc++-v3/testsuite/20_util/pointer_traits/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/pointer_traits/requirements/typedefs.cc index c682557a0e3..47b5212ff01 100644 --- a/libstdc++-v3/testsuite/20_util/pointer_traits/requirements/typedefs.cc +++ b/libstdc++-v3/testsuite/20_util/pointer_traits/requirements/typedefs.cc @@ -32,6 +32,7 @@ void test01() typedef typename test_type::pointer pointer; typedef typename test_type::element_type element_type; typedef typename test_type::difference_type difference_type; + typedef typename test_type::template rebind<char> rebind_type; } int main() diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc index 39f9ce3b42e..d2110ca8b39 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc @@ -32,9 +32,9 @@ void test01() { X* px = 0; std::shared_ptr<X> p1(px); // { dg-error "here" } - // { dg-error "incomplete" "" { target *-*-* } 771 } + // { dg-error "incomplete" "" { target *-*-* } 775 } std::shared_ptr<X> p9(ap()); // { dg-error "here" } - // { dg-error "incomplete" "" { target *-*-* } 865 } + // { dg-error "incomplete" "" { target *-*-* } 869 } } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/52924.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/52924.cc new file mode 100644 index 00000000000..0cd6bad6401 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/52924.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++0x" } +// { dg-do compile } + +// Copyright (C) 2012 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <memory> + +// libstdc++/52924 + +struct A { } a; + +struct D { + ~D() noexcept(false) { } + void operator()(A*) { } +} d; + +auto sp = std::shared_ptr<A>(&a, d); + +template<typename T> +struct Alloc : std::allocator<T> +{ + Alloc() = default; + ~Alloc() noexcept(false) { } + template<typename U> Alloc(const Alloc<U>&) { } +}; + +Alloc<A> al; + +auto as = std::allocate_shared<A>(al); diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/808590.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/808590.cc new file mode 100644 index 00000000000..7ccd8da6b3f --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/808590.cc @@ -0,0 +1,48 @@ +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <vector> +#include <stdexcept> + +// 4.4.x only +struct c +{ + void *m; + + c(void* o = 0) : m(o) {} + c(const c &r) : m(r.m) {} + + template<class T> + explicit c(T &o) : m((void*)0xdeadfbeef) { } +}; + +int main() +{ + std::vector<c> cbs; + const c cb((void*)0xcafebabe); + + for (int fd = 62; fd < 67; ++fd) + { + cbs.resize(fd + 1); + cbs[fd] = cb; + } + + for (int fd = 62; fd< 67; ++fd) + if (cb.m != cbs[fd].m) + throw std::runtime_error("wrong"); + return 0; +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/requirements/dr801.cc b/libstdc++-v3/testsuite/20_util/tuple/requirements/dr801.cc index fd21b9ee5c5..879bfd126bb 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/requirements/dr801.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/requirements/dr801.cc @@ -29,7 +29,7 @@ void test_trivial() // static_assert(std::is_literal_type<tuple_type>::value, "! literal"); static_assert(std::has_trivial_copy_constructor<tuple_type>::value, "! triv copy"); - static_assert(std::has_trivial_destructor<tuple_type>::value, + static_assert(std::is_trivially_destructible<tuple_type>::value, "! triv destructor"); // static_assert(std::is_standard_layout<tuple_type>::value, // "! standard layout"); diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after.cc b/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after.cc index 60297551dcd..4cc1cfcf78d 100644 --- a/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after.cc +++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after.cc @@ -1,6 +1,6 @@ // { dg-options "-std=gnu++0x" } -// Copyright (C) 2010 Free Software Foundation, Inc. +// Copyright (C) 2010, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -34,6 +34,10 @@ test01() VERIFY( before == fl1.before_begin() ); VERIFY( end == fl1.end() ); + + // no-op just to check that debug mode does not see any problem with it. + fl1.splice_after(fl1.before_begin(), std::move(fl2), + fl2.before_begin(), fl2.begin()); } int diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after5_neg.cc b/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after5_neg.cc new file mode 100644 index 00000000000..6b7d0da8815 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after5_neg.cc @@ -0,0 +1,41 @@ +// { dg-options "-std=gnu++0x" } +// { dg-require-debug-mode "" } +// { dg-do run { xfail *-*-* } } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <forward_list> +#include <testsuite_allocator.h> + +void +test01() +{ + typedef __gnu_test::uneq_allocator<int> alloc_type; + + std::forward_list<int, alloc_type> fl1({1, 2, 3}, alloc_type(1)); + std::forward_list<int, alloc_type> fl2({1, 2, 3}, alloc_type(2)); + + fl1.splice_after(fl1.before_begin(), fl2); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after6_neg.cc b/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after6_neg.cc new file mode 100644 index 00000000000..620bb5c92cd --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after6_neg.cc @@ -0,0 +1,41 @@ +// { dg-options "-std=gnu++0x" } +// { dg-require-debug-mode "" } +// { dg-do run { xfail *-*-* } } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <forward_list> +#include <testsuite_allocator.h> + +void +test01() +{ + typedef __gnu_test::uneq_allocator<int> alloc_type; + + std::forward_list<int, alloc_type> fl1({1, 2, 3}, alloc_type(1)); + std::forward_list<int, alloc_type> fl2({1, 2, 3}, alloc_type(2)); + + fl1.splice_after(fl1.before_begin(), fl2, fl2.begin()); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after7_neg.cc b/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after7_neg.cc new file mode 100644 index 00000000000..a2b5cfad949 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/splice_after7_neg.cc @@ -0,0 +1,41 @@ +// { dg-options "-std=gnu++0x" } +// { dg-require-debug-mode "" } +// { dg-do run { xfail *-*-* } } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <forward_list> +#include <testsuite_allocator.h> + +void +test01() +{ + typedef __gnu_test::uneq_allocator<int> alloc_type; + + std::forward_list<int, alloc_type> fl1({1, 2, 3}, alloc_type(1)); + std::forward_list<int, alloc_type> fl2({1, 2, 3}, alloc_type(2)); + + fl1.splice_after(fl1.before_begin(), fl2, fl2.begin(), fl2.end()); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/6.cc b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/6.cc new file mode 100644 index 00000000000..e160381a776 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/modifiers/6.cc @@ -0,0 +1,94 @@ +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <forward_list> + +#include <testsuite_hooks.h> + +void test01() +{ + bool test __attribute__((unused)) = true; + + std::forward_list<int> fl1(1, 5), fl2(1, 4), fl3(1, 3), + fl4(1, 2), fl5(1, 1), fl6(1, 0); + + fl1.splice_after(fl1.before_begin(), fl2); + + auto it = fl1.begin(); + + VERIFY( *it == 4 ); + + ++it; + + VERIFY( *it == 5 ); + + fl3.splice_after(fl3.before_begin(), fl4, fl4.before_begin()); + + it = fl3.begin(); + + VERIFY( *it == 2 ); + + ++it; + + VERIFY( *it == 3 ); + + fl5.splice_after(fl5.before_begin(), fl6, fl6.before_begin(), fl6.end()); + + it = fl5.begin(); + + VERIFY( *it == 0 ); + + ++it; + + VERIFY( *it == 1 ); + + fl1.merge(fl2); + + it = fl1.begin(); + + VERIFY( *it == 4 ); + + ++it; + + VERIFY( *it == 5 ); + + fl1.merge(fl3, std::less<int>()); + + it = fl1.begin(); + + VERIFY( *it == 2 ); + + ++it; + + VERIFY( *it == 3 ); + + ++it; + + VERIFY( *it == 4 ); + + ++it; + + VERIFY( *it == 5 ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/operations/1.cc b/libstdc++-v3/testsuite/23_containers/forward_list/operations/1.cc index 5a996f3411e..4a9e3644527 100644 --- a/libstdc++-v3/testsuite/23_containers/forward_list/operations/1.cc +++ b/libstdc++-v3/testsuite/23_containers/forward_list/operations/1.cc @@ -1,6 +1,6 @@ // { dg-options "-std=gnu++0x" } -// Copyright (C) 2008, 2009 Free Software Foundation, Inc. +// Copyright (C) 2008, 2009, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -68,7 +68,7 @@ test02() VERIFY(*befy == 10.0); ++befy; - VERIFY(*befy == 15.0); + VERIFY(*befy == 14.0); } // This test verifies the following: diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/52942.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/52942.cc new file mode 100644 index 00000000000..bf05fab0d28 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/52942.cc @@ -0,0 +1,37 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <unordered_map> +#include <functional> + +struct TFoo {}; + +struct TFoo_hash +{ + std::size_t operator()(const TFoo &) const { return 0; } +}; + +void f1(std::unordered_map<TFoo, int, TFoo_hash> &) {} + +void f2() +{ + std::unordered_map<TFoo, int, TFoo_hash> map1; + std::bind(f1, std::ref(map1)); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53067.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53067.cc new file mode 100644 index 00000000000..704f5998c0d --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/requirements/53067.cc @@ -0,0 +1,28 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <unordered_map> +#include <functional> + +void f() +{ + std::unordered_map<int, int> Foo; + ref(Foo); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/instantiation_neg.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/instantiation_neg.cc index eb16e81a4d3..ac304776cad 100644 --- a/libstdc++-v3/testsuite/23_containers/unordered_set/instantiation_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/instantiation_neg.cc @@ -2,7 +2,7 @@ // { dg-options "-std=gnu++0x" } // { dg-require-normal-mode "" } -// Copyright (C) 2011 Free Software Foundation, Inc. +// Copyright (C) 2011, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -19,7 +19,7 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// { dg-error "static assertion failed" "" { target *-*-* } 185 } +// { dg-error "with noexcept" "" { target *-*-* } 248 } #include <unordered_set> @@ -35,7 +35,10 @@ namespace void test01() { - std::__unordered_set<int, hash_without_noexcept, - std::equal_to<int>, std::allocator<int>, - false> us; + using traits = std::__detail::_Hashtable_traits<false, true, true>; + using hashtable = std::__uset_hashtable<int, hash_without_noexcept, + std::equal_to<int>, + std::allocator<int>, traits>; + + hashtable ht; } diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/requirements/52942.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/requirements/52942.cc new file mode 100644 index 00000000000..067e57a5e26 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/requirements/52942.cc @@ -0,0 +1,37 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <unordered_set> +#include <functional> + +struct TFoo {}; + +struct TFoo_hash +{ + std::size_t operator()(const TFoo &) const { return 0; } +}; + +void f1(std::unordered_set<TFoo, TFoo_hash> &) {} + +void f2() +{ + std::unordered_set<TFoo, TFoo_hash> set1; + std::bind(f1, std::ref(set1)); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/requirements/53067.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/requirements/53067.cc new file mode 100644 index 00000000000..760f10c7e85 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/requirements/53067.cc @@ -0,0 +1,28 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <unordered_set> +#include <functional> + +void f() +{ + std::unordered_set<int> Foo; + ref(Foo); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/stable_partition/moveable.cc b/libstdc++-v3/testsuite/25_algorithms/stable_partition/moveable.cc index b649b10e3cd..95d50061879 100644 --- a/libstdc++-v3/testsuite/25_algorithms/stable_partition/moveable.cc +++ b/libstdc++-v3/testsuite/25_algorithms/stable_partition/moveable.cc @@ -35,6 +35,11 @@ const int A[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; const int B[] = {2, 4, 6, 8, 10, 12, 14, 16, 1, 3, 5, 7, 9, 11, 13, 15, 17}; const int N = sizeof(A) / sizeof(int); +// Check that starting with a true predicate works too. (PR52822) +const int A2[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; +const int B2[] = {2, 4, 6, 8, 10, 12, 14, 16, 3, 5, 7, 9, 11, 13, 15, 17}; +const int N2 = sizeof(A2) / sizeof(int); + struct Pred { bool @@ -42,7 +47,7 @@ struct Pred { return (x.val % 2) == 0; } }; -// 25.2.12 stable_partition() +// 25.2.12 stable_partition(), starting with a false predicate. void test01() { @@ -56,9 +61,24 @@ test01() VERIFY( std::equal(s1, s1 + N, B) ); } +// 25.2.12 stable_partition(), starting with a true predicate. +void +test02() +{ + bool test __attribute__((unused)) = true; + + rvalstruct s1[N2]; + std::copy(A2, A2 + N2, s1); + Container con(s1, s1 + N2); + + std::stable_partition(con.begin(), con.end(), Pred()); + VERIFY( std::equal(s1, s1 + N2, B2) ); +} + int main() { test01(); + test02(); return 0; } diff --git a/libstdc++-v3/testsuite/25_algorithms/stable_partition/pr52822.cc b/libstdc++-v3/testsuite/25_algorithms/stable_partition/pr52822.cc new file mode 100644 index 00000000000..c5f95f36779 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/stable_partition/pr52822.cc @@ -0,0 +1,43 @@ +// { dg-options "-std=gnu++0x" } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without Pred 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// 25.2.12 [lib.alg.partitions] Partitions. + +#include <algorithm> +#include <vector> +#include <testsuite_hooks.h> + +bool true_vector_pred(const std::vector<int>&) { return true; } + +void +test01() +{ + std::vector<std::vector<int> > v(1); + v[0].push_back(7); + VERIFY( v[0].size() == 1 ); + std::stable_partition(v.begin(), v.end(), &true_vector_pred); + VERIFY( v[0].size() == 1 ); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/26_numerics/cmath/51083.cc b/libstdc++-v3/testsuite/26_numerics/headers/cmath/51083.cc index 8ba9b10e5d8..8ba9b10e5d8 100644 --- a/libstdc++-v3/testsuite/26_numerics/cmath/51083.cc +++ b/libstdc++-v3/testsuite/26_numerics/headers/cmath/51083.cc diff --git a/libstdc++-v3/testsuite/Makefile.am b/libstdc++-v3/testsuite/Makefile.am index 7094ad52991..0cf8de501c8 100644 --- a/libstdc++-v3/testsuite/Makefile.am +++ b/libstdc++-v3/testsuite/Makefile.am @@ -134,7 +134,7 @@ check-DEJAGNU $(check_DEJAGNU_normal_targets): check-DEJAGNU%: site.exp normal0) \ if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \ $$runtest $(AM_RUNTESTFLAGS) $(RUNTESTDEFAULTFLAGS) \ - $(RUNTESTFLAGS) abi.exp; \ + $(RUNTESTFLAGS) abi.exp prettyprinters.exp; \ else echo "WARNING: could not find \`runtest'" 1>&2; :;\ fi; \ dirs="`cd $$srcdir; echo [013-9][0-9]_*/*`";; \ diff --git a/libstdc++-v3/testsuite/Makefile.in b/libstdc++-v3/testsuite/Makefile.in index 0bef85abb8c..5cf725490b5 100644 --- a/libstdc++-v3/testsuite/Makefile.in +++ b/libstdc++-v3/testsuite/Makefile.in @@ -578,7 +578,7 @@ check-DEJAGNU $(check_DEJAGNU_normal_targets): check-DEJAGNU%: site.exp normal0) \ if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \ $$runtest $(AM_RUNTESTFLAGS) $(RUNTESTDEFAULTFLAGS) \ - $(RUNTESTFLAGS) abi.exp; \ + $(RUNTESTFLAGS) abi.exp prettyprinters.exp; \ else echo "WARNING: could not find \`runtest'" 1>&2; :;\ fi; \ dirs="`cd $$srcdir; echo [013-9][0-9]_*/*`";; \ diff --git a/libstdc++-v3/testsuite/lib/prune.exp b/libstdc++-v3/testsuite/lib/prune.exp index a5644061d23..a2371c60d5f 100644 --- a/libstdc++-v3/testsuite/lib/prune.exp +++ b/libstdc++-v3/testsuite/lib/prune.exp @@ -32,6 +32,12 @@ proc dg-prune-output { args } { proc libstdc++-dg-prune { system text } { global additional_prunes +# send_user "Before:$text\n" + + # Ignore caret diagnostics. Unfortunately dejaGNU trims leading + # spaces, so one cannot rely on them being present. + regsub -all "(^|\n)\[^\n\]+\n *\\^\n" $text "\n" text + # Cygwin warns about -ffunction-sections regsub -all "(^|\n)\[^\n\]*: -ffunction-sections may affect debugging on some targets\[^\n\]*" $text "" text @@ -68,5 +74,6 @@ proc libstdc++-dg-prune { system text } { } } +# send_user "After:$text\n" return $text } diff --git a/libstdc++-v3/testsuite/performance/30_threads/future/polling.cc b/libstdc++-v3/testsuite/performance/30_threads/future/polling.cc index 83fde27100f..26cf632e429 100644 --- a/libstdc++-v3/testsuite/performance/30_threads/future/polling.cc +++ b/libstdc++-v3/testsuite/performance/30_threads/future/polling.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2009, 2010 Free Software Foundation, Inc. +// Copyright (C) 2009, 2010, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -22,7 +22,7 @@ inline bool is_ready(std::shared_future<void>& f) { - return f.wait_for(std::chrono::microseconds(1)); + return f.wait_for(std::chrono::microseconds(1)) == std::future_status::ready; } void poll(std::shared_future<void> f) diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc index a0294c694cd..4721ccd6042 100644 --- a/libstdc++-v3/testsuite/util/testsuite_abi.cc +++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc @@ -530,7 +530,7 @@ compare_symbols(const char* baseline_file, const char* test_file, } } - cout << "\n\t\t=== libstdc++-v3 check-abi Summary ===" << endl; + cout << "\n\t\t==== libstdc++-v3 check-abi Summary ====" << endl; cout << endl; cout << "# of added symbols:\t\t " << added_names.size() << endl; cout << "# of missing symbols:\t\t " << missing_names.size() << endl; diff --git a/libstdc++-v3/testsuite/util/testsuite_common_types.h b/libstdc++-v3/testsuite/util/testsuite_common_types.h index 03be0acac25..c9be94d8f21 100644 --- a/libstdc++-v3/testsuite/util/testsuite_common_types.h +++ b/libstdc++-v3/testsuite/util/testsuite_common_types.h @@ -549,7 +549,7 @@ namespace __gnu_test typedef std::has_trivial_default_constructor<_Tp> ctor_p; static_assert(ctor_p::value, "default constructor not trivial"); - typedef std::has_trivial_destructor<_Tp> dtor_p; + typedef std::is_trivially_destructible<_Tp> dtor_p; static_assert(dtor_p::value, "destructor not trivial"); } }; |