summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-07-25 05:49:31 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-07-25 05:49:31 +0000
commitabe9b8fe3bba6eeaa83f40f2a72ced6ff1020e58 (patch)
tree3a8fe60232cfdfa19c991a924860ac2eabd4d60d /gcc
parent6894bbe64f107255663b0e2514f3a8b778174f2b (diff)
downloadgcc-abe9b8fe3bba6eeaa83f40f2a72ced6ff1020e58.tar.gz
2011-07-25 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 176732 using svnmerge. 2011-07-25 Basile Starynkevitch <basile@starynkevitch.net> * gcc/melt-build.tpl (warmelt-upgrade-translator, meltrun-generate): Use $(WARMELT_LAST). * gcc/melt-built.mk: Regenerate. * gcc/Makefile.in (upgrade-warmelt): Depend upon $(WARMELT_LAST). Merged with trunk. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@176733 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog444
-rw-r--r--gcc/ChangeLog.MELT6
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/Makefile.in11
-rw-r--r--gcc/ada/ChangeLog49
-rw-r--r--gcc/ada/gcc-interface/Makefile.in1
-rw-r--r--gcc/ada/gcc-interface/decl.c55
-rw-r--r--gcc/ada/gcc-interface/gigi.h17
-rw-r--r--gcc/ada/gcc-interface/trans.c164
-rw-r--r--gcc/ada/gcc-interface/utils.c65
-rw-r--r--gcc/ada/gcc-interface/utils2.c42
-rw-r--r--gcc/ada/init.c33
-rw-r--r--gcc/ada/tracebak.c4
-rw-r--r--gcc/basic-block.h39
-rw-r--r--gcc/bb-reorder.c187
-rw-r--r--gcc/c-decl.c8
-rw-r--r--gcc/c-family/ChangeLog24
-rw-r--r--gcc/c-family/c-common.c40
-rw-r--r--gcc/c-family/c-common.h1
-rw-r--r--gcc/c-family/c-opts.c3
-rw-r--r--gcc/c-family/c-pragma.c49
-rw-r--r--gcc/c-family/c-pretty-print.c6
-rw-r--r--gcc/c-family/c.opt4
-rw-r--r--gcc/cfg.c2
-rw-r--r--gcc/cfgrtl.c32
-rw-r--r--gcc/cgraphunit.c24
-rw-r--r--gcc/collect2.c19
-rw-r--r--gcc/common.opt8
-rw-r--r--gcc/config.gcc30
-rw-r--r--gcc/config/arm/arm.c2
-rw-r--r--gcc/config/i386/i386.c89
-rw-r--r--gcc/config/rs6000/rs6000.c11
-rw-r--r--gcc/config/sol2-c.c5
-rwxr-xr-xgcc/configure179
-rw-r--r--gcc/configure.ac11
-rw-r--r--gcc/cp/ChangeLog31
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/decl.c2
-rw-r--r--gcc/cp/error.c5
-rw-r--r--gcc/cp/name-lookup.c64
-rw-r--r--gcc/cp/parser.c18
-rw-r--r--gcc/cp/typeck2.c6
-rw-r--r--gcc/doc/invoke.texi33
-rw-r--r--gcc/dwarf2cfi.c1725
-rw-r--r--gcc/dwarf2out.c711
-rw-r--r--gcc/dwarf2out.h5
-rw-r--r--gcc/except.c166
-rw-r--r--gcc/except.h1
-rw-r--r--gcc/fortran/ChangeLog31
-rw-r--r--gcc/fortran/gfortran.texi2
-rw-r--r--gcc/fortran/resolve.c8
-rw-r--r--gcc/fortran/trans-array.c33
-rw-r--r--gcc/fortran/trans-array.h2
-rw-r--r--gcc/fortran/trans-openmp.c18
-rw-r--r--gcc/fortran/trans-stmt.c104
-rw-r--r--gcc/fortran/trans.c188
-rw-r--r--gcc/fortran/trans.h7
-rw-r--r--gcc/gcc.c4
-rw-r--r--gcc/graphite-clast-to-gimple.c779
-rw-r--r--gcc/graphite-clast-to-gimple.h12
-rw-r--r--gcc/graphite-dependences.c9
-rw-r--r--gcc/graphite-ppl.h11
-rw-r--r--gcc/jump.c150
-rw-r--r--gcc/melt-build.mk60
-rw-r--r--gcc/melt-build.tpl18
-rw-r--r--gcc/testsuite/ChangeLog65
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/decltype21.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist17.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist36.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist5.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist52.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist55.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/initlist7.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/override1.C1
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/override3.C24
-rw-r--r--gcc/testsuite/g++.dg/opt/builtins2.C11
-rw-r--r--gcc/testsuite/g++.dg/other/error27.C12
-rw-r--r--gcc/testsuite/g++.dg/other/pragma-re-1.C38
-rw-r--r--gcc/testsuite/gcc.dg/graphite/run-id-pr47654.c24
-rw-r--r--gcc/testsuite/gcc.dg/pr45819.c20
-rw-r--r--gcc/testsuite/gcc.dg/pr49705.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-vzeroupper-16.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-vzeroupper-17.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-vzeroupper-18.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr43662.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr43869.c2
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/callabi/callabi.exp2
-rw-r--r--gcc/testsuite/gfortran.dg/coarray_25.f9018
-rw-r--r--gcc/testsuite/gfortran.dg/coarray_4.f902
-rw-r--r--gcc/testsuite/gfortran.dg/namelist_72.f33
-rw-r--r--gcc/testsuite/lib/target-supports.exp45
-rw-r--r--gcc/toplev.c4
-rw-r--r--gcc/tree-cfg.c2
-rw-r--r--gcc/tree-ssa-forwprop.c8
-rw-r--r--gcc/tree-ssa-reassoc.c11
-rw-r--r--gcc/var-tracking.c3
96 files changed, 4276 insertions, 1980 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b9d95fa5b6e..31c140d9d35 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,447 @@
+2011-07-24 Richard Henderson <rth@redhat.com>
+
+ PR debug/49831
+ * dwarf2cfi.c (connect_traces): Allow unvisited traces. Skip
+ them entirely.
+
+2011-07-24 Richard Henderson <rth@redhat.com>
+
+ PR debug/49825
+ * dwarf2cfi.c (dwarf2out_stack_adjust): Move A_O_A test earlier.
+ (dwarf2out_notice_stack_adjust): Use args_size from call_insn.
+
+2011-07-24 Richard Henderson <rth@redhat.com>
+
+ PR debug/49827
+ * dwarf2cfi.c (create_trace_edges): Handle sequences properly.
+
+2011-07-24 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c (maybe_record_trace_start): Add abnormal parameter.
+ Zero args_size for abnormal edges. Adjust all callers.
+
+2011-07-24 Richard Henderson <rth@redhat.com>
+
+ PR debug/49825
+ * dwarf2cfi.c (cfi_row_equal_p): Don't compare args_size.
+
+2011-07-24 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR bootstrap/49835
+ * collect2.c (demangle_flag): Removed.
+
+2011-07-24 Sandra Loosemore <sandra@codesourcery.com>
+
+ * configure.ac (demangler_in_ld): Default to yes.
+ * configure: Regenerated.
+ * collect2.c (main): When HAVE_LD_DEMANGLE is defined, don't
+ mess with COLLECT_NO_DEMANGLE, and just pass --demangle and
+ --no-demangle options straight through to ld. When
+ HAVE_LD_DEMANGLE is not defined, set COLLECT_NO_DEMANGLE in a
+ way that has the intended effect on Windows.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c: Include basic-block.h.
+ (dw_label_info): Remove.
+ (trace_work_list, trace_index): New.
+ (remember_row, emit_cfa_remember): Remove.
+ (dw_trace_info_hash, dw_trace_info_eq): New.
+ (get_trace_index, get_trace_info): New.
+ (save_point_p): New.
+ (free_cfi_row): Remove.
+ (add_cfi): Do not emit DW_CFA_remember_state.
+ (cfa_row_equal_p): New.
+ (barrier_args_size): Remove.
+ (compute_barrier_args_size_1, compute_barrier_args_size): Remove.
+ (dwarf2out_notice_stack_adjust): Don't compute_barrier_args_size.
+ (maybe_record_trace_start, create_trace_edges, scan_trace): New.
+ (dwarf2out_cfi_begin_epilogue): Remove.
+ (dwarf2out_frame_debug_restore_state): Remove.
+ (connect_traces, create_pseudo_cfg): New.
+ (create_cfi_notes, execute_dwarf2_frame): Rewrite using traces.
+ * Makefile.in (dwarf2cfi.o): Update.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c (dw_trace_info): New.
+ (dw_label_info): New.
+ (cie_return_save): New.
+ (cur_trace): New.
+ (queued_args_size): Rename from args_size. Update all users.
+ (cfa_store, cfa_temp, regs_saved_in_regs): Remove.
+ (def_cfa_1): Use cur_trace instead of cfa_*.
+ (dwarf2out_stack_adjust, record_reg_saved_in_reg): Likewise.
+ (clobbers_queued_reg_save, reg_saved_in): Likewise.
+ (dwarf2out_frame_debug_expr): Likewise.
+ (create_cie_data): Split out from ...
+ (execute_dwarf2_frame): ... here. Initialize cur_trace.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c (regs_saved_in_regs): Allocate from heap, not gc.
+ Update all users to match.
+ (execute_dwarf2_frame): Free reg_saved_in_data.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c (queued_reg_save): Reorder for packing. Don't GTY.
+ (queued_reg_saves): Don't GTY. Change to a VEC.
+ (queue_reg_save): Update to match.
+ (dwarf2out_flush_queued_reg_saves): Likewise.
+ (clobbers_queued_reg_save): Likewise.
+ (reg_saved_in): Likewise.
+ (execute_dwarf2_frame): Free queued_reg_saves.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c (dw_cfi_row_ref): Remove. Update all users.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c (add_cfi_args_size): Split out from...
+ (dwarf2out_args_size): ... here.
+ (add_cfi_restore): Split out from ...
+ (dwarf2out_frame_debug_cfa_restore): ... here.
+ (def_cfa_0): Split out from ...
+ (def_cfa_1): ... here.
+ (cfi_oprnd_equal_p, cfi_equal_p): New.
+ (change_cfi_row): New.
+ (add_cfis_to_fde): Set fde->dw_fde_switch_cfi_index.
+ (create_cfi_notes): Use change_cfi_row at SWITCH_TEXT note.
+ (output_cfis): Remove.
+ * dwarf2out.c (output_fde): Simplify output_cfi loop.
+ (dwarf2out_switch_text_section): Don't call output_cfis.
+ (dw_val_equal_p, loc_descr_equal_p_1, loc_descr_equal_p): New.
+ * dwarf2out.h: Update decls.
+ (enum dw_val_class): Add dw_val_class_none.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c (update_row_reg_save): New.
+ (dwarf2out_frame_debug_cfa_expression): Use it.
+ (dwarf2out_frame_debug_cfa_restore): Likewise.
+ (reg_save): Likewise. Do not emit DW_CFA_same_value.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c (add_cfi_insn): Rename from cfi_insn. Update all users.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * dwarf2cfi.c (dw_cfi_row, dw_cfi_row_ref): New.
+ (cie_cfi_row): New.
+ (new_cfi_row, copy_cfi_row, free_cfi_row): New.
+ (cfa, old_cfa, cfa_remember, old_cfa_remember, old_args_size): Remove.
+ (cur_row, remember_row): New.
+ (def_cfa_1): Use cur_row instead of the old_* variables.
+ (dwarf2out_frame_debug_restore_state): Similarly.
+ (dwarf2out_args_size, dwarf2out_notice_stack_adjust): Likewise.
+ (dwarf2out_frame_debug_def_cfa): Use a local variable instead of cfa.
+ (dwarf2out_frame_debug_adjust_cfa): Likewise.
+ (dwarf2out_frame_debug_cfa_offset): Likewise.
+ (dwarf2out_frame_debug_expr): Likewise.
+ (execute_dwarf2_frame): Set up cur_row.
+ * dwarf2out.h (struct cfa_loc): Mark for GTY.
+
+2011-07-23 Richard Henderson <rth@redhat.com>
+
+ * basic-block.h (EDGE_PRESERVE): New.
+ (EDGE_ALL_FLAGS, EDGE_COMPLEX): Include it.
+ * bb-reorder.c: Include except.h.
+ (fix_up_crossing_landing_pad): New.
+ (find_rarely_executed_basic_blocks_and_crossing_edges): Place
+ landing pads in the right partition. Duplicate as necessary.
+ (partition_hot_cold_basic_blocks): Fix up DF info after
+ duplicating landing pads.
+ * cfg.c (dump_edge_info): Add crossing and preserve to bitnames.
+ * cfgrtl.c (rtl_verify_flow_info_1): Validate that EDGE_CROSSING
+ is set properly. Validate that EH edges are not CROSSING.
+ * except.c (expand_dw2_landing_pad_for_region): Split out from ...
+ (dw2_build_landing_pads): ... here.
+ (convert_to_eh_region_ranges): Remove code to fixup crossing
+ landing pads.
+ * except.h (expand_dw2_landing_pad_for_region): Declare.
+ * tree-cfg.c (gimple_can_merge_blocks_p): Don't merge PRESERVE edges.
+
+2011-07-23 Richard Earnshaw <rearnsha@arm.com>
+
+ PR target/49816
+ * arm.c (aapcs_vfp_allocate_return_reg): Return NULL on failure.
+
+2011-07-22 Jason Merrill <jason@redhat.com>
+
+ * doc/invoke.texi (C++ Dialect Options): Document -Wno-narrowing.
+
+2011-07-22 Richard Henderson <rth@redhat.com>
+
+ * bb-reorder.c (gate_handle_partition_blocks): Honor optimize.
+
+2011-07-22 Richard Henderson <rth@redhat.com>
+
+ * jump.c (maybe_propagate_label_ref): Split out of...
+ (mark_all_labels): ... here. Do not attempt label_ref
+ propagation while in cfglayout mode.
+
+2011-07-22 Jakub Jelinek <jakub@redhat.com>
+
+ * dwarf2out.c (struct macinfo_struct): Change code to unsigned char.
+ (DEBUG_MACRO_SECTION, DEBUG_MACRO_SECTION_LABEL): Define.
+ (dwarf_attr_name): Handle DW_AT_GNU_macros.
+ (dwarf2out_define): If the vector is empty and
+ lineno is 0, emit a dummy entry first.
+ (dwarf2out_undef): Likewise. Remove redundant semicolon.
+ (htab_macinfo_hash, htab_macinfo_eq, output_macinfo_op,
+ optimize_macinfo_range): New functions.
+ (output_macinfo): Use them. If !dwarf_strict and .debug_str is
+ mergeable, optimize longer strings using
+ DW_MACRO_GNU_{define,undef}_indirect and if HAVE_COMDAT_GROUP,
+ optimize longer sequences of define/undef ops from headers
+ using DW_MACRO_GNU_transparent_include. For !dwarf_strict
+ emit a section headers.
+ (dwarf2out_init): For !dwarf_strict set debug_macinfo_section
+ and macinfo_section_label to DEBUG_MACRO_SECTION
+ resp. DEBUG_MACRO_SECTION_LABEL.
+ (dwarf2out_finish): For !dwarf_strict emit DW_AT_GNU_macros
+ instead of DW_AT_macro_info.
+
+ PR other/32998
+ * common.opt (grecord-gcc-switches, gno-record-gcc-switches): New
+ options.
+ * dwarf2out.c: Include opts.h.
+ (dchar_p): New typedef. Define heap VEC for it.
+ (producer_string): New variable.
+ (gen_producer_string): New function.
+ (gen_compile_unit_die): Use it.
+ (dwarf2out_finish): Fix up comp_unit_die () DW_AT_producer
+ if needed.
+ * Makefile.in (dwarf2out.o): Depend on $(OPTS_H).
+ * doc/invoke.texi: Document -grecord-gcc-switches and
+ -gno-record-gcc-switches, add a -grecord-gcc-switches reference
+ to -frecord-gcc-switches description.
+
+2011-07-22 Jason Merrill <jason@redhat.com>
+
+ PR c++/30112
+ * c-decl.c (c_linkage_bindings): Define.
+
+2011-07-22 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR debug/49815
+ * var-tracking.c (vt_finalize): Always free windowed_parm_regs.
+
+2011-07-22 H.J. Lu <hongjiu.lu@intel.com>
+
+ * config/i386/i386.c (ix86_option_override_internal): Disallow
+ MS ABI in x32 mode.
+ (ix86_init_builtins): Call ix86_init_builtins_va_builtins_abi
+ only for TARGET_LP64.
+ (ix86_handle_abi_attribute): Check TARGET_LP64 instead of
+ TARGET_64BIT.
+
+2011-07-22 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * config/rs6000/rs6000.c (rs6000_xcoff_strip_dollar): Rewrite to
+ avoid warnings when GCC is built with a C++ compiler.
+
+2011-07-22 Martin Jambor <mjambor@suse.cz>
+
+ PR lto/49796
+ * cgraphunit.c (verify_edge_corresponds_to_fndecl): Return false
+ if decl node is in another partition, call cgraph_get_node only
+ once.
+
+2011-07-22 Uros Bizjak <ubizjak@gmail.com>
+
+ * config.gcc (x86_64-*-linux*): Set
+ default_gnu_indirect_function to yes.
+
+2011-07-22 Richard Guenther <rguenther@suse.de>
+
+ PR tree-optimization/45819
+ * tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Properly
+ preserve volatile and notrap flags.
+
+2011-07-22 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+ Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+
+ PR bootstrap/49794
+ * configure.ac: Test AM_ICONV with CXX.
+ * configure: Regenerate.
+ * config/sol2-c.c (solaris_format_types): Use EXPORTED_CONST.
+
+2011-07-22 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ PR bootstrap/49797
+ * graphite-clast-to-gimple.c (CLOOG_LANGUAGE_C): Provide if missing.
+ (set_cloog_options): Use it.
+
+2011-07-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/49756
+ * gcc.c (main): Call stack_limit_increase (64MB).
+ * toplev.c (toplev_main): Likewise.
+
+2011-07-21 H.J. Lu <hongjiu.lu@intel.com>
+
+ * config/i386/i386.c (ix86_expand_call): Call copy_to_mode_reg
+ instead of force_reg.
+
+2011-07-21 H.J. Lu <hongjiu.lu@intel.com>
+
+ * config/i386/i386.c (ix86_expand_move): Convert to Pmode if
+ needed and use force_reg after convert.
+ (ix86_expand_call): Likewise.
+ (ix86_expand_special_args_builtin): Likewise.
+ (ix86_expand_builtin): Likewise.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ PR middle-end/47654
+ PR middle-end/49649
+ * graphite-clast-to-gimple.c (type_for_clast_term): Pass v1 and v2
+ in parameter. Initialize v1 and v2 based on the values returned
+ by clast_name_to_lb_ub.
+ (type_for_clast_red): Pass v1 and v2 in parameter, and set their
+ values.
+ (type_for_clast_bin): Same.
+ (type_for_clast_expr): Same.
+ (type_for_clast_eq): Update calls to type_for_clast_expr.
+ (type_for_clast_for): Same.
+ (build_iv_mapping): Same.
+ * graphite-ppl.h (value_min): New.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ * graphite-clast-to-gimple.c (type_for_interval): Generate signed
+ types whenever possible.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ * graphite-clast-to-gimple.c (struct clast_name_index): Add lb
+ and ub fields.
+ (new_clast_name_index): Add lb and ub parameters.
+ (free_clast_name_index): New.
+ (clast_name_to_lb_ub): New.
+ (save_clast_name_index): Add lb and ub parameters.
+ (compute_bounds_for_param): New.
+ (type_for_level): Removed.
+ (type_for_clast_for): Removed level parameter. Do not call
+ type_for_level.
+ (graphite_create_new_loop): Store the lb and ub for the clast_name
+ of the iterator of the loop that has been generated.
+ (graphite_create_new_loop_guard): Remove parameter level.
+ (create_params_index): Store the lb and ub of each parameter.
+ (gloog): Use free_clast_name_index. Pass to create_params_index
+ the current scop.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ * graphite-clast-to-gimple.c (max_signed_precision_type): Removed.
+ (max_precision_type): Inline max_signed_precision_type.
+ (type_for_clast_red): Use max_precision_type.
+ (type_for_clast_bin): Same.
+ (type_for_clast_for): Same.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ * graphite-clast-to-gimple.c (gcc_type_for_interval): Renamed
+ type_for_interval.
+ (gcc_type_for_value): Renamed type_for_value.
+ (gcc_type_for_clast_term): Renamed type_for_clast_term.
+ (gcc_type_for_clast_expr): Renamed type_for_clast_expr.
+ (gcc_type_for_clast_red): Renamed type_for_clast_red.
+ (gcc_type_for_clast_bin): Renamed type_for_clast_bin.
+ (gcc_type_for_clast_eq): Renamed type_for_clast_eq.
+ (graphite_translate_clast_equation): Update calls.
+ (compute_type_for_level): Renamed type_for_level.
+ (gcc_type_for_iv_of_clast_loop): Renamed type_for_clast_for.
+ (build_iv_mapping): Update calls.
+ (graphite_create_new_loop_guard): Same.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ * graphite-clast-to-gimple.c (clast_get_body_of_loop): Add fixme
+ comment.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ * graphite-clast-to-gimple.c (struct ivs_params): New.
+ (clast_name_to_gcc): Use ivs_params to pass around parameters.
+ (clast_to_gcc_expression): Same.
+ (clast_to_gcc_expression_red): Same.
+ (gcc_type_for_clast_term): Same.
+ (gcc_type_for_clast_expr): Same.
+ (gcc_type_for_clast_red): Same.
+ (gcc_type_for_clast_bin): Same.
+ (gcc_type_for_clast_eq): Same.
+ (graphite_translate_clast_equation): Same.
+ (graphite_create_guard_cond_expr): Same.
+ (graphite_create_new_guard): Same.
+ (graphite_create_new_loop): Same.
+ (build_iv_mapping): Same.
+ (translate_clast_user): Same.
+ (graphite_create_new_loop_guard): Same.
+ (translate_clast): Same.
+ (translate_clast_for_loop): Same.
+ (translate_clast_for): Same.
+ (translate_clast_guard): Same.
+ (initialize_cloog_names): Fix typo.
+ (gloog): Initialize an ivs_params struct, pass it to translate_clast.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ * graphite-clast-to-gimple.c (struct clast_name_index): Add level.
+ (new_clast_name_index): Add level parameter.
+ (clast_name_to_level): New.
+ (save_clast_name_index): Add level parameter.
+ (newivs_to_depth_to_newiv): Removed.
+ (clast_name_to_gcc): Inlined newivs_to_depth_to_newiv.
+ (graphite_create_new_loop): Add level parameter. Pass level to
+ save_clast_name_index.
+ (translate_clast_for_loop): Pass level to graphite_create_new_loop.
+ (create_params_index): Pass level to save_clast_name_index.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ * graphite-clast-to-gimple.c (graphite_create_new_loop): Do not
+ recompute type, lb, and ub. Get them from...
+ (graphite_create_new_loop_guard): ...here. Pass in parameter
+ pointers to type, lb, and ub.
+ (translate_clast_for_loop): Update function calls.
+ (translate_clast_for): Same.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ * graphite-clast-to-gimple.c (compute_bounds_for_level): Call
+ psct_dynamic_dim.
+ (translate_clast_for_loop): Pass loop level to dependency_in_loop_p.
+ (gcc_type_for_iv_of_clast_loop): Update use of level.
+ (gloog): Start counting nesting level from 0.
+ * graphite-clast-to-gimple.h (get_scattering_level): Removed.
+ * graphite-dependences.c (graphite_carried_dependence_level_k): Call
+ psct_dynamic_dim on level.
+
+2011-07-21 H.J. Lu <hongjiu.lu@intel.com>
+
+ * config/i386/i386.c (ix86_legitimize_address): Convert to
+ Pmode if needed.
+
+2011-07-21 H.J. Lu <hongjiu.lu@intel.com>
+
+ * config/i386/i386.c (function_value_64): Always return pointers
+ in Pmode.
+ (ix86_promote_function_mode): New.
+ (TARGET_PROMOTE_FUNCTION_MODE): Likewise.
+
+2011-07-21 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ PR tree-optimization/49749
+ * tree-ssa-reassoc.c (get_rank): Fix operand scan conditions and
+ remove no-longer-used maxrank variable.
+
2011-07-21 Georg-Johann Lay <avr@gjlay.de>
-
+
* config/avr/avr.c (final_prescan_insn): Fix printing of rtx_costs.
2011-07-21 Jason Merrill <jason@redhat.com>
diff --git a/gcc/ChangeLog.MELT b/gcc/ChangeLog.MELT
index 84641c645d8..23650fa3bcf 100644
--- a/gcc/ChangeLog.MELT
+++ b/gcc/ChangeLog.MELT
@@ -1,4 +1,10 @@
+2011-07-25 Basile Starynkevitch <basile@starynkevitch.net>
+ * melt-build.tpl (warmelt-upgrade-translator, meltrun-generate):
+ Use $(WARMELT_LAST).
+ * melt-built.mk: Regenerate.
+ * Makefile.in (upgrade-warmelt): Depend upon $(WARMELT_LAST).
+ Merged with trunk.
2011-07-24 Basile Starynkevitch <basile@starynkevitch.net>
{{reverting to rev.176695}}
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index db6d0cbcd95..427f0a7ed13 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20110721
+20110725
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e8bf826a02b..dcaf0c0fcde 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3027,10 +3027,10 @@ dwarf2out.o : dwarf2out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(GGC_H) $(EXCEPT_H) dwarf2asm.h $(TM_P_H) langhooks.h $(HASHTAB_H) \
gt-dwarf2out.h $(TARGET_H) $(CGRAPH_H) $(MD5_H) $(INPUT_H) $(FUNCTION_H) \
$(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) $(CFGLAYOUT_H) \
- tree-pretty-print.h $(COMMON_TARGET_H)
+ tree-pretty-print.h $(COMMON_TARGET_H) $(OPTS_H)
dwarf2cfi.o : dwarf2cfi.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
version.h $(RTL_H) $(FUNCTION_H) $(DWARF2_H) dwarf2asm.h dwarf2out.h \
- $(GGC_H) $(TM_P_H) $(TARGET_H) $(TREE_PASS_H)
+ $(GGC_H) $(TM_P_H) $(TARGET_H) $(TREE_PASS_H) $(BASIC_BLOCK_H)
dwarf2asm.o : dwarf2asm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(FLAGS_H) $(RTL_H) $(TREE_H) output.h dwarf2asm.h $(TM_P_H) $(GGC_H) \
gt-dwarf2asm.h $(DWARF2_H) $(SPLAY_TREE_H) $(TARGET_H)
@@ -3537,7 +3537,7 @@ bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) $(FLAGS_H) $(TIMEVAR_H) output.h $(CFGLAYOUT_H) $(FIBHEAP_H) \
$(TARGET_H) $(FUNCTION_H) $(TM_P_H) $(OBSTACK_H) $(EXPR_H) $(REGS_H) \
$(PARAMS_H) toplev.h $(DIAGNOSTIC_CORE_H) $(TREE_PASS_H) $(DF_H) \
- bb-reorder.h
+ $(EXCEPT_H) bb-reorder.h
tracer.o : tracer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) $(BASIC_BLOCK_H) hard-reg-set.h output.h $(CFGLAYOUT_H) \
$(FLAGS_H) $(TIMEVAR_H) $(PARAMS_H) $(COVERAGE_H) $(FIBHEAP_H) \
@@ -5487,12 +5487,11 @@ install-melt-default-modules-list: $(melt_default_modules_list).modlis $(wildcar
.PHONY: upgrade-warmelt upgrade-bigmelt
-upgrade-warmelt:
+upgrade-warmelt: $(WARMELT_LAST)
$(MAKE) Makefile $(melt_default_modules_list).modlis
#it is important to call the warmelt-upgrade-translator before the
#meltrun-generate
- $(MAKE) warmelt-upgrade-translator
- $(MAKE) meltrun-generate
+ $(MAKE) warmelt-upgrade-translator meltrun-generate
for f in $(wildcard meltrunsup*.[ch]); do \
cp $$f $$f-tmp; \
cp $(srcdir)/melt/generated/$$f $$f-old; \
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 1a616a5f208..d91f54f98ab 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,52 @@
+2011-07-24 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Subprogram_Type>: If the
+ subprogram has copy-in copy-out parameters, try to promote the mode of
+ the return type if it is passed in registers.
+
+2011-07-24 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/utils2.c (build_binary_op) <ARRAY_REF>: Do not mark the
+ left operand as addressable.
+
+2011-07-24 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/gigi.h (build_function_stub): Remove.
+ (build_return_expr): Likewise.
+ (convert_vms_descriptor): Declare.
+ * gcc-interface/utils.c (convert_vms_descriptor): Make global.
+ (build_function_stub): Move to...
+ * gcc-interface/utils2.c (build_return_expr): Move to...
+ * gcc-interface/trans.c (build_function_stub): ...here.
+ (build_return_expr): ...here.
+ (Subprogram_Body_to_gnu): Add local variable for language_function.
+ Disconnect the parameter attributes cache, if any, once done with it.
+ Call end_subprog_body only after setting the end_locus.
+ Build the stub associated with the function, if any, at the very end.
+ (gnat_to_gnu) <N_Return_Statement>: Remove couple of useless local
+ variables and streamline control flow.
+
+2011-07-23 Arnaud Charlet <charlet@adacore.com>
+
+ PR ada/49819
+ * gcc-interface/Makefile.in (powerpc-linux): Remove reference to
+ g-trasym-dwarf.adb.
+
+2011-07-22 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ PR bootstrap/49794
+ * init.c [sun && __SVR4 && !__vxworks] (__gnat_install_handler):
+ Assign to act.sa_sigaction.
+ * tracebak.c [USE_GENERIC_UNWINDER] (__gnat_backtrace): Cast
+ current->return_address to char * before arithmetic.
+
+2011-07-22 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * init.c [sgi] (__gnat_error_handler): Update sigaction(2) citation.
+ Correct argument types.
+ Extract code from reason.
+ (__gnat_install_handler): Assign to act.sa_sigaction.
+
2011-07-21 Eric Botcazou <ebotcazou@adacore.com>
* gcc-interface/Make-lang.in (GNAT1_ADA_OBJS): Move ada/b_gnat1.o to...
diff --git a/gcc/ada/gcc-interface/Makefile.in b/gcc/ada/gcc-interface/Makefile.in
index 0b5c8795a7a..2616fea7b4d 100644
--- a/gcc/ada/gcc-interface/Makefile.in
+++ b/gcc/ada/gcc-interface/Makefile.in
@@ -1820,7 +1820,6 @@ ifeq ($(strip $(filter-out powerpc% linux%,$(arch) $(osys))),)
s-osinte.adb<s-osinte-posix.adb \
s-tpopsp.adb<s-tpopsp-posix-foreign.adb \
g-sercom.adb<g-sercom-linux.adb \
- g-trasym.adb<g-trasym-dwarf.adb \
$(ATOMICS_TARGET_PAIRS)
ifeq ($(strip $(filter-out xenomai,$(THREAD_KIND))),)
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index 1f9083a454e..99be625ecd1 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -4245,17 +4245,50 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
}
}
- /* Do not compute record for out parameters if subprogram is
- stubbed since structures are incomplete for the back-end. */
- if (gnu_field_list && Convention (gnat_entity) != Convention_Stubbed)
- finish_record_type (gnu_return_type, nreverse (gnu_field_list),
- 0, debug_info_p);
-
- /* If we have a CICO list but it has only one entry, we convert
- this function into a function that simply returns that one
- object. */
- if (list_length (gnu_cico_list) == 1)
- gnu_return_type = TREE_TYPE (TREE_PURPOSE (gnu_cico_list));
+ if (gnu_cico_list)
+ {
+ /* If we have a CICO list but it has only one entry, we convert
+ this function into a function that returns this object. */
+ if (list_length (gnu_cico_list) == 1)
+ gnu_return_type = TREE_TYPE (TREE_PURPOSE (gnu_cico_list));
+
+ /* Do not finalize the return type if the subprogram is stubbed
+ since structures are incomplete for the back-end. */
+ else if (Convention (gnat_entity) != Convention_Stubbed)
+ {
+ finish_record_type (gnu_return_type, nreverse (gnu_field_list),
+ 0, false);
+
+ /* Try to promote the mode of the return type if it is passed
+ in registers, again to speed up accesses. */
+ if (TYPE_MODE (gnu_return_type) == BLKmode
+ && !targetm.calls.return_in_memory (gnu_return_type,
+ NULL_TREE))
+ {
+ unsigned int size
+ = TREE_INT_CST_LOW (TYPE_SIZE (gnu_return_type));
+ unsigned int i = BITS_PER_UNIT;
+ enum machine_mode mode;
+
+ while (i < size)
+ i <<= 1;
+ mode = mode_for_size (i, MODE_INT, 0);
+ if (mode != BLKmode)
+ {
+ SET_TYPE_MODE (gnu_return_type, mode);
+ TYPE_ALIGN (gnu_return_type)
+ = GET_MODE_ALIGNMENT (mode);
+ TYPE_SIZE (gnu_return_type)
+ = bitsize_int (GET_MODE_BITSIZE (mode));
+ TYPE_SIZE_UNIT (gnu_return_type)
+ = size_int (GET_MODE_SIZE (mode));
+ }
+ }
+
+ if (debug_info_p)
+ rest_of_record_type_compilation (gnu_return_type);
+ }
+ }
if (Has_Stdcall_Convention (gnat_entity))
prepend_one_attribute_to
diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h
index 3833d014992..e8a725979e8 100644
--- a/gcc/ada/gcc-interface/gigi.h
+++ b/gcc/ada/gcc-interface/gigi.h
@@ -706,10 +706,6 @@ extern tree build_vms_descriptor (tree type, Mechanism_Type mech,
extern tree build_vms_descriptor32 (tree type, Mechanism_Type mech,
Entity_Id gnat_entity);
-/* Build a stub for the subprogram specified by the GCC tree GNU_SUBPROG
- and the GNAT node GNAT_SUBPROG. */
-extern void build_function_stub (tree gnu_subprog, Entity_Id gnat_subprog);
-
/* Build a type to be used to represent an aliased object whose nominal type
is an unconstrained array. This consists of a RECORD_TYPE containing a
field of TEMPLATE_TYPE and a field of OBJECT_TYPE, which is an ARRAY_TYPE.
@@ -812,13 +808,9 @@ extern tree build_cond_expr (tree result_type, tree condition_operand,
tree true_operand, tree false_operand);
/* Similar, but for COMPOUND_EXPR. */
-
extern tree build_compound_expr (tree result_type, tree stmt_operand,
tree expr_operand);
-/* Similar, but for RETURN_EXPR. */
-extern tree build_return_expr (tree ret_obj, tree ret_val);
-
/* Build a CALL_EXPR to call FUNDECL with one argument, ARG. Return
the CALL_EXPR. */
extern tree build_call_1_expr (tree fundecl, tree arg);
@@ -893,6 +885,15 @@ extern tree build_allocator (tree type, tree init, tree result_type,
extern tree fill_vms_descriptor (tree gnu_type, tree gnu_expr,
Node_Id gnat_actual);
+/* Convert GNU_EXPR, a pointer to a VMS descriptor, to GNU_TYPE, a regular
+ pointer or fat pointer type. GNU_EXPR_ALT_TYPE is the alternate (32-bit)
+ pointer type of GNU_EXPR. BY_REF is true if the result is to be used by
+ reference. GNAT_SUBPROG is the subprogram to which the VMS descriptor is
+ passed. */
+extern tree convert_vms_descriptor (tree gnu_type, tree gnu_expr,
+ tree gnu_expr_alt_type, bool by_ref,
+ Entity_Id gnat_subprog);
+
/* Indicate that we need to take the address of T and that it therefore
should not be allocated in a register. Returns true if successful. */
extern bool gnat_mark_addressable (tree t);
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index bf533bdf332..b0b83b3383b 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -2428,6 +2428,107 @@ establish_gnat_vms_condition_handler (void)
add_stmt (establish_stmt);
}
+
+/* Similar, but for RETURN_EXPR. If RET_VAL is non-null, build a RETURN_EXPR
+ around the assignment of RET_VAL to RET_OBJ. Otherwise just build a bare
+ RETURN_EXPR around RESULT_OBJ, which may be null in this case. */
+
+static tree
+build_return_expr (tree ret_obj, tree ret_val)
+{
+ tree result_expr;
+
+ if (ret_val)
+ {
+ /* The gimplifier explicitly enforces the following invariant:
+
+ RETURN_EXPR
+ |
+ MODIFY_EXPR
+ / \
+ / \
+ RET_OBJ ...
+
+ As a consequence, type consistency dictates that we use the type
+ of the RET_OBJ as the operation type. */
+ tree operation_type = TREE_TYPE (ret_obj);
+
+ /* Convert the right operand to the operation type. Note that it's the
+ same transformation as in the MODIFY_EXPR case of build_binary_op,
+ with the assumption that the type cannot involve a placeholder. */
+ if (operation_type != TREE_TYPE (ret_val))
+ ret_val = convert (operation_type, ret_val);
+
+ result_expr = build2 (MODIFY_EXPR, operation_type, ret_obj, ret_val);
+ }
+ else
+ result_expr = ret_obj;
+
+ return build1 (RETURN_EXPR, void_type_node, result_expr);
+}
+
+/* Build a stub for the subprogram specified by the GCC tree GNU_SUBPROG
+ and the GNAT node GNAT_SUBPROG. */
+
+static void
+build_function_stub (tree gnu_subprog, Entity_Id gnat_subprog)
+{
+ tree gnu_subprog_type, gnu_subprog_addr, gnu_subprog_call;
+ tree gnu_subprog_param, gnu_stub_param, gnu_param;
+ tree gnu_stub_decl = DECL_FUNCTION_STUB (gnu_subprog);
+ VEC(tree,gc) *gnu_param_vec = NULL;
+
+ gnu_subprog_type = TREE_TYPE (gnu_subprog);
+
+ /* Initialize the information structure for the function. */
+ allocate_struct_function (gnu_stub_decl, false);
+ set_cfun (NULL);
+
+ begin_subprog_body (gnu_stub_decl);
+
+ start_stmt_group ();
+ gnat_pushlevel ();
+
+ /* Loop over the parameters of the stub and translate any of them
+ passed by descriptor into a by reference one. */
+ for (gnu_stub_param = DECL_ARGUMENTS (gnu_stub_decl),
+ gnu_subprog_param = DECL_ARGUMENTS (gnu_subprog);
+ gnu_stub_param;
+ gnu_stub_param = TREE_CHAIN (gnu_stub_param),
+ gnu_subprog_param = TREE_CHAIN (gnu_subprog_param))
+ {
+ if (DECL_BY_DESCRIPTOR_P (gnu_stub_param))
+ {
+ gcc_assert (DECL_BY_REF_P (gnu_subprog_param));
+ gnu_param
+ = convert_vms_descriptor (TREE_TYPE (gnu_subprog_param),
+ gnu_stub_param,
+ DECL_PARM_ALT_TYPE (gnu_stub_param),
+ DECL_BY_DOUBLE_REF_P (gnu_subprog_param),
+ gnat_subprog);
+ }
+ else
+ gnu_param = gnu_stub_param;
+
+ VEC_safe_push (tree, gc, gnu_param_vec, gnu_param);
+ }
+
+ /* Invoke the internal subprogram. */
+ gnu_subprog_addr = build1 (ADDR_EXPR, build_pointer_type (gnu_subprog_type),
+ gnu_subprog);
+ gnu_subprog_call = build_call_vec (TREE_TYPE (gnu_subprog_type),
+ gnu_subprog_addr, gnu_param_vec);
+
+ /* Propagate the return value, if any. */
+ if (VOID_TYPE_P (TREE_TYPE (gnu_subprog_type)))
+ add_stmt (gnu_subprog_call);
+ else
+ add_stmt (build_return_expr (DECL_RESULT (gnu_stub_decl),
+ gnu_subprog_call));
+
+ gnat_poplevel ();
+ end_subprog_body (end_stmt_group ());
+}
/* Subroutine of gnat_to_gnu to process gnat_node, an N_Subprogram_Body. We
don't return anything. */
@@ -2455,6 +2556,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
/* The entry in the CI_CO_LIST that represents a function return, if any. */
tree gnu_return_var_elmt = NULL_TREE;
tree gnu_result;
+ struct language_function *gnu_subprog_language;
VEC(parm_attr,gc) *cache;
/* If this is a generic object or if it has been eliminated,
@@ -2496,8 +2598,8 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
/* Initialize the information structure for the function. */
allocate_struct_function (gnu_subprog_decl, false);
- DECL_STRUCT_FUNCTION (gnu_subprog_decl)->language
- = ggc_alloc_cleared_language_function ();
+ gnu_subprog_language = ggc_alloc_cleared_language_function ();
+ DECL_STRUCT_FUNCTION (gnu_subprog_decl)->language = gnu_subprog_language;
set_cfun (NULL);
begin_subprog_body (gnu_subprog_decl);
@@ -2594,7 +2696,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
/* If we populated the parameter attributes cache, we need to make sure that
the cached expressions are evaluated on all the possible paths leading to
their uses. So we force their evaluation on entry of the function. */
- cache = DECL_STRUCT_FUNCTION (gnu_subprog_decl)->language->parm_attr_cache;
+ cache = gnu_subprog_language->parm_attr_cache;
if (cache)
{
struct parm_attr_d *pa;
@@ -2614,6 +2716,8 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
add_stmt (gnu_result);
gnu_result = end_stmt_group ();
+
+ gnu_subprog_language->parm_attr_cache = NULL;
}
/* If we are dealing with a return from an Ada procedure with parameters
@@ -2650,14 +2754,14 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
VEC_pop (tree, gnu_return_label_stack);
- end_subprog_body (gnu_result);
-
/* Attempt setting the end_locus of our GCC body tree, typically a
BIND_EXPR or STATEMENT_LIST, then the end_locus of our GCC subprogram
declaration tree. */
set_end_locus_from_node (gnu_result, gnat_node);
set_end_locus_from_node (gnu_subprog_decl, gnat_node);
+ end_subprog_body (gnu_result);
+
/* Finally annotate the parameters and disconnect the trees for parameters
that we have turned into variables since they are now unusable. */
for (gnat_param = First_Formal_With_Extras (gnat_subprog_id);
@@ -2675,12 +2779,13 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
save_gnu_tree (gnat_param, NULL_TREE, false);
}
- if (DECL_FUNCTION_STUB (gnu_subprog_decl))
- build_function_stub (gnu_subprog_decl, gnat_subprog_id);
-
if (gnu_return_var_elmt)
TREE_VALUE (gnu_return_var_elmt) = void_type_node;
+ /* If there is a stub associated with the function, build it now. */
+ if (DECL_FUNCTION_STUB (gnu_subprog_decl))
+ build_function_stub (gnu_subprog_decl, gnat_subprog_id);
+
mark_out_of_scope (Defining_Unit_Name (Specification (gnat_node)));
}
@@ -5085,23 +5190,22 @@ gnat_to_gnu (Node_Id gnat_node)
case N_Return_Statement:
{
- tree gnu_ret_val, gnu_ret_obj;
+ tree gnu_ret_obj, gnu_ret_val;
/* If the subprogram is a function, we must return the expression. */
if (Present (Expression (gnat_node)))
{
tree gnu_subprog_type = TREE_TYPE (current_function_decl);
- tree gnu_ret_type = TREE_TYPE (gnu_subprog_type);
- tree gnu_result_decl = DECL_RESULT (current_function_decl);
- gnu_ret_val = gnat_to_gnu (Expression (gnat_node));
/* If this function has copy-in/copy-out parameters, get the real
- variable and type for the return. See Subprogram_to_gnu. */
+ object for the return. See Subprogram_to_gnu. */
if (TYPE_CI_CO_LIST (gnu_subprog_type))
- {
- gnu_result_decl = VEC_last (tree, gnu_return_var_stack);
- gnu_ret_type = TREE_TYPE (gnu_result_decl);
- }
+ gnu_ret_obj = VEC_last (tree, gnu_return_var_stack);
+ else
+ gnu_ret_obj = DECL_RESULT (current_function_decl);
+
+ /* Get the GCC tree for the expression to be returned. */
+ gnu_ret_val = gnat_to_gnu (Expression (gnat_node));
/* Do not remove the padding from GNU_RET_VAL if the inner type is
self-referential since we want to allocate the fixed size. */
@@ -5112,7 +5216,7 @@ gnat_to_gnu (Node_Id gnat_node)
(TYPE_SIZE (TREE_TYPE (gnu_ret_val))))
gnu_ret_val = TREE_OPERAND (gnu_ret_val, 0);
- /* If the subprogram returns by direct reference, return a pointer
+ /* If the function returns by direct reference, return a pointer
to the return value. */
if (TYPE_RETURN_BY_DIRECT_REF_P (gnu_subprog_type)
|| By_Ref (gnat_node))
@@ -5124,37 +5228,33 @@ gnat_to_gnu (Node_Id gnat_node)
{
gnu_ret_val = maybe_unconstrained_array (gnu_ret_val);
gnu_ret_val = build_allocator (TREE_TYPE (gnu_ret_val),
- gnu_ret_val, gnu_ret_type,
+ gnu_ret_val,
+ TREE_TYPE (gnu_ret_obj),
Procedure_To_Call (gnat_node),
Storage_Pool (gnat_node),
gnat_node, false);
}
- /* If the subprogram returns by invisible reference, dereference
+ /* If the function returns by invisible reference, dereference
the pointer it is passed using the type of the return value
and build the copy operation manually. This ensures that we
don't copy too much data, for example if the return type is
unconstrained with a maximum size. */
if (TREE_ADDRESSABLE (gnu_subprog_type))
{
- gnu_ret_obj
+ tree gnu_ret_deref
= build_unary_op (INDIRECT_REF, TREE_TYPE (gnu_ret_val),
- gnu_result_decl);
+ gnu_ret_obj);
gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE,
- gnu_ret_obj, gnu_ret_val);
+ gnu_ret_deref, gnu_ret_val);
add_stmt_with_node (gnu_result, gnat_node);
gnu_ret_val = NULL_TREE;
- gnu_ret_obj = gnu_result_decl;
}
-
- /* Otherwise, build a regular return. */
- else
- gnu_ret_obj = gnu_result_decl;
}
else
{
- gnu_ret_val = NULL_TREE;
gnu_ret_obj = NULL_TREE;
+ gnu_ret_val = NULL_TREE;
}
/* If we have a return label defined, convert this into a branch to
@@ -5167,13 +5267,15 @@ gnat_to_gnu (Node_Id gnat_node)
gnu_result = build1 (GOTO_EXPR, void_type_node,
VEC_last (tree, gnu_return_label_stack));
+
/* When not optimizing, make sure the return is preserved. */
if (!optimize && Comes_From_Source (gnat_node))
DECL_ARTIFICIAL (VEC_last (tree, gnu_return_label_stack)) = 0;
- break;
}
- gnu_result = build_return_expr (gnu_ret_obj, gnu_ret_val);
+ /* Otherwise, build a regular return. */
+ else
+ gnu_result = build_return_expr (gnu_ret_obj, gnu_ret_val);
}
break;
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index c6078659cb2..1ea34b1ed7c 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -3295,7 +3295,7 @@ convert_vms_descriptor32 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog)
reference. GNAT_SUBPROG is the subprogram to which the VMS descriptor is
passed. */
-static tree
+tree
convert_vms_descriptor (tree gnu_type, tree gnu_expr, tree gnu_expr_alt_type,
bool by_ref, Entity_Id gnat_subprog)
{
@@ -3344,69 +3344,6 @@ convert_vms_descriptor (tree gnu_type, tree gnu_expr, tree gnu_expr_alt_type,
return build3 (COND_EXPR, gnu_type, is64bit, gnu_expr64, gnu_expr32);
}
-
-/* Build a stub for the subprogram specified by the GCC tree GNU_SUBPROG
- and the GNAT node GNAT_SUBPROG. */
-
-void
-build_function_stub (tree gnu_subprog, Entity_Id gnat_subprog)
-{
- tree gnu_subprog_type, gnu_subprog_addr, gnu_subprog_call;
- tree gnu_subprog_param, gnu_stub_param, gnu_param;
- tree gnu_stub_decl = DECL_FUNCTION_STUB (gnu_subprog);
- VEC(tree,gc) *gnu_param_vec = NULL;
-
- gnu_subprog_type = TREE_TYPE (gnu_subprog);
-
- /* Initialize the information structure for the function. */
- allocate_struct_function (gnu_stub_decl, false);
- set_cfun (NULL);
-
- begin_subprog_body (gnu_stub_decl);
-
- start_stmt_group ();
- gnat_pushlevel ();
-
- /* Loop over the parameters of the stub and translate any of them
- passed by descriptor into a by reference one. */
- for (gnu_stub_param = DECL_ARGUMENTS (gnu_stub_decl),
- gnu_subprog_param = DECL_ARGUMENTS (gnu_subprog);
- gnu_stub_param;
- gnu_stub_param = TREE_CHAIN (gnu_stub_param),
- gnu_subprog_param = TREE_CHAIN (gnu_subprog_param))
- {
- if (DECL_BY_DESCRIPTOR_P (gnu_stub_param))
- {
- gcc_assert (DECL_BY_REF_P (gnu_subprog_param));
- gnu_param
- = convert_vms_descriptor (TREE_TYPE (gnu_subprog_param),
- gnu_stub_param,
- DECL_PARM_ALT_TYPE (gnu_stub_param),
- DECL_BY_DOUBLE_REF_P (gnu_subprog_param),
- gnat_subprog);
- }
- else
- gnu_param = gnu_stub_param;
-
- VEC_safe_push (tree, gc, gnu_param_vec, gnu_param);
- }
-
- /* Invoke the internal subprogram. */
- gnu_subprog_addr = build1 (ADDR_EXPR, build_pointer_type (gnu_subprog_type),
- gnu_subprog);
- gnu_subprog_call = build_call_vec (TREE_TYPE (gnu_subprog_type),
- gnu_subprog_addr, gnu_param_vec);
-
- /* Propagate the return value, if any. */
- if (VOID_TYPE_P (TREE_TYPE (gnu_subprog_type)))
- add_stmt (gnu_subprog_call);
- else
- add_stmt (build_return_expr (DECL_RESULT (gnu_stub_decl),
- gnu_subprog_call));
-
- gnat_poplevel ();
- end_subprog_body (end_stmt_group ());
-}
/* Build a type to be used to represent an aliased object whose nominal type
is an unconstrained array. This consists of a RECORD_TYPE containing a
diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c
index 44eb5cbfbca..5f3f03a3e0d 100644
--- a/gcc/ada/gcc-interface/utils2.c
+++ b/gcc/ada/gcc-interface/utils2.c
@@ -721,11 +721,6 @@ build_binary_op (enum tree_code op_code, tree result_type,
unneeded sign conversions when sizetype is wider than integer. */
right_operand = convert (right_base_type, right_operand);
right_operand = convert (sizetype, right_operand);
-
- if (!TREE_CONSTANT (right_operand)
- || !TREE_CONSTANT (TYPE_MIN_VALUE (right_type)))
- gnat_mark_addressable (left_operand);
-
modulus = NULL_TREE;
break;
@@ -1407,43 +1402,6 @@ build_compound_expr (tree result_type, tree stmt_operand, tree expr_operand)
return result;
}
-/* Similar, but for RETURN_EXPR. If RET_VAL is non-null, build a RETURN_EXPR
- around the assignment of RET_VAL to RET_OBJ. Otherwise just build a bare
- RETURN_EXPR around RESULT_OBJ, which may be null in this case. */
-
-tree
-build_return_expr (tree ret_obj, tree ret_val)
-{
- tree result_expr;
-
- if (ret_val)
- {
- /* The gimplifier explicitly enforces the following invariant:
-
- RETURN_EXPR
- |
- MODIFY_EXPR
- / \
- / \
- RET_OBJ ...
-
- As a consequence, type consistency dictates that we use the type
- of the RET_OBJ as the operation type. */
- tree operation_type = TREE_TYPE (ret_obj);
-
- /* Convert the right operand to the operation type. Note that it's the
- same transformation as in the MODIFY_EXPR case of build_binary_op,
- with the assumption that the type cannot involve a placeholder. */
- if (operation_type != TREE_TYPE (ret_val))
- ret_val = convert (operation_type, ret_val);
-
- result_expr = build2 (MODIFY_EXPR, operation_type, ret_obj, ret_val);
- }
- else
- result_expr = ret_obj;
-
- return build1 (RETURN_EXPR, void_type_node, result_expr);
-}
/* Build a CALL_EXPR to call FUNDECL with one argument, ARG. Return
the CALL_EXPR. */
diff --git a/gcc/ada/init.c b/gcc/ada/init.c
index 888ec208ca1..b46cafdbbc8 100644
--- a/gcc/ada/init.c
+++ b/gcc/ada/init.c
@@ -763,16 +763,31 @@ extern struct Exception_Data _abort_signal;
connecting that handler, with the effects described in the sigaction
man page:
- SA_SIGINFO [...]
- If cleared and the signal is caught, the first argument is
- also the signal number but the second argument is the signal
- code identifying the cause of the signal. The third argument
- points to a sigcontext_t structure containing the receiving
- process's context when the signal was delivered. */
+ SA_SIGINFO If set and the signal is caught, sig is passed as the
+ first argument to the signal-catching function. If the
+ second argument is not equal to NULL, it points to a
+ siginfo_t structure containing the reason why the
+ signal was generated [see siginfo(5)]; the third
+ argument points to a ucontext_t structure containing
+ the receiving process's context when the signal was
+ delivered [see ucontext(5)]. If cleared and the signal
+ is caught, the first argument is also the signal number
+ but the second argument is the signal code identifying
+ the cause of the signal. The third argument points to a
+ sigcontext_t structure containing the receiving
+ process's context when the signal was delivered. This
+ is the default behavior (see signal(5) for more
+ details). Additionally, when SA_SIGINFO is set for a
+ signal, multiple occurrences of that signal will be
+ queued for delivery in FIFO order (see sigqueue(3) for
+ a more detailed explanation of this concept), if those
+ occurrences of that signal were generated using
+ sigqueue(3). */
static void
-__gnat_error_handler (int sig, int code, sigcontext_t *sc ATTRIBUTE_UNUSED)
+__gnat_error_handler (int sig, siginfo_t *reason, void *uc ATTRIBUTE_UNUSED)
{
+ int code = reason == NULL ? 0 : reason->si_code;
struct Exception_Data *exception;
const char *msg;
@@ -859,7 +874,7 @@ __gnat_install_handler (void)
exceptions. Make sure that the handler isn't interrupted by another
signal that might cause a scheduling event! */
- act.sa_handler = __gnat_error_handler;
+ act.sa_sigaction = __gnat_error_handler;
act.sa_flags = SA_NODEFER + SA_RESTART;
sigfillset (&act.sa_mask);
sigemptyset (&act.sa_mask);
@@ -1031,7 +1046,7 @@ __gnat_install_handler (void)
exceptions. Make sure that the handler isn't interrupted by another
signal that might cause a scheduling event! */
- act.sa_handler = __gnat_error_handler;
+ act.sa_sigaction = __gnat_error_handler;
act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
sigemptyset (&act.sa_mask);
diff --git a/gcc/ada/tracebak.c b/gcc/ada/tracebak.c
index 6764cd42755..23fc5c79858 100644
--- a/gcc/ada/tracebak.c
+++ b/gcc/ada/tracebak.c
@@ -482,12 +482,12 @@ __gnat_backtrace (void **array,
while (cnt < size)
{
if (STOP_FRAME (current, top_stack) ||
- !VALID_STACK_FRAME((char *)(current->return_address + PC_ADJUST)))
+ !VALID_STACK_FRAME(((char *) current->return_address) + PC_ADJUST))
break;
if (current->return_address < exclude_min
|| current->return_address > exclude_max)
- array[cnt++] = current->return_address + PC_ADJUST;
+ array[cnt++] = ((char *) current->return_address) + PC_ADJUST;
current = (struct layout *) ((size_t) current->next + FRAME_OFFSET (1));
}
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index 29c1167cfe7..c03129c6abf 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -65,31 +65,34 @@ DEF_VEC_P(edge);
DEF_VEC_ALLOC_P(edge,gc);
DEF_VEC_ALLOC_P(edge,heap);
-#define EDGE_FALLTHRU 1 /* 'Straight line' flow */
-#define EDGE_ABNORMAL 2 /* Strange flow, like computed
+/* Always update the table in cfg.c dump_edge_info. */
+#define EDGE_FALLTHRU 0x0001 /* 'Straight line' flow */
+#define EDGE_ABNORMAL 0x0002 /* Strange flow, like computed
label, or eh */
-#define EDGE_ABNORMAL_CALL 4 /* Call with abnormal exit
+#define EDGE_ABNORMAL_CALL 0x0004 /* Call with abnormal exit
like an exception, or sibcall */
-#define EDGE_EH 8 /* Exception throw */
-#define EDGE_FAKE 16 /* Not a real edge (profile.c) */
-#define EDGE_DFS_BACK 32 /* A backwards edge */
-#define EDGE_CAN_FALLTHRU 64 /* Candidate for straight line
+#define EDGE_EH 0x0008 /* Exception throw */
+#define EDGE_FAKE 0x0010 /* Not a real edge (profile.c) */
+#define EDGE_DFS_BACK 0x0020 /* A backwards edge */
+#define EDGE_CAN_FALLTHRU 0x0040 /* Candidate for straight line
flow. */
-#define EDGE_IRREDUCIBLE_LOOP 128 /* Part of irreducible loop. */
-#define EDGE_SIBCALL 256 /* Edge from sibcall to exit. */
-#define EDGE_LOOP_EXIT 512 /* Exit of a loop. */
-#define EDGE_TRUE_VALUE 1024 /* Edge taken when controlling
+#define EDGE_IRREDUCIBLE_LOOP 0x0080 /* Part of irreducible loop. */
+#define EDGE_SIBCALL 0x0100 /* Edge from sibcall to exit. */
+#define EDGE_LOOP_EXIT 0x0200 /* Exit of a loop. */
+#define EDGE_TRUE_VALUE 0x0400 /* Edge taken when controlling
predicate is nonzero. */
-#define EDGE_FALSE_VALUE 2048 /* Edge taken when controlling
+#define EDGE_FALSE_VALUE 0x0800 /* Edge taken when controlling
predicate is zero. */
-#define EDGE_EXECUTABLE 4096 /* Edge is executable. Only
+#define EDGE_EXECUTABLE 0x1000 /* Edge is executable. Only
valid during SSA-CCP. */
-#define EDGE_CROSSING 8192 /* Edge crosses between hot
+#define EDGE_CROSSING 0x2000 /* Edge crosses between hot
and cold sections, when we
do partitioning. */
-#define EDGE_ALL_FLAGS 16383
+#define EDGE_PRESERVE 0x4000 /* Never merge blocks via this edge. */
+#define EDGE_ALL_FLAGS 0x7fff
-#define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH)
+#define EDGE_COMPLEX \
+ (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH | EDGE_PRESERVE)
/* Counter summary from the last set of coverage counts read by
profile.c. */
@@ -203,7 +206,9 @@ DEF_VEC_ALLOC_P(basic_block,heap);
the compilation, so they are never cleared.
All other flags may be cleared by clear_bb_flags(). It is generally
- a bad idea to rely on any flags being up-to-date. */
+ a bad idea to rely on any flags being up-to-date.
+
+ Always update the table in cfg.c dump_bb_info. */
enum bb_flags
{
diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index fac5b296af2..11423fed29a 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -87,6 +87,7 @@
#include "tree-pass.h"
#include "df.h"
#include "bb-reorder.h"
+#include "except.h"
/* The number of rounds. In most cases there will only be 4 rounds, but
when partitioning hot and cold basic blocks into separate sections of
@@ -1208,6 +1209,79 @@ get_uncond_jump_length (void)
return length;
}
+/* Emit a barrier into the footer of BB. */
+
+static void
+emit_barrier_after_bb (basic_block bb)
+{
+ rtx barrier = emit_barrier_after (BB_END (bb));
+ bb->il.rtl->footer = unlink_insn_chain (barrier, barrier);
+}
+
+/* The landing pad OLD_LP, in block OLD_BB, has edges from both partitions.
+ Duplicate the landing pad and split the edges so that no EH edge
+ crosses partitions. */
+
+static void
+fix_up_crossing_landing_pad (eh_landing_pad old_lp, basic_block old_bb)
+{
+ eh_landing_pad new_lp;
+ basic_block new_bb, last_bb, post_bb;
+ rtx new_label, jump, post_label;
+ unsigned new_partition;
+ edge_iterator ei;
+ edge e;
+
+ /* Generate the new landing-pad structure. */
+ new_lp = gen_eh_landing_pad (old_lp->region);
+ new_lp->post_landing_pad = old_lp->post_landing_pad;
+ new_lp->landing_pad = gen_label_rtx ();
+ LABEL_PRESERVE_P (new_lp->landing_pad) = 1;
+
+ /* Put appropriate instructions in new bb. */
+ new_label = emit_label (new_lp->landing_pad);
+
+ expand_dw2_landing_pad_for_region (old_lp->region);
+
+ post_bb = BLOCK_FOR_INSN (old_lp->landing_pad);
+ post_bb = single_succ (post_bb);
+ post_label = block_label (post_bb);
+ jump = emit_jump_insn (gen_jump (post_label));
+ JUMP_LABEL (jump) = post_label;
+
+ /* Create new basic block to be dest for lp. */
+ last_bb = EXIT_BLOCK_PTR->prev_bb;
+ new_bb = create_basic_block (new_label, jump, last_bb);
+ new_bb->aux = last_bb->aux;
+ last_bb->aux = new_bb;
+
+ emit_barrier_after_bb (new_bb);
+
+ make_edge (new_bb, post_bb, 0);
+
+ /* Make sure new bb is in the other partition. */
+ new_partition = BB_PARTITION (old_bb);
+ new_partition ^= BB_HOT_PARTITION | BB_COLD_PARTITION;
+ BB_SET_PARTITION (new_bb, new_partition);
+
+ /* Fix up the edges. */
+ for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)) != NULL; )
+ if (BB_PARTITION (e->src) == new_partition)
+ {
+ rtx insn = BB_END (e->src);
+ rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+
+ gcc_assert (note != NULL);
+ gcc_checking_assert (INTVAL (XEXP (note, 0)) == old_lp->index);
+ XEXP (note, 0) = GEN_INT (new_lp->index);
+
+ /* Adjust the edge to the new destination. */
+ redirect_edge_succ (e, new_bb);
+ }
+ else
+ ei_next (&ei);
+}
+
/* Find the basic blocks that are rarely executed and need to be moved to
a separate section of the .o file (to cut down on paging and improve
cache locality). Return a vector of all edges that cross. */
@@ -1221,7 +1295,6 @@ find_rarely_executed_basic_blocks_and_crossing_edges (void)
edge_iterator ei;
/* Mark which partition (hot/cold) each basic block belongs in. */
-
FOR_EACH_BB (bb)
{
if (probably_never_executed_bb_p (bb))
@@ -1230,32 +1303,71 @@ find_rarely_executed_basic_blocks_and_crossing_edges (void)
BB_SET_PARTITION (bb, BB_HOT_PARTITION);
}
- /* Mark every edge that crosses between sections. */
-
- FOR_EACH_BB (bb)
- FOR_EACH_EDGE (e, ei, bb->succs)
+ /* The format of .gcc_except_table does not allow landing pads to
+ be in a different partition as the throw. Fix this by either
+ moving or duplicating the landing pads. */
+ if (cfun->eh->lp_array)
{
- if (e->src != ENTRY_BLOCK_PTR
- && e->dest != EXIT_BLOCK_PTR
- && BB_PARTITION (e->src) != BB_PARTITION (e->dest))
+ unsigned i;
+ eh_landing_pad lp;
+
+ FOR_EACH_VEC_ELT (eh_landing_pad, cfun->eh->lp_array, i, lp)
{
- e->flags |= EDGE_CROSSING;
- VEC_safe_push (edge, heap, crossing_edges, e);
+ bool all_same, all_diff;
+
+ if (lp == NULL)
+ continue;
+
+ all_same = all_diff = true;
+ bb = BLOCK_FOR_INSN (lp->landing_pad);
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ gcc_assert (e->flags & EDGE_EH);
+ if (BB_PARTITION (bb) == BB_PARTITION (e->src))
+ all_diff = false;
+ else
+ all_same = false;
+ }
+
+ if (all_same)
+ ;
+ else if (all_diff)
+ {
+ int which = BB_PARTITION (bb);
+ which ^= BB_HOT_PARTITION | BB_COLD_PARTITION;
+ BB_SET_PARTITION (bb, which);
+ }
+ else
+ fix_up_crossing_landing_pad (lp, bb);
}
- else
- e->flags &= ~EDGE_CROSSING;
}
- return crossing_edges;
-}
+ /* Mark every edge that crosses between sections. */
-/* Emit a barrier into the footer of BB. */
+ FOR_EACH_BB (bb)
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ unsigned int flags = e->flags;
+
+ /* We should never have EDGE_CROSSING set yet. */
+ gcc_checking_assert ((flags & EDGE_CROSSING) == 0);
+
+ if (e->src != ENTRY_BLOCK_PTR
+ && e->dest != EXIT_BLOCK_PTR
+ && BB_PARTITION (e->src) != BB_PARTITION (e->dest))
+ {
+ VEC_safe_push (edge, heap, crossing_edges, e);
+ flags |= EDGE_CROSSING;
+ }
-static void
-emit_barrier_after_bb (basic_block bb)
-{
- rtx barrier = emit_barrier_after (BB_END (bb));
- bb->il.rtl->footer = unlink_insn_chain (barrier, barrier);
+ /* Now that we've split eh edges as appropriate, allow landing pads
+ to be merged with the post-landing pads. */
+ flags &= ~EDGE_PRESERVE;
+
+ e->flags = flags;
+ }
+
+ return crossing_edges;
}
/* If any destination of a crossing edge does not have a label, add label;
@@ -2108,6 +2220,8 @@ partition_hot_cold_basic_blocks (void)
if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1)
return 0;
+ df_set_flags (DF_DEFER_INSN_RESCAN);
+
crossing_edges = find_rarely_executed_basic_blocks_and_crossing_edges ();
if (crossing_edges == NULL)
return 0;
@@ -2139,6 +2253,38 @@ partition_hot_cold_basic_blocks (void)
VEC_free (edge, heap, crossing_edges);
+ /* ??? FIXME: DF generates the bb info for a block immediately.
+ And by immediately, I mean *during* creation of the block.
+
+ #0 df_bb_refs_collect
+ #1 in df_bb_refs_record
+ #2 in create_basic_block_structure
+
+ Which means that the bb_has_eh_pred test in df_bb_refs_collect
+ will *always* fail, because no edges can have been added to the
+ block yet. Which of course means we don't add the right
+ artificial refs, which means we fail df_verify (much) later.
+
+ Cleanest solution would seem to make DF_DEFER_INSN_RESCAN imply
+ that we also shouldn't grab data from the new blocks those new
+ insns are in either. In this way one can create the block, link
+ it up properly, and have everything Just Work later, when deferred
+ insns are processed.
+
+ In the meantime, we have no other option but to throw away all
+ of the DF data and recompute it all. */
+ if (cfun->eh->lp_array)
+ {
+ df_finish_pass (true);
+ df_scan_alloc (NULL);
+ df_scan_blocks ();
+ /* Not all post-landing pads use all of the EH_RETURN_DATA_REGNO
+ data. We blindly generated all of them when creating the new
+ landing pad. Delete those assignments we don't use. */
+ df_set_flags (DF_LR_RUN_DCE);
+ df_analyze ();
+ }
+
return TODO_verify_flow | TODO_verify_rtl_sharing;
}
@@ -2212,6 +2358,7 @@ gate_handle_partition_blocks (void)
user defined section attributes. Don't call it if either case
arises. */
return (flag_reorder_blocks_and_partition
+ && optimize
&& !DECL_ONE_ONLY (current_function_decl)
&& !user_defined_section_attribute);
}
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 3ed3c46e64c..33d2615bc22 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -8501,6 +8501,14 @@ identifier_global_value (tree t)
return 0;
}
+/* In C, the only C-linkage public declaration is at file scope. */
+
+tree
+c_linkage_bindings (tree name)
+{
+ return identifier_global_value (name);
+}
+
/* Record a builtin type for C. If NAME is non-NULL, it is the name used;
otherwise the name is found in ridpointers from RID_INDEX. */
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index c5f2306ca62..be7317d0eb2 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,27 @@
+2011-07-22 Jason Merrill <jason@redhat.com>
+
+ PR c++/49793
+ * c.opt (Wnarrowing): New.
+
+ PR c++/30112
+ * c-common.h: Declare c_linkage_bindings.
+ * c-pragma.c (handle_pragma_redefine_extname): Use it.
+
+ PR c++/49813
+ * c-opts.c (set_std_cxx0x): Set flag_isoc94 and flag_isoc99.
+ * c-pretty-print.c (pp_c_cv_qualifiers): Check c_dialect_cxx as well
+ as flag_isoc99 for 'restrict'.
+ (pp_c_specifier_qualifier_list): Likewise for _Complex.
+
+2011-07-21 Ian Lance Taylor <iant@google.com>
+
+ PR middle-end/49705
+ * c-common.c (c_disable_warnings): New static function.
+ (c_enable_warnings): New static function.
+ (c_fully_fold_internal): Change local unused_p to bool. Call
+ c_disable_warnings and c_enable_warnings rather than change
+ c_inhibit_evaluation_warnings.
+
2011-07-20 Jason Merrill <jason@redhat.com>
PR c++/6709 (DR 743)
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 6078d948ae4..96275bac70a 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -963,6 +963,32 @@ fix_string_type (tree value)
return value;
}
+/* If DISABLE is true, stop issuing warnings. This is used when
+ parsing code that we know will not be executed. This function may
+ be called multiple times, and works as a stack. */
+
+static void
+c_disable_warnings (bool disable)
+{
+ if (disable)
+ {
+ ++c_inhibit_evaluation_warnings;
+ fold_defer_overflow_warnings ();
+ }
+}
+
+/* If ENABLE is true, reenable issuing warnings. */
+
+static void
+c_enable_warnings (bool enable)
+{
+ if (enable)
+ {
+ --c_inhibit_evaluation_warnings;
+ fold_undefer_and_ignore_overflow_warnings ();
+ }
+}
+
/* Fully fold EXPR, an expression that was not folded (beyond integer
constant expressions and null pointer constants) when being built
up. If IN_INIT, this is in a static initializer and certain
@@ -1029,7 +1055,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
bool op0_const = true, op1_const = true, op2_const = true;
bool op0_const_self = true, op1_const_self = true, op2_const_self = true;
bool nowarning = TREE_NO_WARNING (expr);
- int unused_p;
+ bool unused_p;
/* This function is not relevant to C++ because C++ folds while
parsing, and may need changes to be correct for C++ when C++
@@ -1278,10 +1304,10 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
unused_p = (op0 == (code == TRUTH_ANDIF_EXPR
? truthvalue_false_node
: truthvalue_true_node));
- c_inhibit_evaluation_warnings += unused_p;
+ c_disable_warnings (unused_p);
op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
STRIP_TYPE_NOPS (op1);
- c_inhibit_evaluation_warnings -= unused_p;
+ c_enable_warnings (unused_p);
if (op0 != orig_op0 || op1 != orig_op1 || in_init)
ret = in_init
@@ -1313,15 +1339,15 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self);
STRIP_TYPE_NOPS (op0);
- c_inhibit_evaluation_warnings += (op0 == truthvalue_false_node);
+ c_disable_warnings (op0 == truthvalue_false_node);
op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
STRIP_TYPE_NOPS (op1);
- c_inhibit_evaluation_warnings -= (op0 == truthvalue_false_node);
+ c_enable_warnings (op0 == truthvalue_false_node);
- c_inhibit_evaluation_warnings += (op0 == truthvalue_true_node);
+ c_disable_warnings (op0 == truthvalue_true_node);
op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self);
STRIP_TYPE_NOPS (op2);
- c_inhibit_evaluation_warnings -= (op0 == truthvalue_true_node);
+ c_enable_warnings (op0 == truthvalue_true_node);
if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2)
ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2);
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 13aae0f3ecc..202be02a0f3 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -710,6 +710,7 @@ extern void c_register_addr_space (const char *str, addr_space_t as);
extern bool in_late_binary_op;
extern const char *c_addr_space_name (addr_space_t as);
extern tree identifier_global_value (tree);
+extern tree c_linkage_bindings (tree);
extern void record_builtin_type (enum rid, const char *, tree);
extern tree build_void_list_node (void);
extern void start_fname_decls (void);
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 5cf58acd62d..3227f7b9860 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -1488,6 +1488,9 @@ set_std_cxx0x (int iso)
flag_no_gnu_keywords = iso;
flag_no_nonansi_builtin = iso;
flag_iso = iso;
+ /* C++0x includes the C99 standard library. */
+ flag_isoc94 = 1;
+ flag_isoc99 = 1;
cxx_dialect = cxx0x;
}
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index 93735aa2523..5c8bc1f8ac7 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -417,8 +417,9 @@ static void handle_pragma_redefine_extname (cpp_reader *);
static void
handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy))
{
- tree oldname, newname, decl, x;
+ tree oldname, newname, decls, x;
enum cpp_ttype t;
+ bool found;
if (pragma_lex (&oldname) != CPP_NAME)
GCC_BAD ("malformed #pragma redefine_extname, ignored");
@@ -428,26 +429,42 @@ handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy))
if (t != CPP_EOF)
warning (OPT_Wpragmas, "junk at end of %<#pragma redefine_extname%>");
- decl = identifier_global_value (oldname);
- if (decl
- && (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
- && (TREE_CODE (decl) == FUNCTION_DECL
- || TREE_CODE (decl) == VAR_DECL)
- && has_c_linkage (decl))
+ found = false;
+ for (decls = c_linkage_bindings (oldname);
+ decls; )
{
- if (DECL_ASSEMBLER_NAME_SET_P (decl))
+ tree decl;
+ if (TREE_CODE (decls) == TREE_LIST)
{
- const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- name = targetm.strip_name_encoding (name);
-
- if (strcmp (name, IDENTIFIER_POINTER (newname)))
- warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to "
- "conflict with previous rename");
+ decl = TREE_VALUE (decls);
+ decls = TREE_CHAIN (decls);
}
else
- change_decl_assembler_name (decl, newname);
+ {
+ decl = decls;
+ decls = NULL_TREE;
+ }
+
+ if ((TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
+ && (TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == VAR_DECL))
+ {
+ found = true;
+ if (DECL_ASSEMBLER_NAME_SET_P (decl))
+ {
+ const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ name = targetm.strip_name_encoding (name);
+
+ if (strcmp (name, IDENTIFIER_POINTER (newname)))
+ warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to "
+ "conflict with previous rename");
+ }
+ else
+ change_decl_assembler_name (decl, newname);
+ }
}
- else
+
+ if (!found)
/* We have to add this to the rename list even if there's already
a global value that doesn't meet the above criteria, because in
C++ "struct foo {...};" puts "foo" in the current namespace but
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index 977f79ed7df..53d39d643d0 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -205,7 +205,8 @@ pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type)
{
if (previous)
pp_c_whitespace (pp);
- pp_c_ws_string (pp, flag_isoc99 ? "restrict" : "__restrict__");
+ pp_c_ws_string (pp, (flag_isoc99 && !c_dialect_cxx ()
+ ? "restrict" : "__restrict__"));
}
}
@@ -476,7 +477,8 @@ pp_c_specifier_qualifier_list (c_pretty_printer *pp, tree t)
case VECTOR_TYPE:
case COMPLEX_TYPE:
if (code == COMPLEX_TYPE)
- pp_c_ws_string (pp, flag_isoc99 ? "_Complex" : "__complex__");
+ pp_c_ws_string (pp, (flag_isoc99 && !c_dialect_cxx ()
+ ? "_Complex" : "__complex__"));
else if (code == VECTOR_TYPE)
{
pp_c_ws_string (pp, "__vector");
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 00bdd93f124..617ea2d8905 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -489,6 +489,10 @@ Wmultichar
C ObjC C++ ObjC++ Warning
Warn about use of multi-character character constants
+Wnarrowing
+C ObjC C++ ObjC++ Warning Var(warn_narrowing) Init(1)
+-Wno-narrowing In C++0x mode, ignore ill-formed narrowing conversions within { }
+
Wnested-externs
C ObjC Var(warn_nested_externs) Warning
Warn about \"extern\" declarations not at file scope
diff --git a/gcc/cfg.c b/gcc/cfg.c
index 00d1d5cb7d8..ca04c94770e 100644
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -720,7 +720,7 @@ dump_edge_info (FILE *file, edge e, int do_succ)
static const char * const bitnames[] = {
"fallthru", "ab", "abcall", "eh", "fake", "dfs_back",
"can_fallthru", "irreducible", "sibcall", "loop_exit",
- "true", "false", "exec"
+ "true", "false", "exec", "crossing", "preserve"
};
int comma = 0;
int i, flags = e->flags;
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index b8843cae579..076ff03d056 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -1820,18 +1820,38 @@ rtl_verify_flow_info_1 (void)
}
FOR_EACH_EDGE (e, ei, bb->succs)
{
+ bool is_crossing;
+
if (e->flags & EDGE_FALLTHRU)
+ n_fallthru++, fallthru = e;
+
+ is_crossing = (BB_PARTITION (e->src) != BB_PARTITION (e->dest)
+ && e->src != ENTRY_BLOCK_PTR
+ && e->dest != EXIT_BLOCK_PTR);
+ if (e->flags & EDGE_CROSSING)
{
- n_fallthru++, fallthru = e;
- if ((e->flags & EDGE_CROSSING)
- || (BB_PARTITION (e->src) != BB_PARTITION (e->dest)
- && e->src != ENTRY_BLOCK_PTR
- && e->dest != EXIT_BLOCK_PTR))
- {
+ if (!is_crossing)
+ {
+ error ("EDGE_CROSSING incorrectly set across same section");
+ err = 1;
+ }
+ if (e->flags & EDGE_FALLTHRU)
+ {
error ("fallthru edge crosses section boundary (bb %i)",
e->src->index);
err = 1;
}
+ if (e->flags & EDGE_EH)
+ {
+ error ("EH edge crosses section boundary (bb %i)",
+ e->src->index);
+ err = 1;
+ }
+ }
+ else if (is_crossing)
+ {
+ error ("EDGE_CROSSING missing across section boundary");
+ err = 1;
}
if ((e->flags & ~(EDGE_DFS_BACK
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 83ac720c797..93664f9d8a4 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -456,17 +456,23 @@ cgraph_debug_gimple_stmt (struct function *this_cfun, gimple stmt)
static bool
verify_edge_corresponds_to_fndecl (struct cgraph_edge *e, tree decl)
{
- if (!e->callee->global.inlined_to
- && decl
- && cgraph_get_node (decl)
- && (e->callee->former_clone_of
- != cgraph_function_or_thunk_node (cgraph_get_node (decl), NULL)->decl)
+ struct cgraph_node *node;
+
+ if (!decl || e->callee->global.inlined_to)
+ return false;
+ node = cgraph_get_node (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)
+ return false;
+ node = cgraph_function_or_thunk_node (node, NULL);
+
+ if ((e->callee->former_clone_of != node->decl)
/* IPA-CP sometimes redirect edge to clone and then back to the former
function. This ping-pong has to go, eventaully. */
- && (cgraph_function_or_thunk_node (cgraph_get_node (decl), NULL)
- != cgraph_function_or_thunk_node (e->callee, NULL))
- && !clone_of_p (cgraph_get_node (decl),
- e->callee))
+ && (node != cgraph_function_or_thunk_node (e->callee, NULL))
+ && !clone_of_p (node, e->callee))
return true;
else
return false;
diff --git a/gcc/collect2.c b/gcc/collect2.c
index dadf82d34b1..cf39693f653 100644
--- a/gcc/collect2.c
+++ b/gcc/collect2.c
@@ -179,7 +179,6 @@ struct head
bool vflag; /* true if -v or --version */
static int rflag; /* true if -r */
static int strip_flag; /* true if -s */
-static const char *demangle_flag;
#ifdef COLLECT_EXPORT_LIST
static int export_flag; /* true if -bE */
static int aix64_flag; /* true if -b64 */
@@ -1112,10 +1111,12 @@ main (int argc, char **argv)
num_c_args = argc + 9;
+#ifndef HAVE_LD_DEMANGLE
no_demangle = !! getenv ("COLLECT_NO_DEMANGLE");
/* Suppress demangling by the real linker, which may be broken. */
- putenv (xstrdup ("COLLECT_NO_DEMANGLE="));
+ putenv (xstrdup ("COLLECT_NO_DEMANGLE=1"));
+#endif
#if defined (COLLECT2_HOST_INITIALIZATION)
/* Perform system dependent initialization, if necessary. */
@@ -1405,12 +1406,6 @@ main (int argc, char **argv)
/* After the first file, put in the c++ rt0. */
first_file = 1;
-#ifdef HAVE_LD_DEMANGLE
- if (!demangle_flag && !no_demangle)
- demangle_flag = "--demangle";
- if (demangle_flag)
- *ld1++ = *ld2++ = demangle_flag;
-#endif
while ((arg = *++argv) != (char *) 0)
{
*ld1++ = *ld2++ = arg;
@@ -1514,16 +1509,16 @@ main (int argc, char **argv)
case '-':
if (strcmp (arg, "--no-demangle") == 0)
{
- demangle_flag = arg;
+#ifndef HAVE_LD_DEMANGLE
no_demangle = 1;
ld1--;
ld2--;
+#endif
}
else if (strncmp (arg, "--demangle", 10) == 0)
{
- demangle_flag = arg;
- no_demangle = 0;
#ifndef HAVE_LD_DEMANGLE
+ no_demangle = 0;
if (arg[10] == '=')
{
enum demangling_styles style
@@ -1533,9 +1528,9 @@ main (int argc, char **argv)
else
current_demangling_style = style;
}
-#endif
ld1--;
ld2--;
+#endif
}
else if (strncmp (arg, "--sysroot=", 10) == 0)
target_system_root = arg + 10;
diff --git a/gcc/common.opt b/gcc/common.opt
index 1874ca6788d..a25424c9542 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2313,6 +2313,14 @@ ggdb
Common JoinedOrMissing
Generate debug information in default extended format
+gno-record-gcc-switches
+Common RejectNegative Var(dwarf_record_gcc_switches,0) Init(0)
+Don't record gcc command line switches in DWARF DW_AT_producer.
+
+grecord-gcc-switches
+Common RejectNegative Var(dwarf_record_gcc_switches,1)
+Record gcc command line switches in DWARF DW_AT_producer.
+
gstabs
Common JoinedOrMissing Negative(gstabs+)
Generate debug information in STABS format
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 4a16ff836be..2eca5a91de4 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -1312,10 +1312,18 @@ i[34567]86-*-linux* | i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-knetbsd*-gnu | i
tm_file="${tm_file} i386/gnu-user.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" ;;
- i[34567]86-*-kfreebsd*-gnu) tm_file="${tm_file} 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" ;;
- i[34567]86-*-gnu*) tm_file="$tm_file i386/gnu-user.h gnu.h i386/gnu.h";;
+ i[34567]86-*-knetbsd*-gnu)
+ tm_file="${tm_file} 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"
+ ;;
+ i[34567]86-*-kopensolaris*-gnu)
+ tm_file="${tm_file} 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"
+ ;;
esac
tmake_file="${tmake_file} i386/t-crtstuff"
# This is a hack to avoid a configuration mismatch
@@ -1327,10 +1335,16 @@ x86_64-*-linux* | x86_64-*-kfreebsd*-gnu | x86_64-*-knetbsd*-gnu)
i386/x86-64.h i386/gnu-user64.h"
case ${target} in
x86_64-*-linux*)
- tm_file="${tm_file} linux.h i386/linux64.h"
- default_gnu_indirect_function=glibc-2011 ;;
- x86_64-*-kfreebsd*-gnu) tm_file="${tm_file} kfreebsd-gnu.h i386/kfreebsd-gnu64.h" ;;
- x86_64-*-knetbsd*-gnu) tm_file="${tm_file} knetbsd-gnu.h" ;;
+ tm_file="${tm_file} linux.h i386/linux64.h"
+ # Assume modern glibc
+ default_gnu_indirect_function=yes
+ ;;
+ x86_64-*-kfreebsd*-gnu)
+ tm_file="${tm_file} kfreebsd-gnu.h i386/kfreebsd-gnu64.h"
+ ;;
+ x86_64-*-knetbsd*-gnu)
+ tm_file="${tm_file} knetbsd-gnu.h"
+ ;;
esac
tmake_file="${tmake_file} i386/t-linux64 i386/t-crtstuff"
x86_multilibs="${with_multilib_list}"
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 6e2b799fe57..a51c87a078f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3996,7 +3996,7 @@ aapcs_vfp_allocate_return_reg (enum arm_pcs pcs_variant ATTRIBUTE_UNUSED,
const_tree type ATTRIBUTE_UNUSED)
{
if (!use_vfp_abi (pcs_variant, false))
- return false;
+ return NULL;
if (mode == BLKmode || (mode == TImode && !TARGET_NEON))
{
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index da6c888ed46..96263ed9835 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -3133,6 +3133,9 @@ ix86_option_override_internal (bool main_args_p)
if (!global_options_set.x_ix86_abi)
ix86_abi = DEFAULT_ABI;
+ if (ix86_abi == MS_ABI && TARGET_X32)
+ error ("MS ABI not supported in x32 mode");
+
if (global_options_set.x_ix86_cmodel)
{
switch (ix86_cmodel)
@@ -7078,6 +7081,11 @@ function_value_64 (enum machine_mode orig_mode, enum machine_mode mode,
return gen_rtx_REG (mode, AX_REG);
}
}
+ else if (POINTER_TYPE_P (valtype))
+ {
+ /* Pointers are always returned in Pmode. */
+ mode = Pmode;
+ }
ret = construct_container (mode, orig_mode, valtype, 1,
X86_64_REGPARM_MAX, X86_64_SSE_REGPARM_MAX,
@@ -7147,6 +7155,22 @@ ix86_function_value (const_tree valtype, const_tree fntype_or_decl,
return ix86_function_value_1 (valtype, fntype_or_decl, orig_mode, mode);
}
+/* Pointer function arguments and return values are promoted to Pmode. */
+
+static enum machine_mode
+ix86_promote_function_mode (const_tree type, enum machine_mode mode,
+ int *punsignedp, const_tree fntype,
+ int for_return)
+{
+ if (type != NULL_TREE && POINTER_TYPE_P (type))
+ {
+ *punsignedp = POINTERS_EXTEND_UNSIGNED;
+ return Pmode;
+ }
+ return default_promote_function_mode (type, mode, punsignedp, fntype,
+ for_return);
+}
+
rtx
ix86_libcall_value (enum machine_mode mode)
{
@@ -12623,7 +12647,11 @@ ix86_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
rtx temp = gen_reg_rtx (Pmode);
rtx val = force_operand (XEXP (x, 1), temp);
if (val != temp)
- emit_move_insn (temp, val);
+ {
+ if (GET_MODE (val) != Pmode)
+ val = convert_to_mode (Pmode, val, 1);
+ emit_move_insn (temp, val);
+ }
XEXP (x, 1) = temp;
return x;
@@ -12634,7 +12662,11 @@ ix86_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
rtx temp = gen_reg_rtx (Pmode);
rtx val = force_operand (XEXP (x, 0), temp);
if (val != temp)
- emit_move_insn (temp, val);
+ {
+ if (GET_MODE (val) != Pmode)
+ val = convert_to_mode (Pmode, val, 1);
+ emit_move_insn (temp, val);
+ }
XEXP (x, 0) = temp;
return x;
@@ -14964,6 +14996,8 @@ ix86_expand_move (enum machine_mode mode, rtx operands[])
op1 = force_operand (op1, op0);
if (op1 == op0)
return;
+ if (GET_MODE (op1) != mode)
+ op1 = convert_to_mode (mode, op1, 1);
}
else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
&& SYMBOL_REF_DLLIMPORT_P (op1))
@@ -21481,8 +21515,10 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
? !sibcall_insn_operand (XEXP (fnaddr, 0), Pmode)
: !call_insn_operand (XEXP (fnaddr, 0), Pmode))
{
- fnaddr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
- fnaddr = gen_rtx_MEM (QImode, fnaddr);
+ fnaddr = XEXP (fnaddr, 0);
+ if (GET_MODE (fnaddr) != Pmode)
+ fnaddr = convert_to_mode (Pmode, fnaddr, 1);
+ fnaddr = gen_rtx_MEM (QImode, copy_to_mode_reg (Pmode, fnaddr));
}
call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
@@ -25460,7 +25496,7 @@ ix86_init_builtins (void)
ix86_init_mmx_sse_builtins ();
- if (TARGET_64BIT)
+ if (TARGET_LP64)
ix86_init_builtins_va_builtins_abi ();
#ifdef SUBTARGET_INIT_BUILTINS
@@ -26706,7 +26742,11 @@ ix86_expand_special_args_builtin (const struct builtin_description *d,
op = expand_normal (arg);
gcc_assert (target == 0);
if (memory)
- target = gen_rtx_MEM (tmode, copy_to_mode_reg (Pmode, op));
+ {
+ if (GET_MODE (op) != Pmode)
+ op = convert_to_mode (Pmode, op, 1);
+ target = gen_rtx_MEM (tmode, force_reg (Pmode, op));
+ }
else
target = force_reg (tmode, op);
arg_adjust = 1;
@@ -26749,7 +26789,9 @@ ix86_expand_special_args_builtin (const struct builtin_description *d,
if (i == memory)
{
/* This must be the memory operand. */
- op = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, op));
+ if (GET_MODE (op) != Pmode)
+ op = convert_to_mode (Pmode, op, 1);
+ op = gen_rtx_MEM (mode, force_reg (Pmode, op));
gcc_assert (GET_MODE (op) == mode
|| GET_MODE (op) == VOIDmode);
}
@@ -26975,8 +27017,9 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
mode1 = insn_data[icode].operand[1].mode;
mode2 = insn_data[icode].operand[2].mode;
- op0 = force_reg (Pmode, op0);
- op0 = gen_rtx_MEM (mode1, op0);
+ if (GET_MODE (op0) != Pmode)
+ op0 = convert_to_mode (Pmode, op0, 1);
+ op0 = gen_rtx_MEM (mode1, force_reg (Pmode, op0));
if (!insn_data[icode].operand[0].predicate (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
@@ -27007,7 +27050,11 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
op0 = expand_normal (arg0);
icode = CODE_FOR_sse2_clflush;
if (!insn_data[icode].operand[0].predicate (op0, Pmode))
- op0 = copy_to_mode_reg (Pmode, op0);
+ {
+ if (GET_MODE (op0) != Pmode)
+ op0 = convert_to_mode (Pmode, op0, 1);
+ op0 = force_reg (Pmode, op0);
+ }
emit_insn (gen_sse2_clflush (op0));
return 0;
@@ -27020,7 +27067,11 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
op1 = expand_normal (arg1);
op2 = expand_normal (arg2);
if (!REG_P (op0))
- op0 = copy_to_mode_reg (Pmode, op0);
+ {
+ if (GET_MODE (op0) != Pmode)
+ op0 = convert_to_mode (Pmode, op0, 1);
+ op0 = force_reg (Pmode, op0);
+ }
if (!REG_P (op1))
op1 = copy_to_mode_reg (SImode, op1);
if (!REG_P (op2))
@@ -27100,7 +27151,11 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
op0 = expand_normal (arg0);
icode = CODE_FOR_lwp_llwpcb;
if (!insn_data[icode].operand[0].predicate (op0, Pmode))
- op0 = copy_to_mode_reg (Pmode, op0);
+ {
+ if (GET_MODE (op0) != Pmode)
+ op0 = convert_to_mode (Pmode, op0, 1);
+ op0 = force_reg (Pmode, op0);
+ }
emit_insn (gen_lwp_llwpcb (op0));
return 0;
@@ -27159,7 +27214,10 @@ rdrand_step:
arg0 = CALL_EXPR_ARG (exp, 0);
op1 = expand_normal (arg0);
if (!address_operand (op1, VOIDmode))
- op1 = copy_addr_to_reg (op1);
+ {
+ op1 = convert_memory_address (Pmode, op1);
+ op1 = copy_addr_to_reg (op1);
+ }
emit_move_insn (gen_rtx_MEM (mode0, op1), op0);
op1 = gen_reg_rtx (SImode);
@@ -29258,7 +29316,7 @@ ix86_handle_abi_attribute (tree *node, tree name,
*no_add_attrs = true;
return NULL_TREE;
}
- if (!TARGET_64BIT)
+ if (!TARGET_LP64)
{
warning (OPT_Wattributes, "%qE attribute only available for 64-bit",
name);
@@ -34970,6 +35028,9 @@ ix86_autovectorize_vector_sizes (void)
#undef TARGET_FUNCTION_VALUE_REGNO_P
#define TARGET_FUNCTION_VALUE_REGNO_P ix86_function_value_regno_p
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE ix86_promote_function_mode
+
#undef TARGET_SECONDARY_RELOAD
#define TARGET_SECONDARY_RELOAD ix86_secondary_reload
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 20b3cb8fea6..0d4e6d5069f 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -21894,17 +21894,18 @@ const char *
rs6000_xcoff_strip_dollar (const char *name)
{
char *strip, *p;
- int len;
+ const char *q;
+ size_t len;
- p = strchr (name, '$');
+ q = (const char *) strchr (name, '$');
- if (p == 0 || p == name)
+ if (q == 0 || q == name)
return name;
len = strlen (name);
- strip = (char *) alloca (len + 1);
+ strip = XALLOCAVEC (char, len + 1);
strcpy (strip, name);
- p = strchr (strip, '$');
+ p = strip + (q - name);
while (p)
{
*p = '_';
diff --git a/gcc/config/sol2-c.c b/gcc/config/sol2-c.c
index ff42c38952d..0076be741ce 100644
--- a/gcc/config/sol2-c.c
+++ b/gcc/config/sol2-c.c
@@ -1,5 +1,6 @@
/* Solaris support needed only by C/C++ frontends.
- Copyright (C) 2004, 2005, 2007, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2007, 2009, 2010, 2011
+ Free Software Foundation, Inc.
Contributed by CodeSourcery, LLC.
This file is part of GCC.
@@ -68,7 +69,7 @@ static const format_char_info cmn_err_char_table[] =
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
};
-const format_kind_info solaris_format_types[] = {
+EXPORTED_CONST format_kind_info solaris_format_types[] = {
{ "cmn_err", cmn_err_length_specs, cmn_err_char_table, "", NULL,
cmn_err_flag_specs, cmn_err_flag_pairs,
FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK,
diff --git a/gcc/configure b/gcc/configure
index 0295fc67dfe..1a4c1b70448 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -3413,7 +3413,7 @@ fi
if test "${with_demangler_in_ld+set}" = set; then :
withval=$with_demangler_in_ld; demangler_in_ld="$with_demangler_in_ld"
else
- demangler_in_ld=no
+ demangler_in_ld=yes
fi
@@ -9294,6 +9294,8 @@ $as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h
fi
+# g++ on Solaris 10+ defines _XOPEN_SOURCE=600, which exposes a different
+# iconv() prototype.
if test "X$prefix" = "XNONE"; then
acl_final_prefix="$ac_default_prefix"
@@ -9835,6 +9837,175 @@ fi
fi
+if test "$ENABLE_BUILD_WITH_CXX" = "yes"; then :
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+
+
+ am_save_CPPFLAGS="$CPPFLAGS"
+
+ for element in $INCICONV; do
+ haveit=
+ for x in $CPPFLAGS; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+ fi
+ done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5
+$as_echo_n "checking for iconv... " >&6; }
+if test "${am_cv_func_iconv+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ am_cv_func_iconv="no, consider installing GNU libiconv"
+ am_cv_lib_iconv=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <iconv.h>
+int
+main ()
+{
+iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ am_cv_func_iconv=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test "$am_cv_func_iconv" != yes; then
+ am_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBICONV"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <iconv.h>
+int
+main ()
+{
+iconv_t cd = iconv_open("","");
+ iconv(cd,NULL,NULL,NULL,NULL);
+ iconv_close(cd);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ am_cv_lib_iconv=yes
+ am_cv_func_iconv=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$am_save_LIBS"
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5
+$as_echo "$am_cv_func_iconv" >&6; }
+ if test "$am_cv_func_iconv" = yes; then
+
+$as_echo "#define HAVE_ICONV 1" >>confdefs.h
+
+ fi
+ if test "$am_cv_lib_iconv" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5
+$as_echo_n "checking how to link with libiconv... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5
+$as_echo "$LIBICONV" >&6; }
+ else
+ CPPFLAGS="$am_save_CPPFLAGS"
+ LIBICONV=
+ LTLIBICONV=
+ fi
+
+
+
+ if test "$am_cv_func_iconv" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5
+$as_echo_n "checking for iconv declaration... " >&6; }
+ if test "${am_cv_proto_iconv+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ am_cv_proto_iconv_arg1=""
+else
+ am_cv_proto_iconv_arg1="const"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"
+fi
+
+ am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:-
+ }$am_cv_proto_iconv" >&5
+$as_echo "${ac_t:-
+ }$am_cv_proto_iconv" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define ICONV_CONST $am_cv_proto_iconv_arg1
+_ACEOF
+
+ fi
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+else
@@ -9990,6 +10161,8 @@ _ACEOF
fi
+fi
+
# Until we have in-tree GNU iconv:
LIBICONV_DEP=
@@ -17628,7 +17801,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 17631 "configure"
+#line 17804 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -17734,7 +17907,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 17737 "configure"
+#line 17910 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 54b6c9d88cd..9d7bb66be20 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -222,7 +222,7 @@ fi
AC_ARG_WITH(demangler-in-ld,
[AS_HELP_STRING([--with-demangler-in-ld], [try to use demangler in GNU ld])],
demangler_in_ld="$with_demangler_in_ld",
-demangler_in_ld=no)
+demangler_in_ld=yes)
# ----------------------
# Find default assembler
@@ -1041,7 +1041,14 @@ case "${host}" in
esac
AC_FUNC_FORK
-AM_ICONV
+# g++ on Solaris 10+ defines _XOPEN_SOURCE=600, which exposes a different
+# iconv() prototype.
+AS_IF([test "$ENABLE_BUILD_WITH_CXX" = "yes"],
+ [AC_LANG_PUSH([C++])
+ AM_ICONV
+ AC_LANG_POP([C++])],
+ [AM_ICONV])
+
# Until we have in-tree GNU iconv:
LIBICONV_DEP=
AC_SUBST(LIBICONV_DEP)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e314ae2a614..a0f1f22bcdd 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,34 @@
+2011-07-23 Jason Merrill <jason@redhat.com>
+
+ PR c++/49823
+ * parser.c (cp_parser_qualifying_entity): Handle templates.
+
+2011-07-22 Jason Merrill <jason@redhat.com>
+
+ PR c++/49793
+ * typeck2.c (check_narrowing): Downgrade permerror to pedwarn.
+ Make conditional on -Wnarrowing.
+
+2011-07-22 Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ Warn about the use of final/override in non-c++0x mode, and
+ add __final for non-c++0x mode.
+ * cp-tree.h (cpp0x_warn_str): Add CPP0X_OVERRIDE_CONTROLS.
+ * error.c (maybe_warn_cpp0x): Adjust.
+ * parser.c (cp_parser_virt_specifier_seq_opt): Use it. Add
+ '__final' as a non-c++0x alternative for 'final'.
+
+2011-07-22 Jason Merrill <jason@redhat.com>
+ Mark Glisse <marc.glisse@normalesup.org>
+
+ PR c++/30112
+ * decl.c (cp_finish_decl): Apply pragma redefine_extname in
+ other namespaces as well.
+ * name-lookup.c (c_linkage_bindings): Define.
+ (lookup_extern_c_fun_in_all_ns): Rename from
+ lookup_extern_c_fun_binding_in_all_ns. Return tree.
+ (pushdecl_maybe_friend_1): Adjust. Copy DECL_ASSEMBLER_NAME.
+
2011-07-20 Jason Merrill <jason@redhat.com>
* parser.c (cp_parser_initializer_list): Handle C99 .id= and [N]=
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c5905850ca4..fb171782cd7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -393,7 +393,9 @@ typedef enum cpp0x_warn_str
/* defaulted and deleted functions */
CPP0X_DEFAULTED_DELETED,
/* inline namespaces */
- CPP0X_INLINE_NAMESPACES
+ CPP0X_INLINE_NAMESPACES,
+ /* override controls, override/final */
+ CPP0X_OVERRIDE_CONTROLS
} cpp0x_warn_str;
/* The various kinds of operation used by composite_pointer_type. */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 067930375a8..2000bd4a79d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5919,7 +5919,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
cleanup = NULL_TREE;
/* If a name was specified, get the string. */
- if (global_scope_p (current_binding_level))
+ if (at_namespace_scope_p ())
asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
if (asmspec_tree && asmspec_tree != error_mark_node)
asmspec = TREE_STRING_POINTER (asmspec_tree);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 2d7c0f1f0b6..d435bbe9fce 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -3227,6 +3227,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
"inline namespaces "
"only available with -std=c++0x or -std=gnu++0x");
break;
+ case CPP0X_OVERRIDE_CONTROLS:
+ pedwarn (input_location, 0,
+ "override controls (override/final) "
+ "only available with -std=c++0x or -std=gnu++0x");
+ break;
default:
gcc_unreachable();
}
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 00d21d2e904..1afd9edffec 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -52,7 +52,7 @@ static bool qualified_lookup_using_namespace (tree, tree,
struct scope_binding *, int);
static tree lookup_type_current_level (tree);
static tree push_using_directive (tree);
-static cxx_binding* lookup_extern_c_fun_binding_in_all_ns (tree);
+static tree lookup_extern_c_fun_in_all_ns (tree);
/* The :: namespace. */
@@ -768,18 +768,12 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
&& !DECL_ARTIFICIAL (x)
&& !DECL_IN_SYSTEM_HEADER (x))
{
- cxx_binding *function_binding =
- lookup_extern_c_fun_binding_in_all_ns (x);
- tree previous = (function_binding
- ? function_binding->value
- : NULL_TREE);
+ tree previous = lookup_extern_c_fun_in_all_ns (x);
if (previous
&& !DECL_ARTIFICIAL (previous)
&& !DECL_IN_SYSTEM_HEADER (previous)
&& DECL_CONTEXT (previous) != DECL_CONTEXT (x))
{
- tree previous = function_binding->value;
-
/* In case either x or previous is declared to throw an exception,
make sure both exception specifications are equal. */
if (decls_match (x, previous))
@@ -805,6 +799,9 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
"due to different exception specifications");
return error_mark_node;
}
+ if (DECL_ASSEMBLER_NAME_SET_P (previous))
+ SET_DECL_ASSEMBLER_NAME (x,
+ DECL_ASSEMBLER_NAME (previous));
}
else
{
@@ -1996,14 +1993,14 @@ binding_for_name (cp_binding_level *scope, tree name)
}
/* Walk through the bindings associated to the name of FUNCTION,
- and return the first binding that declares a function with a
+ and return the first declaration of a function with a
"C" linkage specification, a.k.a 'extern "C"'.
This function looks for the binding, regardless of which scope it
has been defined in. It basically looks in all the known scopes.
Note that this function does not lookup for bindings of builtin functions
or for functions declared in system headers. */
-static cxx_binding*
-lookup_extern_c_fun_binding_in_all_ns (tree function)
+static tree
+lookup_extern_c_fun_in_all_ns (tree function)
{
tree name;
cxx_binding *iter;
@@ -2017,17 +2014,52 @@ lookup_extern_c_fun_binding_in_all_ns (tree function)
iter;
iter = iter->previous)
{
- if (iter->value
- && TREE_CODE (iter->value) == FUNCTION_DECL
- && DECL_EXTERN_C_P (iter->value)
- && !DECL_ARTIFICIAL (iter->value))
+ tree ovl;
+ for (ovl = iter->value; ovl; ovl = OVL_NEXT (ovl))
{
- return iter;
+ tree decl = OVL_CURRENT (ovl);
+ if (decl
+ && TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_EXTERN_C_P (decl)
+ && !DECL_ARTIFICIAL (decl))
+ {
+ return decl;
+ }
}
}
return NULL;
}
+/* Returns a list of C-linkage decls with the name NAME. */
+
+tree
+c_linkage_bindings (tree name)
+{
+ tree decls = NULL_TREE;
+ cxx_binding *iter;
+
+ for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name);
+ iter;
+ iter = iter->previous)
+ {
+ tree ovl;
+ for (ovl = iter->value; ovl; ovl = OVL_NEXT (ovl))
+ {
+ tree decl = OVL_CURRENT (ovl);
+ if (decl
+ && DECL_EXTERN_C_P (decl)
+ && !DECL_ARTIFICIAL (decl))
+ {
+ if (decls == NULL_TREE)
+ decls = decl;
+ else
+ decls = tree_cons (NULL_TREE, decl, decls);
+ }
+ }
+ }
+ return decls;
+}
+
/* Insert another USING_DECL into the current binding level, returning
this declaration. If this is a redeclaration, do nothing, and
return NULL_TREE if this not in namespace scope (in namespace
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 285180152e3..4e7d905627a 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4638,7 +4638,9 @@ cp_parser_qualifying_entity (cp_parser *parser,
cp_parser_simulate_error (parser);
return error_mark_node;
}
- return TYPE_NAME (scope);
+ if (TYPE_NAME (scope))
+ scope = TYPE_NAME (scope);
+ return scope;
}
/* Before we try to parse the class-name, we must save away the
@@ -15596,9 +15598,19 @@ cp_parser_virt_specifier_seq_opt (cp_parser* parser)
if (token->type != CPP_NAME)
break;
if (!strcmp (IDENTIFIER_POINTER(token->u.value), "override"))
- virt_specifier = VIRT_SPEC_OVERRIDE;
+ {
+ maybe_warn_cpp0x (CPP0X_OVERRIDE_CONTROLS);
+ virt_specifier = VIRT_SPEC_OVERRIDE;
+ }
else if (!strcmp (IDENTIFIER_POINTER(token->u.value), "final"))
- virt_specifier = VIRT_SPEC_FINAL;
+ {
+ maybe_warn_cpp0x (CPP0X_OVERRIDE_CONTROLS);
+ virt_specifier = VIRT_SPEC_FINAL;
+ }
+ else if (!strcmp (IDENTIFIER_POINTER(token->u.value), "__final"))
+ {
+ virt_specifier = VIRT_SPEC_FINAL;
+ }
else
break;
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index bdd2452ffe1..727a88bd363 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -719,7 +719,7 @@ check_narrowing (tree type, tree init)
bool ok = true;
REAL_VALUE_TYPE d;
- if (!ARITHMETIC_TYPE_P (type))
+ if (!warn_narrowing || !ARITHMETIC_TYPE_P (type))
return;
if (BRACE_ENCLOSED_INITIALIZER_P (init)
@@ -777,8 +777,8 @@ check_narrowing (tree type, tree init)
}
if (!ok)
- permerror (input_location, "narrowing conversion of %qE from %qT "
- "to %qT inside { }", init, ftype, type);
+ pedwarn (input_location, OPT_Wnarrowing, "narrowing conversion of %qE "
+ "from %qT to %qT inside { }", init, ftype, type);
}
/* Process the initializer INIT for a variable of type TYPE, emitting
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c0d458588f0..342ac14834e 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -11,7 +11,7 @@
@c man begin COPYRIGHT
Copyright @copyright{} 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
@@ -328,7 +328,8 @@ Objective-C and Objective-C++ Dialects}.
-fstack-usage -ftest-coverage -ftime-report -fvar-tracking @gol
-fvar-tracking-assignments -fvar-tracking-assignments-toggle @gol
-g -g@var{level} -gtoggle -gcoff -gdwarf-@var{version} @gol
--ggdb -gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol
+-ggdb -grecord-gcc-switches -gno-record-gcc-switches @gol
+-gstabs -gstabs+ -gstrict-dwarf -gno-strict-dwarf @gol
-gvms -gxcoff -gxcoff+ @gol
-fno-merge-debug-strings -fno-dwarf2-cfi-asm @gol
-fdebug-prefix-map=@var{old}=@var{new} @gol
@@ -2352,6 +2353,18 @@ an instance of a derived class through a pointer to a base class if the
base class does not have a virtual destructor. This warning is enabled
by @option{-Wall}.
+@item -Wno-narrowing @r{(C++ and Objective-C++ only)}
+@opindex Wnarrowing
+@opindex Wno-narrowing
+With -std=c++0x, suppress the diagnostic required by the standard for
+narrowing conversions within @samp{@{ @}}, e.g.
+
+@smallexample
+int i = @{ 2.2 @}; // error: narrowing from double to int
+@end smallexample
+
+This flag can be useful for compiling valid C++98 code in C++0x mode.
+
@item -Wnoexcept @r{(C++ and Objective-C++ only)}
@opindex Wnoexcept
@opindex Wno-noexcept
@@ -4692,6 +4705,20 @@ 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.
+@item -grecord-gcc-switches
+@opindex grecord-gcc-switches
+This switch causes the command line options, that were used to invoke the
+compiler and may affect code generation, to be appended to the
+DW_AT_producer attribute in DWARF debugging information. The options
+are concatenated with spaces separating them from each other and from
+the compiler version. See also @option{-frecord-gcc-switches} for another
+way of storing compiler options into the object file.
+
+@item -gno-record-gcc-switches
+@opindex gno-record-gcc-switches
+Disallow appending command line options to the DW_AT_producer attribute
+in DWARF debugging information. This is the default.
+
@item -gstrict-dwarf
@opindex gstrict-dwarf
Disallow using extensions of later DWARF standard version than selected
@@ -18035,6 +18062,8 @@ usually takes the form of a section containing ASCII text. This
switch is related to the @option{-fverbose-asm} switch, but that
switch only records information in the assembler output file as
comments, so it never reaches the object file.
+See also @option{-grecord-gcc-switches} for another
+way of storing compiler options into the object file.
@item -fpic
@opindex fpic
diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
index 4e648ae417c..57fe566baf9 100644
--- a/gcc/dwarf2cfi.c
+++ b/gcc/dwarf2cfi.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "flags.h"
#include "rtl.h"
#include "function.h"
+#include "basic-block.h"
#include "dwarf2.h"
#include "dwarf2out.h"
#include "dwarf2asm.h"
@@ -58,19 +59,142 @@ along with GCC; see the file COPYING3. If not see
/* Maximum size (in bytes) of an artificially generated label. */
#define MAX_ARTIFICIAL_LABEL_BYTES 30
+/* A collected description of an entire row of the abstract CFI table. */
+typedef struct GTY(()) dw_cfi_row_struct
+{
+ /* The expression that computes the CFA, expressed in two different ways.
+ The CFA member for the simple cases, and the full CFI expression for
+ the complex cases. The later will be a DW_CFA_cfa_expression. */
+ dw_cfa_location cfa;
+ dw_cfi_ref cfa_cfi;
+
+ /* The expressions for any register column that is saved. */
+ cfi_vec reg_save;
+
+ /* The value of any DW_CFA_GNU_args_size. */
+ HOST_WIDE_INT args_size;
+} dw_cfi_row;
+
+/* The caller's ORIG_REG is saved in SAVED_IN_REG. */
+typedef struct GTY(()) reg_saved_in_data_struct {
+ rtx orig_reg;
+ rtx saved_in_reg;
+} reg_saved_in_data;
+
+DEF_VEC_O (reg_saved_in_data);
+DEF_VEC_ALLOC_O (reg_saved_in_data, heap);
+
+/* Since we no longer have a proper CFG, we're going to create a facsimile
+ of one on the fly while processing the frame-related insns.
+
+ We create dw_trace_info structures for each extended basic block beginning
+ and ending at a "save point". Save points are labels, barriers, certain
+ notes, and of course the beginning and end of the function.
+
+ As we encounter control transfer insns, we propagate the "current"
+ row state across the edges to the starts of traces. When checking is
+ enabled, we validate that we propagate the same data from all sources.
+
+ All traces are members of the TRACE_INFO array, in the order in which
+ they appear in the instruction stream.
+
+ All save points are present in the TRACE_INDEX hash, mapping the insn
+ starting a trace to the dw_trace_info describing the trace. */
+
+typedef struct
+{
+ /* The insn that begins the trace. */
+ rtx head;
+
+ /* The row state at the beginning and end of the trace. */
+ dw_cfi_row *beg_row, *end_row;
+
+ /* True if this trace immediately follows NOTE_INSN_SWITCH_TEXT_SECTIONS. */
+ bool switch_sections;
+
+ /* The following variables contain data used in interpreting frame related
+ expressions. These are not part of the "real" row state as defined by
+ Dwarf, but it seems like they need to be propagated into a trace in case
+ frame related expressions have been sunk. */
+ /* ??? This seems fragile. These variables are fragments of a larger
+ expression. If we do not keep the entire expression together, we risk
+ not being able to put it together properly. Consider forcing targets
+ to generate self-contained expressions and dropping all of the magic
+ interpretation code in this file. Or at least refusing to shrink wrap
+ any frame related insn that doesn't contain a complete expression. */
+
+ /* The register used for saving registers to the stack, and its offset
+ from the CFA. */
+ dw_cfa_location cfa_store;
+
+ /* A temporary register holding an integral value used in adjusting SP
+ or setting up the store_reg. The "offset" field holds the integer
+ value, not an offset. */
+ dw_cfa_location cfa_temp;
+
+ /* A set of registers saved in other registers. This is the inverse of
+ the row->reg_save info, if the entry is a DW_CFA_register. This is
+ implemented as a flat array because it normally contains zero or 1
+ entry, depending on the target. IA-64 is the big spender here, using
+ a maximum of 5 entries. */
+ VEC(reg_saved_in_data, heap) *regs_saved_in_regs;
+
+} dw_trace_info;
+
+DEF_VEC_O (dw_trace_info);
+DEF_VEC_ALLOC_O (dw_trace_info, heap);
+
+typedef dw_trace_info *dw_trace_info_ref;
+
+DEF_VEC_P (dw_trace_info_ref);
+DEF_VEC_ALLOC_P (dw_trace_info_ref, heap);
+
+/* The variables making up the pseudo-cfg, as described above. */
+static VEC (dw_trace_info, heap) *trace_info;
+static VEC (dw_trace_info_ref, heap) *trace_work_list;
+static htab_t trace_index;
+
/* A vector of call frame insns for the CIE. */
cfi_vec cie_cfi_vec;
+/* The state of the first row of the FDE table, which includes the
+ state provided by the CIE. */
+static GTY(()) dw_cfi_row *cie_cfi_row;
+
+static GTY(()) reg_saved_in_data *cie_return_save;
+
static GTY(()) unsigned long dwarf2out_cfi_label_num;
/* The insn after which a new CFI note should be emitted. */
-static rtx cfi_insn;
+static rtx add_cfi_insn;
/* When non-null, add_cfi will add the CFI to this vector. */
static cfi_vec *add_cfi_vec;
-/* True if remember_state should be emitted before following CFI directive. */
-static bool emit_cfa_remember;
+/* The current instruction trace. */
+static dw_trace_info *cur_trace;
+
+/* The current, i.e. most recently generated, row of the CFI table. */
+static dw_cfi_row *cur_row;
+
+/* We delay emitting a register save until either (a) we reach the end
+ of the prologue or (b) the register is clobbered. This clusters
+ register saves so that there are fewer pc advances. */
+
+typedef struct {
+ rtx reg;
+ rtx saved_reg;
+ HOST_WIDE_INT cfa_offset;
+} queued_reg_save;
+
+DEF_VEC_O (queued_reg_save);
+DEF_VEC_ALLOC_O (queued_reg_save, heap);
+
+static VEC(queued_reg_save, heap) *queued_reg_saves;
+
+/* The (really) current value for DW_CFA_GNU_args_size. We delay actually
+ emitting this data, i.e. updating CUR_ROW, without async unwind. */
+static HOST_WIDE_INT queued_args_size;
/* True if any CFI directives were emitted at the current insn. */
static bool any_cfis_emitted;
@@ -79,11 +203,6 @@ static bool any_cfis_emitted;
static unsigned dw_stack_pointer_regnum;
static unsigned dw_frame_pointer_regnum;
-
-static void dwarf2out_cfi_begin_epilogue (rtx insn);
-static void dwarf2out_frame_debug_restore_state (void);
-
-
/* Hook used by __throw. */
rtx
@@ -153,6 +272,59 @@ expand_builtin_init_dwarf_reg_sizes (tree address)
targetm.init_dwarf_reg_sizes_extra (address);
}
+
+static hashval_t
+dw_trace_info_hash (const void *ptr)
+{
+ const dw_trace_info *ti = (const dw_trace_info *) ptr;
+ return INSN_UID (ti->head);
+}
+
+static int
+dw_trace_info_eq (const void *ptr_a, const void *ptr_b)
+{
+ const dw_trace_info *a = (const dw_trace_info *) ptr_a;
+ const dw_trace_info *b = (const dw_trace_info *) ptr_b;
+ return a->head == b->head;
+}
+
+static unsigned
+get_trace_index (dw_trace_info *trace)
+{
+ return trace - VEC_address (dw_trace_info, trace_info);
+}
+
+static dw_trace_info *
+get_trace_info (rtx insn)
+{
+ dw_trace_info dummy;
+ dummy.head = insn;
+ return (dw_trace_info *)
+ htab_find_with_hash (trace_index, &dummy, INSN_UID (insn));
+}
+
+static bool
+save_point_p (rtx insn)
+{
+ /* Labels, except those that are really jump tables. */
+ if (LABEL_P (insn))
+ return inside_basic_block_p (insn);
+
+ /* We split traces at the prologue/epilogue notes because those
+ are points at which the unwind info is usually stable. This
+ makes it easier to find spots with identical unwind info so
+ that we can use remember/restore_state opcodes. */
+ if (NOTE_P (insn))
+ switch (NOTE_KIND (insn))
+ {
+ case NOTE_INSN_PROLOGUE_END:
+ case NOTE_INSN_EPILOGUE_BEG:
+ return true;
+ }
+
+ return false;
+}
+
/* Divide OFF by DWARF_CIE_DATA_ALIGNMENT, asserting no remainder. */
static inline HOST_WIDE_INT
@@ -185,6 +357,31 @@ new_cfi (void)
return cfi;
}
+/* Return a newly allocated CFI row, with no defined data. */
+
+static dw_cfi_row *
+new_cfi_row (void)
+{
+ dw_cfi_row *row = ggc_alloc_cleared_dw_cfi_row ();
+
+ row->cfa.reg = INVALID_REGNUM;
+
+ return row;
+}
+
+/* Return a copy of an existing CFI row. */
+
+static dw_cfi_row *
+copy_cfi_row (dw_cfi_row *src)
+{
+ dw_cfi_row *dst = ggc_alloc_dw_cfi_row ();
+
+ *dst = *src;
+ dst->reg_save = VEC_copy (dw_cfi_ref, gc, src->reg_save);
+
+ return dst;
+}
+
/* Generate a new label for the CFI info to refer to. */
static char *
@@ -203,27 +400,51 @@ dwarf2out_cfi_label (void)
static void
add_cfi (dw_cfi_ref cfi)
{
- if (emit_cfa_remember)
- {
- dw_cfi_ref cfi_remember;
-
- /* Emit the state save. */
- emit_cfa_remember = false;
- cfi_remember = new_cfi ();
- cfi_remember->dw_cfi_opc = DW_CFA_remember_state;
- add_cfi (cfi_remember);
- }
-
any_cfis_emitted = true;
- if (cfi_insn != NULL)
+
+ if (add_cfi_insn != NULL)
{
- cfi_insn = emit_note_after (NOTE_INSN_CFI, cfi_insn);
- NOTE_CFI (cfi_insn) = cfi;
+ add_cfi_insn = emit_note_after (NOTE_INSN_CFI, add_cfi_insn);
+ NOTE_CFI (add_cfi_insn) = cfi;
}
+
if (add_cfi_vec != NULL)
VEC_safe_push (dw_cfi_ref, gc, *add_cfi_vec, cfi);
}
+static void
+add_cfi_args_size (HOST_WIDE_INT size)
+{
+ dw_cfi_ref cfi = new_cfi ();
+
+ cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
+
+ add_cfi (cfi);
+}
+
+static void
+add_cfi_restore (unsigned reg)
+{
+ dw_cfi_ref cfi = new_cfi ();
+
+ cfi->dw_cfi_opc = (reg & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore);
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+
+ add_cfi (cfi);
+}
+
+/* Perform ROW->REG_SAVE[COLUMN] = CFI. CFI may be null, indicating
+ that the register column is no longer saved. */
+
+static void
+update_row_reg_save (dw_cfi_row *row, unsigned column, dw_cfi_ref cfi)
+{
+ if (VEC_length (dw_cfi_ref, row->reg_save) <= column)
+ VEC_safe_grow_cleared (dw_cfi_ref, gc, row->reg_save, column + 1);
+ VEC_replace (dw_cfi_ref, row->reg_save, column, cfi);
+}
+
/* This function fills in aa dw_cfa_location structure from a dwarf location
descriptor sequence. */
@@ -371,28 +592,6 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, dw_cfa_location *remember)
}
}
-/* The current rule for calculating the DWARF2 canonical frame address. */
-static dw_cfa_location cfa;
-
-/* A copy of the CFA, for comparison purposes. */
-static dw_cfa_location old_cfa;
-
-/* The register used for saving registers to the stack, and its offset
- from the CFA. */
-static dw_cfa_location cfa_store;
-
-/* The current save location around an epilogue. */
-static dw_cfa_location cfa_remember;
-
-/* Like cfa_remember, but a copy of old_cfa. */
-static dw_cfa_location old_cfa_remember;
-
-/* The running total of the size of arguments pushed onto the stack. */
-static HOST_WIDE_INT args_size;
-
-/* The last args_size we actually output. */
-static HOST_WIDE_INT old_args_size;
-
/* Determine if two dw_cfa_location structures define the same data. */
bool
@@ -405,67 +604,154 @@ cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2)
|| loc1->base_offset == loc2->base_offset));
}
-/* This routine does the actual work. The CFA is now calculated from
- the dw_cfa_location structure. */
+/* Determine if two CFI operands are identical. */
-static void
-def_cfa_1 (dw_cfa_location *loc_p)
+static bool
+cfi_oprnd_equal_p (enum dw_cfi_oprnd_type t, dw_cfi_oprnd *a, dw_cfi_oprnd *b)
{
- dw_cfi_ref cfi;
- dw_cfa_location loc;
+ switch (t)
+ {
+ case dw_cfi_oprnd_unused:
+ return true;
+ case dw_cfi_oprnd_reg_num:
+ return a->dw_cfi_reg_num == b->dw_cfi_reg_num;
+ case dw_cfi_oprnd_offset:
+ return a->dw_cfi_offset == b->dw_cfi_offset;
+ case dw_cfi_oprnd_addr:
+ return (a->dw_cfi_addr == b->dw_cfi_addr
+ || strcmp (a->dw_cfi_addr, b->dw_cfi_addr) == 0);
+ case dw_cfi_oprnd_loc:
+ return loc_descr_equal_p (a->dw_cfi_loc, b->dw_cfi_loc);
+ }
+ gcc_unreachable ();
+}
+
+/* Determine if two CFI entries are identical. */
+
+static bool
+cfi_equal_p (dw_cfi_ref a, dw_cfi_ref b)
+{
+ enum dwarf_call_frame_info opc;
+
+ /* Make things easier for our callers, including missing operands. */
+ if (a == b)
+ return true;
+ if (a == NULL || b == NULL)
+ return false;
+
+ /* Obviously, the opcodes must match. */
+ opc = a->dw_cfi_opc;
+ if (opc != b->dw_cfi_opc)
+ return false;
+
+ /* Compare the two operands, re-using the type of the operands as
+ already exposed elsewhere. */
+ return (cfi_oprnd_equal_p (dw_cfi_oprnd1_desc (opc),
+ &a->dw_cfi_oprnd1, &b->dw_cfi_oprnd1)
+ && cfi_oprnd_equal_p (dw_cfi_oprnd2_desc (opc),
+ &a->dw_cfi_oprnd2, &b->dw_cfi_oprnd2));
+}
+
+/* Determine if two CFI_ROW structures are identical. */
+
+static bool
+cfi_row_equal_p (dw_cfi_row *a, dw_cfi_row *b)
+{
+ size_t i, n_a, n_b, n_max;
+
+ if (a->cfa_cfi)
+ {
+ if (!cfi_equal_p (a->cfa_cfi, b->cfa_cfi))
+ return false;
+ }
+ else if (!cfa_equal_p (&a->cfa, &b->cfa))
+ return false;
+
+ /* Logic suggests that we compare args_size here. However, if
+ EXIT_IGNORE_STACK we don't bother tracking the args_size after
+ the last time it really matters within the function. This does
+ in fact lead to paths with differing arg_size, but in cases for
+ which it doesn't matter. */
+ /* ??? If we really want to sanity check the output of the optimizers,
+ find a way to backtrack from epilogues to the last EH site. This
+ would allow us to distinguish regions with garbage args_size and
+ regions where paths ought to agree. */
+
+ n_a = VEC_length (dw_cfi_ref, a->reg_save);
+ n_b = VEC_length (dw_cfi_ref, b->reg_save);
+ n_max = MAX (n_a, n_b);
+
+ for (i = 0; i < n_max; ++i)
+ {
+ dw_cfi_ref r_a = NULL, r_b = NULL;
+
+ if (i < n_a)
+ r_a = VEC_index (dw_cfi_ref, a->reg_save, i);
+ if (i < n_b)
+ r_b = VEC_index (dw_cfi_ref, b->reg_save, i);
+
+ if (!cfi_equal_p (r_a, r_b))
+ return false;
+ }
+
+ return true;
+}
- cfa = *loc_p;
- loc = *loc_p;
+/* The CFA is now calculated from NEW_CFA. Consider OLD_CFA in determining
+ what opcode to emit. Returns the CFI opcode to effect the change, or
+ NULL if NEW_CFA == OLD_CFA. */
- if (cfa_store.reg == loc.reg && loc.indirect == 0)
- cfa_store.offset = loc.offset;
+static dw_cfi_ref
+def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
+{
+ dw_cfi_ref cfi;
/* If nothing changed, no need to issue any call frame instructions. */
- if (cfa_equal_p (&loc, &old_cfa))
- return;
+ if (cfa_equal_p (old_cfa, new_cfa))
+ return NULL;
cfi = new_cfi ();
- if (loc.reg == old_cfa.reg && !loc.indirect && !old_cfa.indirect)
+ if (new_cfa->reg == old_cfa->reg && !new_cfa->indirect && !old_cfa->indirect)
{
/* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
the CFA register did not change but the offset did. The data
factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or
in the assembler via the .cfi_def_cfa_offset directive. */
- if (loc.offset < 0)
+ if (new_cfa->offset < 0)
cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
else
cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
- cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = new_cfa->offset;
}
#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */
- else if (loc.offset == old_cfa.offset
- && old_cfa.reg != INVALID_REGNUM
- && !loc.indirect
- && !old_cfa.indirect)
+ else if (new_cfa->offset == old_cfa->offset
+ && old_cfa->reg != INVALID_REGNUM
+ && !new_cfa->indirect
+ && !old_cfa->indirect)
{
/* Construct a "DW_CFA_def_cfa_register <register>" instruction,
indicating the CFA register has changed to <register> but the
offset has not changed. */
cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
- cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
}
#endif
- else if (loc.indirect == 0)
+ else if (new_cfa->indirect == 0)
{
/* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
indicating the CFA register has changed to <register> with
the specified offset. The data factoring for DW_CFA_def_cfa_sf
happens in output_cfi, or in the assembler via the .cfi_def_cfa
directive. */
- if (loc.offset < 0)
+ if (new_cfa->offset < 0)
cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
else
cfi->dw_cfi_opc = DW_CFA_def_cfa;
- cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
- cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = new_cfa->offset;
}
else
{
@@ -475,12 +761,32 @@ def_cfa_1 (dw_cfa_location *loc_p)
struct dw_loc_descr_struct *loc_list;
cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
- loc_list = build_cfa_loc (&loc, 0);
+ loc_list = build_cfa_loc (new_cfa, 0);
cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
}
- add_cfi (cfi);
- old_cfa = loc;
+ return cfi;
+}
+
+/* Similarly, but take OLD_CFA from CUR_ROW, and update it after the fact. */
+
+static void
+def_cfa_1 (dw_cfa_location *new_cfa)
+{
+ dw_cfi_ref cfi;
+
+ if (cur_trace->cfa_store.reg == new_cfa->reg && new_cfa->indirect == 0)
+ cur_trace->cfa_store.offset = new_cfa->offset;
+
+ cfi = def_cfa_0 (&cur_row->cfa, new_cfa);
+ if (cfi)
+ {
+ cur_row->cfa = *new_cfa;
+ if (cfi->dw_cfi_opc == DW_CFA_def_cfa_expression)
+ cur_row->cfa_cfi = cfi;
+
+ add_cfi (cfi);
+ }
}
/* Add the CFI for saving a register. REG is the CFA column number.
@@ -503,7 +809,8 @@ reg_save (unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
cfi->dw_cfi_opc = DW_CFA_expression;
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
cfi->dw_cfi_oprnd2.dw_cfi_loc
- = build_cfa_aligned_loc (&cfa, offset, fde->stack_realignment);
+ = build_cfa_aligned_loc (&cur_row->cfa, offset,
+ fde->stack_realignment);
}
else if (sreg == INVALID_REGNUM)
{
@@ -516,7 +823,13 @@ reg_save (unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
}
else if (sreg == reg)
- cfi->dw_cfi_opc = DW_CFA_same_value;
+ {
+ /* While we could emit something like DW_CFA_same_value or
+ DW_CFA_restore, we never expect to see something like that
+ in a prologue. This is more likely to be a bug. A backend
+ can always bypass this by using REG_CFA_RESTORE directly. */
+ gcc_unreachable ();
+ }
else
{
cfi->dw_cfi_opc = DW_CFA_register;
@@ -524,6 +837,7 @@ reg_save (unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
}
add_cfi (cfi);
+ update_row_reg_save (cur_row, reg, cfi);
}
/* Given a SET, calculate the amount of stack adjustment it
@@ -616,196 +930,17 @@ stack_adjust_offset (const_rtx pattern, HOST_WIDE_INT cur_args_size,
return offset;
}
-/* Precomputed args_size for CODE_LABELs and BARRIERs preceeding them,
- indexed by INSN_UID. */
-
-static HOST_WIDE_INT *barrier_args_size;
-
-/* Helper function for compute_barrier_args_size. Handle one insn. */
-
-static HOST_WIDE_INT
-compute_barrier_args_size_1 (rtx insn, HOST_WIDE_INT cur_args_size,
- VEC (rtx, heap) **next)
-{
- HOST_WIDE_INT offset = 0;
- int i;
-
- if (! RTX_FRAME_RELATED_P (insn))
- {
- if (prologue_epilogue_contains (insn))
- /* Nothing */;
- else if (GET_CODE (PATTERN (insn)) == SET)
- offset = stack_adjust_offset (PATTERN (insn), cur_args_size, 0);
- else if (GET_CODE (PATTERN (insn)) == PARALLEL
- || GET_CODE (PATTERN (insn)) == SEQUENCE)
- {
- /* There may be stack adjustments inside compound insns. Search
- for them. */
- for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
- offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i),
- cur_args_size, offset);
- }
- }
- else
- {
- rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
-
- if (expr)
- {
- expr = XEXP (expr, 0);
- if (GET_CODE (expr) == PARALLEL
- || GET_CODE (expr) == SEQUENCE)
- for (i = 1; i < XVECLEN (expr, 0); i++)
- {
- rtx elem = XVECEXP (expr, 0, i);
-
- if (GET_CODE (elem) == SET && !RTX_FRAME_RELATED_P (elem))
- offset += stack_adjust_offset (elem, cur_args_size, offset);
- }
- }
- }
-
-#ifndef STACK_GROWS_DOWNWARD
- offset = -offset;
-#endif
-
- cur_args_size += offset;
- if (cur_args_size < 0)
- cur_args_size = 0;
-
- if (JUMP_P (insn))
- {
- rtx dest = JUMP_LABEL (insn);
-
- if (dest)
- {
- if (barrier_args_size [INSN_UID (dest)] < 0)
- {
- barrier_args_size [INSN_UID (dest)] = cur_args_size;
- VEC_safe_push (rtx, heap, *next, dest);
- }
- }
- }
-
- return cur_args_size;
-}
-
-/* Walk the whole function and compute args_size on BARRIERs. */
-
-static void
-compute_barrier_args_size (void)
-{
- int max_uid = get_max_uid (), i;
- rtx insn;
- VEC (rtx, heap) *worklist, *next, *tmp;
-
- barrier_args_size = XNEWVEC (HOST_WIDE_INT, max_uid);
- for (i = 0; i < max_uid; i++)
- barrier_args_size[i] = -1;
-
- worklist = VEC_alloc (rtx, heap, 20);
- next = VEC_alloc (rtx, heap, 20);
- insn = get_insns ();
- barrier_args_size[INSN_UID (insn)] = 0;
- VEC_quick_push (rtx, worklist, insn);
- for (;;)
- {
- while (!VEC_empty (rtx, worklist))
- {
- rtx prev, body, first_insn;
- HOST_WIDE_INT cur_args_size;
-
- first_insn = insn = VEC_pop (rtx, worklist);
- cur_args_size = barrier_args_size[INSN_UID (insn)];
- prev = prev_nonnote_insn (insn);
- if (prev && BARRIER_P (prev))
- barrier_args_size[INSN_UID (prev)] = cur_args_size;
-
- for (; insn; insn = NEXT_INSN (insn))
- {
- if (INSN_DELETED_P (insn) || NOTE_P (insn))
- continue;
- if (BARRIER_P (insn))
- break;
-
- if (LABEL_P (insn))
- {
- if (insn == first_insn)
- continue;
- else if (barrier_args_size[INSN_UID (insn)] < 0)
- {
- barrier_args_size[INSN_UID (insn)] = cur_args_size;
- continue;
- }
- else
- {
- /* The insns starting with this label have been
- already scanned or are in the worklist. */
- break;
- }
- }
-
- body = PATTERN (insn);
- if (GET_CODE (body) == SEQUENCE)
- {
- HOST_WIDE_INT dest_args_size = cur_args_size;
- for (i = 1; i < XVECLEN (body, 0); i++)
- if (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0))
- && INSN_FROM_TARGET_P (XVECEXP (body, 0, i)))
- dest_args_size
- = compute_barrier_args_size_1 (XVECEXP (body, 0, i),
- dest_args_size, &next);
- else
- cur_args_size
- = compute_barrier_args_size_1 (XVECEXP (body, 0, i),
- cur_args_size, &next);
-
- if (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0)))
- compute_barrier_args_size_1 (XVECEXP (body, 0, 0),
- dest_args_size, &next);
- else
- cur_args_size
- = compute_barrier_args_size_1 (XVECEXP (body, 0, 0),
- cur_args_size, &next);
- }
- else
- cur_args_size
- = compute_barrier_args_size_1 (insn, cur_args_size, &next);
- }
- }
-
- if (VEC_empty (rtx, next))
- break;
-
- /* Swap WORKLIST with NEXT and truncate NEXT for next iteration. */
- tmp = next;
- next = worklist;
- worklist = tmp;
- VEC_truncate (rtx, next, 0);
- }
-
- VEC_free (rtx, heap, worklist);
- VEC_free (rtx, heap, next);
-}
-
/* Add a CFI to update the running total of the size of arguments
pushed onto the stack. */
static void
dwarf2out_args_size (HOST_WIDE_INT size)
{
- dw_cfi_ref cfi;
-
- if (size == old_args_size)
+ if (size == cur_row->args_size)
return;
- old_args_size = size;
-
- cfi = new_cfi ();
- cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
- cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
- add_cfi (cfi);
+ cur_row->args_size = size;
+ add_cfi_args_size (size);
}
/* Record a stack adjustment of OFFSET bytes. */
@@ -813,12 +948,19 @@ dwarf2out_args_size (HOST_WIDE_INT size)
static void
dwarf2out_stack_adjust (HOST_WIDE_INT offset)
{
- if (cfa.reg == dw_stack_pointer_regnum)
- cfa.offset += offset;
+ dw_cfa_location loc = cur_row->cfa;
- if (cfa_store.reg == dw_stack_pointer_regnum)
- cfa_store.offset += offset;
+ if (loc.reg == dw_stack_pointer_regnum)
+ loc.offset += offset;
+ if (cur_trace->cfa_store.reg == dw_stack_pointer_regnum)
+ cur_trace->cfa_store.offset += offset;
+
+ /* ??? The assumption seems to be that if A_O_A, the only CFA adjustments
+ involving the stack pointer are inside the prologue and marked as
+ RTX_FRAME_RELATED_P. That said, should we not verify this assumption
+ by *asserting* A_O_A at this point? Why else would we have a change
+ to the stack pointer? */
if (ACCUMULATE_OUTGOING_ARGS)
return;
@@ -826,13 +968,13 @@ dwarf2out_stack_adjust (HOST_WIDE_INT offset)
offset = -offset;
#endif
- args_size += offset;
- if (args_size < 0)
- args_size = 0;
+ queued_args_size += offset;
+ if (queued_args_size < 0)
+ queued_args_size = 0;
- def_cfa_1 (&cfa);
+ def_cfa_1 (&loc);
if (flag_asynchronous_unwind_tables)
- dwarf2out_args_size (args_size);
+ dwarf2out_args_size (queued_args_size);
}
/* Check INSN to see if it looks like a push or a stack adjustment, and
@@ -862,7 +1004,8 @@ dwarf2out_notice_stack_adjust (rtx insn, bool after_p)
/* If only calls can throw, and we have a frame pointer,
save up adjustments until we see the CALL_INSN. */
- if (!flag_asynchronous_unwind_tables && cfa.reg != dw_stack_pointer_regnum)
+ if (!flag_asynchronous_unwind_tables
+ && cur_row->cfa.reg != dw_stack_pointer_regnum)
{
if (CALL_P (insn) && !after_p)
{
@@ -881,31 +1024,13 @@ dwarf2out_notice_stack_adjust (rtx insn, bool after_p)
if (CALL_P (insn) && !after_p)
{
if (!flag_asynchronous_unwind_tables)
- dwarf2out_args_size (args_size);
+ dwarf2out_args_size (queued_args_size);
return;
}
else if (BARRIER_P (insn))
- {
- /* Don't call compute_barrier_args_size () if the only
- BARRIER is at the end of function. */
- if (barrier_args_size == NULL && next_nonnote_insn (insn))
- compute_barrier_args_size ();
- if (barrier_args_size == NULL)
- offset = 0;
- else
- {
- offset = barrier_args_size[INSN_UID (insn)];
- if (offset < 0)
- offset = 0;
- }
-
- offset -= args_size;
-#ifndef STACK_GROWS_DOWNWARD
- offset = -offset;
-#endif
- }
+ return;
else if (GET_CODE (PATTERN (insn)) == SET)
- offset = stack_adjust_offset (PATTERN (insn), args_size, 0);
+ offset = stack_adjust_offset (PATTERN (insn), queued_args_size, 0);
else if (GET_CODE (PATTERN (insn)) == PARALLEL
|| GET_CODE (PATTERN (insn)) == SEQUENCE)
{
@@ -914,7 +1039,7 @@ dwarf2out_notice_stack_adjust (rtx insn, bool after_p)
for (offset = 0, i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i),
- args_size, offset);
+ queued_args_size, offset);
}
else
return;
@@ -925,36 +1050,6 @@ dwarf2out_notice_stack_adjust (rtx insn, bool after_p)
dwarf2out_stack_adjust (offset);
}
-/* We delay emitting a register save until either (a) we reach the end
- of the prologue or (b) the register is clobbered. This clusters
- register saves so that there are fewer pc advances. */
-
-struct GTY(()) queued_reg_save {
- struct queued_reg_save *next;
- rtx reg;
- HOST_WIDE_INT cfa_offset;
- rtx saved_reg;
-};
-
-static GTY(()) struct queued_reg_save *queued_reg_saves;
-
-/* The caller's ORIG_REG is saved in SAVED_IN_REG. */
-typedef struct GTY(()) reg_saved_in_data {
- rtx orig_reg;
- rtx saved_in_reg;
-} reg_saved_in_data;
-
-DEF_VEC_O (reg_saved_in_data);
-DEF_VEC_ALLOC_O (reg_saved_in_data, gc);
-
-/* A set of registers saved in other registers. This is implemented as
- a flat array because it normally contains zero or 1 entry, depending
- on the target. IA-64 is the big spender here, using a maximum of
- 5 entries. */
-static GTY(()) VEC(reg_saved_in_data, gc) *regs_saved_in_regs;
-
-static GTY(()) reg_saved_in_data *cie_return_save;
-
/* Short-hand inline for the very common D_F_R (REGNO (x)) operation. */
/* ??? This ought to go into dwarf2out.h, except that dwarf2out.h is
used in places where rtl is prohibited. */
@@ -984,11 +1079,12 @@ record_reg_saved_in_reg (rtx dest, rtx src)
reg_saved_in_data *elt;
size_t i;
- FOR_EACH_VEC_ELT (reg_saved_in_data, regs_saved_in_regs, i, elt)
+ FOR_EACH_VEC_ELT (reg_saved_in_data, cur_trace->regs_saved_in_regs, i, elt)
if (compare_reg_or_pc (elt->orig_reg, src))
{
if (dest == NULL)
- VEC_unordered_remove(reg_saved_in_data, regs_saved_in_regs, i);
+ VEC_unordered_remove (reg_saved_in_data,
+ cur_trace->regs_saved_in_regs, i);
else
elt->saved_in_reg = dest;
return;
@@ -997,7 +1093,8 @@ record_reg_saved_in_reg (rtx dest, rtx src)
if (dest == NULL)
return;
- elt = VEC_safe_push(reg_saved_in_data, gc, regs_saved_in_regs, NULL);
+ elt = VEC_safe_push (reg_saved_in_data, heap,
+ cur_trace->regs_saved_in_regs, NULL);
elt->orig_reg = src;
elt->saved_in_reg = dest;
}
@@ -1008,24 +1105,21 @@ record_reg_saved_in_reg (rtx dest, rtx src)
static void
queue_reg_save (rtx reg, rtx sreg, HOST_WIDE_INT offset)
{
- struct queued_reg_save *q;
+ queued_reg_save *q;
+ size_t i;
/* Duplicates waste space, but it's also necessary to remove them
for correctness, since the queue gets output in reverse order. */
- for (q = queued_reg_saves; q != NULL; q = q->next)
+ FOR_EACH_VEC_ELT (queued_reg_save, queued_reg_saves, i, q)
if (compare_reg_or_pc (q->reg, reg))
- break;
+ goto found;
- if (q == NULL)
- {
- q = ggc_alloc_queued_reg_save ();
- q->next = queued_reg_saves;
- queued_reg_saves = q;
- }
+ q = VEC_safe_push (queued_reg_save, heap, queued_reg_saves, NULL);
+ found:
q->reg = reg;
- q->cfa_offset = offset;
q->saved_reg = sreg;
+ q->cfa_offset = offset;
}
/* Output all the entries in QUEUED_REG_SAVES. */
@@ -1033,9 +1127,10 @@ queue_reg_save (rtx reg, rtx sreg, HOST_WIDE_INT offset)
static void
dwarf2out_flush_queued_reg_saves (void)
{
- struct queued_reg_save *q;
+ queued_reg_save *q;
+ size_t i;
- for (q = queued_reg_saves; q; q = q->next)
+ FOR_EACH_VEC_ELT (queued_reg_save, queued_reg_saves, i, q)
{
unsigned int reg, sreg;
@@ -1052,7 +1147,7 @@ dwarf2out_flush_queued_reg_saves (void)
reg_save (reg, sreg, q->cfa_offset);
}
- queued_reg_saves = NULL;
+ VEC_truncate (queued_reg_save, queued_reg_saves, 0);
}
/* Does INSN clobber any register which QUEUED_REG_SAVES lists a saved
@@ -1063,17 +1158,19 @@ dwarf2out_flush_queued_reg_saves (void)
static bool
clobbers_queued_reg_save (const_rtx insn)
{
- struct queued_reg_save *q;
+ queued_reg_save *q;
+ size_t iq;
- for (q = queued_reg_saves; q; q = q->next)
+ FOR_EACH_VEC_ELT (queued_reg_save, queued_reg_saves, iq, q)
{
- size_t i;
+ size_t ir;
reg_saved_in_data *rir;
if (modified_in_p (q->reg, insn))
return true;
- FOR_EACH_VEC_ELT (reg_saved_in_data, regs_saved_in_regs, i, rir)
+ FOR_EACH_VEC_ELT (reg_saved_in_data,
+ cur_trace->regs_saved_in_regs, ir, rir)
if (compare_reg_or_pc (q->reg, rir->orig_reg)
&& modified_in_p (rir->saved_in_reg, insn))
return true;
@@ -1088,54 +1185,50 @@ static rtx
reg_saved_in (rtx reg)
{
unsigned int regn = REGNO (reg);
- struct queued_reg_save *q;
+ queued_reg_save *q;
reg_saved_in_data *rir;
size_t i;
- for (q = queued_reg_saves; q; q = q->next)
+ FOR_EACH_VEC_ELT (queued_reg_save, queued_reg_saves, i, q)
if (q->saved_reg && regn == REGNO (q->saved_reg))
return q->reg;
- FOR_EACH_VEC_ELT (reg_saved_in_data, regs_saved_in_regs, i, rir)
+ FOR_EACH_VEC_ELT (reg_saved_in_data, cur_trace->regs_saved_in_regs, i, rir)
if (regn == REGNO (rir->saved_in_reg))
return rir->orig_reg;
return NULL_RTX;
}
-
-/* A temporary register holding an integral value used in adjusting SP
- or setting up the store_reg. The "offset" field holds the integer
- value, not an offset. */
-static dw_cfa_location cfa_temp;
-
/* A subroutine of dwarf2out_frame_debug, process a REG_DEF_CFA note. */
static void
dwarf2out_frame_debug_def_cfa (rtx pat)
{
- memset (&cfa, 0, sizeof (cfa));
+ dw_cfa_location loc;
+
+ memset (&loc, 0, sizeof (loc));
switch (GET_CODE (pat))
{
case PLUS:
- cfa.reg = dwf_regno (XEXP (pat, 0));
- cfa.offset = INTVAL (XEXP (pat, 1));
+ loc.reg = dwf_regno (XEXP (pat, 0));
+ loc.offset = INTVAL (XEXP (pat, 1));
break;
case REG:
- cfa.reg = dwf_regno (pat);
+ loc.reg = dwf_regno (pat);
break;
case MEM:
- cfa.indirect = 1;
+ loc.indirect = 1;
pat = XEXP (pat, 0);
if (GET_CODE (pat) == PLUS)
{
- cfa.base_offset = INTVAL (XEXP (pat, 1));
+ loc.base_offset = INTVAL (XEXP (pat, 1));
pat = XEXP (pat, 0);
}
- cfa.reg = dwf_regno (pat);
+ loc.reg = dwf_regno (pat);
break;
default:
@@ -1143,7 +1236,7 @@ dwarf2out_frame_debug_def_cfa (rtx pat)
gcc_unreachable ();
}
- def_cfa_1 (&cfa);
+ def_cfa_1 (&loc);
}
/* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note. */
@@ -1151,6 +1244,7 @@ dwarf2out_frame_debug_def_cfa (rtx pat)
static void
dwarf2out_frame_debug_adjust_cfa (rtx pat)
{
+ dw_cfa_location loc = cur_row->cfa;
rtx src, dest;
gcc_assert (GET_CODE (pat) == SET);
@@ -1160,8 +1254,8 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat)
switch (GET_CODE (src))
{
case PLUS:
- gcc_assert (dwf_regno (XEXP (src, 0)) == cfa.reg);
- cfa.offset -= INTVAL (XEXP (src, 1));
+ gcc_assert (dwf_regno (XEXP (src, 0)) == loc.reg);
+ loc.offset -= INTVAL (XEXP (src, 1));
break;
case REG:
@@ -1171,10 +1265,10 @@ dwarf2out_frame_debug_adjust_cfa (rtx pat)
gcc_unreachable ();
}
- cfa.reg = dwf_regno (dest);
- gcc_assert (cfa.indirect == 0);
+ loc.reg = dwf_regno (dest);
+ gcc_assert (loc.indirect == 0);
- def_cfa_1 (&cfa);
+ def_cfa_1 (&loc);
}
/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_OFFSET note. */
@@ -1195,12 +1289,12 @@ dwarf2out_frame_debug_cfa_offset (rtx set)
switch (GET_CODE (addr))
{
case REG:
- gcc_assert (dwf_regno (addr) == cfa.reg);
- offset = -cfa.offset;
+ gcc_assert (dwf_regno (addr) == cur_row->cfa.reg);
+ offset = -cur_row->cfa.offset;
break;
case PLUS:
- gcc_assert (dwf_regno (XEXP (addr, 0)) == cfa.reg);
- offset = INTVAL (XEXP (addr, 1)) - cfa.offset;
+ gcc_assert (dwf_regno (XEXP (addr, 0)) == cur_row->cfa.reg);
+ offset = INTVAL (XEXP (addr, 1)) - cur_row->cfa.offset;
break;
default:
gcc_unreachable ();
@@ -1211,7 +1305,7 @@ dwarf2out_frame_debug_cfa_offset (rtx set)
span = NULL;
sregno = DWARF_FRAME_RETURN_COLUMN;
}
- else
+ else
{
span = targetm.dwarf_register_span (src);
sregno = dwf_regno (src);
@@ -1274,6 +1368,7 @@ dwarf2out_frame_debug_cfa_expression (rtx set)
{
rtx src, dest, span;
dw_cfi_ref cfi = new_cfi ();
+ unsigned regno;
dest = SET_DEST (set);
src = SET_SRC (set);
@@ -1284,8 +1379,10 @@ dwarf2out_frame_debug_cfa_expression (rtx set)
span = targetm.dwarf_register_span (src);
gcc_assert (!span);
+ regno = dwf_regno (src);
+
cfi->dw_cfi_opc = DW_CFA_expression;
- cfi->dw_cfi_oprnd1.dw_cfi_reg_num = dwf_regno (src);
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = regno;
cfi->dw_cfi_oprnd2.dw_cfi_loc
= mem_loc_descriptor (XEXP (dest, 0), get_address_mode (dest),
GET_MODE (dest), VAR_INIT_STATUS_INITIALIZED);
@@ -1293,6 +1390,7 @@ dwarf2out_frame_debug_cfa_expression (rtx set)
/* ??? We'd like to use queue_reg_save, were the interface different,
and, as above, we could manage flushing for epilogues. */
add_cfi (cfi);
+ update_row_reg_save (cur_row, regno, cfi);
}
/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note. */
@@ -1300,13 +1398,10 @@ dwarf2out_frame_debug_cfa_expression (rtx set)
static void
dwarf2out_frame_debug_cfa_restore (rtx reg)
{
- dw_cfi_ref cfi = new_cfi ();
unsigned int regno = dwf_regno (reg);
- cfi->dw_cfi_opc = (regno & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore);
- cfi->dw_cfi_oprnd1.dw_cfi_reg_num = regno;
-
- add_cfi (cfi);
+ add_cfi_restore (regno);
+ update_row_reg_save (cur_row, regno, NULL);
}
/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_WINDOW_SAVE.
@@ -1366,7 +1461,9 @@ dwarf2out_frame_debug_cfa_window_save (void)
Invariants / Summaries of Rules
cfa current rule for calculating the CFA. It usually
- consists of a register and an offset.
+ consists of a register and an offset. This is
+ actually stored in cur_row->cfa, but abbreviated
+ for the purposes of this documentation.
cfa_store register used by prologue code to save things to the stack
cfa_store.offset is the offset from the value of
cfa_store.reg to the actual CFA
@@ -1520,6 +1617,7 @@ dwarf2out_frame_debug_cfa_window_save (void)
static void
dwarf2out_frame_debug_expr (rtx expr)
{
+ dw_cfa_location cfa = cur_row->cfa;
rtx src, dest, span;
HOST_WIDE_INT offset;
dw_fde_ref fde;
@@ -1563,7 +1661,8 @@ dwarf2out_frame_debug_expr (rtx expr)
{
/* Stack adjustment combining might combine some post-prologue
stack adjustment into a prologue stack adjustment. */
- HOST_WIDE_INT offset = stack_adjust_offset (elem, args_size, 0);
+ HOST_WIDE_INT offset
+ = stack_adjust_offset (elem, queued_args_size, 0);
if (offset != 0)
dwarf2out_stack_adjust (offset);
@@ -1604,8 +1703,8 @@ dwarf2out_frame_debug_expr (rtx expr)
FP. So we just rely on the backends to only set
RTX_FRAME_RELATED_P on appropriate insns. */
cfa.reg = dwf_regno (dest);
- cfa_temp.reg = cfa.reg;
- cfa_temp.offset = cfa.offset;
+ cur_trace->cfa_temp.reg = cfa.reg;
+ cur_trace->cfa_temp.offset = cfa.offset;
}
else
{
@@ -1642,8 +1741,9 @@ dwarf2out_frame_debug_expr (rtx expr)
offset = INTVAL (XEXP (src, 1));
break;
case REG:
- gcc_assert (dwf_regno (XEXP (src, 1)) == cfa_temp.reg);
- offset = cfa_temp.offset;
+ gcc_assert (dwf_regno (XEXP (src, 1))
+ == cur_trace->cfa_temp.reg);
+ offset = cur_trace->cfa_temp.offset;
break;
default:
gcc_unreachable ();
@@ -1665,8 +1765,8 @@ dwarf2out_frame_debug_expr (rtx expr)
offset = -offset;
if (cfa.reg == dw_stack_pointer_regnum)
cfa.offset += offset;
- if (cfa_store.reg == dw_stack_pointer_regnum)
- cfa_store.offset += offset;
+ if (cur_trace->cfa_store.reg == dw_stack_pointer_regnum)
+ cur_trace->cfa_store.offset += offset;
}
else if (dest == hard_frame_pointer_rtx)
{
@@ -1699,28 +1799,29 @@ dwarf2out_frame_debug_expr (rtx expr)
cfa.offset += offset;
cfa.reg = dwf_regno (dest);
/* Or used to save regs to the stack. */
- cfa_temp.reg = cfa.reg;
- cfa_temp.offset = cfa.offset;
+ cur_trace->cfa_temp.reg = cfa.reg;
+ cur_trace->cfa_temp.offset = cfa.offset;
}
/* Rule 5 */
else if (REG_P (XEXP (src, 0))
- && dwf_regno (XEXP (src, 0)) == cfa_temp.reg
+ && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg
&& XEXP (src, 1) == stack_pointer_rtx)
{
/* Setting a scratch register that we will use instead
of SP for saving registers to the stack. */
gcc_assert (cfa.reg == dw_stack_pointer_regnum);
- cfa_store.reg = dwf_regno (dest);
- cfa_store.offset = cfa.offset - cfa_temp.offset;
+ cur_trace->cfa_store.reg = dwf_regno (dest);
+ cur_trace->cfa_store.offset
+ = cfa.offset - cur_trace->cfa_temp.offset;
}
/* Rule 9 */
else if (GET_CODE (src) == LO_SUM
&& CONST_INT_P (XEXP (src, 1)))
{
- cfa_temp.reg = dwf_regno (dest);
- cfa_temp.offset = INTVAL (XEXP (src, 1));
+ cur_trace->cfa_temp.reg = dwf_regno (dest);
+ cur_trace->cfa_temp.offset = INTVAL (XEXP (src, 1));
}
else
gcc_unreachable ();
@@ -1729,18 +1830,18 @@ dwarf2out_frame_debug_expr (rtx expr)
/* Rule 6 */
case CONST_INT:
- cfa_temp.reg = dwf_regno (dest);
- cfa_temp.offset = INTVAL (src);
+ cur_trace->cfa_temp.reg = dwf_regno (dest);
+ cur_trace->cfa_temp.offset = INTVAL (src);
break;
/* Rule 7 */
case IOR:
gcc_assert (REG_P (XEXP (src, 0))
- && dwf_regno (XEXP (src, 0)) == cfa_temp.reg
+ && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg
&& CONST_INT_P (XEXP (src, 1)));
- cfa_temp.reg = dwf_regno (dest);
- cfa_temp.offset |= INTVAL (XEXP (src, 1));
+ cur_trace->cfa_temp.reg = dwf_regno (dest);
+ cur_trace->cfa_temp.offset |= INTVAL (XEXP (src, 1));
break;
/* Skip over HIGH, assuming it will be followed by a LO_SUM,
@@ -1767,10 +1868,11 @@ dwarf2out_frame_debug_expr (rtx expr)
Thus we must flush whatever we have queued first. */
dwarf2out_flush_queued_reg_saves ();
- gcc_assert (cfa_store.reg == dwf_regno (XEXP (src, 0)));
+ gcc_assert (cur_trace->cfa_store.reg
+ == dwf_regno (XEXP (src, 0)));
fde->stack_realign = 1;
fde->stack_realignment = INTVAL (XEXP (src, 1));
- cfa_store.offset = 0;
+ cur_trace->cfa_store.offset = 0;
if (cfa.reg != dw_stack_pointer_regnum
&& cfa.reg != dw_frame_pointer_regnum)
@@ -1801,16 +1903,16 @@ dwarf2out_frame_debug_expr (rtx expr)
offset = -INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1));
gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
- && cfa_store.reg == dw_stack_pointer_regnum);
+ && cur_trace->cfa_store.reg == dw_stack_pointer_regnum);
- cfa_store.offset += offset;
+ cur_trace->cfa_store.offset += offset;
if (cfa.reg == dw_stack_pointer_regnum)
- cfa.offset = cfa_store.offset;
+ cfa.offset = cur_trace->cfa_store.offset;
if (GET_CODE (XEXP (dest, 0)) == POST_MODIFY)
- offset -= cfa_store.offset;
+ offset -= cur_trace->cfa_store.offset;
else
- offset = -cfa_store.offset;
+ offset = -cur_trace->cfa_store.offset;
break;
/* Rule 11 */
@@ -1823,9 +1925,9 @@ dwarf2out_frame_debug_expr (rtx expr)
gcc_assert ((REGNO (XEXP (XEXP (dest, 0), 0))
== STACK_POINTER_REGNUM)
- && cfa_store.reg == dw_stack_pointer_regnum);
+ && cur_trace->cfa_store.reg == dw_stack_pointer_regnum);
- cfa_store.offset += offset;
+ cur_trace->cfa_store.offset += offset;
/* Rule 18: If stack is aligned, we will use FP as a
reference to represent the address of the stored
@@ -1835,16 +1937,16 @@ dwarf2out_frame_debug_expr (rtx expr)
&& src == hard_frame_pointer_rtx)
{
gcc_assert (cfa.reg != dw_frame_pointer_regnum);
- cfa_store.offset = 0;
+ cur_trace->cfa_store.offset = 0;
}
if (cfa.reg == dw_stack_pointer_regnum)
- cfa.offset = cfa_store.offset;
+ cfa.offset = cur_trace->cfa_store.offset;
if (GET_CODE (XEXP (dest, 0)) == POST_DEC)
- offset += -cfa_store.offset;
+ offset += -cur_trace->cfa_store.offset;
else
- offset = -cfa_store.offset;
+ offset = -cur_trace->cfa_store.offset;
break;
/* Rule 12 */
@@ -1865,12 +1967,12 @@ dwarf2out_frame_debug_expr (rtx expr)
if (cfa.reg == regno)
offset -= cfa.offset;
- else if (cfa_store.reg == regno)
- offset -= cfa_store.offset;
+ else if (cur_trace->cfa_store.reg == regno)
+ offset -= cur_trace->cfa_store.offset;
else
{
- gcc_assert (cfa_temp.reg == regno);
- offset -= cfa_temp.offset;
+ gcc_assert (cur_trace->cfa_temp.reg == regno);
+ offset -= cur_trace->cfa_temp.offset;
}
}
break;
@@ -1883,21 +1985,22 @@ dwarf2out_frame_debug_expr (rtx expr)
if (cfa.reg == regno)
offset = -cfa.offset;
- else if (cfa_store.reg == regno)
- offset = -cfa_store.offset;
+ else if (cur_trace->cfa_store.reg == regno)
+ offset = -cur_trace->cfa_store.offset;
else
{
- gcc_assert (cfa_temp.reg == regno);
- offset = -cfa_temp.offset;
+ gcc_assert (cur_trace->cfa_temp.reg == regno);
+ offset = -cur_trace->cfa_temp.offset;
}
}
break;
/* Rule 14 */
case POST_INC:
- gcc_assert (cfa_temp.reg == dwf_regno (XEXP (XEXP (dest, 0), 0)));
- offset = -cfa_temp.offset;
- cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
+ gcc_assert (cur_trace->cfa_temp.reg
+ == dwf_regno (XEXP (XEXP (dest, 0), 0)));
+ offset = -cur_trace->cfa_temp.offset;
+ cur_trace->cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
break;
default:
@@ -2149,6 +2252,48 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
dwarf2out_flush_queued_reg_saves ();
}
+/* Emit CFI info to change the state from OLD_ROW to NEW_ROW. */
+
+static void
+change_cfi_row (dw_cfi_row *old_row, dw_cfi_row *new_row)
+{
+ size_t i, n_old, n_new, n_max;
+ dw_cfi_ref cfi;
+
+ if (new_row->cfa_cfi && !cfi_equal_p (old_row->cfa_cfi, new_row->cfa_cfi))
+ add_cfi (new_row->cfa_cfi);
+ else
+ {
+ cfi = def_cfa_0 (&old_row->cfa, &new_row->cfa);
+ if (cfi)
+ add_cfi (cfi);
+ }
+
+ if (old_row->args_size != new_row->args_size)
+ add_cfi_args_size (new_row->args_size);
+
+ n_old = VEC_length (dw_cfi_ref, old_row->reg_save);
+ n_new = VEC_length (dw_cfi_ref, new_row->reg_save);
+ n_max = MAX (n_old, n_new);
+
+ for (i = 0; i < n_max; ++i)
+ {
+ dw_cfi_ref r_old = NULL, r_new = NULL;
+
+ if (i < n_old)
+ r_old = VEC_index (dw_cfi_ref, old_row->reg_save, i);
+ if (i < n_new)
+ r_new = VEC_index (dw_cfi_ref, new_row->reg_save, i);
+
+ if (r_old == r_new)
+ ;
+ else if (r_new == NULL)
+ add_cfi_restore (i);
+ else if (!cfi_equal_p (r_old, r_new))
+ add_cfi (r_new);
+ }
+}
+
/* Examine CFI and return true if a cfi label and set_loc is needed
beforehand. Even when generating CFI assembler instructions, we
still have to add the cfi to the list so that lookup_cfa_1 works
@@ -2202,6 +2347,8 @@ add_cfis_to_fde (void)
if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
{
+ fde->dw_fde_switch_cfi_index
+ = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
/* Don't attempt to advance_loc4 between labels
in different sections. */
first = true;
@@ -2244,176 +2391,380 @@ add_cfis_to_fde (void)
}
}
-/* Scan the function and create the initial set of CFI notes. */
-
+/* If LABEL is the start of a trace, then initialize the state of that
+ trace from CUR_TRACE and CUR_ROW. */
+
static void
-create_cfi_notes (void)
+maybe_record_trace_start (rtx start, rtx origin, bool abnormal)
{
- rtx insn;
+ dw_trace_info *ti;
+
+ /* Sync queued data before propagating to a destination,
+ lest we propagate out-of-date data. */
+ dwarf2out_flush_queued_reg_saves ();
+ dwarf2out_args_size (queued_args_size);
- for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
+ ti = get_trace_info (start);
+ gcc_assert (ti != NULL);
+
+ if (dump_file)
{
- rtx pat;
+ fprintf (dump_file, " saw edge from trace %u to %u (via %s %d)\n",
+ get_trace_index (cur_trace), get_trace_index (ti),
+ (origin ? rtx_name[(int) GET_CODE (origin)] : "fallthru"),
+ (origin ? INSN_UID (origin) : 0));
+ }
- cfi_insn = PREV_INSN (insn);
+ if (ti->beg_row == NULL)
+ {
+ /* This is the first time we've encountered this trace. Propagate
+ state across the edge and push the trace onto the work list. */
+ ti->beg_row = copy_cfi_row (cur_row);
+ /* On all abnormal edges, especially EH and non-local-goto, we take
+ care to free the pushed arguments. */
+ if (abnormal)
+ ti->beg_row->args_size = 0;
+
+ ti->cfa_store = cur_trace->cfa_store;
+ ti->cfa_temp = cur_trace->cfa_temp;
+ ti->regs_saved_in_regs = VEC_copy (reg_saved_in_data, heap,
+ cur_trace->regs_saved_in_regs);
+
+ VEC_safe_push (dw_trace_info_ref, heap, trace_work_list, ti);
+
+ if (dump_file)
+ fprintf (dump_file, "\tpush trace %u to worklist\n",
+ get_trace_index (ti));
+ }
+ else
+ {
+ /* We ought to have the same state incoming to a given trace no
+ matter how we arrive at the trace. Anything else means we've
+ got some kind of optimization error. */
+ gcc_checking_assert (cfi_row_equal_p (cur_row, ti->beg_row));
+ }
+}
- if (BARRIER_P (insn))
+/* Propagate CUR_TRACE state to the destinations implied by INSN. */
+/* ??? Sadly, this is in large part a duplicate of make_edges. */
+
+static void
+create_trace_edges (rtx insn)
+{
+ rtx tmp, lab;
+ int i, n;
+
+ if (JUMP_P (insn))
+ {
+ if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
+ ;
+ else if (tablejump_p (insn, NULL, &tmp))
{
- dwarf2out_frame_debug (insn, false);
- continue;
- }
+ rtvec vec;
+
+ tmp = PATTERN (tmp);
+ vec = XVEC (tmp, GET_CODE (tmp) == ADDR_DIFF_VEC);
- if (NOTE_P (insn))
+ n = GET_NUM_ELEM (vec);
+ for (i = 0; i < n; ++i)
+ {
+ lab = XEXP (RTVEC_ELT (vec, i), 0);
+ maybe_record_trace_start (lab, insn, false);
+ }
+ }
+ else if (computed_jump_p (insn))
{
- switch (NOTE_KIND (insn))
+ for (lab = forced_labels; lab; lab = XEXP (lab, 1))
+ maybe_record_trace_start (XEXP (lab, 0), insn, true);
+ }
+ else if (returnjump_p (insn))
+ ;
+ else if ((tmp = extract_asm_operands (PATTERN (insn))) != NULL)
+ {
+ n = ASM_OPERANDS_LABEL_LENGTH (tmp);
+ for (i = 0; i < n; ++i)
{
- case NOTE_INSN_PROLOGUE_END:
- dwarf2out_flush_queued_reg_saves ();
- break;
+ lab = XEXP (ASM_OPERANDS_LABEL (tmp, i), 0);
+ maybe_record_trace_start (lab, insn, true);
+ }
+ }
+ else
+ {
+ lab = JUMP_LABEL (insn);
+ gcc_assert (lab != NULL);
+ maybe_record_trace_start (lab, insn, false);
+ }
+ }
+ else if (CALL_P (insn))
+ {
+ /* Sibling calls don't have edges inside this function. */
+ if (SIBLING_CALL_P (insn))
+ return;
- case NOTE_INSN_EPILOGUE_BEG:
-#if defined(HAVE_epilogue)
- dwarf2out_cfi_begin_epilogue (insn);
-#endif
- break;
+ /* Process non-local goto edges. */
+ if (can_nonlocal_goto (insn))
+ for (lab = nonlocal_goto_handler_labels; lab; lab = XEXP (lab, 1))
+ maybe_record_trace_start (XEXP (lab, 0), insn, true);
+ }
+ else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ rtx seq = PATTERN (insn);
+ int i, n = XVECLEN (seq, 0);
+ for (i = 0; i < n; ++i)
+ create_trace_edges (XVECEXP (seq, 0, i));
+ return;
+ }
- case NOTE_INSN_CFA_RESTORE_STATE:
- cfi_insn = insn;
- dwarf2out_frame_debug_restore_state ();
- break;
- }
- continue;
+ /* Process EH edges. */
+ if (CALL_P (insn) || cfun->can_throw_non_call_exceptions)
+ {
+ eh_landing_pad lp = get_eh_landing_pad_from_rtx (insn);
+ if (lp)
+ maybe_record_trace_start (lp->landing_pad, insn, true);
+ }
+}
+
+/* Scan the trace beginning at INSN and create the CFI notes for the
+ instructions therein. */
+
+static void
+scan_trace (dw_trace_info *trace)
+{
+ rtx insn = trace->head;
+
+ if (dump_file)
+ fprintf (dump_file, "Processing trace %u : start at %s %d\n",
+ get_trace_index (trace), rtx_name[(int) GET_CODE (insn)],
+ INSN_UID (insn));
+
+ trace->end_row = copy_cfi_row (trace->beg_row);
+
+ cur_trace = trace;
+ cur_row = trace->end_row;
+ queued_args_size = cur_row->args_size;
+
+ for (insn = NEXT_INSN (insn); insn ; insn = NEXT_INSN (insn))
+ {
+ rtx pat;
+
+ add_cfi_insn = PREV_INSN (insn);
+
+ /* Notice the end of a trace. */
+ if (BARRIER_P (insn) || save_point_p (insn))
+ {
+ dwarf2out_flush_queued_reg_saves ();
+ dwarf2out_args_size (queued_args_size);
+
+ /* Propagate across fallthru edges. */
+ if (!BARRIER_P (insn))
+ maybe_record_trace_start (insn, NULL, false);
+ break;
}
- if (!NONDEBUG_INSN_P (insn))
+ if (DEBUG_INSN_P (insn) || !inside_basic_block_p (insn))
continue;
pat = PATTERN (insn);
if (asm_noperands (pat) >= 0)
{
dwarf2out_frame_debug (insn, false);
- continue;
+ add_cfi_insn = insn;
}
-
- if (GET_CODE (pat) == SEQUENCE)
+ else
{
- int i, n = XVECLEN (pat, 0);
- for (i = 1; i < n; ++i)
- dwarf2out_frame_debug (XVECEXP (pat, 0, i), false);
+ if (GET_CODE (pat) == SEQUENCE)
+ {
+ int i, n = XVECLEN (pat, 0);
+ for (i = 1; i < n; ++i)
+ dwarf2out_frame_debug (XVECEXP (pat, 0, i), false);
+ }
+
+ if (CALL_P (insn))
+ dwarf2out_frame_debug (insn, false);
+ else if (find_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL)
+ || (cfun->can_throw_non_call_exceptions
+ && can_throw_internal (insn)))
+ dwarf2out_flush_queued_reg_saves ();
+
+ /* Do not separate tablejump insns from their ADDR_DIFF_VEC.
+ Putting the note after the VEC should be ok. */
+ if (!tablejump_p (insn, NULL, &add_cfi_insn))
+ add_cfi_insn = insn;
+
+ dwarf2out_frame_debug (insn, true);
}
- if (CALL_P (insn)
- || find_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL))
- dwarf2out_frame_debug (insn, false);
+ /* Note that a test for control_flow_insn_p does exactly the
+ same tests as are done to actually create the edges. So
+ always call the routine and let it not create edges for
+ non-control-flow insns. */
+ create_trace_edges (insn);
+ }
+
+ add_cfi_insn = NULL;
+ cur_row = NULL;
+ cur_trace = NULL;
+}
- /* Do not separate tablejump insns from their ADDR_DIFF_VEC.
- Putting the note after the VEC should be ok. */
- if (!tablejump_p (insn, NULL, &cfi_insn))
- cfi_insn = insn;
+/* Scan the function and create the initial set of CFI notes. */
- dwarf2out_frame_debug (insn, true);
+static void
+create_cfi_notes (void)
+{
+ dw_trace_info *ti;
+
+ gcc_checking_assert (queued_reg_saves == NULL);
+ gcc_checking_assert (trace_work_list == NULL);
+
+ /* Always begin at the entry trace. */
+ ti = VEC_index (dw_trace_info, trace_info, 0);
+ scan_trace (ti);
+
+ while (!VEC_empty (dw_trace_info_ref, trace_work_list))
+ {
+ ti = VEC_pop (dw_trace_info_ref, trace_work_list);
+ scan_trace (ti);
}
- cfi_insn = NULL;
+ VEC_free (queued_reg_save, heap, queued_reg_saves);
+ VEC_free (dw_trace_info_ref, heap, trace_work_list);
}
-/* Determine if we need to save and restore CFI information around this
- epilogue. If SIBCALL is true, then this is a sibcall epilogue. If
- we do need to save/restore, then emit the save now, and insert a
- NOTE_INSN_CFA_RESTORE_STATE at the appropriate place in the stream. */
+/* Insert CFI notes between traces to properly change state between them. */
+/* ??? TODO: Make use of remember/restore_state. */
static void
-dwarf2out_cfi_begin_epilogue (rtx insn)
+connect_traces (void)
{
- bool saw_frp = false;
- rtx i;
+ unsigned i, n = VEC_length (dw_trace_info, trace_info);
+ dw_trace_info *prev_ti, *ti;
- /* Scan forward to the return insn, noticing if there are possible
- frame related insns. */
- for (i = NEXT_INSN (insn); i ; i = NEXT_INSN (i))
+ prev_ti = VEC_index (dw_trace_info, trace_info, 0);
+
+ for (i = 1; i < n; ++i)
{
- if (!INSN_P (i))
+ dw_cfi_row *old_row;
+
+ ti = VEC_index (dw_trace_info, trace_info, i);
+
+ /* ??? Ideally, we should have both queued and processed. However
+ the current representation of constant pools on various targets
+ is indistinguishable from unreachable code. Assume for the
+ moment that we can simply skip over such traces. */
+ /* ??? Consider creating a DATA_INSN rtx code to indicate that
+ these are not "real" instructions, and should not be considered.
+ This could be generically useful for tablejump data as well. */
+ if (ti->beg_row == NULL)
continue;
+ gcc_assert (ti->end_row != NULL);
+
+ /* In dwarf2out_switch_text_section, we'll begin a new FDE
+ for the portion of the function in the alternate text
+ section. The row state at the very beginning of that
+ new FDE will be exactly the row state from the CIE. */
+ if (ti->switch_sections)
+ old_row = cie_cfi_row;
+ else
+ old_row = prev_ti->end_row;
- /* Look for both regular and sibcalls to end the block. */
- if (returnjump_p (i))
- break;
- if (CALL_P (i) && SIBLING_CALL_P (i))
- break;
+ add_cfi_insn = ti->head;
+ change_cfi_row (old_row, ti->beg_row);
- if (GET_CODE (PATTERN (i)) == SEQUENCE)
+ if (dump_file && add_cfi_insn != ti->head)
{
- int idx;
- rtx seq = PATTERN (i);
-
- if (returnjump_p (XVECEXP (seq, 0, 0)))
- break;
- if (CALL_P (XVECEXP (seq, 0, 0))
- && SIBLING_CALL_P (XVECEXP (seq, 0, 0)))
- break;
-
- for (idx = 0; idx < XVECLEN (seq, 0); idx++)
- if (RTX_FRAME_RELATED_P (XVECEXP (seq, 0, idx)))
- saw_frp = true;
- }
-
- if (RTX_FRAME_RELATED_P (i))
- saw_frp = true;
- }
+ rtx note;
- /* If the port doesn't emit epilogue unwind info, we don't need a
- save/restore pair. */
- if (!saw_frp)
- return;
+ fprintf (dump_file, "Fixup between trace %u and %u:\n", i - 1, i);
- /* Otherwise, search forward to see if the return insn was the last
- basic block of the function. If so, we don't need save/restore. */
- gcc_assert (i != NULL);
- i = next_real_insn (i);
- if (i == NULL)
- return;
+ note = ti->head;
+ do
+ {
+ note = NEXT_INSN (note);
+ gcc_assert (NOTE_P (note) && NOTE_KIND (note) == NOTE_INSN_CFI);
+ output_cfi_directive (dump_file, NOTE_CFI (note));
+ }
+ while (note != add_cfi_insn);
+ }
- /* Insert the restore before that next real insn in the stream, and before
- a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be
- properly nested. This should be after any label or alignment. This
- will be pushed into the CFI stream by the function below. */
- while (1)
- {
- rtx p = PREV_INSN (i);
- if (!NOTE_P (p))
- break;
- if (NOTE_KIND (p) == NOTE_INSN_BASIC_BLOCK)
- break;
- i = p;
+ prev_ti = ti;
}
- emit_note_before (NOTE_INSN_CFA_RESTORE_STATE, i);
-
- emit_cfa_remember = true;
-
- /* And emulate the state save. */
- gcc_assert (!cfa_remember.in_use);
- cfa_remember = cfa;
- old_cfa_remember = old_cfa;
- cfa_remember.in_use = 1;
}
-/* A "subroutine" of dwarf2out_cfi_begin_epilogue. Emit the restore
- required. */
+/* Set up the pseudo-cfg of instruction traces, as described at the
+ block comment at the top of the file. */
static void
-dwarf2out_frame_debug_restore_state (void)
+create_pseudo_cfg (void)
{
- dw_cfi_ref cfi = new_cfi ();
+ bool saw_barrier, switch_sections;
+ dw_trace_info *ti;
+ rtx insn;
+ unsigned i;
+
+ /* The first trace begins at the start of the function,
+ and begins with the CIE row state. */
+ trace_info = VEC_alloc (dw_trace_info, heap, 16);
+ ti = VEC_quick_push (dw_trace_info, trace_info, NULL);
+
+ memset (ti, 0, sizeof (*ti));
+ ti->head = get_insns ();
+ ti->beg_row = cie_cfi_row;
+ ti->cfa_store = cie_cfi_row->cfa;
+ ti->cfa_temp.reg = INVALID_REGNUM;
+ if (cie_return_save)
+ VEC_safe_push (reg_saved_in_data, heap,
+ ti->regs_saved_in_regs, cie_return_save);
- cfi->dw_cfi_opc = DW_CFA_restore_state;
- add_cfi (cfi);
+ /* Walk all the insns, collecting start of trace locations. */
+ saw_barrier = false;
+ switch_sections = false;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ if (BARRIER_P (insn))
+ saw_barrier = true;
+ else if (NOTE_P (insn)
+ && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+ {
+ /* We should have just seen a barrier. */
+ gcc_assert (saw_barrier);
+ switch_sections = true;
+ }
+ /* Watch out for save_point notes between basic blocks.
+ In particular, a note after a barrier. Do not record these,
+ delaying trace creation until the label. */
+ else if (save_point_p (insn)
+ && (LABEL_P (insn) || !saw_barrier))
+ {
+ ti = VEC_safe_push (dw_trace_info, heap, trace_info, NULL);
+ memset (ti, 0, sizeof (*ti));
+ ti->head = insn;
+ ti->switch_sections = switch_sections;
- gcc_assert (cfa_remember.in_use);
- cfa = cfa_remember;
- old_cfa = old_cfa_remember;
- cfa_remember.in_use = 0;
+ saw_barrier = false;
+ switch_sections = false;
+ }
+ }
+
+ /* Create the trace index after we've finished building trace_info,
+ avoiding stale pointer problems due to reallocation. */
+ trace_index = htab_create (VEC_length (dw_trace_info, trace_info),
+ dw_trace_info_hash, dw_trace_info_eq, NULL);
+ FOR_EACH_VEC_ELT (dw_trace_info, trace_info, i, ti)
+ {
+ void **slot;
+
+ if (dump_file)
+ fprintf (dump_file, "Creating trace %u : start at %s %d%s\n", i,
+ rtx_name[(int) GET_CODE (ti->head)], INSN_UID (ti->head),
+ ti->switch_sections ? " (section switch)" : "");
+
+ slot = htab_find_slot_with_hash (trace_index, ti,
+ INSN_UID (ti->head), INSERT);
+ gcc_assert (*slot == NULL);
+ *slot = (void *) ti;
+ }
}
-
+
/* Record the initial position of the return address. RTL is
INCOMING_RETURN_ADDR_RTX. */
@@ -2472,95 +2823,96 @@ initial_return_save (rtx rtl)
{
if (reg != INVALID_REGNUM)
record_reg_saved_in_reg (rtl, pc_rtx);
- reg_save (DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset);
+ reg_save (DWARF_FRAME_RETURN_COLUMN, reg, offset - cur_row->cfa.offset);
}
}
-/* Annotate the function with NOTE_INSN_CFI notes to record the CFI
- state at each location within the function. These notes will be
- emitted during pass_final. */
-
-static unsigned int
-execute_dwarf2_frame (void)
+static void
+create_cie_data (void)
{
- /* The first time we're called, compute the incoming frame state. */
- if (cie_cfi_vec == NULL)
- {
- dw_cfa_location loc;
+ dw_cfa_location loc;
+ dw_trace_info cie_trace;
- dw_stack_pointer_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
- dw_frame_pointer_regnum = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
+ dw_stack_pointer_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
+ dw_frame_pointer_regnum = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
- add_cfi_vec = &cie_cfi_vec;
+ memset (&cie_trace, 0, sizeof(cie_trace));
+ cur_trace = &cie_trace;
- memset (&old_cfa, 0, sizeof (old_cfa));
- old_cfa.reg = INVALID_REGNUM;
+ add_cfi_vec = &cie_cfi_vec;
+ cie_cfi_row = cur_row = new_cfi_row ();
- /* On entry, the Canonical Frame Address is at SP. */
- memset(&loc, 0, sizeof (loc));
- loc.reg = dw_stack_pointer_regnum;
- loc.offset = INCOMING_FRAME_SP_OFFSET;
- def_cfa_1 (&loc);
+ /* On entry, the Canonical Frame Address is at SP. */
+ memset(&loc, 0, sizeof (loc));
+ loc.reg = dw_stack_pointer_regnum;
+ loc.offset = INCOMING_FRAME_SP_OFFSET;
+ def_cfa_1 (&loc);
- if (targetm.debug_unwind_info () == UI_DWARF2
- || targetm_common.except_unwind_info (&global_options) == UI_DWARF2)
+ if (targetm.debug_unwind_info () == UI_DWARF2
+ || targetm_common.except_unwind_info (&global_options) == UI_DWARF2)
+ {
+ initial_return_save (INCOMING_RETURN_ADDR_RTX);
+
+ /* For a few targets, we have the return address incoming into a
+ register, but choose a different return column. This will result
+ in a DW_CFA_register for the return, and an entry in
+ regs_saved_in_regs to match. If the target later stores that
+ return address register to the stack, we want to be able to emit
+ the DW_CFA_offset against the return column, not the intermediate
+ save register. Save the contents of regs_saved_in_regs so that
+ we can re-initialize it at the start of each function. */
+ switch (VEC_length (reg_saved_in_data, cie_trace.regs_saved_in_regs))
{
- initial_return_save (INCOMING_RETURN_ADDR_RTX);
-
- /* For a few targets, we have the return address incoming into a
- register, but choose a different return column. This will result
- in a DW_CFA_register for the return, and an entry in
- regs_saved_in_regs to match. If the target later stores that
- return address register to the stack, we want to be able to emit
- the DW_CFA_offset against the return column, not the intermediate
- save register. Save the contents of regs_saved_in_regs so that
- we can re-initialize it at the start of each function. */
- switch (VEC_length (reg_saved_in_data, regs_saved_in_regs))
- {
- case 0:
- break;
- case 1:
- cie_return_save = ggc_alloc_reg_saved_in_data ();
- *cie_return_save = *VEC_index (reg_saved_in_data,
- regs_saved_in_regs, 0);
- regs_saved_in_regs = NULL;
- break;
- default:
- gcc_unreachable ();
- }
+ case 0:
+ break;
+ case 1:
+ cie_return_save = ggc_alloc_reg_saved_in_data ();
+ *cie_return_save = *VEC_index (reg_saved_in_data,
+ cie_trace.regs_saved_in_regs, 0);
+ VEC_free (reg_saved_in_data, heap, cie_trace.regs_saved_in_regs);
+ break;
+ default:
+ gcc_unreachable ();
}
-
- add_cfi_vec = NULL;
}
- /* Set up state for generating call frame debug info. */
- gcc_checking_assert (queued_reg_saves == NULL);
- gcc_checking_assert (regs_saved_in_regs == NULL);
-
- memset (&cfa, 0, sizeof(cfa));
- cfa.reg = dw_stack_pointer_regnum;
- cfa.offset = INCOMING_FRAME_SP_OFFSET;
-
- old_cfa = cfa;
- cfa_store = cfa;
+ add_cfi_vec = NULL;
+ cur_row = NULL;
+ cur_trace = NULL;
+}
- memset (&cfa_temp, 0, sizeof(cfa_temp));
- cfa_temp.reg = INVALID_REGNUM;
+/* Annotate the function with NOTE_INSN_CFI notes to record the CFI
+ state at each location within the function. These notes will be
+ emitted during pass_final. */
- if (cie_return_save)
- VEC_safe_push (reg_saved_in_data, gc, regs_saved_in_regs, cie_return_save);
+static unsigned int
+execute_dwarf2_frame (void)
+{
+ /* The first time we're called, compute the incoming frame state. */
+ if (cie_cfi_vec == NULL)
+ create_cie_data ();
dwarf2out_alloc_current_fde ();
+ create_pseudo_cfg ();
+
/* Do the work. */
create_cfi_notes ();
+ connect_traces ();
add_cfis_to_fde ();
- /* Reset all function-specific information, particularly for GC. */
- XDELETEVEC (barrier_args_size);
- barrier_args_size = NULL;
- regs_saved_in_regs = NULL;
- queued_reg_saves = NULL;
+ /* Free all the data we allocated. */
+ {
+ size_t i;
+ dw_trace_info *ti;
+
+ FOR_EACH_VEC_ELT (dw_trace_info, trace_info, i, ti)
+ VEC_free (reg_saved_in_data, heap, ti->regs_saved_in_regs);
+ }
+ VEC_free (dw_trace_info, heap, trace_info);
+
+ htab_delete (trace_index);
+ trace_index = NULL;
return 0;
}
@@ -2649,7 +3001,7 @@ output_cfa_loc (dw_cfi_ref cfi, int for_eh)
if (cfi->dw_cfi_opc == DW_CFA_expression)
{
- unsigned r =
+ unsigned r =
DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
dw2_asm_output_data (1, r, NULL);
loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
@@ -2675,7 +3027,7 @@ output_cfa_loc_raw (dw_cfi_ref cfi)
if (cfi->dw_cfi_opc == DW_CFA_expression)
{
- unsigned r =
+ unsigned r =
DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
fprintf (asm_out_file, "%#x,", r);
loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
@@ -2962,175 +3314,6 @@ dwarf2out_emit_cfi (dw_cfi_ref cfi)
if (dwarf2out_do_cfi_asm ())
output_cfi_directive (asm_out_file, cfi);
}
-
-/* Output CFIs from VEC, up to index UPTO, to bring current FDE to the
- same state as after executing CFIs in CFI chain. DO_CFI_ASM is
- true if .cfi_* directives shall be emitted, false otherwise. If it
- is false, FDE and FOR_EH are the other arguments to pass to
- output_cfi. */
-
-void
-output_cfis (cfi_vec vec, int upto, bool do_cfi_asm,
- dw_fde_ref fde, bool for_eh)
-{
- int ix;
- struct dw_cfi_struct cfi_buf;
- dw_cfi_ref cfi2;
- dw_cfi_ref cfi_args_size = NULL, cfi_cfa = NULL, cfi_cfa_offset = NULL;
- VEC(dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32);
- unsigned int len, idx;
-
- for (ix = 0; ix < upto + 1; ix++)
- {
- dw_cfi_ref cfi = ix < upto ? VEC_index (dw_cfi_ref, vec, ix) : NULL;
- switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop)
- {
- case DW_CFA_advance_loc:
- case DW_CFA_advance_loc1:
- case DW_CFA_advance_loc2:
- case DW_CFA_advance_loc4:
- case DW_CFA_MIPS_advance_loc8:
- case DW_CFA_set_loc:
- /* All advances should be ignored. */
- break;
- case DW_CFA_remember_state:
- {
- dw_cfi_ref args_size = cfi_args_size;
-
- /* Skip everything between .cfi_remember_state and
- .cfi_restore_state. */
- ix++;
- if (ix == upto)
- goto flush_all;
-
- for (; ix < upto; ix++)
- {
- cfi2 = VEC_index (dw_cfi_ref, vec, ix);
- if (cfi2->dw_cfi_opc == DW_CFA_restore_state)
- break;
- else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size)
- args_size = cfi2;
- else
- gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state);
- }
-
- cfi_args_size = args_size;
- break;
- }
- case DW_CFA_GNU_args_size:
- cfi_args_size = cfi;
- break;
- case DW_CFA_GNU_window_save:
- goto flush_all;
- case DW_CFA_offset:
- case DW_CFA_offset_extended:
- case DW_CFA_offset_extended_sf:
- case DW_CFA_restore:
- case DW_CFA_restore_extended:
- case DW_CFA_undefined:
- case DW_CFA_same_value:
- case DW_CFA_register:
- case DW_CFA_val_offset:
- case DW_CFA_val_offset_sf:
- case DW_CFA_expression:
- case DW_CFA_val_expression:
- case DW_CFA_GNU_negative_offset_extended:
- if (VEC_length (dw_cfi_ref, regs)
- <= cfi->dw_cfi_oprnd1.dw_cfi_reg_num)
- VEC_safe_grow_cleared (dw_cfi_ref, heap, regs,
- cfi->dw_cfi_oprnd1.dw_cfi_reg_num + 1);
- VEC_replace (dw_cfi_ref, regs, cfi->dw_cfi_oprnd1.dw_cfi_reg_num,
- cfi);
- break;
- case DW_CFA_def_cfa:
- case DW_CFA_def_cfa_sf:
- case DW_CFA_def_cfa_expression:
- cfi_cfa = cfi;
- cfi_cfa_offset = cfi;
- break;
- case DW_CFA_def_cfa_register:
- cfi_cfa = cfi;
- break;
- case DW_CFA_def_cfa_offset:
- case DW_CFA_def_cfa_offset_sf:
- cfi_cfa_offset = cfi;
- break;
- case DW_CFA_nop:
- gcc_assert (cfi == NULL);
- flush_all:
- len = VEC_length (dw_cfi_ref, regs);
- for (idx = 0; idx < len; idx++)
- {
- cfi2 = VEC_replace (dw_cfi_ref, regs, idx, NULL);
- if (cfi2 != NULL
- && cfi2->dw_cfi_opc != DW_CFA_restore
- && cfi2->dw_cfi_opc != DW_CFA_restore_extended)
- {
- if (do_cfi_asm)
- output_cfi_directive (asm_out_file, cfi2);
- else
- output_cfi (cfi2, fde, for_eh);
- }
- }
- if (cfi_cfa && cfi_cfa_offset && cfi_cfa_offset != cfi_cfa)
- {
- gcc_assert (cfi_cfa->dw_cfi_opc != DW_CFA_def_cfa_expression);
- cfi_buf = *cfi_cfa;
- switch (cfi_cfa_offset->dw_cfi_opc)
- {
- case DW_CFA_def_cfa_offset:
- cfi_buf.dw_cfi_opc = DW_CFA_def_cfa;
- cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
- break;
- case DW_CFA_def_cfa_offset_sf:
- cfi_buf.dw_cfi_opc = DW_CFA_def_cfa_sf;
- cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
- break;
- case DW_CFA_def_cfa:
- case DW_CFA_def_cfa_sf:
- cfi_buf.dw_cfi_opc = cfi_cfa_offset->dw_cfi_opc;
- cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd2;
- break;
- default:
- gcc_unreachable ();
- }
- cfi_cfa = &cfi_buf;
- }
- else if (cfi_cfa_offset)
- cfi_cfa = cfi_cfa_offset;
- if (cfi_cfa)
- {
- if (do_cfi_asm)
- output_cfi_directive (asm_out_file, cfi_cfa);
- else
- output_cfi (cfi_cfa, fde, for_eh);
- }
- cfi_cfa = NULL;
- cfi_cfa_offset = NULL;
- if (cfi_args_size
- && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset)
- {
- if (do_cfi_asm)
- output_cfi_directive (asm_out_file, cfi_args_size);
- else
- output_cfi (cfi_args_size, fde, for_eh);
- }
- cfi_args_size = NULL;
- if (cfi == NULL)
- {
- VEC_free (dw_cfi_ref, heap, regs);
- return;
- }
- else if (do_cfi_asm)
- output_cfi_directive (asm_out_file, cfi);
- else
- output_cfi (cfi, fde, for_eh);
- break;
- default:
- gcc_unreachable ();
- }
- }
-}
/* Save the result of dwarf2out_do_frame across PCH.
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 6046ba9c6ab..d430753bfe5 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -94,6 +94,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pass.h"
#include "tree-flow.h"
#include "cfglayout.h"
+#include "opts.h"
static void dwarf2out_source_line (unsigned int, const char *, int, bool);
static rtx last_var_location_insn;
@@ -518,11 +519,9 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
char *section_start_label, int fde_encoding, char *augmentation,
bool any_lsda_needed, int lsda_encoding)
{
- int ix;
const char *begin, *end;
static unsigned int j;
char l1[20], l2[20];
- dw_cfi_ref cfi;
targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh,
/* empty */ 0);
@@ -602,36 +601,24 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
dw2_asm_output_data_uleb128 (0, "Augmentation size");
}
- /* Loop through the Call Frame Instructions associated with
- this FDE. */
+ /* Loop through the Call Frame Instructions associated with this FDE. */
fde->dw_fde_current_label = begin;
- if (fde->dw_fde_second_begin == NULL)
- FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
- output_cfi (cfi, fde, for_eh);
- else if (!second)
- {
- if (fde->dw_fde_switch_cfi_index > 0)
- FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
- {
- if (ix == fde->dw_fde_switch_cfi_index)
- break;
- output_cfi (cfi, fde, for_eh);
- }
- }
- else
- {
- int i, from = 0;
- int until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
+ {
+ size_t from, until, i;
- if (fde->dw_fde_switch_cfi_index > 0)
- {
- from = fde->dw_fde_switch_cfi_index;
- output_cfis (fde->dw_fde_cfi, from, false, fde, for_eh);
- }
- for (i = from; i < until; i++)
- output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i),
- fde, for_eh);
- }
+ from = 0;
+ until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
+
+ if (fde->dw_fde_second_begin == NULL)
+ ;
+ else if (!second)
+ until = fde->dw_fde_switch_cfi_index;
+ else
+ from = fde->dw_fde_switch_cfi_index;
+
+ for (i = from; i < until; i++)
+ output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i), fde, for_eh);
+ }
/* If we are to emit a ref/link from function bodies to their frame tables,
do it now. This is typically performed to make sure that tables
@@ -1183,16 +1170,8 @@ dwarf2out_switch_text_section (void)
= (sect == text_section
|| (cold_text_section && sect == cold_text_section));
- fde->dw_fde_switch_cfi_index = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
-
if (dwarf2out_do_cfi_asm ())
- {
- dwarf2out_do_cfi_startproc (true);
- /* As this is a different FDE, insert all current CFI instructions
- again. */
- output_cfis (fde->dw_fde_cfi, fde->dw_fde_switch_cfi_index,
- true, fde, true);
- }
+ dwarf2out_do_cfi_startproc (true);
var_location_switch_text_section ();
@@ -1638,6 +1617,109 @@ add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr)
*d = descr;
}
+/* Compare two location operands for exact equality. */
+
+static bool
+dw_val_equal_p (dw_val_node *a, dw_val_node *b)
+{
+ if (a->val_class != b->val_class)
+ return false;
+ switch (a->val_class)
+ {
+ case dw_val_class_none:
+ return true;
+ case dw_val_class_addr:
+ return rtx_equal_p (a->v.val_addr, b->v.val_addr);
+
+ case dw_val_class_offset:
+ case dw_val_class_unsigned_const:
+ case dw_val_class_const:
+ case dw_val_class_range_list:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
+ /* These are all HOST_WIDE_INT, signed or unsigned. */
+ return a->v.val_unsigned == b->v.val_unsigned;
+
+ case dw_val_class_loc:
+ return a->v.val_loc == b->v.val_loc;
+ case dw_val_class_loc_list:
+ return a->v.val_loc_list == b->v.val_loc_list;
+ case dw_val_class_die_ref:
+ return a->v.val_die_ref.die == b->v.val_die_ref.die;
+ case dw_val_class_fde_ref:
+ return a->v.val_fde_index == b->v.val_fde_index;
+ case dw_val_class_lbl_id:
+ return strcmp (a->v.val_lbl_id, b->v.val_lbl_id) == 0;
+ case dw_val_class_str:
+ return a->v.val_str == b->v.val_str;
+ case dw_val_class_flag:
+ return a->v.val_flag == b->v.val_flag;
+ case dw_val_class_file:
+ return a->v.val_file == b->v.val_file;
+ case dw_val_class_decl_ref:
+ return a->v.val_decl_ref == b->v.val_decl_ref;
+
+ case dw_val_class_const_double:
+ return (a->v.val_double.high == b->v.val_double.high
+ && a->v.val_double.low == b->v.val_double.low);
+
+ case dw_val_class_vec:
+ {
+ size_t a_len = a->v.val_vec.elt_size * a->v.val_vec.length;
+ size_t b_len = b->v.val_vec.elt_size * b->v.val_vec.length;
+
+ return (a_len == b_len
+ && !memcmp (a->v.val_vec.array, b->v.val_vec.array, a_len));
+ }
+
+ case dw_val_class_data8:
+ return memcmp (a->v.val_data8, b->v.val_data8, 8) == 0;
+
+ case dw_val_class_vms_delta:
+ return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)
+ && !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1));
+ }
+ gcc_unreachable ();
+}
+
+/* Compare two location atoms for exact equality. */
+
+static bool
+loc_descr_equal_p_1 (dw_loc_descr_ref a, dw_loc_descr_ref b)
+{
+ if (a->dw_loc_opc != b->dw_loc_opc)
+ return false;
+
+ /* ??? This is only ever set for DW_OP_constNu, for N equal to the
+ address size, but since we always allocate cleared storage it
+ should be zero for other types of locations. */
+ if (a->dtprel != b->dtprel)
+ return false;
+
+ return (dw_val_equal_p (&a->dw_loc_oprnd1, &b->dw_loc_oprnd1)
+ && dw_val_equal_p (&a->dw_loc_oprnd2, &b->dw_loc_oprnd2));
+}
+
+/* Compare two complete location expressions for exact equality. */
+
+bool
+loc_descr_equal_p (dw_loc_descr_ref a, dw_loc_descr_ref b)
+{
+ while (1)
+ {
+ if (a == b)
+ return true;
+ if (a == NULL || b == NULL)
+ return false;
+ if (!loc_descr_equal_p_1 (a, b))
+ return false;
+
+ a = a->dw_loc_next;
+ b = b->dw_loc_next;
+ }
+}
+
+
/* Add a constant OFFSET to a location expression. */
static void
@@ -2770,7 +2852,7 @@ struct GTY(()) dw_ranges_struct {
/* A structure to hold a macinfo entry. */
typedef struct GTY(()) macinfo_struct {
- unsigned HOST_WIDE_INT code;
+ unsigned char code;
unsigned HOST_WIDE_INT lineno;
const char *info;
}
@@ -3417,6 +3499,9 @@ static void gen_scheduled_generic_parms_dies (void);
#ifndef DEBUG_MACINFO_SECTION
#define DEBUG_MACINFO_SECTION ".debug_macinfo"
#endif
+#ifndef DEBUG_MACRO_SECTION
+#define DEBUG_MACRO_SECTION ".debug_macro"
+#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
@@ -3474,6 +3559,9 @@ static void gen_scheduled_generic_parms_dies (void);
#ifndef DEBUG_MACINFO_SECTION_LABEL
#define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo"
#endif
+#ifndef DEBUG_MACRO_SECTION_LABEL
+#define DEBUG_MACRO_SECTION_LABEL "Ldebug_macro"
+#endif
/* Definitions of defaults for formats and names of various special
@@ -4015,6 +4103,8 @@ dwarf_attr_name (unsigned int attr)
return "DW_AT_GNU_all_call_sites";
case DW_AT_GNU_all_source_call_sites:
return "DW_AT_GNU_all_source_call_sites";
+ case DW_AT_GNU_macros:
+ return "DW_AT_GNU_macros";
case DW_AT_GNAT_descriptive_type:
return "DW_AT_GNAT_descriptive_type";
@@ -18108,13 +18198,123 @@ gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
}
+typedef const char *dchar_p; /* For DEF_VEC_P. */
+DEF_VEC_P(dchar_p);
+DEF_VEC_ALLOC_P(dchar_p,heap);
+
+static char *producer_string;
+
+/* Return a heap allocated producer string including command line options
+ if -grecord-gcc-switches. */
+
+static char *
+gen_producer_string (void)
+{
+ size_t j;
+ VEC(dchar_p, heap) *switches = NULL;
+ const char *language_string = lang_hooks.name;
+ char *producer, *tail;
+ const char *p;
+ size_t len = dwarf_record_gcc_switches ? 0 : 3;
+ size_t plen = strlen (language_string) + 1 + strlen (version_string);
+
+ for (j = 1; dwarf_record_gcc_switches && j < save_decoded_options_count; j++)
+ switch (save_decoded_options[j].opt_index)
+ {
+ case OPT_o:
+ case OPT_d:
+ case OPT_dumpbase:
+ case OPT_dumpdir:
+ case OPT_auxbase:
+ case OPT_auxbase_strip:
+ case OPT_quiet:
+ case OPT_version:
+ case OPT_v:
+ case OPT_w:
+ case OPT_L:
+ case OPT_D:
+ case OPT_I:
+ case OPT_U:
+ case OPT_SPECIAL_unknown:
+ case OPT_SPECIAL_ignore:
+ case OPT_SPECIAL_program_name:
+ case OPT_SPECIAL_input_file:
+ case OPT_grecord_gcc_switches:
+ case OPT_gno_record_gcc_switches:
+ case OPT__output_pch_:
+ case OPT_fdiagnostics_show_location_:
+ case OPT_fdiagnostics_show_option:
+ case OPT____:
+ case OPT__sysroot_:
+ case OPT_nostdinc:
+ case OPT_nostdinc__:
+ /* Ignore these. */
+ continue;
+ default:
+ gcc_checking_assert (save_decoded_options[j].canonical_option[0][0]
+ == '-');
+ switch (save_decoded_options[j].canonical_option[0][1])
+ {
+ case 'M':
+ case 'i':
+ case 'W':
+ continue;
+ case 'f':
+ if (strncmp (save_decoded_options[j].canonical_option[0] + 2,
+ "dump", 4) == 0)
+ continue;
+ break;
+ default:
+ break;
+ }
+ VEC_safe_push (dchar_p, heap, switches,
+ save_decoded_options[j].orig_option_with_args_text);
+ len += strlen (save_decoded_options[j].orig_option_with_args_text) + 1;
+ break;
+ }
+
+ producer = XNEWVEC (char, plen + 1 + len + 1);
+ tail = producer;
+ sprintf (tail, "%s %s", language_string, version_string);
+ tail += plen;
+
+ if (!dwarf_record_gcc_switches)
+ {
+#ifdef MIPS_DEBUGGING_INFO
+ /* The MIPS/SGI compilers place the 'cc' command line options in the
+ producer string. The SGI debugger looks for -g, -g1, -g2, or -g3;
+ if they do not appear in the producer string, the debugger reaches
+ the conclusion that the object file is stripped and has no debugging
+ information. To get the MIPS/SGI debugger to believe that there is
+ debugging information in the object file, we add a -g to the producer
+ string. */
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ {
+ memcpy (tail, " -g", 3);
+ tail += 3;
+ }
+#endif
+ }
+
+ FOR_EACH_VEC_ELT (dchar_p, switches, j, p)
+ {
+ len = strlen (p);
+ *tail = ' ';
+ memcpy (tail + 1, p, len);
+ tail += len + 1;
+ }
+
+ *tail = '\0';
+ VEC_free (dchar_p, heap, switches);
+ return producer;
+}
+
/* Generate the DIE for the compilation unit. */
static dw_die_ref
gen_compile_unit_die (const char *filename)
{
dw_die_ref die;
- char producer[250];
const char *language_string = lang_hooks.name;
int language;
@@ -18128,20 +18328,9 @@ gen_compile_unit_die (const char *filename)
add_comp_dir_attribute (die);
}
- sprintf (producer, "%s %s", language_string, version_string);
-
-#ifdef MIPS_DEBUGGING_INFO
- /* The MIPS/SGI compilers place the 'cc' command line options in the producer
- string. The SGI debugger looks for -g, -g1, -g2, or -g3; if they do
- not appear in the producer string, the debugger reaches the conclusion
- that the object file is stripped and has no debugging information.
- To get the MIPS/SGI debugger to believe that there is debugging
- information in the object file, we add a -g to the producer string. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
- strcat (producer, " -g");
-#endif
-
- add_AT_string (die, DW_AT_producer, producer);
+ if (producer_string == NULL)
+ producer_string = gen_producer_string ();
+ add_AT_string (die, DW_AT_producer, producer_string);
/* If our producer is LTO try to figure out a common language to use
from the global list of translation units. */
@@ -20291,6 +20480,15 @@ dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED,
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
macinfo_entry e;
+ /* Insert a dummy first entry to be able to optimize the whole
+ predefined macro block using DW_MACRO_GNU_transparent_include. */
+ if (VEC_empty (macinfo_entry, macinfo_table) && lineno == 0)
+ {
+ e.code = 0;
+ e.lineno = 0;
+ e.info = NULL;
+ VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+ }
e.code = DW_MACINFO_define;
e.lineno = lineno;
e.info = xstrdup (buffer);;
@@ -20309,58 +20507,386 @@ dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
macinfo_entry e;
+ /* Insert a dummy first entry to be able to optimize the whole
+ predefined macro block using DW_MACRO_GNU_transparent_include. */
+ if (VEC_empty (macinfo_entry, macinfo_table) && lineno == 0)
+ {
+ e.code = 0;
+ e.lineno = 0;
+ e.info = NULL;
+ VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
+ }
e.code = DW_MACINFO_undef;
e.lineno = lineno;
- e.info = xstrdup (buffer);;
+ e.info = xstrdup (buffer);
VEC_safe_push (macinfo_entry, gc, macinfo_table, &e);
}
}
+/* Routines to manipulate hash table of CUs. */
+
+static hashval_t
+htab_macinfo_hash (const void *of)
+{
+ const macinfo_entry *const entry =
+ (const macinfo_entry *) of;
+
+ return htab_hash_string (entry->info);
+}
+
+static int
+htab_macinfo_eq (const void *of1, const void *of2)
+{
+ const macinfo_entry *const entry1 = (const macinfo_entry *) of1;
+ const macinfo_entry *const entry2 = (const macinfo_entry *) of2;
+
+ return !strcmp (entry1->info, entry2->info);
+}
+
+/* Output a single .debug_macinfo entry. */
+
+static void
+output_macinfo_op (macinfo_entry *ref)
+{
+ int file_num;
+ size_t len;
+ struct indirect_string_node *node;
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ switch (ref->code)
+ {
+ case DW_MACINFO_start_file:
+ file_num = maybe_emit_file (lookup_filename (ref->info));
+ dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
+ dw2_asm_output_data_uleb128 (ref->lineno,
+ "Included from line number %lu",
+ (unsigned long) ref->lineno);
+ dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info);
+ break;
+ case DW_MACINFO_end_file:
+ dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ len = strlen (ref->info) + 1;
+ if (!dwarf_strict
+ && len > DWARF_OFFSET_SIZE
+ && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+ && (debug_str_section->common.flags & SECTION_MERGE) != 0)
+ {
+ ref->code = ref->code == DW_MACINFO_define
+ ? DW_MACRO_GNU_define_indirect
+ : DW_MACRO_GNU_undef_indirect;
+ output_macinfo_op (ref);
+ return;
+ }
+ dw2_asm_output_data (1, ref->code,
+ ref->code == DW_MACINFO_define
+ ? "Define macro" : "Undefine macro");
+ dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
+ (unsigned long) ref->lineno);
+ dw2_asm_output_nstring (ref->info, -1, "The macro");
+ break;
+ case DW_MACRO_GNU_define_indirect:
+ case DW_MACRO_GNU_undef_indirect:
+ node = find_AT_string (ref->info);
+ if (node->form != DW_FORM_strp)
+ {
+ char label[32];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+ ++dw2_string_counter;
+ node->label = xstrdup (label);
+ node->form = DW_FORM_strp;
+ }
+ dw2_asm_output_data (1, ref->code,
+ ref->code == DW_MACRO_GNU_define_indirect
+ ? "Define macro indirect"
+ : "Undefine macro indirect");
+ dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
+ (unsigned long) ref->lineno);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+ debug_str_section, "The macro: \"%s\"",
+ ref->info);
+ break;
+ case DW_MACRO_GNU_transparent_include:
+ dw2_asm_output_data (1, ref->code, "Transparent include");
+ ASM_GENERATE_INTERNAL_LABEL (label,
+ DEBUG_MACRO_SECTION_LABEL, ref->lineno);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
+ break;
+ default:
+ fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
+ ASM_COMMENT_START, (unsigned long) ref->code);
+ break;
+ }
+}
+
+/* Attempt to make a sequence of define/undef macinfo ops shareable with
+ other compilation unit .debug_macinfo sections. IDX is the first
+ index of a define/undef, return the number of ops that should be
+ emitted in a comdat .debug_macinfo section and emit
+ a DW_MACRO_GNU_transparent_include entry referencing it.
+ If the define/undef entry should be emitted normally, return 0. */
+
+static unsigned
+optimize_macinfo_range (unsigned int idx, VEC (macinfo_entry, gc) *files,
+ htab_t *macinfo_htab)
+{
+ macinfo_entry *first, *second, *cur, *inc;
+ char linebuf[sizeof (HOST_WIDE_INT) * 3 + 1];
+ unsigned char checksum[16];
+ struct md5_ctx ctx;
+ char *grp_name, *tail;
+ const char *base;
+ unsigned int i, count, encoded_filename_len, linebuf_len;
+ void **slot;
+
+ first = VEC_index (macinfo_entry, macinfo_table, idx);
+ second = VEC_index (macinfo_entry, macinfo_table, idx + 1);
+
+ /* Optimize only if there are at least two consecutive define/undef ops,
+ and either all of them are before first DW_MACINFO_start_file
+ with lineno 0 (i.e. predefined macro block), or all of them are
+ in some included header file. */
+ if (second->code != DW_MACINFO_define && second->code != DW_MACINFO_undef)
+ return 0;
+ if (VEC_empty (macinfo_entry, files))
+ {
+ if (first->lineno != 0 || second->lineno != 0)
+ return 0;
+ }
+ else if (first->lineno == 0)
+ return 0;
+
+ /* Find the last define/undef entry that can be grouped together
+ with first and at the same time compute md5 checksum of their
+ codes, linenumbers and strings. */
+ md5_init_ctx (&ctx);
+ for (i = idx; VEC_iterate (macinfo_entry, macinfo_table, i, cur); i++)
+ if (cur->code != DW_MACINFO_define && cur->code != DW_MACINFO_undef)
+ break;
+ else if (first->lineno == 0 && cur->lineno != 0)
+ break;
+ else
+ {
+ unsigned char code = cur->code;
+ md5_process_bytes (&code, 1, &ctx);
+ checksum_uleb128 (cur->lineno, &ctx);
+ md5_process_bytes (cur->info, strlen (cur->info) + 1, &ctx);
+ }
+ md5_finish_ctx (&ctx, checksum);
+ count = i - idx;
+
+ /* From the containing include filename (if any) pick up just
+ usable characters from its basename. */
+ if (first->lineno == 0)
+ base = "";
+ else
+ base = lbasename (VEC_last (macinfo_entry, files)->info);
+ for (encoded_filename_len = 0, i = 0; base[i]; i++)
+ if (ISIDNUM (base[i]) || base[i] == '.')
+ encoded_filename_len++;
+ /* Count . at the end. */
+ if (encoded_filename_len)
+ encoded_filename_len++;
+
+ sprintf (linebuf, HOST_WIDE_INT_PRINT_UNSIGNED, first->lineno);
+ linebuf_len = strlen (linebuf);
+
+ /* The group name format is: wmN.[<encoded filename>.]<lineno>.<md5sum> */
+ grp_name = XNEWVEC (char, 4 + encoded_filename_len + linebuf_len + 1
+ + 16 * 2 + 1);
+ memcpy (grp_name, DWARF_OFFSET_SIZE == 4 ? "wm4." : "wm8.", 4);
+ tail = grp_name + 4;
+ if (encoded_filename_len)
+ {
+ for (i = 0; base[i]; i++)
+ if (ISIDNUM (base[i]) || base[i] == '.')
+ *tail++ = base[i];
+ *tail++ = '.';
+ }
+ memcpy (tail, linebuf, linebuf_len);
+ tail += linebuf_len;
+ *tail++ = '.';
+ for (i = 0; i < 16; i++)
+ sprintf (tail + i * 2, "%02x", checksum[i] & 0xff);
+
+ /* Construct a macinfo_entry for DW_MACRO_GNU_transparent_include
+ in the empty vector entry before the first define/undef. */
+ inc = VEC_index (macinfo_entry, macinfo_table, idx - 1);
+ inc->code = DW_MACRO_GNU_transparent_include;
+ inc->lineno = 0;
+ inc->info = grp_name;
+ if (*macinfo_htab == NULL)
+ *macinfo_htab = htab_create (10, htab_macinfo_hash, htab_macinfo_eq, NULL);
+ /* Avoid emitting duplicates. */
+ slot = htab_find_slot (*macinfo_htab, inc, INSERT);
+ if (*slot != NULL)
+ {
+ free (CONST_CAST (char *, inc->info));
+ inc->code = 0;
+ inc->info = NULL;
+ /* If such an entry has been used before, just emit
+ a DW_MACRO_GNU_transparent_include op. */
+ inc = (macinfo_entry *) *slot;
+ output_macinfo_op (inc);
+ /* And clear all macinfo_entry in the range to avoid emitting them
+ in the second pass. */
+ for (i = idx;
+ VEC_iterate (macinfo_entry, macinfo_table, i, cur)
+ && i < idx + count;
+ i++)
+ {
+ cur->code = 0;
+ free (CONST_CAST (char *, cur->info));
+ cur->info = NULL;
+ }
+ }
+ else
+ {
+ *slot = inc;
+ inc->lineno = htab_elements (*macinfo_htab);
+ output_macinfo_op (inc);
+ }
+ return count;
+}
+
+/* Output macinfo section(s). */
+
static void
output_macinfo (void)
{
unsigned i;
unsigned long length = VEC_length (macinfo_entry, macinfo_table);
macinfo_entry *ref;
+ VEC (macinfo_entry, gc) *files = NULL;
+ htab_t macinfo_htab = NULL;
if (! length)
return;
+ /* output_macinfo* uses these interchangeably. */
+ gcc_assert ((int) DW_MACINFO_define == (int) DW_MACRO_GNU_define
+ && (int) DW_MACINFO_undef == (int) DW_MACRO_GNU_undef
+ && (int) DW_MACINFO_start_file == (int) DW_MACRO_GNU_start_file
+ && (int) DW_MACINFO_end_file == (int) DW_MACRO_GNU_end_file);
+
+ /* For .debug_macro emit the section header. */
+ if (!dwarf_strict)
+ {
+ dw2_asm_output_data (2, 4, "DWARF macro version number");
+ if (DWARF_OFFSET_SIZE == 8)
+ dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
+ else
+ dw2_asm_output_data (1, 2, "Flags: 32-bit, lineptr present");
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_line_section_label,
+ debug_line_section, NULL);
+ }
+
+ /* In the first loop, it emits the primary .debug_macinfo section
+ and after each emitted op the macinfo_entry is cleared.
+ If a longer range of define/undef ops can be optimized using
+ DW_MACRO_GNU_transparent_include, the
+ DW_MACRO_GNU_transparent_include op is emitted and kept in
+ the vector before the first define/undef in the range and the
+ whole range of define/undef ops is not emitted and kept. */
for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
{
switch (ref->code)
{
- case DW_MACINFO_start_file:
+ case DW_MACINFO_start_file:
+ VEC_safe_push (macinfo_entry, gc, files, ref);
+ break;
+ case DW_MACINFO_end_file:
+ if (!VEC_empty (macinfo_entry, files))
{
- int file_num = maybe_emit_file (lookup_filename (ref->info));
- dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
- dw2_asm_output_data_uleb128
- (ref->lineno, "Included from line number %lu",
- (unsigned long)ref->lineno);
- dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info);
+ macinfo_entry *file = VEC_last (macinfo_entry, files);
+ free (CONST_CAST (char *, file->info));
+ VEC_pop (macinfo_entry, files);
}
- break;
- case DW_MACINFO_end_file:
- dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
- break;
- case DW_MACINFO_define:
- dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
- dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
- (unsigned long)ref->lineno);
- dw2_asm_output_nstring (ref->info, -1, "The macro");
- break;
- case DW_MACINFO_undef:
- dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
- dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
- (unsigned long)ref->lineno);
- dw2_asm_output_nstring (ref->info, -1, "The macro");
- break;
- default:
- fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
- ASM_COMMENT_START, (unsigned long)ref->code);
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ if (!dwarf_strict
+ && HAVE_COMDAT_GROUP
+ && VEC_length (macinfo_entry, files) != 1
+ && i > 0
+ && i + 1 < length
+ && VEC_index (macinfo_entry, macinfo_table, i - 1)->code == 0)
+ {
+ unsigned count = optimize_macinfo_range (i, files, &macinfo_htab);
+ if (count)
+ {
+ i += count - 1;
+ continue;
+ }
+ }
+ break;
+ case 0:
+ /* A dummy entry may be inserted at the beginning to be able
+ to optimize the whole block of predefined macros. */
+ if (i == 0)
+ continue;
+ default:
break;
}
+ output_macinfo_op (ref);
+ /* For DW_MACINFO_start_file ref->info has been copied into files
+ vector. */
+ if (ref->code != DW_MACINFO_start_file)
+ free (CONST_CAST (char *, ref->info));
+ ref->info = NULL;
+ ref->code = 0;
}
+
+ if (macinfo_htab == NULL)
+ return;
+
+ htab_delete (macinfo_htab);
+
+ /* If any DW_MACRO_GNU_transparent_include were used, on those
+ DW_MACRO_GNU_transparent_include entries terminate the
+ current chain and switch to a new comdat .debug_macinfo
+ section and emit the define/undef entries within it. */
+ for (i = 0; VEC_iterate (macinfo_entry, macinfo_table, i, ref); i++)
+ switch (ref->code)
+ {
+ case 0:
+ continue;
+ case DW_MACRO_GNU_transparent_include:
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ tree comdat_key = get_identifier (ref->info);
+ /* Terminate the previous .debug_macinfo section. */
+ dw2_asm_output_data (1, 0, "End compilation unit");
+ targetm.asm_out.named_section (DEBUG_MACRO_SECTION,
+ SECTION_DEBUG
+ | SECTION_LINKONCE,
+ comdat_key);
+ ASM_GENERATE_INTERNAL_LABEL (label,
+ DEBUG_MACRO_SECTION_LABEL,
+ ref->lineno);
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+ ref->code = 0;
+ free (CONST_CAST (char *, ref->info));
+ ref->info = NULL;
+ dw2_asm_output_data (2, 4, "DWARF macro version number");
+ if (DWARF_OFFSET_SIZE == 8)
+ dw2_asm_output_data (1, 1, "Flags: 64-bit");
+ else
+ dw2_asm_output_data (1, 0, "Flags: 32-bit");
+ }
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ output_macinfo_op (ref);
+ ref->code = 0;
+ free (CONST_CAST (char *, ref->info));
+ ref->info = NULL;
+ break;
+ default:
+ gcc_unreachable ();
+ }
}
/* Set up for Dwarf output at the start of compilation. */
@@ -20409,7 +20935,9 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
SECTION_DEBUG, NULL);
debug_aranges_section = get_section (DEBUG_ARANGES_SECTION,
SECTION_DEBUG, NULL);
- debug_macinfo_section = get_section (DEBUG_MACINFO_SECTION,
+ debug_macinfo_section = get_section (dwarf_strict
+ ? DEBUG_MACINFO_SECTION
+ : DEBUG_MACRO_SECTION,
SECTION_DEBUG, NULL);
debug_line_section = get_section (DEBUG_LINE_SECTION,
SECTION_DEBUG, NULL);
@@ -20441,7 +20969,9 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
DEBUG_RANGES_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
- DEBUG_MACINFO_SECTION_LABEL, 0);
+ dwarf_strict
+ ? DEBUG_MACINFO_SECTION_LABEL
+ : DEBUG_MACRO_SECTION_LABEL, 0);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
macinfo_table = VEC_alloc (macinfo_entry, gc, 64);
@@ -21774,6 +22304,15 @@ dwarf2out_finish (const char *filename)
htab_t comdat_type_table;
unsigned int i;
+ /* PCH might result in DW_AT_producer string being restored from the
+ header compilation, fix it up if needed. */
+ dw_attr_ref producer = get_AT (comp_unit_die (), DW_AT_producer);
+ if (strcmp (AT_string (producer), producer_string) != 0)
+ {
+ struct indirect_string_node *node = find_AT_string (producer_string);
+ producer->dw_attr_val.v.val_str = node;
+ }
+
gen_scheduled_generic_parms_dies ();
gen_remaining_tmpl_value_param_die_attribute ();
@@ -21984,7 +22523,9 @@ dwarf2out_finish (const char *filename)
debug_line_section_label);
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
- add_AT_macptr (comp_unit_die (), DW_AT_macro_info, macinfo_section_label);
+ add_AT_macptr (comp_unit_die (),
+ dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+ macinfo_section_label);
if (have_location_lists)
optimize_location_lists (comp_unit_die ());
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index 301321155a6..711e8ab0d5e 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -118,7 +118,7 @@ dw_fde_node;
It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET.
Instead of passing around REG and OFFSET, we pass a copy
of this structure. */
-typedef struct cfa_loc {
+typedef struct GTY(()) cfa_loc {
HOST_WIDE_INT offset;
HOST_WIDE_INT base_offset;
/* REG is in DWARF_FRAME_REGNUM space, *not* normal REGNO space. */
@@ -134,6 +134,7 @@ typedef struct cfa_loc {
enum dw_val_class
{
+ dw_val_class_none,
dw_val_class_addr,
dw_val_class_offset,
dw_val_class_loc,
@@ -226,6 +227,7 @@ extern struct dw_loc_descr_struct *build_cfa_aligned_loc
extern struct dw_loc_descr_struct *mem_loc_descriptor
(rtx, enum machine_mode mode, enum machine_mode mem_mode,
enum var_init_status);
+extern bool loc_descr_equal_p (dw_loc_descr_ref, dw_loc_descr_ref);
extern enum machine_mode get_address_mode (rtx mem);
extern dw_fde_ref dwarf2out_alloc_current_fde (void);
@@ -239,7 +241,6 @@ extern void lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc,
extern bool cfa_equal_p (const dw_cfa_location *, const dw_cfa_location *);
extern void output_cfi (dw_cfi_ref, dw_fde_ref, int);
-extern void output_cfis (cfi_vec, int, bool, dw_fde_ref, bool);
extern GTY(()) cfi_vec cie_cfi_vec;
diff --git a/gcc/except.c b/gcc/except.c
index bb16036d361..8d56e105fbe 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -919,6 +919,34 @@ emit_to_new_bb_before (rtx seq, rtx insn)
return bb;
}
+/* A subroutine of dw2_build_landing_pads, also used for edge splitting
+ at the rtl level. Emit the code required by the target at a landing
+ pad for the given region. */
+
+void
+expand_dw2_landing_pad_for_region (eh_region region)
+{
+#ifdef HAVE_exception_receiver
+ if (HAVE_exception_receiver)
+ emit_insn (gen_exception_receiver ());
+ else
+#endif
+#ifdef HAVE_nonlocal_goto_receiver
+ if (HAVE_nonlocal_goto_receiver)
+ emit_insn (gen_nonlocal_goto_receiver ());
+ else
+#endif
+ { /* Nothing */ }
+
+ if (region->exc_ptr_reg)
+ emit_move_insn (region->exc_ptr_reg,
+ gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
+ if (region->filter_reg)
+ emit_move_insn (region->filter_reg,
+ gen_rtx_REG (targetm.eh_return_filter_mode (),
+ EH_RETURN_DATA_REGNO (1)));
+}
+
/* Expand the extra code needed at landing pads for dwarf2 unwinding. */
static void
@@ -926,10 +954,17 @@ dw2_build_landing_pads (void)
{
int i;
eh_landing_pad lp;
+ int e_flags = EDGE_FALLTHRU;
+
+ /* If we're going to partition blocks, we need to be able to add
+ new landing pads later, which means that we need to hold on to
+ the post-landing-pad block. Prevent it from being merged away.
+ We'll remove this bit after partitioning. */
+ if (flag_reorder_blocks_and_partition)
+ e_flags |= EDGE_PRESERVE;
for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
{
- eh_region region;
basic_block bb;
rtx seq;
edge e;
@@ -943,32 +978,13 @@ dw2_build_landing_pads (void)
emit_label (lp->landing_pad);
LABEL_PRESERVE_P (lp->landing_pad) = 1;
-#ifdef HAVE_exception_receiver
- if (HAVE_exception_receiver)
- emit_insn (gen_exception_receiver ());
- else
-#endif
-#ifdef HAVE_nonlocal_goto_receiver
- if (HAVE_nonlocal_goto_receiver)
- emit_insn (gen_nonlocal_goto_receiver ());
- else
-#endif
- { /* Nothing */ }
-
- region = lp->region;
- if (region->exc_ptr_reg)
- emit_move_insn (region->exc_ptr_reg,
- gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
- if (region->filter_reg)
- emit_move_insn (region->filter_reg,
- gen_rtx_REG (targetm.eh_return_filter_mode (),
- EH_RETURN_DATA_REGNO (1)));
+ expand_dw2_landing_pad_for_region (lp->region);
seq = get_insns ();
end_sequence ();
bb = emit_to_new_bb_before (seq, label_rtx (lp->post_landing_pad));
- e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+ e = make_edge (bb, bb->next_bb, e_flags);
e->count = bb->count;
e->probability = REG_BR_PROB_BASE;
}
@@ -2388,9 +2404,6 @@ convert_to_eh_region_ranges (void)
rtx section_switch_note = NULL_RTX;
rtx first_no_action_insn_before_switch = NULL_RTX;
rtx last_no_action_insn_before_switch = NULL_RTX;
- rtx *pad_map = NULL;
- sbitmap pad_loc = NULL;
- int min_labelno = 0, max_labelno = 0;
int saved_call_site_base = call_site_base;
crtl->eh.action_record_data = VEC_alloc (uchar, gc, 64);
@@ -2523,13 +2536,7 @@ convert_to_eh_region_ranges (void)
gcc_assert (crtl->eh.call_site_record[cur_sec] == NULL);
crtl->eh.call_site_record[cur_sec]
= VEC_alloc (call_site_record, gc, 10);
- max_labelno = max_label_num ();
- min_labelno = get_first_label_num ();
- pad_map = XCNEWVEC (rtx, max_labelno - min_labelno + 1);
- pad_loc = sbitmap_alloc (max_labelno - min_labelno + 1);
}
- else if (LABEL_P (iter) && pad_map)
- SET_BIT (pad_loc, CODE_LABEL_NUMBER (iter) - min_labelno);
if (last_action >= -1 && ! first_no_action_insn)
{
@@ -2539,103 +2546,6 @@ convert_to_eh_region_ranges (void)
call_site_base = saved_call_site_base;
- if (pad_map)
- {
- /* When doing hot/cold partitioning, ensure landing pads are
- always in the same section as the EH region, .gcc_except_table
- can't express it otherwise. */
- for (cur_sec = 0; cur_sec < 2; cur_sec++)
- {
- int i, idx;
- int n = VEC_length (call_site_record,
- crtl->eh.call_site_record[cur_sec]);
- basic_block prev_bb = NULL, padbb;
-
- for (i = 0; i < n; ++i)
- {
- struct call_site_record_d *cs =
- VEC_index (call_site_record,
- crtl->eh.call_site_record[cur_sec], i);
- rtx jump, note;
-
- if (cs->landing_pad == NULL_RTX)
- continue;
- idx = CODE_LABEL_NUMBER (cs->landing_pad) - min_labelno;
- /* If the landing pad is in the correct section, nothing
- is needed. */
- if (TEST_BIT (pad_loc, idx) ^ (cur_sec == 0))
- continue;
- /* Otherwise, if we haven't seen this pad yet, we need to
- add a new label and jump to the correct section. */
- if (pad_map[idx] == NULL_RTX)
- {
- pad_map[idx] = gen_label_rtx ();
- if (prev_bb == NULL)
- for (iter = section_switch_note;
- iter; iter = PREV_INSN (iter))
- if (NOTE_INSN_BASIC_BLOCK_P (iter))
- {
- prev_bb = NOTE_BASIC_BLOCK (iter);
- break;
- }
- if (cur_sec == 0)
- {
- note = emit_label_before (pad_map[idx],
- section_switch_note);
- jump = emit_jump_insn_before (gen_jump (cs->landing_pad),
- section_switch_note);
- }
- else
- {
- jump = emit_jump_insn_after (gen_jump (cs->landing_pad),
- section_switch_note);
- note = emit_label_after (pad_map[idx],
- section_switch_note);
- }
- JUMP_LABEL (jump) = cs->landing_pad;
- add_reg_note (jump, REG_CROSSING_JUMP, NULL_RTX);
- iter = NEXT_INSN (cs->landing_pad);
- if (iter && NOTE_INSN_BASIC_BLOCK_P (iter))
- padbb = NOTE_BASIC_BLOCK (iter);
- else
- padbb = NULL;
- if (padbb && prev_bb
- && BB_PARTITION (padbb) != BB_UNPARTITIONED)
- {
- basic_block bb;
- int part
- = BB_PARTITION (padbb) == BB_COLD_PARTITION
- ? BB_HOT_PARTITION : BB_COLD_PARTITION;
- edge_iterator ei;
- edge e;
-
- bb = create_basic_block (note, jump, prev_bb);
- make_single_succ_edge (bb, padbb, EDGE_CROSSING);
- BB_SET_PARTITION (bb, part);
- for (ei = ei_start (padbb->preds);
- (e = ei_safe_edge (ei)); )
- {
- if ((e->flags & (EDGE_EH|EDGE_CROSSING))
- == (EDGE_EH|EDGE_CROSSING))
- {
- redirect_edge_succ (e, bb);
- e->flags &= ~EDGE_CROSSING;
- }
- else
- ei_next (&ei);
- }
- if (cur_sec == 0)
- prev_bb = bb;
- }
- }
- cs->landing_pad = pad_map[idx];
- }
- }
-
- sbitmap_free (pad_loc);
- XDELETEVEC (pad_map);
- }
-
htab_delete (ar_hash);
return 0;
}
diff --git a/gcc/except.h b/gcc/except.h
index 14eca870a70..5d461d7000b 100644
--- a/gcc/except.h
+++ b/gcc/except.h
@@ -253,6 +253,7 @@ extern rtx expand_builtin_dwarf_sp_column (void);
extern void expand_builtin_eh_return (tree, tree);
extern void expand_eh_return (void);
extern rtx expand_builtin_extend_pointer (tree);
+extern void expand_dw2_landing_pad_for_region (eh_region);
typedef tree (*duplicate_eh_regions_map) (tree, void *);
extern struct pointer_map_t *duplicate_eh_regions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 1e9bb56b4d6..533c28c5e06 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,34 @@
+2011-07-23 Tobias Burnus <burnus@net-b.de>
+
+ * resolve.c (resolve_symbol): Fix coarray var decl check.
+
+2011-07-21 Daniel Carrera <dcarrera@gmail.com>
+
+ * trans.c (gfc_allocate_with_status): Split into two functions
+ gfc_allocate_using_malloc and gfc_allocate_usig_lib.
+ (gfc_allocate_using_malloc): The status parameter is now the
+ actual status rather than a pointer. Code cleanup.
+ (gfc_allocate_using_lib): Ditto. Add new parametrs errmsg and
+ errlen. Pass these to the coarray lib.
+ * trans-openmp.c (gfc_omp_clause_default_ctor): Update calls to
+ gfc_allocate_allocatable.
+ (gfc_omp_clause_copy_ctor): Ditto.
+ (gfc_trans_omp_array_reduction): Ditto.
+ * trans-stmt.c (gfc_trans_allocate): Ditto. Update call to
+ gfc_allocate_using_malloc. Pass stat rather than pstat to the allocate
+ fuctions. If using coarray lib, pass errmsg and errlen to the allocate
+ functions. Move error checking outside the if (!gfc_array_allocate)
+ block so that it also affects trees produced by gfc_array_allocate.
+ * trans-array.c (gfc_array_allocate): Add new parameters errmsg
+ and errlen. Replace parameter pstat by status. Code cleanup. Update
+ calls to gfc_allocate_allocatable and gfc_allocate_using_malloc.
+ * trans-array.h (gfc_array_allocate): Update signature of
+ gfc_array_allocate.
+
+2011-07-21 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ * gfortran.texi: Remove a duplicate word.
+
2011-07-21 Tobias Burnus <burnus@net-b.de>
* check.c (gfc_check_present): Allow coarrays.
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index 4db506c5391..4858b2e39e9 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -2461,7 +2461,7 @@ in GNU Fortran; therefore, these features are not yet available.
@node GNU Fortran Compiler Directives
@section GNU Fortran Compiler Directives
-The Fortran standard standard describes how a conforming program shall
+The Fortran standard describes how a conforming program shall
behave; however, the exact implementation is not standardized. In order
to allow the user to choose specific implementation details, compiler
directives can be used to set attributes of variables and procedures
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 71e0ba062f5..e9e7bf00fab 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -12435,16 +12435,14 @@ resolve_symbol (gfc_symbol *sym)
sym->name, &sym->declared_at);
/* F2008, C526. The function-result case was handled above. */
- if (((sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.coarray_comp)
- || sym->attr.codimension)
+ if (sym->attr.codimension
&& !(sym->attr.allocatable || sym->attr.dummy || sym->attr.save
|| sym->ns->save_all
|| sym->ns->proc_name->attr.flavor == FL_MODULE
|| sym->ns->proc_name->attr.is_main_program
|| sym->attr.function || sym->attr.result || sym->attr.use_assoc))
- gfc_error ("Variable '%s' at %L is a coarray or has a coarray "
- "component and is not ALLOCATABLE, SAVE nor a "
- "dummy argument", sym->name, &sym->declared_at);
+ gfc_error ("Variable '%s' at %L is a coarray and is not ALLOCATABLE, SAVE "
+ "nor a dummy argument", sym->name, &sym->declared_at);
/* F2008, C528. */ /* FIXME: sym->as check due to PR 43412. */
else if (sym->attr.codimension && !sym->attr.allocatable
&& sym->as && sym->as->cotype == AS_DEFERRED)
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 9caa17fad04..b959b36374c 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -4383,7 +4383,8 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
/*GCC ARRAYS*/
bool
-gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat)
+gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg,
+ tree errlen)
{
tree tmp;
tree pointer;
@@ -4478,22 +4479,15 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat)
1, msg);
}
- if (pstat != NULL_TREE && !integer_zerop (pstat))
+ if (status != NULL_TREE)
{
- /* Set the status variable if it's present. */
+ tree status_type = TREE_TYPE (status);
stmtblock_t set_status_block;
- tree status_type = pstat ? TREE_TYPE (TREE_TYPE (pstat)) : NULL_TREE;
gfc_start_block (&set_status_block);
- gfc_add_modify (&set_status_block,
- fold_build1_loc (input_location, INDIRECT_REF,
- status_type, pstat),
- build_int_cst (status_type, LIBERROR_ALLOCATION));
-
- tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
- pstat, build_int_cst (TREE_TYPE (pstat), 0));
- error = fold_build3_loc (input_location, COND_EXPR, void_type_node, tmp,
- error, gfc_finish_block (&set_status_block));
+ gfc_add_modify (&set_status_block, status,
+ build_int_cst (status_type, LIBERROR_ALLOCATION));
+ error = gfc_finish_block (&set_status_block);
}
gfc_start_block (&elseblock);
@@ -4502,14 +4496,15 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat)
pointer = gfc_conv_descriptor_data_get (se->expr);
STRIP_NOPS (pointer);
- /* The allocate_array variants take the old pointer as first argument. */
+ /* The allocatable variant takes the old pointer as first argument. */
if (allocatable)
- tmp = gfc_allocate_allocatable_with_status (&elseblock,
- pointer, size, pstat, expr);
+ tmp = gfc_allocate_allocatable (&elseblock, pointer, size,
+ status, errmsg, errlen, expr);
else
- tmp = gfc_allocate_with_status (&elseblock, size, pstat, false);
- tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, pointer,
- tmp);
+ tmp = gfc_allocate_using_malloc (&elseblock, size, status);
+
+ tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
+ pointer, tmp);
gfc_add_expr_to_block (&elseblock, tmp);
diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h
index f29162e5b02..75704ad7454 100644
--- a/gcc/fortran/trans-array.h
+++ b/gcc/fortran/trans-array.h
@@ -24,7 +24,7 @@ tree gfc_array_deallocate (tree, tree, gfc_expr*);
/* Generate code to initialize an allocate an array. Statements are added to
se, which should contain an expression for the array descriptor. */
-bool gfc_array_allocate (gfc_se *, gfc_expr *, tree);
+bool gfc_array_allocate (gfc_se *, gfc_expr *, tree, tree, tree);
/* Allow the bounds of a loop to be set from a callee's array spec. */
void gfc_set_loop_bounds_from_array_spec (gfc_interface_mapping *,
diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index aff8554009c..cd5ef0a4d05 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -188,9 +188,9 @@ gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer)
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
size, esize);
size = gfc_evaluate_now (fold_convert (size_type_node, size), &cond_block);
- ptr = gfc_allocate_allocatable_with_status (&cond_block,
- build_int_cst (pvoid_type_node, 0),
- size, NULL, NULL);
+ ptr = gfc_allocate_allocatable (&cond_block,
+ build_int_cst (pvoid_type_node, 0),
+ size, NULL_TREE, NULL_TREE, NULL_TREE, NULL);
gfc_conv_descriptor_data_set (&cond_block, decl, ptr);
then_b = gfc_finish_block (&cond_block);
@@ -241,9 +241,9 @@ gfc_omp_clause_copy_ctor (tree clause, tree dest, tree src)
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
size, esize);
size = gfc_evaluate_now (fold_convert (size_type_node, size), &block);
- ptr = gfc_allocate_allocatable_with_status (&block,
- build_int_cst (pvoid_type_node, 0),
- size, NULL, NULL);
+ ptr = gfc_allocate_allocatable (&block,
+ build_int_cst (pvoid_type_node, 0),
+ size, NULL_TREE, NULL_TREE, NULL_TREE, NULL);
gfc_conv_descriptor_data_set (&block, dest, ptr);
call = build_call_expr_loc (input_location,
built_in_decls[BUILT_IN_MEMCPY], 3, ptr,
@@ -663,9 +663,9 @@ gfc_trans_omp_array_reduction (tree c, gfc_symbol *sym, locus where)
size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
size, esize);
size = gfc_evaluate_now (fold_convert (size_type_node, size), &block);
- ptr = gfc_allocate_allocatable_with_status (&block,
- build_int_cst (pvoid_type_node, 0),
- size, NULL, NULL);
+ ptr = gfc_allocate_allocatable (&block,
+ build_int_cst (pvoid_type_node, 0),
+ size, NULL_TREE, NULL_TREE, NULL_TREE, NULL);
gfc_conv_descriptor_data_set (&block, decl, ptr);
gfc_add_expr_to_block (&block, gfc_trans_assignment (e1, e2, false,
false));
diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index 1da3a067ea5..75d72a285e0 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -4686,8 +4686,10 @@ gfc_trans_allocate (gfc_code * code)
tree tmp;
tree parm;
tree stat;
- tree pstat;
- tree error_label;
+ tree errmsg;
+ tree errlen;
+ tree label_errmsg;
+ tree label_finish;
tree memsz;
tree expr3;
tree slen3;
@@ -4699,21 +4701,39 @@ gfc_trans_allocate (gfc_code * code)
if (!code->ext.alloc.list)
return NULL_TREE;
- pstat = stat = error_label = tmp = memsz = NULL_TREE;
+ stat = tmp = memsz = NULL_TREE;
+ label_errmsg = label_finish = errmsg = errlen = NULL_TREE;
gfc_init_block (&block);
gfc_init_block (&post);
- /* Either STAT= and/or ERRMSG is present. */
- if (code->expr1 || code->expr2)
+ /* STAT= (and maybe ERRMSG=) is present. */
+ if (code->expr1)
{
+ /* STAT=. */
tree gfc_int4_type_node = gfc_get_int_type (4);
-
stat = gfc_create_var (gfc_int4_type_node, "stat");
- pstat = gfc_build_addr_expr (NULL_TREE, stat);
- error_label = gfc_build_label_decl (NULL_TREE);
- TREE_USED (error_label) = 1;
+ /* ERRMSG= only makes sense with STAT=. */
+ if (code->expr2)
+ {
+ gfc_init_se (&se, NULL);
+ gfc_conv_expr_lhs (&se, code->expr2);
+
+ errlen = gfc_get_expr_charlen (code->expr2);
+ errmsg = gfc_build_addr_expr (pchar_type_node, se.expr);
+ }
+ else
+ {
+ errmsg = null_pointer_node;
+ errlen = build_int_cst (gfc_charlen_type_node, 0);
+ }
+
+ /* GOTO destinations. */
+ label_errmsg = gfc_build_label_decl (NULL_TREE);
+ label_finish = gfc_build_label_decl (NULL_TREE);
+ TREE_USED (label_errmsg) = 1;
+ TREE_USED (label_finish) = 1;
}
expr3 = NULL_TREE;
@@ -4732,7 +4752,7 @@ gfc_trans_allocate (gfc_code * code)
se.descriptor_only = 1;
gfc_conv_expr (&se, expr);
- if (!gfc_array_allocate (&se, expr, pstat))
+ if (!gfc_array_allocate (&se, expr, stat, errmsg, errlen))
{
/* A scalar or derived type. */
@@ -4847,28 +4867,16 @@ gfc_trans_allocate (gfc_code * code)
/* Allocate - for non-pointers with re-alloc checking. */
if (gfc_expr_attr (expr).allocatable)
- tmp = gfc_allocate_allocatable_with_status (&se.pre, se.expr, memsz,
- pstat, expr);
+ tmp = gfc_allocate_allocatable (&se.pre, se.expr, memsz,
+ stat, errmsg, errlen, expr);
else
- tmp = gfc_allocate_with_status (&se.pre, memsz, pstat, false);
+ tmp = gfc_allocate_using_malloc (&se.pre, memsz, stat);
tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
se.expr,
fold_convert (TREE_TYPE (se.expr), tmp));
gfc_add_expr_to_block (&se.pre, tmp);
- if (code->expr1 || code->expr2)
- {
- tmp = build1_v (GOTO_EXPR, error_label);
- parm = fold_build2_loc (input_location, NE_EXPR,
- boolean_type_node, stat,
- build_int_cst (TREE_TYPE (stat), 0));
- tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
- parm, tmp,
- build_empty_stmt (input_location));
- gfc_add_expr_to_block (&se.pre, tmp);
- }
-
if (expr->ts.type == BT_DERIVED && expr->ts.u.derived->attr.alloc_comp)
{
tmp = build_fold_indirect_ref_loc (input_location, se.expr);
@@ -4879,6 +4887,25 @@ gfc_trans_allocate (gfc_code * code)
gfc_add_block_to_block (&block, &se.pre);
+ /* Error checking -- Note: ERRMSG only makes sense with STAT. */
+ if (code->expr1)
+ {
+ /* The coarray library already sets the errmsg. */
+ if (gfc_option.coarray == GFC_FCOARRAY_LIB
+ && gfc_expr_attr (expr).codimension)
+ tmp = build1_v (GOTO_EXPR, label_finish);
+ else
+ tmp = build1_v (GOTO_EXPR, label_errmsg);
+
+ parm = fold_build2_loc (input_location, NE_EXPR,
+ boolean_type_node, stat,
+ build_int_cst (TREE_TYPE (stat), 0));
+ tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
+ parm, tmp,
+ build_empty_stmt (input_location));
+ gfc_add_expr_to_block (&block, tmp);
+ }
+
if (code->expr3 && !code->expr3->mold)
{
/* Initialization via SOURCE block
@@ -5005,16 +5032,11 @@ gfc_trans_allocate (gfc_code * code)
}
- /* STAT block. */
+ /* STAT (ERRMSG only makes sense with STAT). */
if (code->expr1)
{
- tmp = build1_v (LABEL_EXPR, error_label);
+ tmp = build1_v (LABEL_EXPR, label_errmsg);
gfc_add_expr_to_block (&block, tmp);
-
- gfc_init_se (&se, NULL);
- gfc_conv_expr_lhs (&se, code->expr1);
- tmp = convert (TREE_TYPE (se.expr), stat);
- gfc_add_modify (&block, se.expr, tmp);
}
/* ERRMSG block. */
@@ -5022,7 +5044,7 @@ gfc_trans_allocate (gfc_code * code)
{
/* A better error message may be possible, but not required. */
const char *msg = "Attempt to allocate an allocated object";
- tree errmsg, slen, dlen;
+ tree slen, dlen;
gfc_init_se (&se, NULL);
gfc_conv_expr_lhs (&se, code->expr2);
@@ -5050,6 +5072,22 @@ gfc_trans_allocate (gfc_code * code)
gfc_add_expr_to_block (&block, tmp);
}
+ /* STAT (ERRMSG only makes sense with STAT). */
+ if (code->expr1)
+ {
+ tmp = build1_v (LABEL_EXPR, label_finish);
+ gfc_add_expr_to_block (&block, tmp);
+ }
+
+ /* STAT block. */
+ if (code->expr1)
+ {
+ gfc_init_se (&se, NULL);
+ gfc_conv_expr_lhs (&se, code->expr1);
+ tmp = convert (TREE_TYPE (se.expr), stat);
+ gfc_add_modify (&block, se.expr, tmp);
+ }
+
gfc_add_block_to_block (&block, &se.post);
gfc_add_block_to_block (&block, &post);
diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c
index 578f2258247..83fabe2fb2c 100644
--- a/gcc/fortran/trans.c
+++ b/gcc/fortran/trans.c
@@ -565,12 +565,12 @@ gfc_call_malloc (stmtblock_t * block, tree type, tree size)
This function follows the following pseudo-code:
void *
- allocate (size_t size, integer_type* stat)
+ allocate (size_t size, integer_type stat)
{
void *newmem;
- if (stat)
- *stat = 0;
+ if (stat requested)
+ stat = 0;
newmem = malloc (MAX (size, 1));
if (newmem == NULL)
@@ -583,12 +583,11 @@ gfc_call_malloc (stmtblock_t * block, tree type, tree size)
return newmem;
} */
tree
-gfc_allocate_with_status (stmtblock_t * block, tree size, tree status,
- bool coarray_lib)
+gfc_allocate_using_malloc (stmtblock_t * block, tree size, tree status)
{
stmtblock_t alloc_block;
- tree res, tmp, msg, cond;
- tree status_type = status ? TREE_TYPE (TREE_TYPE (status)) : NULL_TREE;
+ tree res, tmp, on_error;
+ tree status_type = status ? TREE_TYPE (status) : NULL_TREE;
/* Evaluate size only once, and make sure it has the right type. */
size = gfc_evaluate_now (size, block);
@@ -599,74 +598,37 @@ gfc_allocate_with_status (stmtblock_t * block, tree size, tree status,
res = gfc_create_var (prvoid_type_node, NULL);
/* Set the optional status variable to zero. */
- if (status != NULL_TREE && !integer_zerop (status))
- {
- tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type,
- fold_build1_loc (input_location, INDIRECT_REF,
- status_type, status),
- build_int_cst (status_type, 0));
- tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
- fold_build2_loc (input_location, NE_EXPR,
- boolean_type_node, status,
- build_int_cst (TREE_TYPE (status), 0)),
- tmp, build_empty_stmt (input_location));
- gfc_add_expr_to_block (block, tmp);
- }
+ if (status != NULL_TREE)
+ gfc_add_expr_to_block (block,
+ fold_build2_loc (input_location, MODIFY_EXPR, status_type,
+ status, build_int_cst (status_type, 0)));
/* The allocation itself. */
gfc_start_block (&alloc_block);
- if (coarray_lib)
- {
- gfc_add_modify (&alloc_block, res,
- fold_convert (prvoid_type_node,
- build_call_expr_loc (input_location,
- gfor_fndecl_caf_register, 6,
- fold_build2_loc (input_location,
- MAX_EXPR, size_type_node, size,
- build_int_cst (size_type_node, 1)),
- build_int_cst (integer_type_node,
- GFC_CAF_COARRAY_ALLOC),
- null_pointer_node, /* token */
- null_pointer_node, /* stat */
- null_pointer_node, /* errmsg, errmsg_len */
- build_int_cst (integer_type_node, 0))));
- }
+ gfc_add_modify (&alloc_block, res,
+ fold_convert (prvoid_type_node,
+ build_call_expr_loc (input_location,
+ built_in_decls[BUILT_IN_MALLOC], 1,
+ fold_build2_loc (input_location,
+ MAX_EXPR, size_type_node, size,
+ build_int_cst (size_type_node, 1)))));
+
+ /* What to do in case of error. */
+ if (status != NULL_TREE)
+ on_error = fold_build2_loc (input_location, MODIFY_EXPR, status_type,
+ status, build_int_cst (status_type, LIBERROR_ALLOCATION));
else
- {
- gfc_add_modify (&alloc_block, res,
- fold_convert (prvoid_type_node,
- build_call_expr_loc (input_location,
- built_in_decls[BUILT_IN_MALLOC], 1,
- fold_build2_loc (input_location,
- MAX_EXPR, size_type_node, size,
- build_int_cst (size_type_node, 1)))));
- }
-
- msg = gfc_build_addr_expr (pchar_type_node, gfc_build_localized_cstring_const
- ("Allocation would exceed memory limit"));
- tmp = build_call_expr_loc (input_location,
- gfor_fndecl_os_error, 1, msg);
-
- if (status != NULL_TREE && !integer_zerop (status))
- {
- /* Set the status variable if it's present. */
- tree tmp2;
-
- cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
- status, build_int_cst (TREE_TYPE (status), 0));
- tmp2 = fold_build2_loc (input_location, MODIFY_EXPR, status_type,
- fold_build1_loc (input_location, INDIRECT_REF,
- status_type, status),
- build_int_cst (status_type, LIBERROR_ALLOCATION));
- tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
- tmp, tmp2);
- }
+ on_error = build_call_expr_loc (input_location, gfor_fndecl_os_error, 1,
+ gfc_build_addr_expr (pchar_type_node,
+ gfc_build_localized_cstring_const
+ ("Allocation would exceed memory limit")));
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
fold_build2_loc (input_location, EQ_EXPR,
boolean_type_node, res,
build_int_cst (prvoid_type_node, 0)),
- tmp, build_empty_stmt (input_location));
+ on_error, build_empty_stmt (input_location));
+
gfc_add_expr_to_block (&alloc_block, tmp);
gfc_add_expr_to_block (block, gfc_finish_block (&alloc_block));
@@ -674,6 +636,61 @@ gfc_allocate_with_status (stmtblock_t * block, tree size, tree status,
}
+/* Allocate memory, using an optional status argument.
+
+ This function follows the following pseudo-code:
+
+ void *
+ allocate (size_t size, integer_type stat)
+ {
+ void *newmem;
+
+ newmem = _caf_register ( size, regtype, NULL, &stat, NULL, NULL);
+ return newmem;
+ } */
+tree
+gfc_allocate_using_lib (stmtblock_t * block, tree size, tree status,
+ tree errmsg, tree errlen)
+{
+ tree res, pstat;
+
+ /* Evaluate size only once, and make sure it has the right type. */
+ size = gfc_evaluate_now (size, block);
+ if (TREE_TYPE (size) != TREE_TYPE (size_type_node))
+ size = fold_convert (size_type_node, size);
+
+ /* Create a variable to hold the result. */
+ res = gfc_create_var (prvoid_type_node, NULL);
+
+ /* The allocation itself. */
+ if (status == NULL_TREE)
+ pstat = null_pointer_node;
+ else
+ pstat = gfc_build_addr_expr (NULL_TREE, status);
+
+ if (errmsg == NULL_TREE)
+ {
+ gcc_assert(errlen == NULL_TREE);
+ errmsg = null_pointer_node;
+ errlen = build_int_cst (integer_type_node, 0);
+ }
+
+ gfc_add_modify (block, res,
+ fold_convert (prvoid_type_node,
+ build_call_expr_loc (input_location,
+ gfor_fndecl_caf_register, 6,
+ fold_build2_loc (input_location,
+ MAX_EXPR, size_type_node, size,
+ build_int_cst (size_type_node, 1)),
+ build_int_cst (integer_type_node,
+ GFC_CAF_COARRAY_ALLOC),
+ null_pointer_node, /* token */
+ pstat, errmsg, errlen)));
+
+ return res;
+}
+
+
/* Generate code for an ALLOCATE statement when the argument is an
allocatable variable. If the variable is currently allocated, it is an
error to allocate it again.
@@ -681,7 +698,7 @@ gfc_allocate_with_status (stmtblock_t * block, tree size, tree status,
This function follows the following pseudo-code:
void *
- allocate_allocatable (void *mem, size_t size, integer_type *stat)
+ allocate_allocatable (void *mem, size_t size, integer_type stat)
{
if (mem == NULL)
return allocate (size, stat);
@@ -691,7 +708,7 @@ gfc_allocate_with_status (stmtblock_t * block, tree size, tree status,
{
free (mem);
mem = allocate (size, stat);
- *stat = LIBERROR_ALLOCATION;
+ stat = LIBERROR_ALLOCATION;
return mem;
}
else
@@ -702,8 +719,8 @@ gfc_allocate_with_status (stmtblock_t * block, tree size, tree status,
expr must be set to the original expression being allocated for its locus
and variable name in case a runtime error has to be printed. */
tree
-gfc_allocate_allocatable_with_status (stmtblock_t * block, tree mem, tree size,
- tree status, gfc_expr* expr)
+gfc_allocate_allocatable (stmtblock_t * block, tree mem, tree size, tree status,
+ tree errmsg, tree errlen, gfc_expr* expr)
{
stmtblock_t alloc_block;
tree res, tmp, null_mem, alloc, error;
@@ -718,11 +735,16 @@ gfc_allocate_allocatable_with_status (stmtblock_t * block, tree mem, tree size,
boolean_type_node, mem,
build_int_cst (type, 0)));
- /* If mem is NULL, we call gfc_allocate_with_status. */
+ /* If mem is NULL, we call gfc_allocate_using_malloc or
+ gfc_allocate_using_lib. */
gfc_start_block (&alloc_block);
- tmp = gfc_allocate_with_status (&alloc_block, size, status,
- gfc_option.coarray == GFC_FCOARRAY_LIB
- && gfc_expr_attr (expr).codimension);
+
+ if (gfc_option.coarray == GFC_FCOARRAY_LIB
+ && gfc_expr_attr (expr).codimension)
+ tmp = gfc_allocate_using_lib (&alloc_block, size, status,
+ errmsg, errlen);
+ else
+ tmp = gfc_allocate_using_malloc (&alloc_block, size, status);
gfc_add_modify (&alloc_block, res, fold_convert (type, tmp));
alloc = gfc_finish_block (&alloc_block);
@@ -747,9 +769,9 @@ gfc_allocate_allocatable_with_status (stmtblock_t * block, tree mem, tree size,
"Attempting to allocate already allocated"
" variable");
- if (status != NULL_TREE && !integer_zerop (status))
+ if (status != NULL_TREE)
{
- tree status_type = TREE_TYPE (TREE_TYPE (status));
+ tree status_type = TREE_TYPE (status);
stmtblock_t set_status_block;
gfc_start_block (&set_status_block);
@@ -758,18 +780,12 @@ gfc_allocate_allocatable_with_status (stmtblock_t * block, tree mem, tree size,
fold_convert (pvoid_type_node, mem));
gfc_add_expr_to_block (&set_status_block, tmp);
- tmp = gfc_allocate_with_status (&set_status_block, size, status, false);
+ tmp = gfc_allocate_using_malloc (&set_status_block, size, status);
gfc_add_modify (&set_status_block, res, fold_convert (type, tmp));
- gfc_add_modify (&set_status_block,
- fold_build1_loc (input_location, INDIRECT_REF,
- status_type, status),
- build_int_cst (status_type, LIBERROR_ALLOCATION));
-
- tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
- status, build_int_cst (status_type, 0));
- error = fold_build3_loc (input_location, COND_EXPR, void_type_node, tmp,
- error, gfc_finish_block (&set_status_block));
+ gfc_add_modify (&set_status_block, status,
+ build_int_cst (status_type, LIBERROR_ALLOCATION));
+ error = gfc_finish_block (&set_status_block);
}
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, null_mem,
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 48e054f2342..73e2fa01e89 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -541,11 +541,12 @@ tree gfc_call_malloc (stmtblock_t *, tree, tree);
tree gfc_build_memcpy_call (tree, tree, tree);
/* Allocate memory for allocatable variables, with optional status variable. */
-tree gfc_allocate_allocatable_with_status (stmtblock_t*,
- tree, tree, tree, gfc_expr*);
+tree gfc_allocate_allocatable (stmtblock_t*, tree, tree,
+ tree, tree, tree, gfc_expr*);
/* Allocate memory, with optional status variable. */
-tree gfc_allocate_with_status (stmtblock_t *, tree, tree, bool);
+tree gfc_allocate_using_malloc (stmtblock_t *, tree, tree);
+tree gfc_allocate_using_lib (stmtblock_t *, tree, tree, tree, tree);
/* Generate code to deallocate an array. */
tree gfc_deallocate_with_status (tree, tree, bool, gfc_expr*);
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 5e5d3c2b81e..fc0cb1b6d75 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -6156,6 +6156,10 @@ main (int argc, char **argv)
signal (SIGCHLD, SIG_DFL);
#endif
+ /* Parsing and gimplification sometimes need quite large stack.
+ Increase stack size limits if possible. */
+ stack_limit_increase (64 * 1024 * 1024);
+
/* Allocate the argument vector. */
alloc_args ();
diff --git a/gcc/graphite-clast-to-gimple.c b/gcc/graphite-clast-to-gimple.c
index 6b17631e408..ee6702012a1 100644
--- a/gcc/graphite-clast-to-gimple.c
+++ b/gcc/graphite-clast-to-gimple.c
@@ -1,5 +1,5 @@
/* Translation of CLAST (CLooG AST) to Gimple.
- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
Contributed by Sebastian Pop <sebastian.pop@amd.com>.
This file is part of GCC.
@@ -40,6 +40,10 @@ along with GCC; see the file COPYING3. If not see
#include "graphite-dependences.h"
#include "graphite-cloog-compat.h"
+#ifndef CLOOG_LANGUAGE_C
+#define CLOOG_LANGUAGE_C LANGUAGE_C
+#endif
+
/* This flag is set when an error occurred during the translation of
CLAST to Gimple. */
static bool gloog_error;
@@ -56,26 +60,73 @@ graphite_verify (void)
#endif
}
-/* Stores the INDEX in a vector for a given clast NAME. */
+/* Stores the INDEX in a vector and the loop nesting LEVEL for a given
+ clast NAME. LB and UB represent the exact lower and upper bounds
+ that can be inferred from the polyhedral representation. */
typedef struct clast_name_index {
int index;
+ int level;
+ mpz_t lb, ub;
const char *name;
} *clast_name_index_p;
/* Returns a pointer to a new element of type clast_name_index_p built
- from NAME and INDEX. */
+ from NAME, INDEX, LEVEL, LB, and UB. */
static inline clast_name_index_p
-new_clast_name_index (const char *name, int index)
+new_clast_name_index (const char *name, int index, int level,
+ mpz_t lb, mpz_t ub)
{
clast_name_index_p res = XNEW (struct clast_name_index);
res->name = name;
+ res->level = level;
res->index = index;
+ mpz_init (res->lb);
+ mpz_init (res->ub);
+ mpz_set (res->lb, lb);
+ mpz_set (res->ub, ub);
return res;
}
+/* Free the memory taken by a clast_name_index struct. */
+
+static void
+free_clast_name_index (void *ptr)
+{
+ struct clast_name_index *c = (struct clast_name_index *) ptr;
+ mpz_clear (c->lb);
+ mpz_clear (c->ub);
+ free (ptr);
+}
+
+/* For a given clast NAME, returns -1 if NAME is not in the
+ INDEX_TABLE, otherwise returns the loop level for the induction
+ variable NAME, or if it is a parameter, the parameter number in the
+ vector of parameters. */
+
+static inline int
+clast_name_to_level (clast_name_p name, htab_t index_table)
+{
+ struct clast_name_index tmp;
+ PTR *slot;
+
+#ifdef CLOOG_ORG
+ gcc_assert (name->type == clast_expr_name);
+ tmp.name = ((const struct clast_name *) name)->name;
+#else
+ tmp.name = name;
+#endif
+
+ slot = htab_find_slot (index_table, &tmp, NO_INSERT);
+
+ if (slot && *slot)
+ return ((struct clast_name_index *) *slot)->level;
+
+ return -1;
+}
+
/* For a given clast NAME, returns -1 if it does not correspond to any
parameter, or otherwise, returns the index in the PARAMS or
SCATTERING_DIMENSIONS vector. */
@@ -101,10 +152,40 @@ clast_name_to_index (clast_name_p name, htab_t index_table)
return -1;
}
-/* Records in INDEX_TABLE the INDEX for NAME. */
+/* For a given clast NAME, initializes the lower and upper bounds LB
+ and UB stored in the INDEX_TABLE. Returns true when NAME has been
+ found in the INDEX_TABLE, false otherwise. */
+
+static inline bool
+clast_name_to_lb_ub (clast_name_p name, htab_t index_table, mpz_t lb, mpz_t ub)
+{
+ struct clast_name_index tmp;
+ PTR *slot;
+
+#ifdef CLOOG_ORG
+ gcc_assert (name->type == clast_expr_name);
+ tmp.name = ((const struct clast_name *) name)->name;
+#else
+ tmp.name = name;
+#endif
+
+ slot = htab_find_slot (index_table, &tmp, NO_INSERT);
+
+ if (slot && *slot)
+ {
+ mpz_set (lb, ((struct clast_name_index *) *slot)->lb);
+ mpz_set (ub, ((struct clast_name_index *) *slot)->ub);
+ return true;
+ }
+
+ return false;
+}
+
+/* Records in INDEX_TABLE the INDEX and LEVEL for NAME. */
static inline void
-save_clast_name_index (htab_t index_table, const char *name, int index)
+save_clast_name_index (htab_t index_table, const char *name,
+ int index, int level, mpz_t lb, mpz_t ub)
{
struct clast_name_index tmp;
PTR *slot;
@@ -116,7 +197,7 @@ save_clast_name_index (htab_t index_table, const char *name, int index)
{
free (*slot);
- *slot = new_clast_name_index (name, index);
+ *slot = new_clast_name_index (name, index, level, lb, ub);
}
}
@@ -139,52 +220,64 @@ eq_clast_name_indexes (const void *e1, const void *e2)
return (elt1->name == elt2->name);
}
-/* For a given scattering dimension, return the new induction variable
- associated to it. */
+
-static inline tree
-newivs_to_depth_to_newiv (VEC (tree, heap) *newivs, int depth)
-{
- return VEC_index (tree, newivs, depth);
-}
+/* NEWIVS_INDEX binds CLooG's scattering name to the index of the tree
+ induction variable in NEWIVS.
-
+ PARAMS_INDEX binds CLooG's parameter name to the index of the tree
+ parameter in PARAMS. */
+
+typedef struct ivs_params {
+ VEC (tree, heap) *params, **newivs;
+ htab_t newivs_index, params_index;
+ sese region;
+} *ivs_params_p;
/* Returns the tree variable from the name NAME that was given in
Cloog representation. */
static tree
-clast_name_to_gcc (clast_name_p name, sese region, VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+clast_name_to_gcc (clast_name_p name, ivs_params_p ip)
{
int index;
- VEC (tree, heap) *params = SESE_PARAMS (region);
- if (params && params_index)
+ if (ip->params && ip->params_index)
{
- index = clast_name_to_index (name, params_index);
+ index = clast_name_to_index (name, ip->params_index);
if (index >= 0)
- return VEC_index (tree, params, index);
+ return VEC_index (tree, ip->params, index);
}
- gcc_assert (newivs && newivs_index);
- index = clast_name_to_index (name, newivs_index);
+ gcc_assert (*(ip->newivs) && ip->newivs_index);
+ index = clast_name_to_index (name, ip->newivs_index);
gcc_assert (index >= 0);
- return newivs_to_depth_to_newiv (newivs, index);
+ return VEC_index (tree, *(ip->newivs), index);
}
-/* Returns the signed maximal precision type for expressions TYPE1 and TYPE2. */
+/* Returns the maximal precision type for expressions TYPE1 and TYPE2. */
static tree
-max_signed_precision_type (tree type1, tree type2)
+max_precision_type (tree type1, tree type2)
{
- int p1 = TYPE_PRECISION (type1);
- int p2 = TYPE_PRECISION (type2);
- int precision;
- tree type;
enum machine_mode mode;
+ int p1, p2, precision;
+ tree type;
+
+ if (POINTER_TYPE_P (type1))
+ return type1;
+
+ if (POINTER_TYPE_P (type2))
+ return type2;
+
+ if (TYPE_UNSIGNED (type1)
+ && TYPE_UNSIGNED (type2))
+ return TYPE_PRECISION (type1) > TYPE_PRECISION (type2) ? type1 : type2;
+
+ p1 = TYPE_PRECISION (type1);
+ p2 = TYPE_PRECISION (type2);
if (p1 > p2)
precision = TYPE_UNSIGNED (type1) ? p1 * 2 : p1;
@@ -210,46 +303,23 @@ max_signed_precision_type (tree type1, tree type2)
return type;
}
-/* Returns the maximal precision type for expressions TYPE1 and TYPE2. */
-
static tree
-max_precision_type (tree type1, tree type2)
-{
- if (POINTER_TYPE_P (type1))
- return type1;
-
- if (POINTER_TYPE_P (type2))
- return type2;
-
- if (!TYPE_UNSIGNED (type1)
- || !TYPE_UNSIGNED (type2))
- return max_signed_precision_type (type1, type2);
-
- return TYPE_PRECISION (type1) > TYPE_PRECISION (type2) ? type1 : type2;
-}
-
-static tree
-clast_to_gcc_expression (tree, struct clast_expr *, sese, VEC (tree, heap) *,
- htab_t, htab_t);
+clast_to_gcc_expression (tree, struct clast_expr *, ivs_params_p);
/* Converts a Cloog reduction expression R with reduction operation OP
to a GCC expression tree of type TYPE. */
static tree
clast_to_gcc_expression_red (tree type, enum tree_code op,
- struct clast_reduction *r,
- sese region, VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+ struct clast_reduction *r, ivs_params_p ip)
{
int i;
- tree res = clast_to_gcc_expression (type, r->elts[0], region, newivs,
- newivs_index, params_index);
+ tree res = clast_to_gcc_expression (type, r->elts[0], ip);
tree operand_type = (op == POINTER_PLUS_EXPR) ? sizetype : type;
for (i = 1; i < r->n; i++)
{
- tree t = clast_to_gcc_expression (operand_type, r->elts[i], region,
- newivs, newivs_index, params_index);
+ tree t = clast_to_gcc_expression (operand_type, r->elts[i], ip);
res = fold_build2 (op, type, res, t);
}
@@ -260,9 +330,7 @@ clast_to_gcc_expression_red (tree type, enum tree_code op,
type TYPE. */
static tree
-clast_to_gcc_expression (tree type, struct clast_expr *e,
- sese region, VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+clast_to_gcc_expression (tree type, struct clast_expr *e, ivs_params_p ip)
{
switch (e->type)
{
@@ -274,8 +342,7 @@ clast_to_gcc_expression (tree type, struct clast_expr *e,
{
if (mpz_cmp_si (t->val, 1) == 0)
{
- tree name = clast_name_to_gcc (t->var, region, newivs,
- newivs_index, params_index);
+ tree name = clast_name_to_gcc (t->var, ip);
if (POINTER_TYPE_P (TREE_TYPE (name)) != POINTER_TYPE_P (type))
name = fold_convert (sizetype, name);
@@ -286,8 +353,7 @@ clast_to_gcc_expression (tree type, struct clast_expr *e,
else if (mpz_cmp_si (t->val, -1) == 0)
{
- tree name = clast_name_to_gcc (t->var, region, newivs,
- newivs_index, params_index);
+ tree name = clast_name_to_gcc (t->var, ip);
if (POINTER_TYPE_P (TREE_TYPE (name)) != POINTER_TYPE_P (type))
name = fold_convert (sizetype, name);
@@ -298,8 +364,7 @@ clast_to_gcc_expression (tree type, struct clast_expr *e,
}
else
{
- tree name = clast_name_to_gcc (t->var, region, newivs,
- newivs_index, params_index);
+ tree name = clast_name_to_gcc (t->var, ip);
tree cst = gmp_cst_to_tree (type, t->val);
if (POINTER_TYPE_P (TREE_TYPE (name)) != POINTER_TYPE_P (type))
@@ -327,17 +392,13 @@ clast_to_gcc_expression (tree type, struct clast_expr *e,
case clast_red_sum:
return clast_to_gcc_expression_red
(type, POINTER_TYPE_P (type) ? POINTER_PLUS_EXPR : PLUS_EXPR,
- r, region, newivs, newivs_index, params_index);
+ r, ip);
case clast_red_min:
- return clast_to_gcc_expression_red (type, MIN_EXPR, r, region,
- newivs, newivs_index,
- params_index);
+ return clast_to_gcc_expression_red (type, MIN_EXPR, r, ip);
case clast_red_max:
- return clast_to_gcc_expression_red (type, MAX_EXPR, r, region,
- newivs, newivs_index,
- params_index);
+ return clast_to_gcc_expression_red (type, MAX_EXPR, r, ip);
default:
gcc_unreachable ();
@@ -349,8 +410,7 @@ clast_to_gcc_expression (tree type, struct clast_expr *e,
{
struct clast_binary *b = (struct clast_binary *) e;
struct clast_expr *lhs = (struct clast_expr *) b->LHS;
- tree tl = clast_to_gcc_expression (type, lhs, region, newivs,
- newivs_index, params_index);
+ tree tl = clast_to_gcc_expression (type, lhs, ip);
tree tr = gmp_cst_to_tree (type, b->RHS);
switch (b->type)
@@ -382,11 +442,12 @@ clast_to_gcc_expression (tree type, struct clast_expr *e,
/* Return a type that could represent the values between V1 and V2. */
static tree
-gcc_type_for_interval (mpz_t v1, mpz_t v2)
+type_for_interval (mpz_t v1, mpz_t v2)
{
bool unsigned_p;
tree type;
enum machine_mode mode;
+ int wider_precision;
int precision = MAX (mpz_sizeinbase (v1, 2),
mpz_sizeinbase (v2, 2));
@@ -402,8 +463,16 @@ gcc_type_for_interval (mpz_t v1, mpz_t v2)
unsigned_p = (mpz_sgn (v2) >= 0);
mode = smallest_mode_for_size (precision, MODE_INT);
- precision = GET_MODE_PRECISION (mode);
- type = build_nonstandard_integer_type (precision, unsigned_p);
+ wider_precision = GET_MODE_PRECISION (mode);
+
+ /* As we want to generate signed types as much as possible, try to
+ fit the interval [v1, v2] in a signed type. For example,
+ supposing that we have the interval [0, 100], instead of
+ generating unsigned char, we want to generate a signed char. */
+ if (unsigned_p && precision < wider_precision)
+ unsigned_p = false;
+
+ type = build_nonstandard_integer_type (wider_precision, unsigned_p);
if (!type)
{
@@ -418,101 +487,169 @@ gcc_type_for_interval (mpz_t v1, mpz_t v2)
otherwise return NULL_TREE. */
static tree
-gcc_type_for_value (mpz_t val)
+type_for_value (mpz_t val)
{
- return gcc_type_for_interval (val, val);
+ return type_for_interval (val, val);
}
-/* Return the type for the clast_term T used in STMT. */
+/* Return the type for the clast_term T. Initializes V1 and V2 to the
+ bounds of the term. */
static tree
-gcc_type_for_clast_term (struct clast_term *t,
- sese region, VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+type_for_clast_term (struct clast_term *t, ivs_params_p ip, mpz_t v1, mpz_t v2)
{
+ clast_name_p name = t->var;
+ bool found = false;
+
gcc_assert (t->expr.type == clast_expr_term);
- if (!t->var)
- return gcc_type_for_value (t->val);
+ if (!name)
+ {
+ mpz_set (v1, t->val);
+ mpz_set (v2, t->val);
+ return type_for_value (t->val);
+ }
+
+ if (ip->params && ip->params_index)
+ found = clast_name_to_lb_ub (name, ip->params_index, v1, v2);
+
+ if (!found)
+ {
+ gcc_assert (*(ip->newivs) && ip->newivs_index);
+ found = clast_name_to_lb_ub (name, ip->newivs_index, v1, v2);
+ gcc_assert (found);
+ }
+
+ mpz_mul (v1, v1, t->val);
+ mpz_mul (v2, v2, t->val);
- return TREE_TYPE (clast_name_to_gcc (t->var, region, newivs,
- newivs_index, params_index));
+ return TREE_TYPE (clast_name_to_gcc (name, ip));
}
static tree
-gcc_type_for_clast_expr (struct clast_expr *, sese,
- VEC (tree, heap) *, htab_t, htab_t);
+type_for_clast_expr (struct clast_expr *, ivs_params_p, mpz_t, mpz_t);
-/* Return the type for the clast_reduction R used in STMT. */
+/* Return the type for the clast_reduction R. Initializes V1 and V2
+ to the bounds of the reduction expression. */
static tree
-gcc_type_for_clast_red (struct clast_reduction *r, sese region,
- VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+type_for_clast_red (struct clast_reduction *r, ivs_params_p ip,
+ mpz_t v1, mpz_t v2)
{
int i;
- tree type = NULL_TREE;
+ tree type = type_for_clast_expr (r->elts[0], ip, v1, v2);
+ mpz_t b1, b2, m1, m2;
if (r->n == 1)
- return gcc_type_for_clast_expr (r->elts[0], region, newivs,
- newivs_index, params_index);
+ return type;
- switch (r->type)
- {
- case clast_red_sum:
- case clast_red_min:
- case clast_red_max:
- type = gcc_type_for_clast_expr (r->elts[0], region, newivs,
- newivs_index, params_index);
- for (i = 1; i < r->n; i++)
- type = max_precision_type (type, gcc_type_for_clast_expr
- (r->elts[i], region, newivs,
- newivs_index, params_index));
-
- return type;
+ mpz_init (b1);
+ mpz_init (b2);
+ mpz_init (m1);
+ mpz_init (m2);
- default:
- break;
+ for (i = 1; i < r->n; i++)
+ {
+ tree t = type_for_clast_expr (r->elts[i], ip, b1, b2);
+ type = max_precision_type (type, t);
+
+ switch (r->type)
+ {
+ case clast_red_sum:
+ value_min (m1, v1, v2);
+ value_min (m2, b1, b2);
+ mpz_add (v1, m1, m2);
+
+ value_max (m1, v1, v2);
+ value_max (m2, b1, b2);
+ mpz_add (v2, m1, m2);
+ break;
+
+ case clast_red_min:
+ value_min (v1, v1, v2);
+ value_min (v2, b1, b2);
+ break;
+
+ case clast_red_max:
+ value_max (v1, v1, v2);
+ value_max (v2, b1, b2);
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
}
- gcc_unreachable ();
- return NULL_TREE;
+ mpz_clear (b1);
+ mpz_clear (b2);
+ mpz_clear (m1);
+ mpz_clear (m2);
+
+ /* Return a type that can represent the result of the reduction. */
+ return max_precision_type (type, type_for_interval (v1, v2));
}
/* Return the type for the clast_binary B used in STMT. */
static tree
-gcc_type_for_clast_bin (struct clast_binary *b,
- sese region, VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+type_for_clast_bin (struct clast_binary *b, ivs_params_p ip, mpz_t v1, mpz_t v2)
{
- tree l = gcc_type_for_clast_expr ((struct clast_expr *) b->LHS, region,
- newivs, newivs_index, params_index);
- tree r = gcc_type_for_value (b->RHS);
- return max_signed_precision_type (l, r);
+ mpz_t one;
+ tree l = type_for_clast_expr ((struct clast_expr *) b->LHS, ip, v1, v2);
+ tree r = type_for_value (b->RHS);
+ tree type = max_precision_type (l, r);
+
+ switch (b->type)
+ {
+ case clast_bin_fdiv:
+ mpz_mdiv (v1, v1, b->RHS);
+ mpz_mdiv (v2, v2, b->RHS);
+ break;
+
+ case clast_bin_cdiv:
+ mpz_mdiv (v1, v1, b->RHS);
+ mpz_mdiv (v2, v2, b->RHS);
+ mpz_init (one);
+ mpz_add (v1, v1, one);
+ mpz_add (v2, v2, one);
+ mpz_clear (one);
+ break;
+
+ case clast_bin_div:
+ mpz_div (v1, v1, b->RHS);
+ mpz_div (v2, v2, b->RHS);
+ break;
+
+ case clast_bin_mod:
+ mpz_mod (v1, v1, b->RHS);
+ mpz_mod (v2, v2, b->RHS);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Return a type that can represent the result of the reduction. */
+ return max_precision_type (type, type_for_interval (v1, v2));
}
/* Returns the type for the CLAST expression E when used in statement
STMT. */
static tree
-gcc_type_for_clast_expr (struct clast_expr *e,
- sese region, VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+type_for_clast_expr (struct clast_expr *e, ivs_params_p ip, mpz_t v1, mpz_t v2)
{
switch (e->type)
{
case clast_expr_term:
- return gcc_type_for_clast_term ((struct clast_term *) e, region,
- newivs, newivs_index, params_index);
+ return type_for_clast_term ((struct clast_term *) e, ip, v1, v2);
case clast_expr_red:
- return gcc_type_for_clast_red ((struct clast_reduction *) e, region,
- newivs, newivs_index, params_index);
+ return type_for_clast_red ((struct clast_reduction *) e, ip, v1, v2);
case clast_expr_bin:
- return gcc_type_for_clast_bin ((struct clast_binary *) e, region,
- newivs, newivs_index, params_index);
+ return type_for_clast_bin ((struct clast_binary *) e, ip, v1, v2);
default:
gcc_unreachable ();
@@ -524,32 +661,32 @@ gcc_type_for_clast_expr (struct clast_expr *e,
/* Returns the type for the equation CLEQ. */
static tree
-gcc_type_for_clast_eq (struct clast_equation *cleq,
- sese region, VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+type_for_clast_eq (struct clast_equation *cleq, ivs_params_p ip)
{
- tree l = gcc_type_for_clast_expr (cleq->LHS, region, newivs,
- newivs_index, params_index);
- tree r = gcc_type_for_clast_expr (cleq->RHS, region, newivs,
- newivs_index, params_index);
+ mpz_t v1, v2;
+ tree l, r;
+
+ mpz_init (v1);
+ mpz_init (v2);
+
+ l = type_for_clast_expr (cleq->LHS, ip, v1, v2);
+ r = type_for_clast_expr (cleq->RHS, ip, v1, v2);
+
+ mpz_clear (v1);
+ mpz_clear (v2);
return max_precision_type (l, r);
}
/* Translates a clast equation CLEQ to a tree. */
static tree
-graphite_translate_clast_equation (sese region,
- struct clast_equation *cleq,
- VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+graphite_translate_clast_equation (struct clast_equation *cleq,
+ ivs_params_p ip)
{
enum tree_code comp;
- tree type = gcc_type_for_clast_eq (cleq, region, newivs, newivs_index,
- params_index);
- tree lhs = clast_to_gcc_expression (type, cleq->LHS, region, newivs,
- newivs_index, params_index);
- tree rhs = clast_to_gcc_expression (type, cleq->RHS, region, newivs,
- newivs_index, params_index);
+ tree type = type_for_clast_eq (cleq, ip);
+ tree lhs = clast_to_gcc_expression (type, cleq->LHS, ip);
+ tree rhs = clast_to_gcc_expression (type, cleq->RHS, ip);
if (cleq->sign == 0)
comp = EQ_EXPR;
@@ -566,18 +703,15 @@ graphite_translate_clast_equation (sese region,
/* Creates the test for the condition in STMT. */
static tree
-graphite_create_guard_cond_expr (sese region, struct clast_guard *stmt,
- VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+graphite_create_guard_cond_expr (struct clast_guard *stmt,
+ ivs_params_p ip)
{
tree cond = NULL;
int i;
for (i = 0; i < stmt->n; i++)
{
- tree eq = graphite_translate_clast_equation (region, &stmt->eq[i],
- newivs, newivs_index,
- params_index);
+ tree eq = graphite_translate_clast_equation (&stmt->eq[i], ip);
if (cond)
cond = fold_build2 (TRUTH_AND_EXPR, TREE_TYPE (eq), cond, eq);
@@ -591,17 +725,32 @@ graphite_create_guard_cond_expr (sese region, struct clast_guard *stmt,
/* Creates a new if region corresponding to Cloog's guard. */
static edge
-graphite_create_new_guard (sese region, edge entry_edge,
- struct clast_guard *stmt,
- VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+graphite_create_new_guard (edge entry_edge, struct clast_guard *stmt,
+ ivs_params_p ip)
{
- tree cond_expr = graphite_create_guard_cond_expr (region, stmt, newivs,
- newivs_index, params_index);
+ tree cond_expr = graphite_create_guard_cond_expr (stmt, ip);
edge exit_edge = create_empty_if_region_on_edge (entry_edge, cond_expr);
return exit_edge;
}
+/* Compute the lower bound LOW and upper bound UP for the parameter
+ PARAM in scop SCOP based on the constraints in the context. */
+
+static void
+compute_bounds_for_param (scop_p scop, int param, mpz_t low, mpz_t up)
+{
+ ppl_Linear_Expression_t le;
+
+ /* Prepare the linear expression corresponding to the parameter that
+ we want to maximize/minimize. */
+ ppl_new_Linear_Expression_with_dimension (&le, scop_nb_params (scop));
+ ppl_set_coef (le, param, 1);
+
+ ppl_max_for_le_pointset (SCOP_CONTEXT (scop), le, up);
+ ppl_min_for_le_pointset (SCOP_CONTEXT (scop), le, low);
+ ppl_delete_Linear_Expression (le);
+}
+
/* Compute the lower bound LOW and upper bound UP for the induction
variable at LEVEL for the statement PBB, based on the transformed
scattering of PBB: T|I|G|Cst, with T the scattering transform, I
@@ -622,7 +771,7 @@ compute_bounds_for_level (poly_bb_p pbb, int level, mpz_t low, mpz_t up)
+ pbb_dim_iter_domain (pbb) + pbb_nb_params (pbb);
ppl_new_Linear_Expression_with_dimension (&le, dim);
- ppl_set_coef (le, 2 * level + 1, 1);
+ ppl_set_coef (le, psct_dynamic_dim (pbb, level), 1);
}
ppl_max_for_le_pointset (ps, le, up);
@@ -631,28 +780,25 @@ compute_bounds_for_level (poly_bb_p pbb, int level, mpz_t low, mpz_t up)
ppl_delete_Pointset_Powerset_C_Polyhedron (ps);
}
-/* Compute the type for the induction variable at LEVEL for the
- statement PBB, based on the transformed schedule of PBB. */
-
-static tree
-compute_type_for_level (poly_bb_p pbb, int level)
-{
- mpz_t low, up;
- tree type;
+/* Walks a CLAST and returns the first statement in the body of a
+ loop.
- mpz_init (low);
- mpz_init (up);
+ FIXME: This function should not be used to get a PBB in the STMT
+ loop in order to find out the iteration domain of the loop: the
+ counter example from Tobias is:
- compute_bounds_for_level (pbb, level, low, up);
- type = gcc_type_for_interval (low, up);
+ | for (i = 0; i < 100; i++)
+ | {
+ | if (i == 0)
+ | S1;
+ | S2;
+ | }
- mpz_clear (low);
- mpz_clear (up);
- return type;
-}
+ This function would return S1 whose iteration domain contains only
+ one point "i = 0", whereas the iteration domain of S2 has 100 points.
-/* Walks a CLAST and returns the first statement in the body of a
- loop. */
+ This should be implemented using some functionality existing in
+ CLooG-ISL. */
static struct clast_user_stmt *
clast_get_body_of_loop (struct clast_stmt *stmt)
@@ -677,17 +823,21 @@ clast_get_body_of_loop (struct clast_stmt *stmt)
from STMT_FOR. */
static tree
-gcc_type_for_iv_of_clast_loop (struct clast_for *stmt_for, int level,
- tree lb_type, tree ub_type)
+type_for_clast_for (struct clast_for *stmt_for, ivs_params_p ip)
{
- struct clast_stmt *stmt = (struct clast_stmt *) stmt_for;
- struct clast_user_stmt *body = clast_get_body_of_loop (stmt);
- CloogStatement *cs = body->statement;
- poly_bb_p pbb = (poly_bb_p) cloog_statement_usr (cs);
+ mpz_t v1, v2;
+ tree lb_type, ub_type;
+
+ mpz_init (v1);
+ mpz_init (v2);
+
+ lb_type = type_for_clast_expr (stmt_for->LB, ip, v1, v2);
+ ub_type = type_for_clast_expr (stmt_for->UB, ip, v1, v2);
+
+ mpz_clear (v1);
+ mpz_clear (v2);
- return max_signed_precision_type (lb_type, max_precision_type
- (ub_type, compute_type_for_level
- (pbb, level - 1)));
+ return max_precision_type (lb_type, ub_type);
}
/* Creates a new LOOP corresponding to Cloog's STMT. Inserts an
@@ -696,23 +846,19 @@ gcc_type_for_iv_of_clast_loop (struct clast_for *stmt_for, int level,
becomes the child loop of the OUTER_LOOP. NEWIVS_INDEX binds
CLooG's scattering name to the induction variable created for the
loop of STMT. The new induction variable is inserted in the NEWIVS
- vector. */
+ vector and is of type TYPE. */
static struct loop *
-graphite_create_new_loop (sese region, edge entry_edge,
- struct clast_for *stmt,
- loop_p outer, VEC (tree, heap) **newivs,
- htab_t newivs_index, htab_t params_index, int level)
+graphite_create_new_loop (edge entry_edge, struct clast_for *stmt,
+ loop_p outer, tree type, tree lb, tree ub,
+ int level, ivs_params_p ip)
{
- tree lb_type = gcc_type_for_clast_expr (stmt->LB, region, *newivs,
- newivs_index, params_index);
- tree ub_type = gcc_type_for_clast_expr (stmt->UB, region, *newivs,
- newivs_index, params_index);
- tree type = gcc_type_for_iv_of_clast_loop (stmt, level, lb_type, ub_type);
- tree lb = clast_to_gcc_expression (type, stmt->LB, region, *newivs,
- newivs_index, params_index);
- tree ub = clast_to_gcc_expression (type, stmt->UB, region, *newivs,
- newivs_index, params_index);
+ mpz_t low, up;
+
+ struct clast_user_stmt *body
+ = clast_get_body_of_loop ((struct clast_stmt *) stmt);
+ poly_bb_p pbb = (poly_bb_p) cloog_statement_usr (body->statement);
+
tree stride = gmp_cst_to_tree (type, stmt->stride);
tree ivvar = create_tmp_var (type, "graphite_IV");
tree iv, iv_after_increment;
@@ -722,9 +868,14 @@ graphite_create_new_loop (sese region, edge entry_edge,
add_referenced_var (ivvar);
- save_clast_name_index (newivs_index, stmt->iterator,
- VEC_length (tree, *newivs));
- VEC_safe_push (tree, heap, *newivs, iv);
+ mpz_init (low);
+ mpz_init (up);
+ compute_bounds_for_level (pbb, level, low, up);
+ save_clast_name_index (ip->newivs_index, stmt->iterator,
+ VEC_length (tree, *(ip->newivs)), level, low, up);
+ mpz_clear (low);
+ mpz_clear (up);
+ VEC_safe_push (tree, heap, *(ip->newivs), iv);
return loop;
}
@@ -732,29 +883,32 @@ graphite_create_new_loop (sese region, edge entry_edge,
induction variables of the loops around GBB in SESE. */
static void
-build_iv_mapping (VEC (tree, heap) *iv_map, sese region,
- VEC (tree, heap) *newivs, htab_t newivs_index,
- struct clast_user_stmt *user_stmt,
- htab_t params_index)
+build_iv_mapping (VEC (tree, heap) *iv_map, struct clast_user_stmt *user_stmt,
+ ivs_params_p ip)
{
struct clast_stmt *t;
int depth = 0;
CloogStatement *cs = user_stmt->statement;
poly_bb_p pbb = (poly_bb_p) cloog_statement_usr (cs);
gimple_bb_p gbb = PBB_BLACK_BOX (pbb);
+ mpz_t v1, v2;
+
+ mpz_init (v1);
+ mpz_init (v2);
for (t = user_stmt->substitutions; t; t = t->next, depth++)
{
struct clast_expr *expr = (struct clast_expr *)
((struct clast_assignment *)t)->RHS;
- tree type = gcc_type_for_clast_expr (expr, region, newivs,
- newivs_index, params_index);
- tree new_name = clast_to_gcc_expression (type, expr, region, newivs,
- newivs_index, params_index);
- loop_p old_loop = gbb_loop_at_index (gbb, region, depth);
+ tree type = type_for_clast_expr (expr, ip, v1, v2);
+ tree new_name = clast_to_gcc_expression (type, expr, ip);
+ loop_p old_loop = gbb_loop_at_index (gbb, ip->region, depth);
VEC_replace (tree, iv_map, old_loop->num, new_name);
}
+
+ mpz_clear (v1);
+ mpz_clear (v2);
}
/* Construct bb_pbb_def with BB and PBB. */
@@ -803,7 +957,7 @@ find_pbb_via_hash (htab_t bb_pbb_mapping, basic_block bb)
return NULL;
}
-/* Check data dependency in LOOP at scattering level LEVEL.
+/* Check data dependency in LOOP at level LEVEL.
BB_PBB_MAPPING is a basic_block and it's related poly_bb_p
mapping. */
@@ -842,17 +996,13 @@ dependency_in_loop_p (loop_p loop, htab_t bb_pbb_mapping, int level)
/* Translates a clast user statement STMT to gimple.
- - REGION is the sese region we used to generate the scop.
- NEXT_E is the edge where new generated code should be attached.
- CONTEXT_LOOP is the loop in which the generated code will be placed
- - BB_PBB_MAPPING is is a basic_block and it's related poly_bb_p mapping.
- - PARAMS_INDEX connects the cloog parameters with the gimple parameters in
- the sese region. */
+ - BB_PBB_MAPPING is is a basic_block and it's related poly_bb_p mapping. */
+
static edge
-translate_clast_user (sese region, struct clast_user_stmt *stmt, edge next_e,
- VEC (tree, heap) **newivs,
- htab_t newivs_index, htab_t bb_pbb_mapping,
- htab_t params_index)
+translate_clast_user (struct clast_user_stmt *stmt, edge next_e,
+ htab_t bb_pbb_mapping, ivs_params_p ip)
{
int i, nb_loops;
basic_block new_bb;
@@ -868,8 +1018,8 @@ translate_clast_user (sese region, struct clast_user_stmt *stmt, edge next_e,
for (i = 0; i < nb_loops; i++)
VEC_quick_push (tree, iv_map, NULL_TREE);
- build_iv_mapping (iv_map, region, *newivs, newivs_index, stmt, params_index);
- next_e = copy_bb_and_scalar_dependences (GBB_BB (gbb), region,
+ build_iv_mapping (iv_map, stmt, ip);
+ next_e = copy_bb_and_scalar_dependences (GBB_BB (gbb), ip->region,
next_e, iv_map);
VEC_free (tree, heap, iv_map);
@@ -884,39 +1034,34 @@ translate_clast_user (sese region, struct clast_user_stmt *stmt, edge next_e,
count is zero (lb > ub). */
static edge
-graphite_create_new_loop_guard (sese region, edge entry_edge,
- struct clast_for *stmt,
- VEC (tree, heap) *newivs,
- htab_t newivs_index, htab_t params_index)
+graphite_create_new_loop_guard (edge entry_edge, struct clast_for *stmt,
+ tree *type, tree *lb, tree *ub,
+ ivs_params_p ip)
{
tree cond_expr;
edge exit_edge;
- tree lb_type = gcc_type_for_clast_expr (stmt->LB, region, newivs,
- newivs_index, params_index);
- tree ub_type = gcc_type_for_clast_expr (stmt->UB, region, newivs,
- newivs_index, params_index);
- tree type = max_precision_type (lb_type, ub_type);
- tree lb = clast_to_gcc_expression (type, stmt->LB, region, newivs,
- newivs_index, params_index);
- tree ub = clast_to_gcc_expression (type, stmt->UB, region, newivs,
- newivs_index, params_index);
+
+ *type = type_for_clast_for (stmt, ip);
+ *lb = clast_to_gcc_expression (*type, stmt->LB, ip);
+ *ub = clast_to_gcc_expression (*type, stmt->UB, ip);
+
/* When ub is simply a constant or a parameter, use lb <= ub. */
- if (TREE_CODE (ub) == INTEGER_CST || TREE_CODE (ub) == SSA_NAME)
- cond_expr = fold_build2 (LE_EXPR, boolean_type_node, lb, ub);
+ if (TREE_CODE (*ub) == INTEGER_CST || TREE_CODE (*ub) == SSA_NAME)
+ cond_expr = fold_build2 (LE_EXPR, boolean_type_node, *lb, *ub);
else
{
- tree one = (POINTER_TYPE_P (type)
+ tree one = (POINTER_TYPE_P (*type)
? size_one_node
- : fold_convert (type, integer_one_node));
+ : fold_convert (*type, integer_one_node));
/* Adding +1 and using LT_EXPR helps with loop latches that have a
loop iteration count of "PARAMETER - 1". For PARAMETER == 0 this becomes
2^k-1 due to integer overflow, and the condition lb <= ub is true,
even if we do not want this. However lb < ub + 1 is false, as
expected. */
- tree ub_one = fold_build2 (POINTER_TYPE_P (type) ? POINTER_PLUS_EXPR
- : PLUS_EXPR, type, ub, one);
+ tree ub_one = fold_build2 (POINTER_TYPE_P (*type) ? POINTER_PLUS_EXPR
+ : PLUS_EXPR, *type, *ub, one);
- cond_expr = fold_build2 (LT_EXPR, boolean_type_node, lb, ub_one);
+ cond_expr = fold_build2 (LT_EXPR, boolean_type_node, *lb, ub_one);
}
exit_edge = create_empty_if_region_on_edge (entry_edge, cond_expr);
@@ -925,27 +1070,20 @@ graphite_create_new_loop_guard (sese region, edge entry_edge,
}
static edge
-translate_clast (sese, loop_p, struct clast_stmt *, edge,
- VEC (tree, heap) **, htab_t, htab_t, int, htab_t);
+translate_clast (loop_p, struct clast_stmt *, edge, htab_t, int, ivs_params_p);
/* Create the loop for a clast for statement.
- - REGION is the sese region we used to generate the scop.
- NEXT_E is the edge where new generated code should be attached.
- - BB_PBB_MAPPING is is a basic_block and it's related poly_bb_p mapping.
- - PARAMS_INDEX connects the cloog parameters with the gimple parameters in
- the sese region. */
+ - BB_PBB_MAPPING is is a basic_block and it's related poly_bb_p mapping. */
+
static edge
-translate_clast_for_loop (sese region, loop_p context_loop,
- struct clast_for *stmt, edge next_e,
- VEC (tree, heap) **newivs,
- htab_t newivs_index, htab_t bb_pbb_mapping,
- int level, htab_t params_index)
+translate_clast_for_loop (loop_p context_loop, struct clast_for *stmt,
+ edge next_e, htab_t bb_pbb_mapping, int level,
+ tree type, tree lb, tree ub, ivs_params_p ip)
{
- struct loop *loop = graphite_create_new_loop (region, next_e, stmt,
- context_loop, newivs,
- newivs_index, params_index,
- level);
+ struct loop *loop = graphite_create_new_loop (next_e, stmt, context_loop,
+ type, lb, ub, level, ip);
edge last_e = single_exit (loop);
edge to_body = single_succ_edge (loop->header);
basic_block after = to_body->dest;
@@ -954,15 +1092,13 @@ translate_clast_for_loop (sese region, loop_p context_loop,
last_e = single_succ_edge (split_edge (last_e));
/* Translate the body of the loop. */
- next_e = translate_clast (region, loop, stmt->body, to_body,
- newivs, newivs_index, bb_pbb_mapping, level + 1,
- params_index);
+ next_e = translate_clast (loop, stmt->body, to_body, bb_pbb_mapping,
+ level + 1, ip);
redirect_edge_succ_nodup (next_e, after);
set_immediate_dominator (CDI_DOMINATORS, next_e->dest, next_e->src);
if (flag_loop_parallelize_all
- && !dependency_in_loop_p (loop, bb_pbb_mapping,
- get_scattering_level (level)))
+ && !dependency_in_loop_p (loop, bb_pbb_mapping, level))
loop->can_be_parallel = true;
return last_e;
@@ -972,49 +1108,38 @@ translate_clast_for_loop (sese region, loop_p context_loop,
protecting the loop, if it is executed zero times. In this guard we create
the real loop structure.
- - REGION is the sese region we used to generate the scop.
- NEXT_E is the edge where new generated code should be attached.
- - BB_PBB_MAPPING is is a basic_block and it's related poly_bb_p mapping.
- - PARAMS_INDEX connects the cloog parameters with the gimple parameters in
- the sese region. */
+ - BB_PBB_MAPPING is is a basic_block and it's related poly_bb_p mapping. */
+
static edge
-translate_clast_for (sese region, loop_p context_loop, struct clast_for *stmt,
- edge next_e, VEC (tree, heap) **newivs,
- htab_t newivs_index, htab_t bb_pbb_mapping, int level,
- htab_t params_index)
+translate_clast_for (loop_p context_loop, struct clast_for *stmt, edge next_e,
+ htab_t bb_pbb_mapping, int level, ivs_params_p ip)
{
- edge last_e = graphite_create_new_loop_guard (region, next_e, stmt, *newivs,
- newivs_index, params_index);
+ tree type, lb, ub;
+ edge last_e = graphite_create_new_loop_guard (next_e, stmt, &type,
+ &lb, &ub, ip);
edge true_e = get_true_edge_from_guard_bb (next_e->dest);
- translate_clast_for_loop (region, context_loop, stmt, true_e, newivs,
- newivs_index, bb_pbb_mapping, level,
- params_index);
+ translate_clast_for_loop (context_loop, stmt, true_e, bb_pbb_mapping, level,
+ type, lb, ub, ip);
return last_e;
}
/* Translates a clast guard statement STMT to gimple.
- - REGION is the sese region we used to generate the scop.
- NEXT_E is the edge where new generated code should be attached.
- CONTEXT_LOOP is the loop in which the generated code will be placed
- - BB_PBB_MAPPING is is a basic_block and it's related poly_bb_p mapping.
- - PARAMS_INDEX connects the cloog parameters with the gimple parameters in
- the sese region. */
+ - BB_PBB_MAPPING is is a basic_block and it's related poly_bb_p mapping. */
+
static edge
-translate_clast_guard (sese region, loop_p context_loop,
- struct clast_guard *stmt, edge next_e,
- VEC (tree, heap) **newivs,
- htab_t newivs_index, htab_t bb_pbb_mapping, int level,
- htab_t params_index)
+translate_clast_guard (loop_p context_loop, struct clast_guard *stmt,
+ edge next_e, htab_t bb_pbb_mapping, int level,
+ ivs_params_p ip)
{
- edge last_e = graphite_create_new_guard (region, next_e, stmt, *newivs,
- newivs_index, params_index);
+ edge last_e = graphite_create_new_guard (next_e, stmt, ip);
edge true_e = get_true_edge_from_guard_bb (next_e->dest);
- translate_clast (region, context_loop, stmt->then, true_e,
- newivs, newivs_index, bb_pbb_mapping,
- level, params_index);
+ translate_clast (context_loop, stmt->then, true_e, bb_pbb_mapping, level, ip);
return last_e;
}
@@ -1024,11 +1149,10 @@ translate_clast_guard (sese region, loop_p context_loop,
- NEXT_E is the edge where new generated code should be attached.
- CONTEXT_LOOP is the loop in which the generated code will be placed
- BB_PBB_MAPPING is is a basic_block and it's related poly_bb_p mapping. */
+
static edge
-translate_clast (sese region, loop_p context_loop, struct clast_stmt *stmt,
- edge next_e, VEC (tree, heap) **newivs,
- htab_t newivs_index, htab_t bb_pbb_mapping, int level,
- htab_t params_index)
+translate_clast (loop_p context_loop, struct clast_stmt *stmt, edge next_e,
+ htab_t bb_pbb_mapping, int level, ivs_params_p ip)
{
if (!stmt)
return next_e;
@@ -1037,36 +1161,28 @@ translate_clast (sese region, loop_p context_loop, struct clast_stmt *stmt,
; /* Do nothing. */
else if (CLAST_STMT_IS_A (stmt, stmt_user))
- next_e = translate_clast_user (region, (struct clast_user_stmt *) stmt,
- next_e, newivs, newivs_index,
- bb_pbb_mapping, params_index);
+ next_e = translate_clast_user ((struct clast_user_stmt *) stmt,
+ next_e, bb_pbb_mapping, ip);
else if (CLAST_STMT_IS_A (stmt, stmt_for))
- next_e = translate_clast_for (region, context_loop,
- (struct clast_for *) stmt, next_e,
- newivs, newivs_index,
- bb_pbb_mapping, level, params_index);
+ next_e = translate_clast_for (context_loop, (struct clast_for *) stmt,
+ next_e, bb_pbb_mapping, level, ip);
else if (CLAST_STMT_IS_A (stmt, stmt_guard))
- next_e = translate_clast_guard (region, context_loop,
- (struct clast_guard *) stmt, next_e,
- newivs, newivs_index,
- bb_pbb_mapping, level, params_index);
+ next_e = translate_clast_guard (context_loop, (struct clast_guard *) stmt,
+ next_e, bb_pbb_mapping, level, ip);
else if (CLAST_STMT_IS_A (stmt, stmt_block))
- next_e = translate_clast (region, context_loop,
- ((struct clast_block *) stmt)->body,
- next_e, newivs, newivs_index,
- bb_pbb_mapping, level, params_index);
+ next_e = translate_clast (context_loop, ((struct clast_block *) stmt)->body,
+ next_e, bb_pbb_mapping, level, ip);
else
gcc_unreachable();
recompute_all_dominators ();
graphite_verify ();
- return translate_clast (region, context_loop, stmt->next, next_e,
- newivs, newivs_index,
- bb_pbb_mapping, level, params_index);
+ return translate_clast (context_loop, stmt->next, next_e, bb_pbb_mapping,
+ level, ip);
}
/* Free the SCATTERING domain list. */
@@ -1105,7 +1221,7 @@ initialize_cloog_names (scop_p scop, CloogProgram *prog)
for (i = 0; i < nb_parameters; i++)
{
- tree param = VEC_index (tree, SESE_PARAMS(region), i);
+ tree param = VEC_index (tree, SESE_PARAMS (region), i);
const char *name = get_name (param);
int len;
@@ -1306,7 +1422,7 @@ set_cloog_options (void)
/* Change cloog output language to C. If we do use FORTRAN instead, cloog
will stop e.g. with "ERROR: unbounded loops not allowed in FORTRAN.", if
we pass an incomplete program to cloog. */
- options->language = LANGUAGE_C;
+ options->language = CLOOG_LANGUAGE_C;
/* Enable complex equality spreading: removes dummy statements
(assignments) in the generated code which repeats the
@@ -1418,14 +1534,24 @@ debug_generated_program (scop_p scop)
back from CLooG names to GCC trees. */
static void
-create_params_index (htab_t index_table, CloogProgram *prog) {
+create_params_index (scop_p scop, htab_t index_table, CloogProgram *prog) {
CloogNames* names = cloog_program_names (prog);
int nb_parameters = cloog_names_nb_parameters (names);
char **parameters = cloog_names_parameters (names);
int i;
+ mpz_t lb, ub;
+
+ mpz_init (lb);
+ mpz_init (ub);
for (i = 0; i < nb_parameters; i++)
- save_clast_name_index (index_table, parameters[i], i);
+ {
+ compute_bounds_for_param (scop, i, lb, ub);
+ save_clast_name_index (index_table, parameters[i], i, i, lb, ub);
+ }
+
+ mpz_clear (lb);
+ mpz_clear (ub);
}
/* GIMPLE Loop Generator: generates loops from STMT in GIMPLE form for
@@ -1442,6 +1568,7 @@ gloog (scop_p scop, htab_t bb_pbb_mapping)
ifsese if_region = NULL;
htab_t newivs_index, params_index;
cloog_prog_clast pc;
+ struct ivs_params ip;
timevar_push (TV_GRAPHITE_CODE_GEN);
gloog_error = false;
@@ -1468,16 +1595,20 @@ gloog (scop_p scop, htab_t bb_pbb_mapping)
context_loop = SESE_ENTRY (region)->src->loop_father;
newivs_index = htab_create (10, clast_name_index_elt_info,
- eq_clast_name_indexes, free);
+ eq_clast_name_indexes, free_clast_name_index);
params_index = htab_create (10, clast_name_index_elt_info,
- eq_clast_name_indexes, free);
+ eq_clast_name_indexes, free_clast_name_index);
+
+ create_params_index (scop, params_index, pc.prog);
- create_params_index (params_index, pc.prog);
+ ip.newivs = &newivs;
+ ip.newivs_index = newivs_index;
+ ip.params = SESE_PARAMS (region);
+ ip.params_index = params_index;
+ ip.region = region;
- translate_clast (region, context_loop, pc.stmt,
- if_region->true_region->entry,
- &newivs, newivs_index,
- bb_pbb_mapping, 1, params_index);
+ translate_clast (context_loop, pc.stmt, if_region->true_region->entry,
+ bb_pbb_mapping, 0, &ip);
graphite_verify ();
scev_reset ();
recompute_all_dominators ();
diff --git a/gcc/graphite-clast-to-gimple.h b/gcc/graphite-clast-to-gimple.h
index 9d599d6d075..b5affd989f0 100644
--- a/gcc/graphite-clast-to-gimple.h
+++ b/gcc/graphite-clast-to-gimple.h
@@ -63,16 +63,4 @@ eq_bb_pbb_map (const void *bb_pbb1, const void *bb_pbb2)
return (bp1->bb->index == bp2->bb->index);
}
-/* Returns the scattering dimension for STMTFOR.
-
- The relationship between dimension in scattering matrix
- and the DEPTH of the loop is:
- DIMENSION = 2*DEPTH - 1
-*/
-
-static inline int get_scattering_level (int depth)
-{
- return 2 * depth - 1;
-}
-
#endif
diff --git a/gcc/graphite-dependences.c b/gcc/graphite-dependences.c
index 081aa691ba6..fb49f161480 100644
--- a/gcc/graphite-dependences.c
+++ b/gcc/graphite-dependences.c
@@ -745,11 +745,13 @@ graphite_carried_dependence_level_k (poly_dr_p pdr1, poly_dr_p pdr2,
{
ppl_Pointset_Powerset_C_Polyhedron_t po;
ppl_Pointset_Powerset_C_Polyhedron_t eqpp;
- graphite_dim_t tdim1 = pbb_nb_scattering_transform (PDR_PBB (pdr1));
- graphite_dim_t ddim1 = pbb_dim_iter_domain (PDR_PBB (pdr1));
+ poly_bb_p pbb = PDR_PBB (pdr1);
+ graphite_dim_t tdim1 = pbb_nb_scattering_transform (pbb);
+ graphite_dim_t ddim1 = pbb_dim_iter_domain (pbb);
ppl_dimension_type dim;
bool empty_p;
poly_ddr_p pddr = new_poly_ddr (pdr1, pdr2, 1, false);
+ graphite_dim_t pos;
if (PDDR_KIND (pddr) == unknown_dependence)
{
@@ -765,7 +767,8 @@ graphite_carried_dependence_level_k (poly_dr_p pdr1, poly_dr_p pdr2,
po = PDDR_DDP (pddr);
ppl_Pointset_Powerset_C_Polyhedron_space_dimension (po, &dim);
- eqpp = build_pairwise_scheduling (dim, level, tdim1 + ddim1, 1);
+ pos = psct_dynamic_dim (pbb, level);
+ eqpp = build_pairwise_scheduling (dim, pos, tdim1 + ddim1, 1);
ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (eqpp, po);
empty_p = ppl_powerset_is_empty (eqpp);
diff --git a/gcc/graphite-ppl.h b/gcc/graphite-ppl.h
index 49bde618f47..5820e19927d 100644
--- a/gcc/graphite-ppl.h
+++ b/gcc/graphite-ppl.h
@@ -124,6 +124,17 @@ ppl_set_coef_tree (ppl_Linear_Expression_t e, ppl_dimension_type i, tree x)
mpz_clear (v);
}
+/* Sets RES to the min of V1 and V2. */
+
+static inline void
+value_min (mpz_t res, mpz_t v1, mpz_t v2)
+{
+ if (mpz_cmp (v1, v2) < 0)
+ mpz_set (res, v1);
+ else
+ mpz_set (res, v2);
+}
+
/* Sets RES to the max of V1 and V2. */
static inline void
diff --git a/gcc/jump.c b/gcc/jump.c
index f337eb3add0..0d29f0fcb18 100644
--- a/gcc/jump.c
+++ b/gcc/jump.c
@@ -200,6 +200,54 @@ init_label_info (rtx f)
}
}
+/* A subroutine of mark_all_labels. Trivially propagate a simple label
+ load into a jump_insn that uses it. */
+
+static void
+maybe_propagate_label_ref (rtx jump_insn, rtx prev_nonjump_insn)
+{
+ rtx label_note, pc, pc_src;
+
+ pc = pc_set (jump_insn);
+ pc_src = pc != NULL ? SET_SRC (pc) : NULL;
+ label_note = find_reg_note (prev_nonjump_insn, REG_LABEL_OPERAND, NULL);
+
+ /* If the previous non-jump insn sets something to a label,
+ something that this jump insn uses, make that label the primary
+ target of this insn if we don't yet have any. That previous
+ insn must be a single_set and not refer to more than one label.
+ The jump insn must not refer to other labels as jump targets
+ and must be a plain (set (pc) ...), maybe in a parallel, and
+ may refer to the item being set only directly or as one of the
+ arms in an IF_THEN_ELSE. */
+
+ if (label_note != NULL && pc_src != NULL)
+ {
+ rtx label_set = single_set (prev_nonjump_insn);
+ rtx label_dest = label_set != NULL ? SET_DEST (label_set) : NULL;
+
+ if (label_set != NULL
+ /* The source must be the direct LABEL_REF, not a
+ PLUS, UNSPEC, IF_THEN_ELSE etc. */
+ && GET_CODE (SET_SRC (label_set)) == LABEL_REF
+ && (rtx_equal_p (label_dest, pc_src)
+ || (GET_CODE (pc_src) == IF_THEN_ELSE
+ && (rtx_equal_p (label_dest, XEXP (pc_src, 1))
+ || rtx_equal_p (label_dest, XEXP (pc_src, 2))))))
+ {
+ /* The CODE_LABEL referred to in the note must be the
+ CODE_LABEL in the LABEL_REF of the "set". We can
+ conveniently use it for the marker function, which
+ requires a LABEL_REF wrapping. */
+ gcc_assert (XEXP (label_note, 0) == XEXP (SET_SRC (label_set), 0));
+
+ mark_jump_label_1 (label_set, jump_insn, false, true);
+
+ gcc_assert (JUMP_LABEL (jump_insn) == XEXP (label_note, 0));
+ }
+ }
+}
+
/* Mark the label each jump jumps to.
Combine consecutive labels, and count uses of labels. */
@@ -207,85 +255,31 @@ static void
mark_all_labels (rtx f)
{
rtx insn;
- rtx prev_nonjump_insn = NULL;
-
- for (insn = f; insn; insn = NEXT_INSN (insn))
- if (NONDEBUG_INSN_P (insn))
- {
- mark_jump_label (PATTERN (insn), insn, 0);
-
- /* If the previous non-jump insn sets something to a label,
- something that this jump insn uses, make that label the primary
- target of this insn if we don't yet have any. That previous
- insn must be a single_set and not refer to more than one label.
- The jump insn must not refer to other labels as jump targets
- and must be a plain (set (pc) ...), maybe in a parallel, and
- may refer to the item being set only directly or as one of the
- arms in an IF_THEN_ELSE. */
- if (! INSN_DELETED_P (insn)
- && JUMP_P (insn)
- && JUMP_LABEL (insn) == NULL)
- {
- rtx label_note = NULL;
- rtx pc = pc_set (insn);
- rtx pc_src = pc != NULL ? SET_SRC (pc) : NULL;
-
- if (prev_nonjump_insn != NULL)
- label_note
- = find_reg_note (prev_nonjump_insn, REG_LABEL_OPERAND, NULL);
-
- if (label_note != NULL && pc_src != NULL)
- {
- rtx label_set = single_set (prev_nonjump_insn);
- rtx label_dest
- = label_set != NULL ? SET_DEST (label_set) : NULL;
-
- if (label_set != NULL
- /* The source must be the direct LABEL_REF, not a
- PLUS, UNSPEC, IF_THEN_ELSE etc. */
- && GET_CODE (SET_SRC (label_set)) == LABEL_REF
- && (rtx_equal_p (label_dest, pc_src)
- || (GET_CODE (pc_src) == IF_THEN_ELSE
- && (rtx_equal_p (label_dest, XEXP (pc_src, 1))
- || rtx_equal_p (label_dest,
- XEXP (pc_src, 2))))))
-
- {
- /* The CODE_LABEL referred to in the note must be the
- CODE_LABEL in the LABEL_REF of the "set". We can
- conveniently use it for the marker function, which
- requires a LABEL_REF wrapping. */
- gcc_assert (XEXP (label_note, 0)
- == XEXP (SET_SRC (label_set), 0));
-
- mark_jump_label_1 (label_set, insn, false, true);
- gcc_assert (JUMP_LABEL (insn)
- == XEXP (SET_SRC (label_set), 0));
- }
- }
- }
- else if (! INSN_DELETED_P (insn))
- prev_nonjump_insn = insn;
- }
- else if (LABEL_P (insn))
- prev_nonjump_insn = NULL;
- /* If we are in cfglayout mode, there may be non-insns between the
- basic blocks. If those non-insns represent tablejump data, they
- contain label references that we must record. */
if (current_ir_type () == IR_RTL_CFGLAYOUT)
{
basic_block bb;
- rtx insn;
FOR_EACH_BB (bb)
{
+ /* In cfglayout mode, we don't bother with trivial next-insn
+ propagation of LABEL_REFs into JUMP_LABEL. This will be
+ handled by other optimizers using better algorithms. */
+ FOR_BB_INSNS (bb, insn)
+ {
+ gcc_assert (! INSN_DELETED_P (insn));
+ if (NONDEBUG_INSN_P (insn))
+ mark_jump_label (PATTERN (insn), insn, 0);
+ }
+
+ /* In cfglayout mode, there may be non-insns between the
+ basic blocks. If those non-insns represent tablejump data,
+ they contain label references that we must record. */
for (insn = bb->il.rtl->header; insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
gcc_assert (JUMP_TABLE_DATA_P (insn));
mark_jump_label (PATTERN (insn), insn, 0);
}
-
for (insn = bb->il.rtl->footer; insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
@@ -294,6 +288,28 @@ mark_all_labels (rtx f)
}
}
}
+ else
+ {
+ rtx prev_nonjump_insn = NULL;
+ for (insn = f; insn; insn = NEXT_INSN (insn))
+ {
+ if (INSN_DELETED_P (insn))
+ ;
+ else if (LABEL_P (insn))
+ prev_nonjump_insn = NULL;
+ else if (NONDEBUG_INSN_P (insn))
+ {
+ mark_jump_label (PATTERN (insn), insn, 0);
+ if (JUMP_P (insn))
+ {
+ if (JUMP_LABEL (insn) == NULL && prev_nonjump_insn != NULL)
+ maybe_propagate_label_ref (insn, prev_nonjump_insn);
+ }
+ else
+ prev_nonjump_insn = insn;
+ }
+ }
+ }
}
/* Given a comparison (CODE ARG0 ARG1), inside an insn, INSN, return a code
diff --git a/gcc/melt-build.mk b/gcc/melt-build.mk
index 844e7e08c53..b14aa3d97b6 100644
--- a/gcc/melt-build.mk
+++ b/gcc/melt-build.mk
@@ -2809,29 +2809,29 @@ $(melt_default_modules_list)-debugnoline.modlis: melt-all-modules melt-modules
### MELT upgrade
.PHONY: warmelt-upgrade-translator
-warmelt-upgrade-translator: \
- melt-sources/warmelt-first.c \
- $(wildcard melt-sources/warmelt-first+*.c) \
- melt-sources/warmelt-base.c \
- $(wildcard melt-sources/warmelt-base+*.c) \
- melt-sources/warmelt-debug.c \
- $(wildcard melt-sources/warmelt-debug+*.c) \
- melt-sources/warmelt-macro.c \
- $(wildcard melt-sources/warmelt-macro+*.c) \
- melt-sources/warmelt-normal.c \
- $(wildcard melt-sources/warmelt-normal+*.c) \
- melt-sources/warmelt-normatch.c \
- $(wildcard melt-sources/warmelt-normatch+*.c) \
- melt-sources/warmelt-genobj.c \
- $(wildcard melt-sources/warmelt-genobj+*.c) \
- melt-sources/warmelt-outobj.c \
- $(wildcard melt-sources/warmelt-outobj+*.c)
+warmelt-upgrade-translator: $(WARMELT_LAST) \
+ $(MELT_LAST_STAGE)/warmelt-first.c \
+ $(wildcard $(MELT_LAST_STAGE)/warmelt-first+*.c) \
+ $(MELT_LAST_STAGE)/warmelt-base.c \
+ $(wildcard $(MELT_LAST_STAGE)/warmelt-base+*.c) \
+ $(MELT_LAST_STAGE)/warmelt-debug.c \
+ $(wildcard $(MELT_LAST_STAGE)/warmelt-debug+*.c) \
+ $(MELT_LAST_STAGE)/warmelt-macro.c \
+ $(wildcard $(MELT_LAST_STAGE)/warmelt-macro+*.c) \
+ $(MELT_LAST_STAGE)/warmelt-normal.c \
+ $(wildcard $(MELT_LAST_STAGE)/warmelt-normal+*.c) \
+ $(MELT_LAST_STAGE)/warmelt-normatch.c \
+ $(wildcard $(MELT_LAST_STAGE)/warmelt-normatch+*.c) \
+ $(MELT_LAST_STAGE)/warmelt-genobj.c \
+ $(wildcard $(MELT_LAST_STAGE)/warmelt-genobj+*.c) \
+ $(MELT_LAST_STAGE)/warmelt-outobj.c \
+ $(wildcard $(MELT_LAST_STAGE)/warmelt-outobj+*.c)
@echo upgrading the MELT translator
@which unifdef || (echo missing unifdef for warmelt-upgrade-translator; exit 1)
@which indent || (echo missing indent for warmelt-upgrade-translator; exit 1)
@echo upgrading MELT translator warmelt-first
- for f in melt-sources/warmelt-first*.c ; do \
+ for f in $(MELT_LAST_STAGE)/warmelt-first*.c ; do \
bf=`basename $$f`; \
rm -f $(srcdir)/melt/generated/$$bf-tmp; \
grep -v '^#line' < $$f \
@@ -2847,7 +2847,7 @@ warmelt-upgrade-translator: \
rm $(MELT_STAGE_ZERO)/warmelt-first*.o
@echo upgrading MELT translator warmelt-base
- for f in melt-sources/warmelt-base*.c ; do \
+ for f in $(MELT_LAST_STAGE)/warmelt-base*.c ; do \
bf=`basename $$f`; \
rm -f $(srcdir)/melt/generated/$$bf-tmp; \
grep -v '^#line' < $$f \
@@ -2863,7 +2863,7 @@ warmelt-upgrade-translator: \
rm $(MELT_STAGE_ZERO)/warmelt-base*.o
@echo upgrading MELT translator warmelt-debug
- for f in melt-sources/warmelt-debug*.c ; do \
+ for f in $(MELT_LAST_STAGE)/warmelt-debug*.c ; do \
bf=`basename $$f`; \
rm -f $(srcdir)/melt/generated/$$bf-tmp; \
grep -v '^#line' < $$f \
@@ -2879,7 +2879,7 @@ warmelt-upgrade-translator: \
rm $(MELT_STAGE_ZERO)/warmelt-debug*.o
@echo upgrading MELT translator warmelt-macro
- for f in melt-sources/warmelt-macro*.c ; do \
+ for f in $(MELT_LAST_STAGE)/warmelt-macro*.c ; do \
bf=`basename $$f`; \
rm -f $(srcdir)/melt/generated/$$bf-tmp; \
grep -v '^#line' < $$f \
@@ -2895,7 +2895,7 @@ warmelt-upgrade-translator: \
rm $(MELT_STAGE_ZERO)/warmelt-macro*.o
@echo upgrading MELT translator warmelt-normal
- for f in melt-sources/warmelt-normal*.c ; do \
+ for f in $(MELT_LAST_STAGE)/warmelt-normal*.c ; do \
bf=`basename $$f`; \
rm -f $(srcdir)/melt/generated/$$bf-tmp; \
grep -v '^#line' < $$f \
@@ -2911,7 +2911,7 @@ warmelt-upgrade-translator: \
rm $(MELT_STAGE_ZERO)/warmelt-normal*.o
@echo upgrading MELT translator warmelt-normatch
- for f in melt-sources/warmelt-normatch*.c ; do \
+ for f in $(MELT_LAST_STAGE)/warmelt-normatch*.c ; do \
bf=`basename $$f`; \
rm -f $(srcdir)/melt/generated/$$bf-tmp; \
grep -v '^#line' < $$f \
@@ -2927,7 +2927,7 @@ warmelt-upgrade-translator: \
rm $(MELT_STAGE_ZERO)/warmelt-normatch*.o
@echo upgrading MELT translator warmelt-genobj
- for f in melt-sources/warmelt-genobj*.c ; do \
+ for f in $(MELT_LAST_STAGE)/warmelt-genobj*.c ; do \
bf=`basename $$f`; \
rm -f $(srcdir)/melt/generated/$$bf-tmp; \
grep -v '^#line' < $$f \
@@ -2943,7 +2943,7 @@ warmelt-upgrade-translator: \
rm $(MELT_STAGE_ZERO)/warmelt-genobj*.o
@echo upgrading MELT translator warmelt-outobj
- for f in melt-sources/warmelt-outobj*.c ; do \
+ for f in $(MELT_LAST_STAGE)/warmelt-outobj*.c ; do \
bf=`basename $$f`; \
rm -f $(srcdir)/melt/generated/$$bf-tmp; \
grep -v '^#line' < $$f \
@@ -2998,15 +2998,15 @@ vpath %.h $(melt_make_source_dir)/generated . $(melt_source_dir)
.PHONY: meltrun-generate
-meltrun-generate: $(melt_default_modules_list).modlis empty-file-for-melt.c \
- melt-all-sources melt-all-modules $(melt_make_cc1_dependency)
+meltrun-generate: $(WARMELT_LAST) $(WARMELT_LAST_MODLIS) empty-file-for-melt.c \
+ $(melt_make_cc1_dependency)
rm -f $(wildcard meltrunsup*)
$(melt_make_cc1) $(melt_make_cc1flags) \
$(meltarg_mode)=runtypesupport \
$(meltarg_tempdir)=. $(meltarg_bootstrapping) $(MELT_DEBUG) \
- $(meltarg_init)=@$(melt_default_modules_list) \
- $(meltarg_module_path)=melt-modules:. \
- $(meltarg_source_path)=melt-sources:. \
+ $(meltarg_init)=@$(basename $(WARMELT_LAST_MODLIS))) \
+ $(meltarg_module_path)=$(MELT_LAST_STAGE):. \
+ $(meltarg_source_path)=$(MELT_LAST_STAGE):$(melt_source_dir):. \
$(meltarg_output)=meltrunsup \
empty-file-for-melt.c
if [ -n "$(GCCMELTRUNGEN_DEST)" ]; then \
diff --git a/gcc/melt-build.tpl b/gcc/melt-build.tpl
index b87e22ddad0..d9701fb87d4 100644
--- a/gcc/melt-build.tpl
+++ b/gcc/melt-build.tpl
@@ -499,17 +499,17 @@ $(melt_default_modules_list)-[+variant+].modlis: melt-all-modules melt-modules
### MELT upgrade
.PHONY: warmelt-upgrade-translator
-warmelt-upgrade-translator: \
+warmelt-upgrade-translator: $(WARMELT_LAST) \
[+FOR melt_translator_file " \\\n"
-+] melt-sources/[+base+].c \
- $(wildcard melt-sources/[+base+]+*.c)[+
++] $(MELT_LAST_STAGE)/[+base+].c \
+ $(wildcard $(MELT_LAST_STAGE)/[+base+]+*.c)[+
ENDFOR melt_translator_file+]
@echo upgrading the MELT translator
@which unifdef || (echo missing unifdef for warmelt-upgrade-translator; exit 1)
@which indent || (echo missing indent for warmelt-upgrade-translator; exit 1)
[+FOR melt_translator_file+]
@echo upgrading MELT translator [+base+]
- for f in melt-sources/[+base+]*.c ; do \
+ for f in $(MELT_LAST_STAGE)/[+base+]*.c ; do \
bf=`basename $$f`; \
rm -f $(srcdir)/melt/generated/$$bf-tmp; \
grep -v '^#line' < $$f \
@@ -553,15 +553,15 @@ vpath %.h $(melt_make_source_dir)/generated . $(melt_source_dir)
.PHONY: meltrun-generate
-meltrun-generate: $(melt_default_modules_list).modlis empty-file-for-melt.c \
- melt-all-sources melt-all-modules $(melt_make_cc1_dependency)
+meltrun-generate: $(WARMELT_LAST) $(WARMELT_LAST_MODLIS) empty-file-for-melt.c \
+ $(melt_make_cc1_dependency)
rm -f $(wildcard meltrunsup*)
$(melt_make_cc1) $(melt_make_cc1flags) \
$(meltarg_mode)=runtypesupport \
$(meltarg_tempdir)=. $(meltarg_bootstrapping) $(MELT_DEBUG) \
- $(meltarg_init)=@$(melt_default_modules_list) \
- $(meltarg_module_path)=melt-modules:. \
- $(meltarg_source_path)=melt-sources:. \
+ $(meltarg_init)=@$(basename $(WARMELT_LAST_MODLIS))) \
+ $(meltarg_module_path)=$(MELT_LAST_STAGE):. \
+ $(meltarg_source_path)=$(MELT_LAST_STAGE):$(melt_source_dir):. \
$(meltarg_output)=meltrunsup \
empty-file-for-melt.c
if [ -n "$(GCCMELTRUNGEN_DEST)" ]; then \
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c49e0b78fe8..9eb5de6fcd5 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,68 @@
+2011-07-23 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/cpp0x/decltype21.C: Add 49823 examples.
+
+2011-07-22 Jason Merrill <jason@redhat.com>
+
+ PR c++/49793
+ * g++.dg/cpp0x/initlist55.C: New.
+
+2011-07-23 Tobias Burnus <burnus@net-b.de>
+
+ PR fortran/49791
+ * gfortran.dg/namelist_72.f: New.
+
+2011-07-23 Tobias Burnus <burnus@net-b.de>
+
+ * gfortran.dg/coarray_25.f90: New.
+
+2011-07-22 Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ * override1.C: This test should use c++0x mode.
+ * override3.C: New. Test the diagnostics in c++98 mode.
+
+2011-07-22 Jason Merrill <jason@redhat.com>
+ Mark Glisse <marc.glisse@normalesup.org>
+
+ PR c++/30112
+ * g++.dg/other/pragma-re-1.C: Add namespace cases.
+
+ PR c++/49813
+ * g++.dg/opt/builtins2.C: New.
+ * g++.dg/other/error27.C: Don't rely on __builtin.
+
+2011-07-22 H.J. Lu <hongjiu.lu@intel.com>
+
+ * gcc/testsuite/gcc.target/i386/avx-vzeroupper-16.c: Only run
+ on lp64 targets.
+ * gcc/testsuite/gcc.target/i386/avx-vzeroupper-17.c: Likewise.
+ * gcc/testsuite/gcc.target/i386/avx-vzeroupper-18.c: Likewise.
+ * gcc/testsuite/gcc.target/i386/pr43662.c: Likewise.
+ * gcc/testsuite/gcc.target/i386/pr43869.c: Likewise.
+
+ * gcc.target/x86_64/abi/callabi/callabi.exp: Check ilp32
+ instead of ia32.
+
+2011-07-22 Richard Guenther <rguenther@suse.de>
+
+ PR tree-optimization/45819
+ * gcc.dg/pr45819.c: New testcase.
+
+2011-07-22 Uros Bizjak <ubizjak@gmail.com>
+
+ * lib/target-supports.exp (check_ifunc_available): Rewrite.
+
+2011-07-21 Sebastian Pop <sebastian.pop@amd.com>
+
+ PR middle-end/47654
+ PR middle-end/49649
+ * gcc.dg/graphite/run-id-pr47654.c: New.
+
+2011-07-21 Ian Lance Taylor <iant@google.com>
+
+ PR middle-end/49705
+ * gcc.dg/pr49705.c: New test.
+
2011-07-21 Uros Bizjak <ubizjak@gmail.com>
* lib/target-supports.exp (check_avx_os_support_available): New.
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype21.C b/gcc/testsuite/g++.dg/cpp0x/decltype21.C
index ee73bfbc36c..733725626c3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/decltype21.C
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype21.C
@@ -10,6 +10,22 @@ struct c : decltype(make<p>()) {};
decltype(make<p>())::t t;
+// PR c++/49823
+
+template < typename T >
+auto f( const T &x )
+ -> typename decltype( x )::type; // ICE on here
+
+template < typename T >
+typename decltype( T{} )::type // ICE on here
+f( T );
+
+template < typename T >
+void f( T x )
+{ typename decltype( x )::type t; } // ICE on here
+
+// Negative tests
+
int f();
decltype(f())::t t2; // { dg-error "not a class" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist17.C b/gcc/testsuite/g++.dg/cpp0x/initlist17.C
index 86371e81969..6ea08d15003 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist17.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist17.C
@@ -1,4 +1,4 @@
-// { dg-options "-std=c++0x" }
+// { dg-options "-std=c++0x -pedantic-errors" }
void f(int i);
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist36.C b/gcc/testsuite/g++.dg/cpp0x/initlist36.C
index 94624c977c9..a703b45907e 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist36.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist36.C
@@ -1,5 +1,5 @@
// PR c++/44358
-// { dg-options "-std=c++0x" }
+// { dg-options "-std=c++0x -pedantic-errors" }
#include <initializer_list>
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist5.C b/gcc/testsuite/g++.dg/cpp0x/initlist5.C
index 32caac38251..dbd17ecbbe2 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist5.C
@@ -1,5 +1,5 @@
// Test for narrowing diagnostics
-// { dg-options "-std=c++0x" }
+// { dg-options "-std=c++0x -pedantic-errors" }
#include <initializer_list>
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist52.C b/gcc/testsuite/g++.dg/cpp0x/initlist52.C
index 22bc2873c7c..17c0cfe3f14 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist52.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist52.C
@@ -1,5 +1,5 @@
// PR c++/45378
-// { dg-options -std=c++0x }
+// { dg-options "-std=c++0x -pedantic-errors" }
int main()
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist55.C b/gcc/testsuite/g++.dg/cpp0x/initlist55.C
new file mode 100644
index 00000000000..cb42e81ed6a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist55.C
@@ -0,0 +1,5 @@
+// Test for -Wno-narrowing
+// { dg-options "-std=c++0x -pedantic-errors -Wno-narrowing" }
+
+int i;
+float d = { i };
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist7.C b/gcc/testsuite/g++.dg/cpp0x/initlist7.C
index 7913ed7edb1..55a0371860f 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist7.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist7.C
@@ -1,5 +1,5 @@
// PR c++/37932
-// { dg-options "-std=c++0x" }
+// { dg-options "-std=c++0x -pedantic-errors" }
typedef enum { AA=1, BB=2 } my_enum;
diff --git a/gcc/testsuite/g++.dg/cpp0x/override1.C b/gcc/testsuite/g++.dg/cpp0x/override1.C
index 83e04790873..ba580b5c09f 100644
--- a/gcc/testsuite/g++.dg/cpp0x/override1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/override1.C
@@ -1,4 +1,5 @@
// { dg-do compile }
+// { dg-options "--std=c++0x" }
struct B
{
virtual void f() final {}
diff --git a/gcc/testsuite/g++.dg/cpp0x/override3.C b/gcc/testsuite/g++.dg/cpp0x/override3.C
new file mode 100644
index 00000000000..2d22cbf2aa7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/override3.C
@@ -0,0 +1,24 @@
+// { dg-do compile }
+// { dg-options "--std=c++98" }
+
+struct B final {}; // { dg-warning "override controls" }
+
+struct D : B {}; // { dg-error "cannot derive from 'final' base" }
+
+struct E __final {};
+
+struct F : E {}; // { dg-error "cannot derive from 'final' base" }
+
+struct G
+{
+ virtual void f();
+};
+
+struct H : G
+{
+ void f() override; // { dg-warning "override controls" }
+};
+
+int main()
+{
+}
diff --git a/gcc/testsuite/g++.dg/opt/builtins2.C b/gcc/testsuite/g++.dg/opt/builtins2.C
new file mode 100644
index 00000000000..00a28dbc1bf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/builtins2.C
@@ -0,0 +1,11 @@
+// PR c++/49813
+// We should handle asinh as a built-in in C++0x mode, even when strict.
+// { dg-options "-std=c++0x" }
+// { dg-final { scan-assembler-not "asinh" } }
+
+#include <math.h>
+
+int main()
+{
+ double das = asinh(1.0);
+}
diff --git a/gcc/testsuite/g++.dg/other/error27.C b/gcc/testsuite/g++.dg/other/error27.C
index de97428571b..ef1e5906b6b 100644
--- a/gcc/testsuite/g++.dg/other/error27.C
+++ b/gcc/testsuite/g++.dg/other/error27.C
@@ -4,10 +4,10 @@
void foo (double x, double y)
{
- __builtin_isgreater(x, y)(); // { dg-error "__builtin_\[^\n\]*cannot be used as a function" }
- __builtin_isless(x, y)(); // { dg-error "__builtin_\[^\n\]*cannot be used as a function" }
- __builtin_isgreaterequal(x, y)(); // { dg-error "__builtin_\[^\n\]*cannot be used as a function" }
- __builtin_islessequal(x, y)(); // { dg-error "__builtin_\[^\n\]*cannot be used as a function" }
- __builtin_isunordered(x, y)(); // { dg-error "__builtin_\[^\n\]*cannot be used as a function" }
- __builtin_islessgreater(x, y)(); // { dg-error "__builtin_\[^\n\]*cannot be used as a function" }
+ __builtin_isgreater(x, y)(); // { dg-error "cannot be used as a function" }
+ __builtin_isless(x, y)(); // { dg-error "cannot be used as a function" }
+ __builtin_isgreaterequal(x, y)(); // { dg-error "cannot be used as a function" }
+ __builtin_islessequal(x, y)(); // { dg-error "cannot be used as a function" }
+ __builtin_isunordered(x, y)(); // { dg-error "cannot be used as a function" }
+ __builtin_islessgreater(x, y)(); // { dg-error "cannot be used as a function" }
}
diff --git a/gcc/testsuite/g++.dg/other/pragma-re-1.C b/gcc/testsuite/g++.dg/other/pragma-re-1.C
index 35ffab1a82c..6a94c5d68a7 100644
--- a/gcc/testsuite/g++.dg/other/pragma-re-1.C
+++ b/gcc/testsuite/g++.dg/other/pragma-re-1.C
@@ -2,6 +2,12 @@
/* { dg-final { scan-assembler-not "foo" } } */
/* { dg-final { scan-assembler "_Z3bazv" } } */
/* { dg-final { scan-assembler-not "baq" } } */
+/* { dg-final { scan-assembler "tut" } } */
+/* { dg-final { scan-assembler-not "gee" } } */
+/* { dg-final { scan-assembler "bang" } } */
+/* { dg-final { scan-assembler-not "whiz" } } */
+/* { dg-final { scan-assembler "eek" } } */
+/* { dg-final { scan-assembler-not "boo" } } */
#ifndef __PRAGMA_REDEFINE_EXTNAME
#error
@@ -17,3 +23,35 @@ int (*p)(void) = foo;
#pragma redefine_extname baz baq
extern int baz(void);
int (*q)(void) = baz;
+
+// PR c++/30112
+// These are expected to work.
+#pragma redefine_extname gee tut
+namespace somewhere {
+ extern "C" int gee(void);
+ int (*r)(void) = gee;
+
+ extern "C" int whiz(void);
+ int whiz(int);
+}
+#pragma redefine_extname whiz bang
+int (*s)() = somewhere::whiz;
+
+namespace elsewhere {
+ extern "C" int whiz(void);
+}
+int (*t)() = elsewhere::whiz;
+
+namespace A
+{
+ extern "C" int boo(void);
+}
+
+namespace B
+{
+ extern "C" int boo(void);
+}
+#pragma redefine_extname boo eek
+
+int (*u)() = A::boo;
+int (*v)() = B::boo;
diff --git a/gcc/testsuite/gcc.dg/graphite/run-id-pr47654.c b/gcc/testsuite/gcc.dg/graphite/run-id-pr47654.c
new file mode 100644
index 00000000000..85b6e8b70f5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/run-id-pr47654.c
@@ -0,0 +1,24 @@
+/* { dg-options "-O -floop-strip-mine" } */
+
+int a[128][40];
+
+void __attribute__ ((noinline, noclone))
+foo (void)
+{
+ int i, j;
+ for (i = 0; i < 40; i++)
+ for (j = 0; j < 128; j++)
+ a[j][i] = 4;
+}
+
+int
+main ()
+{
+ int i, j;
+ foo ();
+ for (i = 0; i < 40; i++)
+ for (j = 0; j < 128; j++)
+ if (a[j][i] != 4)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr45819.c b/gcc/testsuite/gcc.dg/pr45819.c
new file mode 100644
index 00000000000..de968003ef2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr45819.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+struct ehci_regs {
+ char x;
+ unsigned int port_status[0];
+} __attribute__ ((packed));
+
+struct ehci_hcd {
+ struct ehci_regs *regs;
+};
+
+int ehci_hub_control (struct ehci_hcd *ehci, int wIndex)
+{
+ unsigned int *status_reg = &ehci->regs->port_status[wIndex];
+ return *(volatile unsigned int *)status_reg;
+}
+
+/* { dg-final { scan-tree-dump "={v}" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr49705.c b/gcc/testsuite/gcc.dg/pr49705.c
new file mode 100644
index 00000000000..0c326ae3f71
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr49705.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wstrict-overflow" } */
+
+struct glyph
+{
+ long foo, bar, baz;
+};
+
+extern int fatal (char const *, int, int);
+
+int
+check_image_width (int width, int height)
+{
+ if ((((((0 * (0 * 2 + width) - 1) < 0) ? - (~ (0 * (0 * 2 + width) + 0) == -1) - ((((0 * (0 * 2 + width) + 1) << (sizeof ((0 * 2 + width) + 0) * 8 - 2)) - 1) * 2 + 1) : (0 * (0 * 2 + width) + 0))) < 0 ? (2 < 0 ? width < ((((0 * (0 * 2 + width) - 1) < 0) ? - (~ (0 * (0 * 2 + width) + 0) == -1) - ((((0 * (0 * 2 + width) + 1) << (sizeof ((0 * 2 + width) + 0) * 8 - 2)) - 1) * 2 + 1) : (0 * (0 * 2 + width) + 0))) - 2 : ((((0 * (0 * 2 + width) - 1) < 0) ? ((((0 * (0 * 2 + width) + 1) << (sizeof ((0 * 2 + width) + 0) * 8 - 2)) - 1) * 2 + 1) : (0 * (0 * 2 + width) - 1))) - 2 < width) : width < 0 ? 2 <= width + 2 : 2 < 0 ? width <= width + 2 : width + 2 < 2)
+ || ((((((0 * (0 * height + (width + 2)) - 1) < 0) ? - (~ (0 * (0 * height + (width + 2)) + 0) == -1) - ((((0 * (0 * height + (width + 2)) + 1) << (sizeof ((0 * height + (width + 2)) + 0) * 8 - 2)) - 1) * 2 + 1) : (0 * (0 * height + (width + 2)) + 0))) == 0 && (((width + 2) < 0 && 0 < height) || (height < 0 && 0 < (width + 2)))) || (height < 0 ? ((width + 2) < 0 ? (width + 2) < ((((0 * (0 * height + (width + 2)) - 1) < 0) ? ((((0 * (0 * height + (width + 2)) + 1) << (sizeof ((0 * height + (width + 2)) + 0) * 8 - 2)) - 1) * 2 + 1) : (0 * (0 * height + (width + 2)) - 1))) / height : height == -1 ? 0 : ((((0 * (0 * height + (width + 2)) - 1) < 0) ? - (~ (0 * (0 * height + (width + 2)) + 0) == -1) - ((((0 * (0 * height + (width + 2)) + 1) << (sizeof ((0 * height + (width + 2)) + 0) * 8 - 2)) - 1) * 2 + 1) : (0 * (0 * height + (width + 2)) + 0))) / height < (width + 2)) : height == 0 ? 0 : ((width + 2) < 0 ? (width + 2) < ((((0 * (0 * height + (width + 2)) - 1) < 0) ? - (~ (0 * (0 * height + (width + 2)) + 0) == -1) - ((((0 * (0 * height + (width + 2)) + 1) << (sizeof ((0 * height + (width + 2)) + 0) * 8 - 2)) - 1) * 2 + 1) : (0 * (0 * height + (width + 2)) + 0))) / height : ((((0 * (0 * height + (width + 2)) - 1) < 0) ? ((((0 * (0 * height + (width + 2)) + 1) << (sizeof ((0 * height + (width + 2)) + 0) * 8 - 2)) - 1) * 2 + 1) : (0 * (0 * height + (width + 2)) - 1))) / height < (width + 2))))
+ || ((9223372036854775807L < 18446744073709551615UL ? 9223372036854775807L : 18446744073709551615UL) / sizeof (struct glyph)
+ < (width + 2) * height))
+ fatal ("screen size %dx%d too big", width, height);
+}
diff --git a/gcc/testsuite/gcc.target/i386/avx-vzeroupper-16.c b/gcc/testsuite/gcc.target/i386/avx-vzeroupper-16.c
index 095640a5b9c..bc6e0d23c7d 100644
--- a/gcc/testsuite/gcc.target/i386/avx-vzeroupper-16.c
+++ b/gcc/testsuite/gcc.target/i386/avx-vzeroupper-16.c
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { ! { ia32 } } } } */
+/* { dg-do compile { target lp64 } } */
/* { dg-options "-O2 -mavx -mabi=ms -mtune=generic -dp" } */
typedef float __m256 __attribute__ ((__vector_size__ (32), __may_alias__));
diff --git a/gcc/testsuite/gcc.target/i386/avx-vzeroupper-17.c b/gcc/testsuite/gcc.target/i386/avx-vzeroupper-17.c
index ef293b3d633..5d3aa48397c 100644
--- a/gcc/testsuite/gcc.target/i386/avx-vzeroupper-17.c
+++ b/gcc/testsuite/gcc.target/i386/avx-vzeroupper-17.c
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { ! { ia32 } } } } */
+/* { dg-do compile { target lp64 } } */
/* { dg-options "-O2 -mavx -mabi=ms -mtune=generic -dp" } */
typedef float __m256 __attribute__ ((__vector_size__ (32), __may_alias__));
diff --git a/gcc/testsuite/gcc.target/i386/avx-vzeroupper-18.c b/gcc/testsuite/gcc.target/i386/avx-vzeroupper-18.c
index 046b7ef1f8e..06307525d46 100644
--- a/gcc/testsuite/gcc.target/i386/avx-vzeroupper-18.c
+++ b/gcc/testsuite/gcc.target/i386/avx-vzeroupper-18.c
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { ! { ia32 } } } } */
+/* { dg-do compile { target lp64 } } */
/* { dg-options "-O0 -mavx -mabi=ms -mtune=generic -dp" } */
typedef float __m256 __attribute__ ((__vector_size__ (32), __may_alias__));
diff --git a/gcc/testsuite/gcc.target/i386/pr43662.c b/gcc/testsuite/gcc.target/i386/pr43662.c
index 5e75dc54190..2896a1a52c3 100644
--- a/gcc/testsuite/gcc.target/i386/pr43662.c
+++ b/gcc/testsuite/gcc.target/i386/pr43662.c
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { ! { ia32 } } } } */
+/* { dg-do compile { target lp64 } } */
/* { dg-options "-O2" } */
void __attribute__ ((ms_abi)) foo (void)
diff --git a/gcc/testsuite/gcc.target/i386/pr43869.c b/gcc/testsuite/gcc.target/i386/pr43869.c
index 5513b19f50e..4157db1d168 100644
--- a/gcc/testsuite/gcc.target/i386/pr43869.c
+++ b/gcc/testsuite/gcc.target/i386/pr43869.c
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { ! { ia32 } } } } */
+/* { dg-do compile { target lp64 } } */
int __attribute__((__noinline__))
bugged(float f1, float f2, float f3, float f4,
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/callabi/callabi.exp b/gcc/testsuite/gcc.target/x86_64/abi/callabi/callabi.exp
index b0cba178fa2..e76d0c10150 100644
--- a/gcc/testsuite/gcc.target/x86_64/abi/callabi/callabi.exp
+++ b/gcc/testsuite/gcc.target/x86_64/abi/callabi/callabi.exp
@@ -20,7 +20,7 @@
load_lib gcc-dg.exp
if { (![istarget x86_64-*-*] && ![istarget i?86-*-*])
- || [is-effective-target ia32] } then {
+ || [is-effective-target ilp32] } then {
return
}
diff --git a/gcc/testsuite/gfortran.dg/coarray_25.f90 b/gcc/testsuite/gfortran.dg/coarray_25.f90
new file mode 100644
index 00000000000..a78a1962b3b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/coarray_25.f90
@@ -0,0 +1,18 @@
+! { dg-do compile }
+! { dg-options "-fcoarray=single" }
+!
+! Used to be rejected with:
+! Error: Variable 'x' at (1) is a coarray or has a coarray
+! component and is not ALLOCATABLE, SAVE nor a dummy argument
+!
+! Is valid as "a" is allocatable, cf. C526
+! and http://j3-fortran.org/pipermail/j3/2011-June/004403.html
+!
+
+ subroutine test2()
+ type t
+ integer, allocatable :: a(:)[:]
+ end type t
+ type(t) :: x
+ allocate(x%a(1)[*])
+ end subroutine test2
diff --git a/gcc/testsuite/gfortran.dg/coarray_4.f90 b/gcc/testsuite/gfortran.dg/coarray_4.f90
index be2bc4edb5c..cdc4ef88e73 100644
--- a/gcc/testsuite/gfortran.dg/coarray_4.f90
+++ b/gcc/testsuite/gfortran.dg/coarray_4.f90
@@ -31,7 +31,7 @@ subroutine valid2()
integer, allocatable :: b[:]
end type tt
type(tt), save :: foo
- type(tt) :: bar ! { dg-error "is a coarray or has a coarray component" }
+ type(tt) :: bar
end subroutine valid2
subroutine invalid(n)
diff --git a/gcc/testsuite/gfortran.dg/namelist_72.f b/gcc/testsuite/gfortran.dg/namelist_72.f
new file mode 100644
index 00000000000..22c08807616
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/namelist_72.f
@@ -0,0 +1,33 @@
+! { dg-do run }
+!
+! PR fortran/49791
+!
+! Contributed by Elliott Sales de Andrade
+!
+ program namelist_test
+
+ dimension xpos(5000), ypos(5000)
+ namelist /geometry/ xpos, ypos
+
+ xpos = -huge(xpos)
+ ypos = -huge(ypos)
+
+ open(unit=4,file='geometry.in')
+ write(4,'(a)') '$geometry'
+ write(4,'(a)') ' xpos(1)= 0.00, 0.10, 0.20, 0.30, 0.40,'
+ write(4,'(a)') ' ypos(1)= 0.50, 0.60, 0.70, 0.80, 0.90,'
+ write(4,'(a)') '$end'
+
+ close(4)
+
+ open (unit=4,file='geometry.in',status='old',form='formatted')
+ read (4,geometry)
+ close(4, status='delete')
+
+ !print *, 'xpos', xpos(1:10), 'ypos', ypos(1:10)
+
+ if (any (xpos(1:5) /= [0.00, 0.10, 0.20, 0.30, 0.40]))call abort()
+ if (any (ypos(1:5) /= [0.50, 0.60, 0.70, 0.80, 0.90]))call abort()
+ if (any (xpos(6:) /= -huge(xpos))) call abort ()
+ if (any (ypos(6:) /= -huge(ypos))) call abort ()
+ end
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index bec4d6fd762..30cca9922c3 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -361,45 +361,16 @@ proc check_alias_available { } {
return $alias_available_saved
}
-###############################
-# proc check_ifunc_available { }
-###############################
-
-# Determine if the target toolchain supports the ifunc attribute.
-
-# Returns 1 if the target supports ifunc. Returns 0 if the target
-# does not support ifunc.
+# Returns 1 if the target toolchain supports ifunc, 0 otherwise.
proc check_ifunc_available { } {
- global ifunc_available_saved
- global tool
-
- if [info exists ifunc_available_saved] {
- verbose "check_ifunc_available returning saved $ifunc_available_saved" 2
- } else {
- set src ifunc[pid].c
- set obj ifunc[pid].o
- verbose "check_ifunc_available compiling testfile $src" 2
- set f [open $src "w"]
- puts $f "#endif"
- puts $f "#ifdef __cplusplus\nextern \"C\"\n#endif"
- puts $f "void g() {}"
- puts $f "void f() __attribute__((ifunc(\"g\")));"
- close $f
- set lines [${tool}_target_compile $src $obj object ""]
- file delete $src
- remote_file build delete $obj
-
- if [string match "" $lines] then {
- set ifunc_available_saved 1
- } else {
- set ifunc_available_saved 0
- }
-
- verbose "check_ifunc_available returning $ifunc_available_saved" 2
- }
-
- return $ifunc_available_saved
+ return [check_no_compiler_messages ifunc_available object {
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+ void g() {}
+ void f() __attribute__((ifunc("g")));
+ }]
}
# Returns true if --gc-sections is supported on the target.
diff --git a/gcc/toplev.c b/gcc/toplev.c
index fd1a712b89a..300d4d66ea9 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1929,6 +1929,10 @@ do_compile (void)
int
toplev_main (int argc, char **argv)
{
+ /* Parsing and gimplification sometimes need quite large stack.
+ Increase stack size limits if possible. */
+ stack_limit_increase (64 * 1024 * 1024);
+
expandargv (&argc, &argv);
/* Initialization of GCC's environment, and diagnostics. */
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index bc71dd60fa1..12079081914 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -1421,7 +1421,7 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
if (!single_succ_p (a))
return false;
- if (single_succ_edge (a)->flags & (EDGE_ABNORMAL | EDGE_EH))
+ if (single_succ_edge (a)->flags & (EDGE_ABNORMAL | EDGE_EH | EDGE_PRESERVE))
return false;
if (single_succ (a) != b)
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index c08cb18e7af..40db9285b98 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -875,6 +875,8 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
}
*def_rhs_basep = build2 (MEM_REF, TREE_TYPE (*def_rhs_basep),
new_base, new_offset);
+ TREE_THIS_VOLATILE (*def_rhs_basep) = TREE_THIS_VOLATILE (lhs);
+ TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (lhs);
gimple_assign_set_lhs (use_stmt,
unshare_expr (TREE_OPERAND (def_rhs, 0)));
*def_rhs_basep = saved;
@@ -927,9 +929,9 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
tidy_after_forward_propagate_addr (use_stmt);
return res;
}
- /* If the LHS is a plain dereference and the value type is the same as
+ /* If the RHS is a plain dereference and the value type is the same as
that of the pointed-to type of the address we can put the
- dereferenced address on the LHS preserving the original alias-type. */
+ dereferenced address on the RHS preserving the original alias-type. */
else if (gimple_assign_rhs1 (use_stmt) == rhs
&& useless_type_conversion_p
(TREE_TYPE (gimple_assign_lhs (use_stmt)),
@@ -954,6 +956,8 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
}
*def_rhs_basep = build2 (MEM_REF, TREE_TYPE (*def_rhs_basep),
new_base, new_offset);
+ TREE_THIS_VOLATILE (*def_rhs_basep) = TREE_THIS_VOLATILE (rhs);
+ TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (rhs);
gimple_assign_set_rhs1 (use_stmt,
unshare_expr (TREE_OPERAND (def_rhs, 0)));
*def_rhs_basep = saved;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index d8f9e2ecf61..86d26fbcd0f 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -235,7 +235,7 @@ get_rank (tree e)
if (TREE_CODE (e) == SSA_NAME)
{
gimple stmt;
- long rank, maxrank;
+ long rank;
int i, n;
if (TREE_CODE (SSA_NAME_VAR (e)) == PARM_DECL
@@ -258,7 +258,6 @@ get_rank (tree e)
/* Otherwise, find the maximum rank for the operands, or the bb
rank, whichever is less. */
rank = 0;
- maxrank = bb_rank[gimple_bb(stmt)->index];
if (gimple_assign_single_p (stmt))
{
tree rhs = gimple_assign_rhs1 (stmt);
@@ -267,15 +266,15 @@ get_rank (tree e)
rank = MAX (rank, get_rank (rhs));
else
{
- for (i = 0;
- i < n && TREE_OPERAND (rhs, i) && rank != maxrank; i++)
- rank = MAX(rank, get_rank (TREE_OPERAND (rhs, i)));
+ for (i = 0; i < n; i++)
+ if (TREE_OPERAND (rhs, i))
+ rank = MAX(rank, get_rank (TREE_OPERAND (rhs, i)));
}
}
else
{
n = gimple_num_ops (stmt);
- for (i = 1; i < n && rank != maxrank; i++)
+ for (i = 1; i < n; i++)
{
gcc_assert (gimple_op (stmt, i));
rank = MAX(rank, get_rank (gimple_op (stmt, i)));
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index d5a45483ab7..56f698391b7 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -9135,9 +9135,10 @@ vt_finalize (void)
cselib_finish ();
BITMAP_FREE (scratch_regs);
scratch_regs = NULL;
- VEC_free (parm_reg_t, gc, windowed_parm_regs);
}
+ VEC_free (parm_reg_t, gc, windowed_parm_regs);
+
if (vui_vec)
XDELETEVEC (vui_vec);
vui_vec = NULL;