summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-11-21 09:36:11 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-11-21 09:36:11 +0000
commit8726b204214570b8506b06e7f1af935e21cb25c9 (patch)
tree197000f9c24e34c902c5357dd6d522f430ac0722 /gcc
parent0f3b427f9513aaff0bb89af90bb60fd21aa23ce8 (diff)
downloadgcc-8726b204214570b8506b06e7f1af935e21cb25c9.tar.gz
2011-11-21 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 181552 using svnmerge git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@181554 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog357
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/ada/ChangeLog95
-rw-r--r--gcc/ada/a-cbdlli.adb53
-rw-r--r--gcc/ada/a-cfdlli.adb51
-rw-r--r--gcc/ada/checks.adb16
-rw-r--r--gcc/ada/exp_ch6.adb15
-rw-r--r--gcc/ada/exp_util.adb5
-rw-r--r--gcc/ada/gcc-interface/Makefile.in1
-rw-r--r--gcc/ada/gcc-interface/decl.c179
-rw-r--r--gcc/ada/gcc-interface/trans.c226
-rw-r--r--gcc/ada/gcc-interface/utils.c16
-rw-r--r--gcc/ada/gcc-interface/utils2.c8
-rw-r--r--gcc/ada/init.c19
-rw-r--r--gcc/ada/mlib-tgt-specific-darwin.adb12
-rw-r--r--gcc/ada/sinfo.ads5
-rw-r--r--gcc/builtins.c119
-rw-r--r--gcc/config/alpha/alpha.c4
-rw-r--r--gcc/config/arm/arm.c52
-rw-r--r--gcc/config/avr/avr-c.c15
-rw-r--r--gcc/config/avr/avr-devices.c36
-rw-r--r--gcc/config/avr/avr-protos.h12
-rw-r--r--gcc/config/avr/avr.c1856
-rw-r--r--gcc/config/avr/avr.h20
-rw-r--r--gcc/config/avr/avr.md477
-rw-r--r--gcc/config/avr/predicates.md5
-rw-r--r--gcc/config/cris/cris-protos.h2
-rw-r--r--gcc/config/cris/cris.c5
-rw-r--r--gcc/config/cris/cris.h6
-rw-r--r--gcc/config/darwin.h5
-rw-r--r--gcc/config/darwin9.h6
-rw-r--r--gcc/config/host-linux.c4
-rw-r--r--gcc/config/i386/emmintrin.h8
-rw-r--r--gcc/config/i386/i386-builtin-types.def2
-rw-r--r--gcc/config/i386/i386.c247
-rw-r--r--gcc/config/i386/i386.md1
-rw-r--r--gcc/config/i386/i386elf.h4
-rw-r--r--gcc/config/i386/mmx.md4
-rw-r--r--gcc/config/i386/sse.md77
-rw-r--r--gcc/config/mips/mips.c8
-rw-r--r--gcc/config/rs6000/rs6000.c22
-rwxr-xr-xgcc/configure16
-rw-r--r--gcc/configure.ac12
-rw-r--r--gcc/coverage.c37
-rw-r--r--gcc/cp/ChangeLog65
-rw-r--r--gcc/cp/class.c25
-rw-r--r--gcc/cp/cp-tree.def2
-rw-r--r--gcc/cp/cp-tree.h9
-rw-r--r--gcc/cp/decl.c14
-rw-r--r--gcc/cp/error.c1
-rw-r--r--gcc/cp/pt.c112
-rw-r--r--gcc/cp/ptree.c4
-rw-r--r--gcc/cp/search.c8
-rw-r--r--gcc/cp/semantics.c4
-rw-r--r--gcc/cp/tree.c2
-rw-r--r--gcc/cp/typeck.c6
-rw-r--r--gcc/cprop.c56
-rw-r--r--gcc/doc/extend.texi1
-rw-r--r--gcc/doc/invoke.texi9
-rw-r--r--gcc/expmed.c15
-rw-r--r--gcc/expr.c11
-rw-r--r--gcc/expr.h1
-rw-r--r--gcc/final.c29
-rw-r--r--gcc/fold-const.c3
-rw-r--r--gcc/fortran/ChangeLog60
-rw-r--r--gcc/fortran/class.c3
-rw-r--r--gcc/fortran/decl.c179
-rw-r--r--gcc/fortran/gfortran.h4
-rw-r--r--gcc/fortran/interface.c26
-rw-r--r--gcc/fortran/match.c3
-rw-r--r--gcc/fortran/match.h2
-rw-r--r--gcc/fortran/module.c116
-rw-r--r--gcc/fortran/parse.c6
-rw-r--r--gcc/fortran/primary.c339
-rw-r--r--gcc/fortran/resolve.c107
-rw-r--r--gcc/fortran/symbol.c244
-rw-r--r--gcc/fortran/trans-array.c5
-rw-r--r--gcc/fortran/trans-decl.c37
-rw-r--r--gcc/fortran/trans-types.c4
-rw-r--r--gcc/fortran/trans.h1
-rw-r--r--gcc/gimple.c12
-rw-r--r--gcc/optabs.c84
-rw-r--r--gcc/optabs.h4
-rw-r--r--gcc/output.h1
-rw-r--r--gcc/reorg.c4
-rw-r--r--gcc/testsuite/ChangeLog173
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/alias-decl-13.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/alias-decl-15.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/auto27.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr51150.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr51216.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/sfinae11.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/sfinae26.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/sfinae30.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/trailing2.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic120.C24
-rw-r--r--gcc/testsuite/g++.dg/debug/using6.C22
-rw-r--r--gcc/testsuite/g++.dg/eh/array1.C6
-rw-r--r--gcc/testsuite/g++.dg/gcov/gcov-10.C20
-rw-r--r--gcc/testsuite/g++.dg/gcov/gcov-11.C42
-rw-r--r--gcc/testsuite/g++.dg/gcov/gcov-8.C13
-rw-r--r--gcc/testsuite/g++.dg/gcov/gcov-9.C15
-rw-r--r--gcc/testsuite/g++.dg/ipa/pr50605.C40
-rw-r--r--gcc/testsuite/g++.dg/lookup/using46.C62
-rw-r--r--gcc/testsuite/g++.dg/lookup/using47.C29
-rw-r--r--gcc/testsuite/g++.dg/lookup/using48.C23
-rw-r--r--gcc/testsuite/g++.dg/lookup/using49.C20
-rw-r--r--gcc/testsuite/g++.dg/template/error46.C11
-rw-r--r--gcc/testsuite/g++.dg/template/unify11.C8
-rw-r--r--gcc/testsuite/g++.dg/template/virtual2.C11
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/pr50741.C14
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr44707.c2
-rw-r--r--gcc/testsuite/gcc.dg/atomic-generic-aux.c21
-rw-r--r--gcc/testsuite/gcc.dg/atomic-generic.c4
-rw-r--r--gcc/testsuite/gcc.dg/atomic-noinline-aux.c10
-rw-r--r--gcc/testsuite/gcc.dg/atomic-noinline.c2
-rw-r--r--gcc/testsuite/gcc.dg/autopar/pr49960-1.c36
-rw-r--r--gcc/testsuite/gcc.dg/autopar/pr49960.c49
-rw-r--r--gcc/testsuite/gcc.dg/cpp/assert4.c4
-rw-r--r--gcc/testsuite/gcc.dg/delay-slot-2.c116
-rw-r--r--gcc/testsuite/gcc.dg/tm/memopt-13.c1
-rw-r--r--gcc/testsuite/gcc.dg/tm/memopt-6.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr30858.c2
-rw-r--r--gcc/testsuite/gcc.dg/volatile-bitfields-1.c23
-rw-r--r--gcc/testsuite/gcc.misc-tests/gcov-13.c1
-rw-r--r--gcc/testsuite/gcc.misc-tests/gcov-16.c11
-rw-r--r--gcc/testsuite/gcc.misc-tests/gcov-17.c11
-rw-r--r--gcc/testsuite/gcc.target/arm/pr49641.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/pr51235.c17
-rw-r--r--gcc/testsuite/gcc.target/i386/pr51236.c12
-rw-r--r--gcc/testsuite/gfortran.dg/c_ptr_tests_17.f9088
-rw-r--r--gcc/testsuite/gfortran.dg/c_ptr_tests_18.f9035
-rw-r--r--gcc/testsuite/gfortran.dg/constructor_1.f9042
-rw-r--r--gcc/testsuite/gfortran.dg/constructor_2.f9073
-rw-r--r--gcc/testsuite/gfortran.dg/constructor_3.f9047
-rw-r--r--gcc/testsuite/gfortran.dg/constructor_4.f9033
-rw-r--r--gcc/testsuite/gfortran.dg/constructor_5.f9034
-rw-r--r--gcc/testsuite/gfortran.dg/constructor_6.f90171
-rw-r--r--gcc/testsuite/gfortran.dg/function_types_3.f902
-rw-r--r--gcc/testsuite/gfortran.dg/result_1.f907
-rw-r--r--gcc/testsuite/gfortran.dg/structure_constructor_3.f032
-rw-r--r--gcc/testsuite/gfortran.dg/structure_constructor_4.f032
-rw-r--r--gcc/testsuite/gfortran.dg/type_decl_3.f907
-rw-r--r--gcc/testsuite/gfortran.dg/use_only_5.f9038
-rw-r--r--gcc/testsuite/gfortran.dg/used_types_25.f9017
-rw-r--r--gcc/testsuite/gfortran.dg/used_types_26.f9022
-rw-r--r--gcc/testsuite/gnat.dg/discr32.adb21
-rw-r--r--gcc/testsuite/gnat.dg/discr32_pkg.ads24
-rw-r--r--gcc/testsuite/lib/gcc-simulate-thread.exp35
-rw-r--r--gcc/tracer.c9
-rw-r--r--gcc/tree-data-ref.c49
-rw-r--r--gcc/tree-outof-ssa.c2
-rw-r--r--gcc/tree-ssa-live.c6
153 files changed, 5807 insertions, 1697 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 09b031315af..ad20f694d90 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,358 @@
+2011-11-21 Georg-Johann Lay <avr@gjlay.de>
+
+ * config/avr/avr.h (struct base_arch_s): Add field sfr_offset.
+ * config/avr/avr-devices.c: Ditto. And initialize it.
+ * config/avr/avr-c.c (avr_cpu_cpp_builtins): New built-in define
+ __AVR_SFR_OFFSET__.
+ * config/avr/avr-protos.h (out_movqi_r_mr, out_movqi_mr_r): Remove.
+ (out_movhi_r_mr, out_movhi_mr_r): Remove.
+ (out_movsi_r_mr, out_movsi_mr_r): Remove.
+ * config/avr/avr.md (*cbi, *sbi): Use %i instead of %m-0x20.
+ (*insv.io, *insv.not.io): Ditto.
+ * config/avr/avr.c (out_movsi_r_mr, out_movsi_mr_r): Make static.
+ (print_operand): Implement "%i" to print address as I/O address.
+ (output_movqi): Clean up call of out_movqi_mr_r.
+ (output_movhi): Clean up call of out_movhi_mr_r.
+ (avr_file_start): Use avr_current_arch->sfr_offset instead of
+ magic -0x20. Use TMP_REGNO, ZERO_REGNO instead of 0, 1.
+ (avr_out_sbxx_branch): Use %i instead of %m-0x20.
+ (out_movqi_r_mr, out_movqi_mr_r): Ditto. And make static.
+ (out_movhi_r_mr, out_movhi_mr_r): Ditto. And use avr_asm_len.
+ (out_shift_with_cnt): Clean up code: Use avr_asm_len.
+ (output_movsisf): Use output_reload_insisf for all CONSTANT_P sources.
+ (avr_out_movpsi): USE avr_out_reload_inpsi for all CONSTANT_P sources.
+ Clean up call of avr_out_store_psi.
+ (output_reload_in_const): Don't cut symbols longer than 2 bytes.
+ (output_reload_insisf): Filter CONST_INT_P or CONST_DOUBLE_P to
+ try if setting pre-cleared register is advantageous.
+ (avr_out_plus_1): Use gen_int_mode instead of GEN_INT.
+
+2011-11-20 Joey Ye <joey.ye@arm.com>
+
+ * expr.c (expand_expr_real_1): Correctly handle strict volatile
+ bitfield loads smaller than mode size.
+
+2011-11-20 Richard Henderson <rth@redhat.com>
+
+ * config/mips/mips.c (mips_init_libfuncs): Call init_sync_libfuncs.
+
+2011-11-20 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/51235
+ * config/i386/i386.c (ix86_expand_vcond): Generate TARGET_XOP
+ patterns for supported mode only.
+
+ PR target/51236
+ * config/i386/i386.c (ix86_expand_builtin)
+ <IX86_BUILTIN_GATHERALTSIV4DI>: Use CODE_FOR_avx2_gathersiv4di.
+
+2011-11-20 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/i386.md (UNSPEC_MOVNTI): Remove.
+ (UNSPEC_MOVNTQ): New unspec.
+ * config/i386/mmx.md (sse_movntq): Rename from sse_movntdi.
+ Use UNSPEC_MOVNTQ instead of UNSPEC_MOVNT.
+ * config/i386/sse.md (sse2_movnti<mode>): Use UNSPEC_MOVNT instead of
+ UNSPEC_MOVNTI.
+ (STORENT_MODE): Add DI and V4DI modes.
+
+2011-11-20 Nathan Sidwell <nathan@acm.org>
+
+ PR gcov-profile/51113
+ * coverage.c (build_var): Propagate visibility for public
+ decls. Use make_decl_one_only for PIC correctness.
+
+ testsuite/
+ * gcc.misc-tests/gcov-13.c: Check gcovpart-13b coverage
+ * gcc.misc-tests/gcov-16.c: New.
+ * gcc.misc-tests/gcov-17.c: New.
+ * g++.dg/gcov/gcov-8.C: New.
+ * g++.dg/gcov/gcov-9.C: New.
+ * g++.dg/gcov/gcov-10.C: New.
+
+2011-11-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR rtl-optimization/51187
+ * reorg.c (relax_delay_slots): Do not consider a jump useless if there
+ is a barrier between the jump and its target label.
+
+2011-11-19 Patrick Marlier <patrick.marlier@gmail.com>
+
+ PR middle-end/51211
+ * tracer.c (ignore_bb_p): Don't copy GIMPLE_TRANSACTION.
+
+2011-11-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ * expmed.c (store_bit_field_1): Revert bogus formatting change.
+
+2011-11-19 Richard Earnshaw <rearnsha@arm.com>
+
+ PR target/50493
+ * config/arm/arm.c (neon_disambiguate_copy): Correctly handle partial
+ overlap of src and dest operands.
+
+2011-11-19 Iain Sandoe <iains@gcc.gnu.org>
+
+ * config/darwin.h (ASM_DEBUG_SPEC): New.
+ * config/darwin9.h (ASM_DEBUG_SPEC): New.
+
+2011-11-18 Jan Hubicka <jh@suse.cz>
+
+ * config/i386/i386.c (atom_cost): Disable SSE loop until alignment
+ issues are fixed.
+
+2011-11-18 Anatoly Sokolov <aesok@post.ru>
+
+ * config/cris/cris.c (cris_function_value_regno_p): Make static.
+ (TARGET_FUNCTION_VALUE_REGNO_P): Define.
+ * config/cris/cris.h (FUNCTION_VALUE_REGNO_P): Remove.
+ * config/cris/cris-protos.h (cris_function_value_regno_p): Remove.
+
+2011-11-18 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/33944
+ * doc/extend.texi: Document __builtin_ia32_movnti64.
+
+ * config/i386/emmintrin.h (_mm_stream_si64): New.
+
+ * config/i386/i386-builtin-types.def: Add VOID_FTYPE_PLONGLONG_LONGLONG.
+
+ * config/i386/i386.c (ix86_builtins): Add IX86_BUILTIN_MOVNTI64.
+ (bdesc_special_args): Update __builtin_ia32_movnti. Add
+ __builtin_ia32_movnti64.
+ (ix86_expand_special_args_builtin): Handle
+ VOID_FTYPE_PLONGLONG_LONGLONG.
+
+ * config/i386/i386.md (UNSPEC_MOVNTI): New.
+
+ * config/i386/sse.md (sse2_movntsi): Renamed to ...
+ (sse2_movnti<mode>): This.
+
+2011-11-18 Georg-Johann Lay <avr@gjlay.de>
+
+ PR target/49868
+ * config/avr/avr.h (base_arch_s): Add field n_segments.
+ (ADDR_SPACE_PGM1, ADDR_SPACE_PGM2, ADDR_SPACE_PGM3,
+ ADDR_SPACE_PGM4, ADDR_SPACE_PGM5, ADDR_SPACE_PGMX): New address spaces.
+ (AVR_HAVE_ELPM, AVR_HAVE_ELPMX): New defines.
+ (INIT_EXPANDERS): New define.
+ * config/avr/avr-protos.h (avr_mem_pgmx_p): New.
+ (avr_init_expanders): New.
+ (avr_emit_movmemhi, avr_out_movmem): New.
+ (avr_xload_libgcc_p): New.
+ * config/avr/avr-c.c (avr_register_target_pragmas): Register
+ address spaces __pgm1, __pgm2, __pgm3, __pgm4 __pgm5, __pgmx.
+ (avr_cpu_cpp_builtins): Add built-in defines __PGM1,
+ __PGM2, __PGM3, __PGM4, __PGM5, __PGMX.
+ * config/avr/avr-devices.c (avr_arch_types): Set field n_segments.
+
+ * config/avr/avr.c (AVR_SECTION_PROGMEM): Change define to cover
+ 3 bits instead of just 1.
+ (xstring_empty, xstring_e, rampz_rtx): New static GTYed variables.
+ (progmem_section): Change from section to array of sections.
+ (progmem_section_prefix): New static variable.
+ (avr_file_start): Print set for __RAMPZ__
+ (avr_option_override): Move initialization of RTXes from here...
+ (avr_init_expanders): ...to this new function.
+ (avr_pgm_segment): New static function.
+ (avr_decl_pgm_p): Handle error_mark_node.
+ (avr_mem_pgmx_p, avr_decl_pgmx_p): New static functions.
+ (avr_out_xload, avr_find_unused_d_reg): New static functions.
+ (expand_prologue, expand_epilogue): Use rampz_rtx.
+ (print_operand): Hande CONST_STRING.
+ (avr_xload_libgcc_p): New static function.
+ (avr_out_lpm_no_lpmx, avr_out_lpm): Handle ELPM.
+ (avr_progmem_p): Return 2 for 24-bit flash address space.
+ (avr_out_sbxx_branch): Clean-up code from ASn macros.
+ (out_movqi_r_mr, out_movqi_mr_r): Ditto. And recognize RAMPZ's
+ address and print symbolically.
+ (avr_asm_named_section, avr_section_type_flags,
+ avr_encode_section_info, avr_asm_select_section,
+ avr_addr_space_address_mode, avr_addr_space_pointer_mode,
+ avr_addr_space_legitimate_address_p, avr_addr_space_convert,
+ avr_addr_space_legitimize_address): Handle new address spaces.
+ (avr_output_progmem_section_asm_op): New static function.
+ (avr_asm_init_sections): Initialize progmem_section[].
+ (adjust_insn_length): Handle ADJUST_LEN_XLOAD, ADJUST_LEN_MOVMEM.
+ (avr_const_address_lo16): New static function.
+ (avr_assemble_integer): Use it to handle 3-byte integers.
+ (avr_emit_movmemhi, avr_out_movmem): New functions.
+
+ * config/avr/predicates.md (nox_general_operand): Handle new
+ address spaces.
+ * config/avr/avr.md (unspec): Add UNSPEC_MOVMEM.
+ (adjust_len): Add xload, movmem.
+ (SP_ADDR): New define_constants.
+ (isa): Add "lpm", "lpmx", "elpm", "elpmx".
+ (enabled): Handle them.
+ (load<mode>_libgcc): New expander.
+ (*load.<mode>.libgcc): Rename to load_<mode>_libgcc.
+ (xload8_A, xload<mode>_A): New insn-and-splits.
+ (xload_8, xload_<mode>_libgcc, xload_<mode>, loadmem_elpm): New insns.
+ (mov<mode>): Handle new address spaces.
+ (movmemhi): Rewrite using avr_emit_movmemhi.
+ (MOVMEM_r_d): New mode attribute.
+ (movmem_<mode>, movmem_qi_elpm): New insns.
+ (setmemhi, *clrmemqi, *clrmemhi, strlenhi, *strlenhi): Unquote
+ C-code. Use label instead of hard-coded instrunction lengths.
+
+2011-11-18 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/50605
+ * gimple.c (is_gimple_ip_invariant_address): Also handle MEM_REFs
+ of IPA invariant decls.
+
+2011-11-18 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ * tree-outof-ssa.c (insert_back_edge_copies): Add call to
+ mark_dfs_back_edges.
+
+2011-11-18 Iain Sandoe <iains@gcc.gnu.org>
+
+ PR target/49992
+ * configure.ac: Remove ranlib special-casing for Darwin.
+ * configure: Regenerate.
+
+2011-11-18 Uros Bizjak <ubizjak@gmail.com>
+
+ PR tree-optimization/51118
+ * fold-const.c (fold_checksum_tree): Check for TS_TYPED structure
+ before using TREE_TYPE accessor on expr.
+
+2011-11-17 Jan Hubicka <jh@suse.cz>
+
+ PR bootstrap/51134
+ * i386.c (atom_cost): Fix 32bit memset description.
+ (expand_set_or_movmem_via_loop_with_iter): Output proper bounds check
+ for epilogue loops.
+ (expand_movmem_epilogue): Handle epilogues up to size 15 w/o producing
+ byte loop.
+ (decide_alg): sse_loop is not useable wthen SSE2 is disabled;
+ when not optimizing always use rep movsb or lincall; do not produce
+ word sized loops when optimizing memset for size (to avoid need
+ for large constants).
+ (ix86_expand_movmem): Get into sync with ix86_expand_setmem;
+ choose unroll factors better; always do 128bit moves when producing
+ SSE loops; do not produce loopy epilogue when size is too small.
+ (promote_duplicated_reg_to_size): Do not look into desired alignments
+ when doing vector expansion.
+ (ix86_expand_setmem): Track better when promoted value is available;
+ choose unroll factors more sanely. Output loopy epilogue only
+ when needed.
+
+2011-11-17 Steve Ellcey <sje@cup.hp.com>
+
+ PR middle-end/51144
+ * output.h (fprint_w): Remove.
+ * final.c (fprint_w): Remove.
+ (output_addr_const): Change fprint_w back to fprintf.
+
+2011-11-17 Andrew Pinski <apinski@cavium.com>
+
+ * config/host-linux.c (TRY_EMPTY_VM_SPACE): Define for MIPS.
+
+2011-11-17 Andrew MacLeod <amacleod@redhat.com>
+
+ * builtins.c (expand_builtin): Remove 4th parameter representing
+ weak/strong mode when __atomic_compare_exchange becomes a library call.
+
+2011-11-17 Richard Henderson <rth@redhat.com>
+
+ * config/rs6000/rs6000.c (rs6000_expand_atomic_compare_and_swap): Get
+ new pseudo for target after convert_modes.
+ (rs6000_expand_atomic_exchange, rs6000_expand_atomic_op): Likewise.
+
+2011-11-17 Richard Henderson <rth@redhat.com>
+
+ * builtins.c (expand_builtin_mem_thread_fence): Remove.
+ (expand_builtin_mem_signal_fence): Remove.
+ (expand_builtin_atomic_thread_fence): Use expand_mem_thread_fence.
+ (expand_builtin_sync_synchronize): Likewise.
+ (expand_builtin_atomic_signal_fence): Use expand_mem_signal_fence.
+ * optabs.c (expand_asm_memory_barrier): Split out from
+ expand_builtin_mem_signal_fence.
+ (expand_mem_thread_fence): New, a combination of code from
+ expand_builtin_mem_thread_fence and expand_builtin_sync_synchronize.
+ (expand_mem_signal_fence): Moved and renamed from
+ expand_builtin_mem_signal_fence.
+ (expand_atomic_exchange): Use expand_mem_thread_fence.
+ (expand_atomic_load, expand_atomic_store): Likewise.
+ * expr.h, optabs.h: Update decls.
+
+2011-11-17 Bin Cheng <bin.cheng@arm.com>
+
+ PR rtl-optimization/50663
+ * cprop.c (implicit_set_indexes): New global variable.
+ (insert_set_in_table): Add additional parameter and record implicit
+ set information.
+ (hash_scan_set): Add additional parameter and pass it to above.
+ (hash_scan_insn): Pass false to hash_scan_set.
+ (compute_hash_table_work): Pass true to hash_scan_set.
+ (compute_cprop_data): Add implicit set to AVIN of block which the
+ implicit set is recorded for.
+ (one_cprop_pass): Handle implicit_set_indexes array.
+
+2011-11-17 Michael Matz <matz@suse.de>
+
+ PR middle-end/50644
+ PR middle-end/50741
+ * tree-ssa-live.c (mark_all_vars_used_1): Recurse only for decls of
+ current function.
+ (remove_unused_locals): Ditto.
+
+2011-11-16 Richard Henderson <rth@redhat.com>
+
+ * config/alpha/alpha.c (alpha_split_compare_and_swap_12): Copy
+ ALIAS_SET_MEMORY_BARRIER when creating a new memory.
+ (alpha_split_atomic_exchange_12): Likewise.
+ * config/rs6000/rs6000.c (rs6000_adjust_atomic_subword): Likewise.
+
+2011-11-16 Joseph Myers <joseph@codesourcery.com>
+
+ * config/i386/i386elf.h (PREFERRED_DEBUGGING_TYPE): Remove.
+
+2011-11-16 David Edelsohn <dje.gcc@gmail.com>
+
+ * config/rs6000/rs6000.c (rs6000_xcoff_section_type_flags):
+ Default to minimum alignment if decl is NULL.
+
+2011-11-16 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/sse.md (round<mode>2_vec_pack_sfix): Optimize V2DFmode
+ sequence for AVX.
+ (<sse4_1>_round<ssemodesuffix>_vec_pack_sfix<avxsizesuffix>): Ditto.
+
+2011-11-16 Venkataramanan Kumar <venkataramanan.kumar@amd.com>
+
+ * doc/invoke.texi: Document AMD bdver1 and btver1.
+
+2011-11-16 Richard Earnshaw <rearnsha@arm.com>
+ Bernd Schmidt <bernds@coudesourcery.com>
+ Sebastian Huber <sebastian.huber@embedded-brains.de>
+
+ PR target/49641
+ * config/arm/arm.c (store_multiple_sequence): Avoid cases where
+ the base reg is stored iff compiling for Thumb1.
+
+2011-11-16 Razya Ladelsky <razya@il.ibm.com>
+
+ PR tree-optimization/49960
+ * tree-data-ref.c (initialize_data_dependence_relation): Add
+ initializations.
+ Remove call to compute_self_dependence.
+ (compute_affine_dependence): Remove the !DDR_SELF_REFERENCE condition.
+ (compute_self_dependence): Remove old code. Add call to
+ compute_affine_dependence.
+ (compute_all_dependences): Remove call to compute_self_dependence.
+ Add call to compute_affine_dependence.
+
+2011-11-16 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
+
+ PR middle-end/50325
+ * expmed.c (store_bit_field_1): Use extract_bit_field on big
+ endian targets if the source cannot be exactly covered by word
+ mode chunks.
+
2011-11-15 Joseph Myers <joseph@codesourcery.com>
* config/i386/i386elf.h (ASM_OUTPUT_ASCII): Change STRING_LIMIT to
@@ -301,7 +656,7 @@
* ipa.c (varpool_externally_visible_p): Export.
* varpool.c (varpool_add_new_variable): New function.
-2011-11-14 Zolotukhin Michael <michael.v.zolotukhin@gmail.com>
+2011-11-14 Michael Zolotukhin <michael.v.zolotukhin@gmail.com>
Jan Hubicka <jh@suse.cz>
* config/i386/i386.h (processor_costs): Add second dimension to
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index b4ae540ba34..a2efe8dd37d 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20111116
+20111121
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index f8d6489ac83..22f5712ceee 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,11 +1,100 @@
+2011-11-20 Robert Dewar <dewar@adacore.com>
+
+ * exp_ch6.adb, exp_util.adb: Minor reformatting
+
+2011-11-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sinfo.ads (Reference): Document that it is OK to set
+ Is_Known_Non_Null on a temporary initialized to a N_Reference
+ node.
+
+2011-11-20 Matthew Heaney <heaney@adacore.com>
+
+ * a-cbdlli.adb, a-cfdlli.adb (Move): Set Last component to 0
+ for Source list.
+
+2011-11-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ * exp_ch6.adb (Make_Build_In_Place_Call_In_Assignment):
+ Declare NEW_EXPR local variable and attach the
+ temporary to it. Set Is_Known_Non_Null on the temporary.
+ (Make_Build_In_Place_Call_In_Object_Declaration): Likewise.
+ * exp_util.adb (Remove_Side_Effects): Set Is_Known_Non_Null on
+ the temporary created to hold the 'Reference of the expression,
+ if any.
+ * checks.adb (Install_Null_Excluding_Check): Bail out for the
+ Get_Current_Excep.all.all idiom generated by the expander.
+
+2011-11-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/trans.c (struct language_function): Add GNAT_RET.
+ (f_gnat_ret): New macro.
+ (struct nrv_data): Add GNAT_RET.
+ (finalize_nrv_unc_r): New helper function.
+ (finalize_nrv): Add GNAT_RET parameter. Copy it into DATA. If the
+ function returns unconstrained, use finalize_nrv_unc_r as callback.
+ (return_value_ok_for_nrv_p): Test the alignment of RET_OBJ only if
+ RET_OBJ is non-null.
+ (Subprogram_Body_to_gnu): Pass GNAT_RET to finalize_nrv.
+ (gnat_to_gnu) <N_Return_Statement>: In the return-unconstrained case,
+ if optimization is enabled, record candidates for the Named Return
+ Value optimization.
+
+2011-11-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/trans.c (Subprogram_Body_to_gnu): Add comment.
+ (gnat_to_gnu) <N_Return_Statement>: Add 'else' to avoid doing a useless
+ test. Tweak default case.
+ <N_Goto_Statement>: Use better formatting.
+ * gcc-interface/utils2.c (maybe_wrap_malloc): Use INIT_EXPR instead of
+ MODIFY_EXPR to initialize the storage.
+ (build_allocator): Likewise.
+
+2011-11-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Record_Type>: Adjust
+ call to components_to_record.
+ (components_to_record): Add FIRST_FREE_POS parameter. For the variant
+ part, reuse enclosing union even if there is a representation clause
+ on the Unchecked_Union. If there is a variant part, compute the new
+ first free position, if any. Adjust call to self. Use a single field
+ directly only if it hasn't got a representation clause or is placed at
+ offset zero. Create the variant part at offset 0 if all the fields
+ down to this level have a rep clause. Do not chain the variant part
+ immediately and adjust downstream.
+ Do not test ALL_REP before moving the fields without rep clause to the
+ previous level. Call create_rep_part to create the REP part and force
+ a minimum size on it if necessary. Do not chain it immediately.
+ Create a fake REP part if there are fields without rep clause that need
+ to be laid out starting from FIRST_FREE_POS.
+ At the end, chain the REP part and then the variant part.
+ (create_rep_part): New function.
+ (get_rep_part): Minor tweak.
+ * gcc-interface/utils.c (tree_code_for_record_type): Minor tweak.
+
+2011-11-18 Iain Sandoe <iains@gcc.gnu.org>
+
+ PR target/50678
+ * init.c (__gnat_error_handler) [Darwin]: Move workaround to the
+ bug filed as radar #10302855 from __gnat_error_handler to...
+ (__gnat_adjust_context_for_raise) [Darwin]: ...here. New function.
+ (HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE) [Darwin]: Define.
+
+2011-11-18 Tristan Gingold <gingold@adacore.com>
+ Iain Sandoe <iains@gcc.gnu.org>
+
+ PR target/49992
+ * mlib-tgt-specific-darwin.adb (Archive_Indexer_Options): Remove.
+ * gcc-interface/Makefile.in (darwin): Remove ranlib special-casing.
+
2011-11-12 Iain Sandoe <iains@gcc.gnu.org>
* gcc-interface/Makefile.in (stamp-gnatlib-$(RTSDIR)): Don't link
s-oscons.ads.
(OSCONS_CPP, OSCONS_EXTRACT): New.
- (./bldtools/oscons/xoscons): New Target.
- ($(RTSDIR)/s-oscons.ads): New Target.
- (gnatlib): Depend on $(RTSDIR)/s-oscons.ads.
+ (./bldtools/oscons/xoscons): New target.
+ ($(RTSDIR)/s-oscons.ads): Likewise.
+ (gnatlib): Depend on $(RTSDIR)/s-oscons.ads.
* gcc-interface/Make-lang.in (ada/s-oscons.ads) Remove as dependency.
* Make-generated.in: Remove machinery to generate xoscons and
ada/s-oscons.ads.
diff --git a/gcc/ada/a-cbdlli.adb b/gcc/ada/a-cbdlli.adb
index e1f7725d5cd..9e400715940 100644
--- a/gcc/ada/a-cbdlli.adb
+++ b/gcc/ada/a-cbdlli.adb
@@ -1164,18 +1164,67 @@ package body Ada.Containers.Bounded_Doubly_Linked_Lists is
"attempt to tamper with cursors of Source (list is busy)";
end if;
- Clear (Target);
+ Clear (Target); -- checks busy bit of Target
+
+ while Source.Length > 1 loop
+
+ pragma Assert (Source.First in 1 .. Source.Capacity);
+ pragma Assert (Source.Last /= Source.First);
+ pragma Assert (N (Source.First).Prev = 0);
+ pragma Assert (N (Source.Last).Next = 0);
+
+ -- Copy first element from Source to Target
- while Source.Length > 0 loop
X := Source.First;
Append (Target, N (X).Element);
+ -- Unlink first node of Source
+
Source.First := N (X).Next;
N (Source.First).Prev := 0;
Source.Length := Source.Length - 1;
+
+ -- The representation invariants for Source have been restored. It is
+ -- now safe to free the unlinked node, without fear of corrupting the
+ -- active links of Source.
+
+ -- Note that the algorithm we use here models similar algorithms used
+ -- in the unbounded form of the doubly-linked list container. In that
+ -- case, Free is an instantation of Unchecked_Deallocation, which can
+ -- fail (because PE will be raised if controlled Finalize fails), so
+ -- we must defer the call until the very last step. Here in the
+ -- bounded form, Free merely links the node we have just
+ -- "deallocated" onto a list of inactive nodes, so technically Free
+ -- cannot fail. However, for consistency, we handle Free the same way
+ -- here as we do for the unbounded form, with the pessimistic
+ -- assumption that it can fail.
+
Free (Source, X);
end loop;
+
+ if Source.Length = 1 then
+
+ pragma Assert (Source.First in 1 .. Source.Capacity);
+ pragma Assert (Source.Last = Source.First);
+ pragma Assert (N (Source.First).Prev = 0);
+ pragma Assert (N (Source.Last).Next = 0);
+
+ -- Copy element from Source to Target
+
+ X := Source.First;
+ Append (Target, N (X).Element);
+
+ -- Unlink node of Source
+
+ Source.First := 0;
+ Source.Last := 0;
+ Source.Length := 0;
+
+ -- Return the unlinked node to the free store
+
+ Free (Source, X);
+ end if;
end Move;
----------
diff --git a/gcc/ada/a-cfdlli.adb b/gcc/ada/a-cfdlli.adb
index 93a88a725d6..d1bd218972d 100644
--- a/gcc/ada/a-cfdlli.adb
+++ b/gcc/ada/a-cfdlli.adb
@@ -1007,16 +1007,65 @@ package body Ada.Containers.Formal_Doubly_Linked_Lists is
Clear (Target);
- while Source.Length > 0 loop
+ while Source.Length > 1 loop
+
+ pragma Assert (Source.First in 1 .. Source.Capacity);
+ pragma Assert (Source.Last /= Source.First);
+ pragma Assert (N (Source.First).Prev = 0);
+ pragma Assert (N (Source.Last).Next = 0);
+
+ -- Copy first element from Source to Target
+
X := Source.First;
Append (Target, N (X).Element); -- optimize away???
+ -- Unlink first node of Source
+
Source.First := N (X).Next;
N (Source.First).Prev := 0;
Source.Length := Source.Length - 1;
+
+ -- The representation invariants for Source have been restored. It is
+ -- now safe to free the unlinked node, without fear of corrupting the
+ -- active links of Source.
+
+ -- Note that the algorithm we use here models similar algorithms used
+ -- in the unbounded form of the doubly-linked list container. In that
+ -- case, Free is an instantation of Unchecked_Deallocation, which can
+ -- fail (because PE will be raised if controlled Finalize fails), so
+ -- we must defer the call until the very last step. Here in the
+ -- bounded form, Free merely links the node we have just
+ -- "deallocated" onto a list of inactive nodes, so technically Free
+ -- cannot fail. However, for consistency, we handle Free the same way
+ -- here as we do for the unbounded form, with the pessimistic
+ -- assumption that it can fail.
+
Free (Source, X);
end loop;
+
+ if Source.Length = 1 then
+
+ pragma Assert (Source.First in 1 .. Source.Capacity);
+ pragma Assert (Source.Last = Source.First);
+ pragma Assert (N (Source.First).Prev = 0);
+ pragma Assert (N (Source.Last).Next = 0);
+
+ -- Copy element from Source to Target
+
+ X := Source.First;
+ Append (Target, N (X).Element);
+
+ -- Unlink node of Source
+
+ Source.First := 0;
+ Source.Last := 0;
+ Source.Length := 0;
+
+ -- Return the unlinked node to the free store
+
+ Free (Source, X);
+ end if;
end Move;
----------
diff --git a/gcc/ada/checks.adb b/gcc/ada/checks.adb
index 67febfe1919..e6d8bf996ef 100644
--- a/gcc/ada/checks.adb
+++ b/gcc/ada/checks.adb
@@ -5673,6 +5673,22 @@ package body Checks is
return;
end if;
+ -- No check needed for the Get_Current_Excep.all.all idiom generated by
+ -- the expander within exception handlers, since we know that the value
+ -- can never be null.
+
+ -- Is this really the right way to do this? Normally we generate such
+ -- code in the expander with checks off, and that's how we suppress this
+ -- kind of junk check ???
+
+ if Nkind (N) = N_Function_Call
+ and then Nkind (Name (N)) = N_Explicit_Dereference
+ and then Nkind (Prefix (Name (N))) = N_Identifier
+ and then Is_RTE (Entity (Prefix (Name (N))), RE_Get_Current_Excep)
+ then
+ return;
+ end if;
+
-- Otherwise install access check
Insert_Action (N,
diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index 6049c452cb8..227f72921be 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -7954,6 +7954,7 @@ package body Exp_Ch6 is
Obj_Id : Entity_Id;
Ptr_Typ : Entity_Id;
Ptr_Typ_Decl : Node_Id;
+ New_Expr : Node_Id;
Result_Subt : Entity_Id;
Target : Node_Id;
@@ -8033,16 +8034,20 @@ package body Exp_Ch6 is
Insert_After_And_Analyze (Assign, Ptr_Typ_Decl);
-- Finally, create an access object initialized to a reference to the
- -- function call.
+ -- function call. We know this access value is non-null, so mark the
+ -- entity accordingly to suppress junk access checks.
- Obj_Id := Make_Temporary (Loc, 'R');
+ New_Expr := Make_Reference (Loc, Relocate_Node (Func_Call));
+
+ Obj_Id := Make_Temporary (Loc, 'R', New_Expr);
Set_Etype (Obj_Id, Ptr_Typ);
+ Set_Is_Known_Non_Null (Obj_Id);
Obj_Decl :=
Make_Object_Declaration (Loc,
Defining_Identifier => Obj_Id,
Object_Definition => New_Reference_To (Ptr_Typ, Loc),
- Expression => Make_Reference (Loc, Relocate_Node (Func_Call)));
+ Expression => New_Expr);
Insert_After_And_Analyze (Ptr_Typ_Decl, Obj_Decl);
Rewrite (Assign, Make_Null_Statement (Loc));
@@ -8295,12 +8300,14 @@ package body Exp_Ch6 is
end if;
-- Finally, create an access object initialized to a reference to the
- -- function call.
+ -- function call. We know this access value cannot be null, so mark the
+ -- entity accordingly to suppress the access check.
New_Expr := Make_Reference (Loc, Relocate_Node (Func_Call));
Def_Id := Make_Temporary (Loc, 'R', New_Expr);
Set_Etype (Def_Id, Ref_Type);
+ Set_Is_Known_Non_Null (Def_Id);
Insert_After_And_Analyze (Ptr_Typ_Decl,
Make_Object_Declaration (Loc,
diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb
index e675da82889..37a1be0e478 100644
--- a/gcc/ada/exp_util.adb
+++ b/gcc/ada/exp_util.adb
@@ -6710,8 +6710,13 @@ package body Exp_Util is
if Alfa_Mode then
New_Exp := E;
+
+ -- Otherwise generate reference, marking the value as non-null
+ -- since we know it cannot be null and we don't want a check.
+
else
New_Exp := Make_Reference (Loc, E);
+ Set_Is_Known_Non_Null (Def_Id);
end if;
end if;
diff --git a/gcc/ada/gcc-interface/Makefile.in b/gcc/ada/gcc-interface/Makefile.in
index d000b5df779..ebb7ddb949f 100644
--- a/gcc/ada/gcc-interface/Makefile.in
+++ b/gcc/ada/gcc-interface/Makefile.in
@@ -2182,7 +2182,6 @@ ifeq ($(strip $(filter-out darwin%,$(osys))),)
EH_MECHANISM=-gcc
GNATLIB_SHARED = gnatlib-shared-darwin
- RANLIB = ranlib -c
GMEM_LIB = gmemlib
LIBRARY_VERSION := $(LIB_VERSION)
soext = .dylib
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index d7ca5dbbe6e..12971a63038 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -160,7 +160,7 @@ static bool compile_time_known_address_p (Node_Id);
static bool cannot_be_superflat_p (Node_Id);
static bool constructor_address_p (tree);
static void components_to_record (tree, Node_Id, tree, int, bool, bool, bool,
- bool, bool, bool, bool, tree *);
+ bool, bool, bool, bool, tree, tree *);
static Uint annotate_value (tree);
static void annotate_rep (Entity_Id, tree);
static tree build_position_list (tree, bool, tree, tree, unsigned int, tree);
@@ -176,6 +176,7 @@ static unsigned int ceil_alignment (unsigned HOST_WIDE_INT);
static void check_ok_for_atomic (tree, Entity_Id, bool);
static tree create_field_decl_from (tree, tree, tree, tree, tree,
VEC(subst_pair,heap) *);
+static tree create_rep_part (tree, tree, tree);
static tree get_rep_part (tree);
static tree create_variant_part_from (tree, VEC(variant_desc,heap) *, tree,
tree, VEC(subst_pair,heap) *);
@@ -3048,7 +3049,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
gnu_field_list, packed, definition, false,
all_rep, is_unchecked_union, debug_info_p,
false, OK_To_Reorder_Components (gnat_entity),
- NULL);
+ all_rep ? NULL_TREE : bitsize_zero_node, NULL);
/* If it is passed by reference, force BLKmode to ensure that objects
of this type will always be put in memory. */
@@ -7096,6 +7097,10 @@ compare_field_bitpos (const PTR rt1, const PTR rt2)
REORDER is true if we are permitted to reorder components of this type.
+ FIRST_FREE_POS, if nonzero, is the first (lowest) free field position in
+ the outer record type down to this variant level. It is nonzero only if
+ all the fields down to this level have a rep clause and ALL_REP is false.
+
P_GNU_REP_LIST, if nonzero, is a pointer to a list to which each field
with a rep clause is to be added; in this case, that is all that should
be done with such fields. */
@@ -7106,12 +7111,13 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
bool cancel_alignment, bool all_rep,
bool unchecked_union, bool debug_info,
bool maybe_unused, bool reorder,
- tree *p_gnu_rep_list)
+ tree first_free_pos, tree *p_gnu_rep_list)
{
bool all_rep_and_size = all_rep && TYPE_SIZE (gnu_record_type);
bool layout_with_rep = false;
Node_Id component_decl, variant_part;
tree gnu_field, gnu_next, gnu_last;
+ tree gnu_rep_part = NULL_TREE;
tree gnu_variant_part = NULL_TREE;
tree gnu_rep_list = NULL_TREE;
tree gnu_var_list = NULL_TREE;
@@ -7185,7 +7191,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
= concat_name (get_identifier (Get_Name_String (Chars (gnat_discr))),
"XVN");
tree gnu_union_type, gnu_union_name;
- tree gnu_variant_list = NULL_TREE;
+ tree this_first_free_pos, gnu_variant_list = NULL_TREE;
if (TREE_CODE (gnu_name) == TYPE_DECL)
gnu_name = DECL_NAME (gnu_name);
@@ -7193,12 +7199,10 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
gnu_union_name
= concat_name (gnu_name, IDENTIFIER_POINTER (gnu_var_name));
- /* Reuse an enclosing union if all fields are in the variant part
- and there is no representation clause on the record, to match
- the layout of C unions. There is an associated check below. */
- if (!gnu_field_list
- && TREE_CODE (gnu_record_type) == UNION_TYPE
- && !TYPE_PACKED (gnu_record_type))
+ /* Reuse the enclosing union if this is an Unchecked_Union whose fields
+ are all in the variant part, to match the layout of C unions. There
+ is an associated check below. */
+ if (TREE_CODE (gnu_record_type) == UNION_TYPE)
gnu_union_type = gnu_record_type;
else
{
@@ -7210,6 +7214,29 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
TYPE_PACKED (gnu_union_type) = TYPE_PACKED (gnu_record_type);
}
+ /* If all the fields down to this level have a rep clause, find out
+ whether all the fields at this level also have one. If so, then
+ compute the new first free position to be passed downward. */
+ this_first_free_pos = first_free_pos;
+ if (this_first_free_pos)
+ {
+ for (gnu_field = gnu_field_list;
+ gnu_field;
+ gnu_field = DECL_CHAIN (gnu_field))
+ if (DECL_FIELD_OFFSET (gnu_field))
+ {
+ tree pos = bit_position (gnu_field);
+ if (!tree_int_cst_lt (pos, this_first_free_pos))
+ this_first_free_pos
+ = size_binop (PLUS_EXPR, pos, DECL_SIZE (gnu_field));
+ }
+ else
+ {
+ this_first_free_pos = NULL_TREE;
+ break;
+ }
+ }
+
for (variant = First_Non_Pragma (Variants (variant_part));
Present (variant);
variant = Next_Non_Pragma (variant))
@@ -7231,8 +7258,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
TYPE_PACKED (gnu_variant_type) = TYPE_PACKED (gnu_record_type);
/* Similarly, if the outer record has a size specified and all
- fields have record rep clauses, we can propagate the size
- into the variant part. */
+ the fields have a rep clause, we can propagate the size. */
if (all_rep_and_size)
{
TYPE_SIZE (gnu_variant_type) = TYPE_SIZE (gnu_record_type);
@@ -7244,20 +7270,24 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
we aren't sure to really use it at this point, see below. */
components_to_record (gnu_variant_type, Component_List (variant),
NULL_TREE, packed, definition,
- !all_rep_and_size, all_rep,
- unchecked_union, debug_info,
- true, reorder, &gnu_rep_list);
+ !all_rep_and_size, all_rep, unchecked_union,
+ debug_info, true, reorder, this_first_free_pos,
+ all_rep || this_first_free_pos
+ ? NULL : &gnu_rep_list);
gnu_qual = choices_to_gnu (gnu_discr, Discrete_Choices (variant));
-
Set_Present_Expr (variant, annotate_value (gnu_qual));
- /* If this is an Unchecked_Union and we have exactly one field,
- use this field directly to match the layout of C unions. */
- if (unchecked_union
- && TYPE_FIELDS (gnu_variant_type)
- && !DECL_CHAIN (TYPE_FIELDS (gnu_variant_type)))
- gnu_field = TYPE_FIELDS (gnu_variant_type);
+ /* If this is an Unchecked_Union whose fields are all in the variant
+ part and we have a single field with no representation clause or
+ placed at offset zero, use the field directly to match the layout
+ of C unions. */
+ if (TREE_CODE (gnu_record_type) == UNION_TYPE
+ && (gnu_field = TYPE_FIELDS (gnu_variant_type)) != NULL_TREE
+ && !DECL_CHAIN (gnu_field)
+ && (!DECL_FIELD_OFFSET (gnu_field)
+ || integer_zerop (bit_position (gnu_field))))
+ DECL_CONTEXT (gnu_field) = gnu_union_type;
else
{
/* Deal with packedness like in gnat_to_gnu_field. */
@@ -7328,15 +7358,18 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
gnu_variant_part
= create_field_decl (gnu_var_name, gnu_union_type, gnu_record_type,
all_rep ? TYPE_SIZE (gnu_union_type) : 0,
- all_rep ? bitsize_zero_node : 0,
+ all_rep || this_first_free_pos
+ ? bitsize_zero_node : 0,
union_field_packed, 0);
DECL_INTERNAL_P (gnu_variant_part) = 1;
- DECL_CHAIN (gnu_variant_part) = gnu_field_list;
- gnu_field_list = gnu_variant_part;
}
}
+ /* From now on, a zero FIRST_FREE_POS is totally useless. */
+ if (first_free_pos && integer_zerop (first_free_pos))
+ first_free_pos = NULL_TREE;
+
/* Scan GNU_FIELD_LIST and see if any fields have rep clauses and, if we are
permitted to reorder components, self-referential sizes or variable sizes.
If they do, pull them out and put them onto the appropriate list. We have
@@ -7368,33 +7401,24 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
continue;
}
- if (reorder)
+ /* Reorder non-internal fields with non-fixed size. */
+ if (reorder
+ && !DECL_INTERNAL_P (gnu_field)
+ && !(DECL_SIZE (gnu_field)
+ && TREE_CODE (DECL_SIZE (gnu_field)) == INTEGER_CST))
{
- /* Pull out the variant part and put it onto GNU_SELF_LIST. */
- if (gnu_field == gnu_variant_part)
+ tree type_size = TYPE_SIZE (TREE_TYPE (gnu_field));
+
+ if (CONTAINS_PLACEHOLDER_P (type_size))
{
MOVE_FROM_FIELD_LIST_TO (gnu_self_list);
continue;
}
- /* Skip internal fields and fields with fixed size. */
- if (!DECL_INTERNAL_P (gnu_field)
- && !(DECL_SIZE (gnu_field)
- && TREE_CODE (DECL_SIZE (gnu_field)) == INTEGER_CST))
+ if (TREE_CODE (type_size) != INTEGER_CST)
{
- tree type_size = TYPE_SIZE (TREE_TYPE (gnu_field));
-
- if (CONTAINS_PLACEHOLDER_P (type_size))
- {
- MOVE_FROM_FIELD_LIST_TO (gnu_self_list);
- continue;
- }
-
- if (TREE_CODE (type_size) != INTEGER_CST)
- {
- MOVE_FROM_FIELD_LIST_TO (gnu_var_list);
- continue;
- }
+ MOVE_FROM_FIELD_LIST_TO (gnu_var_list);
+ continue;
}
}
@@ -7416,14 +7440,14 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
= chainon (nreverse (gnu_self_list),
chainon (nreverse (gnu_var_list), gnu_field_list));
- /* If we have any fields in our rep'ed field list and it is not the case that
- all the fields in the record have rep clauses and P_REP_LIST is nonzero,
- set it and ignore these fields. */
- if (gnu_rep_list && p_gnu_rep_list && !all_rep)
+ /* If P_REP_LIST is nonzero, this means that we are asked to move the fields
+ in our REP list to the previous level because this level needs them in
+ order to do a correct layout, i.e. avoid having overlapping fields. */
+ if (p_gnu_rep_list && gnu_rep_list)
*p_gnu_rep_list = chainon (*p_gnu_rep_list, gnu_rep_list);
/* Otherwise, sort the fields by bit position and put them into their own
- record, before the others, if we also have fields without rep clauses. */
+ record, before the others, if we also have fields without rep clause. */
else if (gnu_rep_list)
{
tree gnu_rep_type
@@ -7451,11 +7475,12 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
if (gnu_field_list)
{
finish_record_type (gnu_rep_type, gnu_rep_list, 1, debug_info);
- gnu_field
- = create_field_decl (get_identifier ("REP"), gnu_rep_type,
- gnu_record_type, NULL_TREE, NULL_TREE, 0, 1);
- DECL_INTERNAL_P (gnu_field) = 1;
- gnu_field_list = chainon (gnu_field_list, gnu_field);
+
+ /* If FIRST_FREE_POS is nonzero, we need to ensure that the fields
+ without rep clause are laid out starting from this position.
+ Therefore, we force it as a minimal size on the REP part. */
+ gnu_rep_part
+ = create_rep_part (gnu_rep_type, gnu_record_type, first_free_pos);
}
else
{
@@ -7464,6 +7489,28 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
}
}
+ /* If FIRST_FREE_POS is nonzero, we need to ensure that the fields without
+ rep clause are laid out starting from this position. Therefore, if we
+ have not already done so, we create a fake REP part with this size. */
+ if (first_free_pos && !layout_with_rep && !gnu_rep_part)
+ {
+ tree gnu_rep_type = make_node (RECORD_TYPE);
+ finish_record_type (gnu_rep_type, NULL_TREE, 0, debug_info);
+ gnu_rep_part
+ = create_rep_part (gnu_rep_type, gnu_record_type, first_free_pos);
+ }
+
+ /* Now chain the REP part at the end of the reversed field list. */
+ if (gnu_rep_part)
+ gnu_field_list = chainon (gnu_field_list, gnu_rep_part);
+
+ /* And the variant part at the beginning. */
+ if (gnu_variant_part)
+ {
+ DECL_CHAIN (gnu_variant_part) = gnu_field_list;
+ gnu_field_list = gnu_variant_part;
+ }
+
if (cancel_alignment)
TYPE_ALIGN (gnu_record_type) = 0;
@@ -8567,6 +8614,24 @@ create_field_decl_from (tree old_field, tree field_type, tree record_type,
return new_field;
}
+/* Create the REP part of RECORD_TYPE with REP_TYPE. If MIN_SIZE is nonzero,
+ it is the minimal size the REP_PART must have. */
+
+static tree
+create_rep_part (tree rep_type, tree record_type, tree min_size)
+{
+ tree field;
+
+ if (min_size && !tree_int_cst_lt (TYPE_SIZE (rep_type), min_size))
+ min_size = NULL_TREE;
+
+ field = create_field_decl (get_identifier ("REP"), rep_type, record_type,
+ min_size, bitsize_zero_node, 0, 1);
+ DECL_INTERNAL_P (field) = 1;
+
+ return field;
+}
+
/* Return the REP part of RECORD_TYPE, if any. Otherwise return NULL. */
static tree
@@ -8575,10 +8640,10 @@ get_rep_part (tree record_type)
tree field = TYPE_FIELDS (record_type);
/* The REP part is the first field, internal, another record, and its name
- doesn't start with an underscore (i.e. is not generated by the FE). */
+ starts with an 'R'. */
if (DECL_INTERNAL_P (field)
&& TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
- && IDENTIFIER_POINTER (DECL_NAME (field)) [0] != '_')
+ && IDENTIFIER_POINTER (DECL_NAME (field)) [0] == 'R')
return field;
return NULL_TREE;
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 8a74e6ccb45..42b4e9154c3 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -129,6 +129,7 @@ struct GTY(()) language_function {
VEC(parm_attr,gc) *parm_attr_cache;
bitmap named_ret_val;
VEC(tree,gc) *other_ret_val;
+ int gnat_ret;
};
#define f_parm_attr_cache \
@@ -140,6 +141,9 @@ struct GTY(()) language_function {
#define f_other_ret_val \
DECL_STRUCT_FUNCTION (current_function_decl)->language->other_ret_val
+#define f_gnat_ret \
+ DECL_STRUCT_FUNCTION (current_function_decl)->language->gnat_ret
+
/* A structure used to gather together information about a statement group.
We use this to gather related statements, for example the "then" part
of a IF. In the case where it represents a lexical scope, we may also
@@ -2674,12 +2678,20 @@ establish_gnat_vms_condition_handler (void)
first list. These are the Named Return Values.
4. Adjust the relevant RETURN_EXPRs and replace the occurrences of the
- Named Return Values in the function with the RESULT_DECL. */
+ Named Return Values in the function with the RESULT_DECL.
+
+ If the function returns an unconstrained type, things are a bit different
+ because the anonymous return object is allocated on the secondary stack
+ and RESULT_DECL is only a pointer to it. Each return object can be of a
+ different size and is allocated separately so we need not care about the
+ aforementioned overlapping issues. Therefore, we don't collect the other
+ expressions and skip step #2 in the algorithm. */
struct nrv_data
{
bitmap nrv;
tree result;
+ Node_Id gnat_ret;
struct pointer_set_t *visited;
};
@@ -2812,8 +2824,153 @@ finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
*tp = convert (TREE_TYPE (t), dp->result);
/* Avoid walking into the same tree more than once. Unfortunately, we
- can't just use walk_tree_without_duplicates because it would only call
- us for the first occurrence of NRVs in the function body. */
+ can't just use walk_tree_without_duplicates because it would only
+ call us for the first occurrence of NRVs in the function body. */
+ if (pointer_set_insert (dp->visited, *tp))
+ *walk_subtrees = 0;
+
+ return NULL_TREE;
+}
+
+/* Likewise, but used when the function returns an unconstrained type. */
+
+static tree
+finalize_nrv_unc_r (tree *tp, int *walk_subtrees, void *data)
+{
+ struct nrv_data *dp = (struct nrv_data *)data;
+ tree t = *tp;
+
+ /* No need to walk into types. */
+ if (TYPE_P (t))
+ *walk_subtrees = 0;
+
+ /* We need to see the DECL_EXPR of NRVs before any other references so we
+ walk the body of BIND_EXPR before walking its variables. */
+ else if (TREE_CODE (t) == BIND_EXPR)
+ walk_tree (&BIND_EXPR_BODY (t), finalize_nrv_unc_r, data, NULL);
+
+ /* Change RETURN_EXPRs of NRVs to assign to the RESULT_DECL only the final
+ return value built by the allocator instead of the whole construct. */
+ else if (TREE_CODE (t) == RETURN_EXPR
+ && TREE_CODE (TREE_OPERAND (t, 0)) == MODIFY_EXPR)
+ {
+ tree ret_val = TREE_OPERAND (TREE_OPERAND (t, 0), 1);
+
+ /* This is the construct returned by the allocator. */
+ if (TREE_CODE (ret_val) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (ret_val, 0)) == INIT_EXPR)
+ {
+ if (TYPE_IS_FAT_POINTER_P (TREE_TYPE (ret_val)))
+ ret_val
+ = VEC_index (constructor_elt,
+ CONSTRUCTOR_ELTS
+ (TREE_OPERAND (TREE_OPERAND (ret_val, 0), 1)),
+ 1)->value;
+ else
+ ret_val = TREE_OPERAND (TREE_OPERAND (ret_val, 0), 1);
+ }
+
+ /* Strip useless conversions around the return value. */
+ if (gnat_useless_type_conversion (ret_val)
+ || TREE_CODE (ret_val) == VIEW_CONVERT_EXPR)
+ ret_val = TREE_OPERAND (ret_val, 0);
+
+ /* Strip unpadding around the return value. */
+ if (TREE_CODE (ret_val) == COMPONENT_REF
+ && TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (ret_val, 0))))
+ ret_val = TREE_OPERAND (ret_val, 0);
+
+ /* Assign the new return value to the RESULT_DECL. */
+ if (is_nrv_p (dp->nrv, ret_val))
+ TREE_OPERAND (TREE_OPERAND (t, 0), 1)
+ = TREE_OPERAND (DECL_INITIAL (ret_val), 0);
+ }
+
+ /* Adjust the DECL_EXPR of NRVs to call the allocator and save the result
+ into a new variable. */
+ else if (TREE_CODE (t) == DECL_EXPR
+ && is_nrv_p (dp->nrv, DECL_EXPR_DECL (t)))
+ {
+ tree saved_current_function_decl = current_function_decl;
+ tree var = DECL_EXPR_DECL (t);
+ tree alloc, p_array, new_var, new_ret;
+ VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 2);
+
+ /* Create an artificial context to build the allocation. */
+ current_function_decl = decl_function_context (var);
+ start_stmt_group ();
+ gnat_pushlevel ();
+
+ /* This will return a COMPOUND_EXPR with the allocation in the first
+ arm and the final return value in the second arm. */
+ alloc = build_allocator (TREE_TYPE (var), DECL_INITIAL (var),
+ TREE_TYPE (dp->result),
+ Procedure_To_Call (dp->gnat_ret),
+ Storage_Pool (dp->gnat_ret),
+ Empty, false);
+
+ /* The new variable is built as a reference to the allocated space. */
+ new_var
+ = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, DECL_NAME (var),
+ build_reference_type (TREE_TYPE (var)));
+ DECL_BY_REFERENCE (new_var) = 1;
+
+ if (TYPE_IS_FAT_POINTER_P (TREE_TYPE (alloc)))
+ {
+ /* The new initial value is a COMPOUND_EXPR with the allocation in
+ the first arm and the value of P_ARRAY in the second arm. */
+ DECL_INITIAL (new_var)
+ = build2 (COMPOUND_EXPR, TREE_TYPE (new_var),
+ TREE_OPERAND (alloc, 0),
+ VEC_index (constructor_elt,
+ CONSTRUCTOR_ELTS (TREE_OPERAND (alloc, 1)),
+ 0)->value);
+
+ /* Build a modified CONSTRUCTOR that references NEW_VAR. */
+ p_array = TYPE_FIELDS (TREE_TYPE (alloc));
+ CONSTRUCTOR_APPEND_ELT (v, p_array,
+ fold_convert (TREE_TYPE (p_array), new_var));
+ CONSTRUCTOR_APPEND_ELT (v, DECL_CHAIN (p_array),
+ VEC_index (constructor_elt,
+ CONSTRUCTOR_ELTS
+ (TREE_OPERAND (alloc, 1)),
+ 1)->value);
+ new_ret = build_constructor (TREE_TYPE (alloc), v);
+ }
+ else
+ {
+ /* The new initial value is just the allocation. */
+ DECL_INITIAL (new_var) = alloc;
+ new_ret = fold_convert (TREE_TYPE (alloc), new_var);
+ }
+
+ gnat_pushdecl (new_var, Empty);
+
+ /* Destroy the artificial context and insert the new statements. */
+ gnat_zaplevel ();
+ *tp = end_stmt_group ();
+ current_function_decl = saved_current_function_decl;
+
+ /* Chain NEW_VAR immediately after VAR and ignore the latter. */
+ DECL_CHAIN (new_var) = DECL_CHAIN (var);
+ DECL_CHAIN (var) = new_var;
+ DECL_IGNORED_P (var) = 1;
+
+ /* Save the new return value and the dereference of NEW_VAR. */
+ DECL_INITIAL (var)
+ = build2 (COMPOUND_EXPR, TREE_TYPE (var), new_ret,
+ build1 (INDIRECT_REF, TREE_TYPE (var), new_var));
+ /* ??? Kludge to avoid messing up during inlining. */
+ DECL_CONTEXT (var) = NULL_TREE;
+ }
+
+ /* And replace all uses of NRVs with the dereference of NEW_VAR. */
+ else if (is_nrv_p (dp->nrv, t))
+ *tp = TREE_OPERAND (DECL_INITIAL (t), 1);
+
+ /* Avoid walking into the same tree more than once. Unfortunately, we
+ can't just use walk_tree_without_duplicates because it would only
+ call us for the first occurrence of NRVs in the function body. */
if (pointer_set_insert (dp->visited, *tp))
*walk_subtrees = 0;
@@ -2822,13 +2979,14 @@ finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
/* Finalize the Named Return Value optimization for FNDECL. The NRV bitmap
contains the candidates for Named Return Value and OTHER is a list of
- the other return values. */
+ the other return values. GNAT_RET is a representative return node. */
static void
-finalize_nrv (tree fndecl, bitmap nrv, VEC(tree,gc) *other)
+finalize_nrv (tree fndecl, bitmap nrv, VEC(tree,gc) *other, Node_Id gnat_ret)
{
struct cgraph_node *node;
struct nrv_data data;
+ walk_tree_fn func;
unsigned int i;
tree iter;
@@ -2860,8 +3018,13 @@ finalize_nrv (tree fndecl, bitmap nrv, VEC(tree,gc) *other)
/* Adjust the relevant RETURN_EXPRs and replace the occurrences of NRVs. */
data.nrv = nrv;
data.result = DECL_RESULT (fndecl);
+ data.gnat_ret = gnat_ret;
data.visited = pointer_set_create ();
- walk_tree (&DECL_SAVED_TREE (fndecl), finalize_nrv_r, &data, NULL);
+ if (TYPE_RETURN_UNCONSTRAINED_P (TREE_TYPE (fndecl)))
+ func = finalize_nrv_unc_r;
+ else
+ func = finalize_nrv_r;
+ walk_tree (&DECL_SAVED_TREE (fndecl), func, &data, NULL);
pointer_set_destroy (data.visited);
}
@@ -2886,7 +3049,7 @@ return_value_ok_for_nrv_p (tree ret_obj, tree ret_val)
if (TREE_ADDRESSABLE (ret_val))
return false;
- if (DECL_ALIGN (ret_val) > DECL_ALIGN (ret_obj))
+ if (ret_obj && DECL_ALIGN (ret_val) > DECL_ALIGN (ret_obj))
return false;
return true;
@@ -3278,6 +3441,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
save_gnu_tree (gnat_param, NULL_TREE, false);
}
+ /* Disconnect the variable created for the return value. */
if (gnu_return_var_elmt)
TREE_VALUE (gnu_return_var_elmt) = void_type_node;
@@ -3285,8 +3449,10 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
a Named Return Value, finalize the optimization. */
if (optimize && gnu_subprog_language->named_ret_val)
{
- finalize_nrv (gnu_subprog_decl, gnu_subprog_language->named_ret_val,
- gnu_subprog_language->other_ret_val);
+ finalize_nrv (gnu_subprog_decl,
+ gnu_subprog_language->named_ret_val,
+ gnu_subprog_language->other_ret_val,
+ gnu_subprog_language->gnat_ret);
gnu_subprog_language->named_ret_val = NULL;
gnu_subprog_language->other_ret_val = NULL;
}
@@ -5881,6 +6047,34 @@ gnat_to_gnu (Node_Id gnat_node)
else if (TYPE_RETURN_UNCONSTRAINED_P (gnu_subprog_type))
{
gnu_ret_val = maybe_unconstrained_array (gnu_ret_val);
+
+ /* And find out whether this is a candidate for Named Return
+ Value. If so, record it. */
+ if (!TYPE_CI_CO_LIST (gnu_subprog_type) && optimize)
+ {
+ tree ret_val = gnu_ret_val;
+
+ /* Strip useless conversions around the return value. */
+ if (gnat_useless_type_conversion (ret_val))
+ ret_val = TREE_OPERAND (ret_val, 0);
+
+ /* Strip unpadding around the return value. */
+ if (TREE_CODE (ret_val) == COMPONENT_REF
+ && TYPE_IS_PADDING_P
+ (TREE_TYPE (TREE_OPERAND (ret_val, 0))))
+ ret_val = TREE_OPERAND (ret_val, 0);
+
+ /* Now apply the test to the return value. */
+ if (return_value_ok_for_nrv_p (NULL_TREE, ret_val))
+ {
+ if (!f_named_ret_val)
+ f_named_ret_val = BITMAP_GGC_ALLOC ();
+ bitmap_set_bit (f_named_ret_val, DECL_UID (ret_val));
+ if (!f_gnat_ret)
+ f_gnat_ret = gnat_node;
+ }
+ }
+
gnu_ret_val = build_allocator (TREE_TYPE (gnu_ret_val),
gnu_ret_val,
TREE_TYPE (gnu_ret_obj),
@@ -5889,12 +6083,12 @@ gnat_to_gnu (Node_Id gnat_node)
gnat_node, false);
}
- /* If the function returns by invisible reference, dereference
+ /* Otherwise, if it 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))
+ else if (TREE_ADDRESSABLE (gnu_subprog_type))
{
tree gnu_ret_deref
= build_unary_op (INDIRECT_REF, TREE_TYPE (gnu_ret_val),
@@ -5905,11 +6099,9 @@ gnat_to_gnu (Node_Id gnat_node)
gnu_ret_val = NULL_TREE;
}
}
+
else
- {
- gnu_ret_obj = NULL_TREE;
- gnu_ret_val = NULL_TREE;
- }
+ gnu_ret_obj = gnu_ret_val = NULL_TREE;
/* If we have a return label defined, convert this into a branch to
that label. The return proper will be handled elsewhere. */
@@ -5934,8 +6126,8 @@ gnat_to_gnu (Node_Id gnat_node)
break;
case N_Goto_Statement:
- gnu_result = build1 (GOTO_EXPR, void_type_node,
- gnat_to_gnu (Name (gnat_node)));
+ gnu_result
+ = build1 (GOTO_EXPR, void_type_node, gnat_to_gnu (Name (gnat_node)));
break;
/***************************/
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 73657528a8a..a71a3d28878 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -4744,19 +4744,17 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
enum tree_code
tree_code_for_record_type (Entity_Id gnat_type)
{
- Node_Id component_list
- = Component_List (Type_Definition
- (Declaration_Node
- (Implementation_Base_Type (gnat_type))));
- Node_Id component;
-
- /* Make this a UNION_TYPE unless it's either not an Unchecked_Union or
- we have a non-discriminant field outside a variant. In either case,
- it's a RECORD_TYPE. */
+ Node_Id component_list, component;
+ /* Return UNION_TYPE if it's an Unchecked_Union whose non-discriminant
+ fields are all in the variant part. Otherwise, return RECORD_TYPE. */
if (!Is_Unchecked_Union (gnat_type))
return RECORD_TYPE;
+ gnat_type = Implementation_Base_Type (gnat_type);
+ component_list
+ = Component_List (Type_Definition (Declaration_Node (gnat_type)));
+
for (component = First_Non_Pragma (Component_Items (component_list));
Present (component);
component = Next_Non_Pragma (component))
diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c
index c303e2f20a3..f9e48b79fe5 100644
--- a/gcc/ada/gcc-interface/utils2.c
+++ b/gcc/ada/gcc-interface/utils2.c
@@ -2126,7 +2126,7 @@ maybe_wrap_malloc (tree data_size, tree data_type, Node_Id gnat_node)
return
build2 (COMPOUND_EXPR, TREE_TYPE (aligning_field_addr),
- build_binary_op (MODIFY_EXPR, NULL_TREE,
+ build_binary_op (INIT_EXPR, NULL_TREE,
storage_ptr_slot, storage_ptr),
aligning_field_addr);
}
@@ -2279,12 +2279,12 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
CONSTRUCTOR_APPEND_ELT (v, DECL_CHAIN (TYPE_FIELDS (storage_type)),
init);
storage_init
- = build_binary_op (MODIFY_EXPR, NULL_TREE, storage_deref,
+ = build_binary_op (INIT_EXPR, NULL_TREE, storage_deref,
gnat_build_constructor (storage_type, v));
}
else
storage_init
- = build_binary_op (MODIFY_EXPR, NULL_TREE,
+ = build_binary_op (INIT_EXPR, NULL_TREE,
build_component_ref (storage_deref, NULL_TREE,
TYPE_FIELDS (storage_type),
false),
@@ -2332,7 +2332,7 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
storage_deref = build_unary_op (INDIRECT_REF, NULL_TREE, storage);
TREE_THIS_NOTRAP (storage_deref) = 1;
storage_init
- = build_binary_op (MODIFY_EXPR, NULL_TREE, storage_deref, init);
+ = build_binary_op (INIT_EXPR, NULL_TREE, storage_deref, init);
return build2 (COMPOUND_EXPR, result_type, storage_init, storage);
}
diff --git a/gcc/ada/init.c b/gcc/ada/init.c
index 8d2f4e1f235..b6d6e6a57e1 100644
--- a/gcc/ada/init.c
+++ b/gcc/ada/init.c
@@ -2282,11 +2282,12 @@ __gnat_is_stack_guard (mach_vm_address_t addr)
return 0;
}
-static void
-__gnat_error_handler (int sig, siginfo_t *si, void *ucontext ATTRIBUTE_UNUSED)
+#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
+
+void
+__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED,
+ void *ucontext ATTRIBUTE_UNUSED)
{
- struct Exception_Data *exception;
- const char *msg;
#if defined (__x86_64__)
/* Work around radar #10302855/pr50678, where the unwinders (libunwind or
libgcc_s depending on the system revision) and the DWARF unwind data for
@@ -2294,9 +2295,19 @@ __gnat_error_handler (int sig, siginfo_t *si, void *ucontext ATTRIBUTE_UNUSED)
and rdx to be transposed).. */
ucontext_t *uc = (ucontext_t *)ucontext ;
unsigned long t = uc->uc_mcontext->__ss.__rbx;
+
uc->uc_mcontext->__ss.__rbx = uc->uc_mcontext->__ss.__rdx;
uc->uc_mcontext->__ss.__rdx = t;
#endif
+}
+
+static void
+__gnat_error_handler (int sig, siginfo_t *si, void *ucontext)
+{
+ struct Exception_Data *exception;
+ const char *msg;
+
+ __gnat_adjust_context_for_raise (sig, ucontext);
switch (sig)
{
diff --git a/gcc/ada/mlib-tgt-specific-darwin.adb b/gcc/ada/mlib-tgt-specific-darwin.adb
index e04225370eb..13beb04a8bf 100644
--- a/gcc/ada/mlib-tgt-specific-darwin.adb
+++ b/gcc/ada/mlib-tgt-specific-darwin.adb
@@ -36,8 +36,6 @@ package body MLib.Tgt.Specific is
-- Non default subprograms
- function Archive_Indexer_Options return String_List_Access;
-
procedure Build_Dynamic_Library
(Ofiles : Argument_List;
Options : Argument_List;
@@ -62,15 +60,6 @@ package body MLib.Tgt.Specific is
Shared_Options : constant Argument_List :=
(1 => Shared_Libgcc'Access);
- -----------------------------
- -- Archive_Indexer_Options --
- -----------------------------
-
- function Archive_Indexer_Options return String_List_Access is
- begin
- return new String_List'(1 => new String'("-c"));
- end Archive_Indexer_Options;
-
---------------------------
-- Build_Dynamic_Library --
---------------------------
@@ -175,7 +164,6 @@ package body MLib.Tgt.Specific is
end Is_Archive_Ext;
begin
- Archive_Indexer_Options_Ptr := Archive_Indexer_Options'Access;
Build_Dynamic_Library_Ptr := Build_Dynamic_Library'Access;
DLL_Ext_Ptr := DLL_Ext'Access;
Dynamic_Option_Ptr := Dynamic_Option'Access;
diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads
index 35a73f9ad94..3379faef038 100644
--- a/gcc/ada/sinfo.ads
+++ b/gcc/ada/sinfo.ads
@@ -7310,6 +7310,11 @@ package Sinfo is
-- more sense to call it an Expression field, but then we would have to
-- special case the treatment of the N_Reference node.
+ -- Note: evaluating a N_Reference node is guaranteed to yield a non-null
+ -- value at run time. Therefore, it is valid to set Is_Known_Non_Null on
+ -- a temporary initialized to a N_Reference node in order to eliminate
+ -- superfluous access checks.
+
-- Sprint syntax: prefix'reference
-- N_Reference
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 9dc68cc341f..0fc5a420c82 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5672,23 +5672,6 @@ expand_builtin_atomic_is_lock_free (tree exp)
return NULL_RTX;
}
-/* This routine will either emit the mem_thread_fence pattern or issue a
- sync_synchronize to generate a fence for memory model MEMMODEL. */
-
-#ifndef HAVE_mem_thread_fence
-# define HAVE_mem_thread_fence 0
-# define gen_mem_thread_fence(x) (gcc_unreachable (), NULL_RTX)
-#endif
-
-void
-expand_builtin_mem_thread_fence (enum memmodel model)
-{
- if (HAVE_mem_thread_fence)
- emit_insn (gen_mem_thread_fence (GEN_INT (model)));
- else if (model != MEMMODEL_RELAXED)
- expand_builtin_sync_synchronize ();
-}
-
/* Expand the __atomic_thread_fence intrinsic:
void __atomic_thread_fence (enum memmodel)
EXP is the CALL_EXPR. */
@@ -5696,46 +5679,8 @@ expand_builtin_mem_thread_fence (enum memmodel model)
static void
expand_builtin_atomic_thread_fence (tree exp)
{
- enum memmodel model;
-
- model = get_memmodel (CALL_EXPR_ARG (exp, 0));
- expand_builtin_mem_thread_fence (model);
-}
-
-/* This routine will either emit the mem_signal_fence pattern or issue a
- sync_synchronize to generate a fence for memory model MEMMODEL. */
-
-#ifndef HAVE_mem_signal_fence
-# define HAVE_mem_signal_fence 0
-# define gen_mem_signal_fence(x) (gcc_unreachable (), NULL_RTX)
-#endif
-
-static void
-expand_builtin_mem_signal_fence (enum memmodel model)
-{
- if (HAVE_mem_signal_fence)
- emit_insn (gen_mem_signal_fence (GEN_INT (model)));
- else if (model != MEMMODEL_RELAXED)
- {
- rtx asm_op, clob;
-
- /* By default targets are coherent between a thread and the signal
- handler running on the same thread. Thus this really becomes a
- compiler barrier, in that stores must not be sunk past
- (or raised above) a given point. */
-
- /* Generate asm volatile("" : : : "memory") as the memory barrier. */
- asm_op = gen_rtx_ASM_OPERANDS (VOIDmode, empty_string, empty_string, 0,
- rtvec_alloc (0), rtvec_alloc (0),
- rtvec_alloc (0), UNKNOWN_LOCATION);
- MEM_VOLATILE_P (asm_op) = 1;
-
- clob = gen_rtx_SCRATCH (VOIDmode);
- clob = gen_rtx_MEM (BLKmode, clob);
- clob = gen_rtx_CLOBBER (VOIDmode, clob);
-
- emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, asm_op, clob)));
- }
+ enum memmodel model = get_memmodel (CALL_EXPR_ARG (exp, 0));
+ expand_mem_thread_fence (model);
}
/* Expand the __atomic_signal_fence intrinsic:
@@ -5745,10 +5690,8 @@ expand_builtin_mem_signal_fence (enum memmodel model)
static void
expand_builtin_atomic_signal_fence (tree exp)
{
- enum memmodel model;
-
- model = get_memmodel (CALL_EXPR_ARG (exp, 0));
- expand_builtin_mem_signal_fence (model);
+ enum memmodel model = get_memmodel (CALL_EXPR_ARG (exp, 0));
+ expand_mem_signal_fence (model);
}
/* Expand the __sync_synchronize intrinsic. */
@@ -5756,31 +5699,7 @@ expand_builtin_atomic_signal_fence (tree exp)
static void
expand_builtin_sync_synchronize (void)
{
- gimple x;
- VEC (tree, gc) *v_clobbers;
-
-#ifdef HAVE_memory_barrier
- if (HAVE_memory_barrier)
- {
- emit_insn (gen_memory_barrier ());
- return;
- }
-#endif
-
- if (synchronize_libfunc != NULL_RTX)
- {
- emit_library_call (synchronize_libfunc, LCT_NORMAL, VOIDmode, 0);
- return;
- }
-
- /* If no explicit memory barrier instruction is available, create an
- empty asm stmt with a memory clobber. */
- v_clobbers = VEC_alloc (tree, gc, 1);
- VEC_quick_push (tree, v_clobbers,
- tree_cons (NULL, build_string (6, "memory"), NULL));
- x = gimple_build_asm_vec ("", NULL, NULL, v_clobbers, NULL);
- gimple_asm_set_volatile (x, true);
- expand_asm_stmt (x);
+ expand_mem_thread_fence (MEMMODEL_SEQ_CST);
}
@@ -6578,12 +6497,28 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
- mode =
- get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1);
- target = expand_builtin_atomic_compare_exchange (mode, exp, target);
- if (target)
- return target;
- break;
+ {
+ unsigned int nargs, z;
+ VEC(tree,gc) *vec;
+
+ mode =
+ get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1);
+ target = expand_builtin_atomic_compare_exchange (mode, exp, target);
+ if (target)
+ return target;
+
+ /* If this is turned into an external library call, the weak parameter
+ must be dropped to match the expected parameter list. */
+ nargs = call_expr_nargs (exp);
+ vec = VEC_alloc (tree, gc, nargs - 1);
+ for (z = 0; z < 3; z++)
+ VEC_quick_push (tree, vec, CALL_EXPR_ARG (exp, z));
+ /* Skip the boolean weak parameter. */
+ for (z = 4; z < 6; z++)
+ VEC_quick_push (tree, vec, CALL_EXPR_ARG (exp, z));
+ exp = build_call_vec (TREE_TYPE (exp), CALL_EXPR_FN (exp), vec);
+ break;
+ }
case BUILT_IN_ATOMIC_LOAD_1:
case BUILT_IN_ATOMIC_LOAD_2:
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 78717f96d16..e970227dc4c 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -4444,6 +4444,8 @@ alpha_split_compare_and_swap_12 (rtx operands[])
mem = gen_rtx_MEM (DImode, align);
MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (orig_mem);
+ if (MEM_ALIAS_SET (orig_mem) == ALIAS_SET_MEMORY_BARRIER)
+ set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
alpha_pre_atomic_barrier (mod_s);
@@ -4583,6 +4585,8 @@ alpha_split_atomic_exchange_12 (rtx operands[])
mem = gen_rtx_MEM (DImode, align);
MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (orig_mem);
+ if (MEM_ALIAS_SET (orig_mem) == ALIAS_SET_MEMORY_BARRIER)
+ set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
alpha_pre_atomic_barrier (model);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 6ef6f62d28d..e3b0b883ec8 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -10247,6 +10247,9 @@ store_multiple_sequence (rtx *operands, int nops, int nops_total,
rtx base_reg_rtx = NULL;
int i, stm_case;
+ /* Write back of base register is currently only supported for Thumb 1. */
+ int base_writeback = TARGET_THUMB1;
+
/* Can only handle up to MAX_LDM_STM_OPS insns at present, though could be
easily extended if required. */
gcc_assert (nops >= 2 && nops <= MAX_LDM_STM_OPS);
@@ -10304,7 +10307,9 @@ store_multiple_sequence (rtx *operands, int nops, int nops_total,
/* If it isn't an integer register, then we can't do this. */
if (unsorted_regs[i] < 0
|| (TARGET_THUMB1 && unsorted_regs[i] > LAST_LO_REGNUM)
- || (TARGET_THUMB2 && unsorted_regs[i] == base_reg)
+ /* The effects are unpredictable if the base register is
+ both updated and stored. */
+ || (base_writeback && unsorted_regs[i] == base_reg)
|| (TARGET_THUMB2 && unsorted_regs[i] == SP_REGNUM)
|| unsorted_regs[i] > 14)
return 0;
@@ -20723,39 +20728,34 @@ neon_emit_pair_result_insn (enum machine_mode mode,
emit_move_insn (mem, tmp2);
}
-/* Set up operands for a register copy from src to dest, taking care not to
- clobber registers in the process.
- FIXME: This has rather high polynomial complexity (O(n^3)?) but shouldn't
- be called with a large N, so that should be OK. */
+/* Set up OPERANDS for a register copy from SRC to DEST, taking care
+ not to early-clobber SRC registers in the process.
+ We assume that the operands described by SRC and DEST represent a
+ decomposed copy of OPERANDS[1] into OPERANDS[0]. COUNT is the
+ number of components into which the copy has been decomposed. */
void
neon_disambiguate_copy (rtx *operands, rtx *dest, rtx *src, unsigned int count)
{
- unsigned int copied = 0, opctr = 0;
- unsigned int done = (1 << count) - 1;
- unsigned int i, j;
+ unsigned int i;
- while (copied != done)
+ if (!reg_overlap_mentioned_p (operands[0], operands[1])
+ || REGNO (operands[0]) < REGNO (operands[1]))
{
for (i = 0; i < count; i++)
- {
- int good = 1;
-
- for (j = 0; good && j < count; j++)
- if (i != j && (copied & (1 << j)) == 0
- && reg_overlap_mentioned_p (src[j], dest[i]))
- good = 0;
-
- if (good)
- {
- operands[opctr++] = dest[i];
- operands[opctr++] = src[i];
- copied |= 1 << i;
- }
- }
+ {
+ operands[2 * i] = dest[i];
+ operands[2 * i + 1] = src[i];
+ }
+ }
+ else
+ {
+ for (i = 0; i < count; i++)
+ {
+ operands[2 * i] = dest[count - i - 1];
+ operands[2 * i + 1] = src[count - i - 1];
+ }
}
-
- gcc_assert (opctr == count * 2);
}
/* Expand an expression EXP that calls a built-in function,
diff --git a/gcc/config/avr/avr-c.c b/gcc/config/avr/avr-c.c
index 63408c033ca..f0b3a628c2c 100644
--- a/gcc/config/avr/avr-c.c
+++ b/gcc/config/avr/avr-c.c
@@ -37,6 +37,12 @@ void
avr_register_target_pragmas (void)
{
c_register_addr_space ("__pgm", ADDR_SPACE_PGM);
+ c_register_addr_space ("__pgm1", ADDR_SPACE_PGM1);
+ c_register_addr_space ("__pgm2", ADDR_SPACE_PGM2);
+ c_register_addr_space ("__pgm3", ADDR_SPACE_PGM3);
+ c_register_addr_space ("__pgm4", ADDR_SPACE_PGM4);
+ c_register_addr_space ("__pgm5", ADDR_SPACE_PGM5);
+ c_register_addr_space ("__pgmx", ADDR_SPACE_PGMX);
}
@@ -100,6 +106,9 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile)
cpp_define (pfile, "__AVR_ERRATA_SKIP_JMP_CALL__");
}
+ cpp_define_formatted (pfile, "__AVR_SFR_OFFSET__=0x%x",
+ avr_current_arch->sfr_offset);
+
/* Define builtin macros so that the user can easily query if or if not
non-generic address spaces (and which) are supported.
This is only supported for C. For C++, a language extension is needed
@@ -109,6 +118,12 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile)
if (!strcmp (lang_hooks.name, "GNU C"))
{
cpp_define (pfile, "__PGM=__pgm");
+ cpp_define (pfile, "__PGM1=__pgm1");
+ cpp_define (pfile, "__PGM2=__pgm2");
+ cpp_define (pfile, "__PGM3=__pgm3");
+ cpp_define (pfile, "__PGM4=__pgm4");
+ cpp_define (pfile, "__PGM5=__pgm5");
+ cpp_define (pfile, "__PGMX=__pgmx");
}
/* Define builtin macros so that the user can
diff --git a/gcc/config/avr/avr-devices.c b/gcc/config/avr/avr-devices.c
index d0dda8536af..8d6e947f129 100644
--- a/gcc/config/avr/avr-devices.c
+++ b/gcc/config/avr/avr-devices.c
@@ -23,20 +23,30 @@
#include "coretypes.h"
#include "tm.h"
-/* List of all known AVR MCU architectures. */
+/* List of all known AVR MCU architectures.
+ Order as of enum avr_arch from avr.h. */
-const struct base_arch_s avr_arch_types[] = {
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, NULL, "avr2" }, /* unknown device specified */
- { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=1", "avr1" },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=2", "avr2" },
- { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=25", "avr25" },
- { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=3", "avr3" },
- { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=31", "avr31" },
- { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=35", "avr35" },
- { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=4", "avr4" },
- { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=5", "avr5" },
- { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, "__AVR_ARCH__=51", "avr51" },
- { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, "__AVR_ARCH__=6", "avr6" }
+const struct base_arch_s
+avr_arch_types[] =
+{
+ /* unknown device specified */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, NULL, "avr2" },
+ /*
+ A M J LM E E E d S S O # F
+ S U M PO L L I a t F ff 6 l
+ M L P MV P P J - - t a R s 4 a
+ XW M M M a r e s
+ X P t t k h */
+ { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=1", "avr1" },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=2", "avr2" },
+ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=25", "avr25" },
+ { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=3", "avr3" },
+ { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, 32, 2, "__AVR_ARCH__=31", "avr31" },
+ { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=35", "avr35" },
+ { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=4", "avr4" },
+ { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=5", "avr5" },
+ { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 32, 2, "__AVR_ARCH__=51", "avr51" },
+ { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, 32, 4, "__AVR_ARCH__=6", "avr6" }
};
const struct mcu_type_s avr_mcu_types[] = {
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index 6c017e19b40..22b1548ed66 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -34,6 +34,7 @@ extern int avr_hard_regno_rename_ok (unsigned int, unsigned int);
extern rtx avr_return_addr_rtx (int count, rtx tem);
extern void avr_register_target_pragmas (void);
extern bool avr_accumulate_outgoing_args (void);
+extern void avr_init_expanders (void);
#ifdef TREE_CODE
extern void avr_asm_output_aligned_decl_common (FILE*, const_tree, const char*, unsigned HOST_WIDE_INT, unsigned int, bool);
@@ -50,12 +51,6 @@ extern void init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
#ifdef RTX_CODE
extern const char *output_movqi (rtx insn, rtx operands[], int *l);
extern const char *output_movhi (rtx insn, rtx operands[], int *l);
-extern const char *out_movqi_r_mr (rtx insn, rtx op[], int *l);
-extern const char *out_movqi_mr_r (rtx insn, rtx op[], int *l);
-extern const char *out_movhi_r_mr (rtx insn, rtx op[], int *l);
-extern const char *out_movhi_mr_r (rtx insn, rtx op[], int *l);
-extern const char *out_movsi_r_mr (rtx insn, rtx op[], int *l);
-extern const char *out_movsi_mr_r (rtx insn, rtx op[], int *l);
extern const char *output_movsisf (rtx insn, rtx operands[], int *l);
extern const char *avr_out_tstsi (rtx, rtx*, int*);
extern const char *avr_out_tsthi (rtx, rtx*, int*);
@@ -84,6 +79,7 @@ extern bool avr_rotate_bytes (rtx operands[]);
extern void expand_prologue (void);
extern void expand_epilogue (bool);
+extern bool avr_emit_movmemhi (rtx*);
extern int avr_epilogue_uses (int regno);
extern int avr_starting_frame_offset (void);
@@ -94,6 +90,8 @@ extern const char* avr_out_bitop (rtx, rtx*, int*);
extern const char* avr_out_plus (rtx*, int*, int*);
extern const char* avr_out_plus_noclobber (rtx*, int*, int*);
extern const char* avr_out_addto_sp (rtx*, int*);
+extern const char* avr_out_xload (rtx, rtx*, int*);
+extern const char* avr_out_movmem (rtx, rtx*, int*);
extern bool avr_popcount_each_byte (rtx, int, int);
extern int extra_constraint_Q (rtx x);
@@ -122,7 +120,9 @@ extern bool avr_regno_mode_code_ok_for_base_p (int, enum machine_mode, addr_spac
extern rtx avr_incoming_return_addr_rtx (void);
extern rtx avr_legitimize_reload_address (rtx*, enum machine_mode, int, int, int, int, rtx (*)(rtx,int));
extern bool avr_mem_pgm_p (rtx);
+extern bool avr_mem_pgmx_p (rtx);
extern bool avr_load_libgcc_p (rtx);
+extern bool avr_xload_libgcc_p (enum machine_mode);
#endif /* RTX_CODE */
#ifdef REAL_VALUE_TYPE
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index f33c0c50903..f9dd60388df 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -55,11 +55,21 @@
/* Return true if STR starts with PREFIX and false, otherwise. */
#define STR_PREFIX_P(STR,PREFIX) (0 == strncmp (STR, PREFIX, strlen (PREFIX)))
-#define AVR_SECTION_PROGMEM (SECTION_MACH_DEP << 0)
+/* The 4 bits starting at SECTION_MACH_DEP are reverved to store
+ 1 + flash segment where progmem data is to be located.
+ For example, data with __pgm2 is stored as (1+2) * SECTION_MACH_DEP. */
+#define AVR_SECTION_PROGMEM (0xf * SECTION_MACH_DEP)
/* Prototypes for local helper functions. */
+static const char* out_movqi_r_mr (rtx, rtx[], int*);
+static const char* out_movhi_r_mr (rtx, rtx[], int*);
+static const char* out_movsi_r_mr (rtx, rtx[], int*);
+static const char* out_movqi_mr_r (rtx, rtx[], int*);
+static const char* out_movhi_mr_r (rtx, rtx[], int*);
+static const char* out_movsi_mr_r (rtx, rtx[], int*);
+
static int avr_naked_function_p (tree);
static int interrupt_function_p (tree);
static int signal_function_p (tree);
@@ -97,6 +107,13 @@ static GTY(()) rtx tmp_reg_rtx;
/* Zeroed register RTX (gen_rtx_REG (QImode, ZERO_REGNO)) */
static GTY(()) rtx zero_reg_rtx;
+/* RAMPZ special function register */
+static GTY(()) rtx rampz_rtx;
+
+/* RTX containing the strings "" and "e", respectively */
+static GTY(()) rtx xstring_empty;
+static GTY(()) rtx xstring_e;
+
/* RTXs for all general purpose registers as QImode */
static GTY(()) rtx all_regs_rtx[32];
@@ -116,7 +133,17 @@ const struct mcu_type_s *avr_current_device;
static GTY(()) section *progmem_swtable_section;
/* Unnamed section associated to __attribute__((progmem)) aka. PROGMEM. */
-static GTY(()) section *progmem_section;
+static GTY(()) section *progmem_section[6];
+
+static const char * const progmem_section_prefix[6] =
+ {
+ ".progmem.data",
+ ".progmem1.data",
+ ".progmem2.data",
+ ".progmem3.data",
+ ".progmem4.data",
+ ".progmem5.data"
+ };
/* To track if code will use .bss and/or .data. */
bool avr_need_clear_bss_p = false;
@@ -317,8 +344,6 @@ avr_popcount_each_byte (rtx xval, int n_bytes, int pop_mask)
static void
avr_option_override (void)
{
- int regno;
-
flag_delete_null_pointer_checks = 0;
/* caller-save.c looks for call-clobbered hard registers that are assigned
@@ -347,15 +372,6 @@ avr_option_override (void)
avr_current_arch = &avr_arch_types[avr_current_device->arch];
avr_extra_arch_macro = avr_current_device->macro;
- for (regno = 0; regno < 32; regno ++)
- all_regs_rtx[regno] = gen_rtx_REG (QImode, regno);
-
- lpm_reg_rtx = all_regs_rtx[LPM_REGNO];
- tmp_reg_rtx = all_regs_rtx[TMP_REGNO];
- zero_reg_rtx = all_regs_rtx[ZERO_REGNO];
-
- lpm_addr_reg_rtx = gen_rtx_REG (HImode, REG_Z);
-
init_machine_status = avr_init_machine_status;
avr_log_set_avr_log();
@@ -369,6 +385,38 @@ avr_init_machine_status (void)
return ggc_alloc_cleared_machine_function ();
}
+
+/* Implement `INIT_EXPANDERS'. */
+/* The function works like a singleton. */
+
+void
+avr_init_expanders (void)
+{
+ int regno;
+
+ static bool done = false;
+
+ if (done)
+ return;
+ else
+ done = true;
+
+ for (regno = 0; regno < 32; regno ++)
+ all_regs_rtx[regno] = gen_rtx_REG (QImode, regno);
+
+ lpm_reg_rtx = all_regs_rtx[LPM_REGNO];
+ tmp_reg_rtx = all_regs_rtx[TMP_REGNO];
+ zero_reg_rtx = all_regs_rtx[ZERO_REGNO];
+
+ lpm_addr_reg_rtx = gen_rtx_REG (HImode, REG_Z);
+
+ rampz_rtx = gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR));
+
+ xstring_empty = gen_rtx_CONST_STRING (VOIDmode, "");
+ xstring_e = gen_rtx_CONST_STRING (VOIDmode, "e");
+}
+
+
/* Return register class for register R. */
enum reg_class
@@ -414,18 +462,60 @@ avr_scalar_mode_supported_p (enum machine_mode mode)
}
+/* Return the segment number of pgm address space AS, i.e.
+ the 64k block it lives in.
+ Return -1 if unknown, i.e. 24-bit AS in flash.
+ Return -2 for anything else. */
+
+static int
+avr_pgm_segment (addr_space_t as)
+{
+ switch (as)
+ {
+ default: return -2;
+
+ case ADDR_SPACE_PGMX: return -1;
+ case ADDR_SPACE_PGM: return 0;
+ case ADDR_SPACE_PGM1: return 1;
+ case ADDR_SPACE_PGM2: return 2;
+ case ADDR_SPACE_PGM3: return 3;
+ case ADDR_SPACE_PGM4: return 4;
+ case ADDR_SPACE_PGM5: return 5;
+ }
+}
+
+
/* Return TRUE if DECL is a VAR_DECL located in Flash and FALSE, otherwise. */
static bool
avr_decl_pgm_p (tree decl)
{
- if (TREE_CODE (decl) != VAR_DECL)
- return false;
+ if (TREE_CODE (decl) != VAR_DECL
+ || TREE_TYPE (decl) == error_mark_node)
+ {
+ return false;
+ }
return !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (TREE_TYPE (decl)));
}
+/* Return TRUE if DECL is a VAR_DECL located in the 24-bit Flash
+ address space and FALSE, otherwise. */
+
+static bool
+avr_decl_pgmx_p (tree decl)
+{
+ if (TREE_CODE (decl) != VAR_DECL
+ || TREE_TYPE (decl) == error_mark_node)
+ {
+ return false;
+ }
+
+ return (ADDR_SPACE_PGMX == TYPE_ADDR_SPACE (TREE_TYPE (decl)));
+}
+
+
/* Return TRUE if X is a MEM rtx located in Flash and FALSE, otherwise. */
bool
@@ -436,6 +526,17 @@ avr_mem_pgm_p (rtx x)
}
+/* Return TRUE if X is a MEM rtx located in the 24-bit Flash
+ address space and FALSE, otherwise. */
+
+bool
+avr_mem_pgmx_p (rtx x)
+{
+ return (MEM_P (x)
+ && ADDR_SPACE_PGMX == MEM_ADDR_SPACE (x));
+}
+
+
/* A helper for the subsequent function attribute used to dig for
attribute 'name' in a FUNCTION_DECL or FUNCTION_TYPE */
@@ -1041,8 +1142,7 @@ expand_prologue (void)
&& TEST_HARD_REG_BIT (set, REG_Z)
&& TEST_HARD_REG_BIT (set, REG_Z + 1))
{
- emit_move_insn (tmp_reg_rtx,
- gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)));
+ emit_move_insn (tmp_reg_rtx, rampz_rtx);
emit_push_byte (TMP_REGNO, false);
}
@@ -1280,8 +1380,7 @@ expand_epilogue (bool sibcall_p)
&& TEST_HARD_REG_BIT (set, REG_Z + 1))
{
emit_pop_byte (TMP_REGNO);
- emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)),
- tmp_reg_rtx);
+ emit_move_insn (rampz_rtx, tmp_reg_rtx);
}
/* Restore SREG using tmp reg as scratch. */
@@ -1732,7 +1831,7 @@ print_operand (FILE *file, rtx x, int code)
if (code == 'm')
{
if (!CONSTANT_P (addr))
- fatal_insn ("bad address, not a constant):", addr);
+ fatal_insn ("bad address, not a constant:", addr);
/* Assembler template with m-code is data - not progmem section */
if (text_segment_operand (addr, VOIDmode))
if (warning (0, "accessing data memory with"
@@ -1743,6 +1842,24 @@ print_operand (FILE *file, rtx x, int code)
}
output_addr_const (file, addr);
}
+ else if (code == 'i')
+ {
+ if (!io_address_operand (addr, GET_MODE (x)))
+ fatal_insn ("bad address, not an I/O address:", addr);
+
+ switch (INTVAL (addr))
+ {
+ case RAMPZ_ADDR: fprintf (file, "__RAMPZ__"); break;
+ case SREG_ADDR: fprintf (file, "__SREG__"); break;
+ case SP_ADDR: fprintf (file, "__SP_L__"); break;
+ case SP_ADDR+1: fprintf (file, "__SP_H__"); break;
+
+ default:
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX,
+ UINTVAL (addr) - avr_current_arch->sfr_offset);
+ break;
+ }
+ }
else if (code == 'o')
{
if (GET_CODE (addr) != PLUS)
@@ -1795,6 +1912,8 @@ print_operand (FILE *file, rtx x, int code)
REAL_VALUE_TO_TARGET_SINGLE (rv, val);
fprintf (file, "0x%lx", val);
}
+ else if (GET_CODE (x) == CONST_STRING)
+ fputs (XSTR (x, 0), file);
else if (code == 'j')
fputs (cond_string (GET_CODE (x)), file);
else if (code == 'k')
@@ -2247,6 +2366,70 @@ avr_load_libgcc_p (rtx op)
&& avr_mem_pgm_p (op));
}
+/* Return true if a value of mode MODE is read by __xload_* function. */
+
+bool
+avr_xload_libgcc_p (enum machine_mode mode)
+{
+ int n_bytes = GET_MODE_SIZE (mode);
+
+ return (n_bytes > 1
+ && avr_current_arch->n_segments > 1
+ && !AVR_HAVE_ELPMX);
+}
+
+
+/* Find an unused d-register to be used as scratch in INSN.
+ EXCLUDE is either NULL_RTX or some register. In the case where EXCLUDE
+ is a register, skip all possible return values that overlap EXCLUDE.
+ The policy for the returned register is similar to that of
+ `reg_unused_after', i.e. the returned register may overlap the SET_DEST
+ of INSN.
+
+ Return a QImode d-register or NULL_RTX if nothing found. */
+
+static rtx
+avr_find_unused_d_reg (rtx insn, rtx exclude)
+{
+ int regno;
+ bool isr_p = (interrupt_function_p (current_function_decl)
+ || signal_function_p (current_function_decl));
+
+ for (regno = 16; regno < 32; regno++)
+ {
+ rtx reg = all_regs_rtx[regno];
+
+ if ((exclude
+ && reg_overlap_mentioned_p (exclude, reg))
+ || fixed_regs[regno])
+ {
+ continue;
+ }
+
+ /* Try non-live register */
+
+ if (!df_regs_ever_live_p (regno)
+ && (TREE_THIS_VOLATILE (current_function_decl)
+ || cfun->machine->is_OS_task
+ || cfun->machine->is_OS_main
+ || (!isr_p && call_used_regs[regno])))
+ {
+ return reg;
+ }
+
+ /* Any live register can be used if it is unused after.
+ Prologue/epilogue will care for it as needed. */
+
+ if (df_regs_ever_live_p (regno)
+ && reg_unused_after (insn, reg))
+ {
+ return reg;
+ }
+ }
+
+ return NULL_RTX;
+}
+
/* Helper function for the next function in the case where only restricted
version of LPM instruction is available. */
@@ -2279,28 +2462,30 @@ avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen)
gcc_unreachable();
case 1:
- return avr_asm_len ("lpm" CR_TAB
- "mov %0,%3", xop, plen, 2);
+ avr_asm_len ("%4lpm", xop, plen, 1);
+
+ if (regno_dest != LPM_REGNO)
+ avr_asm_len ("mov %0,%3", xop, plen, 1);
+
+ return "";
case 2:
if (REGNO (dest) == REG_Z)
- return avr_asm_len ("lpm" CR_TAB
+ return avr_asm_len ("%4lpm" CR_TAB
"push %3" CR_TAB
"adiw %2,1" CR_TAB
- "lpm" CR_TAB
+ "%4lpm" CR_TAB
"mov %B0,%3" CR_TAB
"pop %A0", xop, plen, 6);
- else
- {
- avr_asm_len ("lpm" CR_TAB
- "mov %A0,%3" CR_TAB
- "adiw %2,1" CR_TAB
- "lpm" CR_TAB
- "mov %B0,%3", xop, plen, 5);
+
+ avr_asm_len ("%4lpm" CR_TAB
+ "mov %A0,%3" CR_TAB
+ "adiw %2,1" CR_TAB
+ "%4lpm" CR_TAB
+ "mov %B0,%3", xop, plen, 5);
- if (!reg_unused_after (insn, addr))
- avr_asm_len ("sbiw %2,1", xop, plen, 1);
- }
+ if (!reg_unused_after (insn, addr))
+ avr_asm_len ("sbiw %2,1", xop, plen, 1);
break; /* 2 */
}
@@ -2310,17 +2495,31 @@ avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen)
case POST_INC:
gcc_assert (REG_Z == REGNO (XEXP (addr, 0))
- && n_bytes <= 2);
+ && n_bytes <= 4);
- avr_asm_len ("lpm" CR_TAB
- "mov %A0,%3" CR_TAB
- "adiw %2,1", xop, plen, 3);
+ if (regno_dest == LPM_REGNO)
+ avr_asm_len ("%4lpm" CR_TAB
+ "adiw %2,1", xop, plen, 2);
+ else
+ avr_asm_len ("%4lpm" CR_TAB
+ "mov %A0,%3" CR_TAB
+ "adiw %2,1", xop, plen, 3);
if (n_bytes >= 2)
- avr_asm_len ("lpm" CR_TAB
+ avr_asm_len ("%4lpm" CR_TAB
"mov %B0,%3" CR_TAB
"adiw %2,1", xop, plen, 3);
+ if (n_bytes >= 3)
+ avr_asm_len ("%4lpm" CR_TAB
+ "mov %C0,%3" CR_TAB
+ "adiw %2,1", xop, plen, 3);
+
+ if (n_bytes >= 4)
+ avr_asm_len ("%4lpm" CR_TAB
+ "mov %D0,%3" CR_TAB
+ "adiw %2,1", xop, plen, 3);
+
break; /* POST_INC */
} /* switch CODE (addr) */
@@ -2337,12 +2536,13 @@ avr_out_lpm_no_lpmx (rtx insn, rtx *xop, int *plen)
static const char*
avr_out_lpm (rtx insn, rtx *op, int *plen)
{
- rtx xop[5];
+ rtx xop[6];
rtx dest = op[0];
rtx src = SET_SRC (single_set (insn));
rtx addr;
int n_bytes = GET_MODE_SIZE (GET_MODE (dest));
int regno_dest;
+ int segment;
if (plen)
*plen = 0;
@@ -2357,17 +2557,66 @@ avr_out_lpm (rtx insn, rtx *op, int *plen)
addr = XEXP (src, 0);
- gcc_assert (!avr_load_libgcc_p (src)
- && REG_P (dest)
- && (REG_P (addr) || POST_INC == GET_CODE (addr)));
+ segment = avr_pgm_segment (MEM_ADDR_SPACE (src));
+
+ gcc_assert (REG_P (dest)
+ && ((segment >= 0
+ && (REG_P (addr) || POST_INC == GET_CODE (addr)))
+ || (GET_CODE (addr) == LO_SUM && segment == -1)));
+
+ if (segment == -1)
+ {
+ /* We are called from avr_out_xload because someone wrote
+ __pgmx on a device with just one flash segment. */
+
+ addr = XEXP (addr, 1);
+ }
xop[0] = dest;
xop[1] = addr;
xop[2] = lpm_addr_reg_rtx;
+ xop[4] = xstring_empty;
+ xop[5] = tmp_reg_rtx;
regno_dest = REGNO (dest);
- if (!AVR_HAVE_LPMX)
+ /* Cut down segment number to a number the device actually
+ supports. We do this late to preserve the address space's
+ name for diagnostics. */
+
+ segment %= avr_current_arch->n_segments;
+
+ /* Set RAMPZ as needed. */
+
+ if (segment)
+ {
+ xop[4] = GEN_INT (segment);
+
+ if (xop[3] = avr_find_unused_d_reg (insn, lpm_addr_reg_rtx),
+ xop[3])
+ {
+ avr_asm_len ("ldi %3,%4" CR_TAB
+ "out __RAMPZ__,%3", xop, plen, 2);
+ }
+ else if (segment == 1)
+ {
+ avr_asm_len ("clr %5" CR_TAB
+ "inc %5" CR_TAB
+ "out __RAMPZ__,%5", xop, plen, 3);
+ }
+ else
+ {
+ avr_asm_len ("mov %5,%2" CR_TAB
+ "ldi %2,%4" CR_TAB
+ "out __RAMPZ__,%2" CR_TAB
+ "mov %2,%5", xop, plen, 4);
+ }
+
+ xop[4] = xstring_e;
+ }
+
+ if ((segment == 0 && !AVR_HAVE_LPMX)
+ || (segment != 0 && !AVR_HAVE_ELPMX))
{
return avr_out_lpm_no_lpmx (insn, xop, plen);
}
@@ -2387,17 +2636,17 @@ avr_out_lpm (rtx insn, rtx *op, int *plen)
gcc_unreachable();
case 1:
- return avr_asm_len ("lpm %0,%a2", xop, plen, -1);
+ return avr_asm_len ("%4lpm %0,%a2", xop, plen, 1);
case 2:
if (REGNO (dest) == REG_Z)
- return avr_asm_len ("lpm __tmp_reg__,%a2+" CR_TAB
- "lpm %B0,%a2" CR_TAB
- "mov %A0,__tmp_reg__", xop, plen, -3);
+ return avr_asm_len ("%4lpm %5,%a2+" CR_TAB
+ "%4lpm %B0,%a2" CR_TAB
+ "mov %A0,%5", xop, plen, 3);
else
{
- avr_asm_len ("lpm %A0,%a2+" CR_TAB
- "lpm %B0,%a2", xop, plen, -2);
+ avr_asm_len ("%4lpm %A0,%a2+" CR_TAB
+ "%4lpm %B0,%a2", xop, plen, 2);
if (!reg_unused_after (insn, addr))
avr_asm_len ("sbiw %2,1", xop, plen, 1);
@@ -2407,9 +2656,9 @@ avr_out_lpm (rtx insn, rtx *op, int *plen)
case 3:
- avr_asm_len ("lpm %A0,%a2+" CR_TAB
- "lpm %B0,%a2+" CR_TAB
- "lpm %C0,%a2", xop, plen, -3);
+ avr_asm_len ("%4lpm %A0,%a2+" CR_TAB
+ "%4lpm %B0,%a2+" CR_TAB
+ "%4lpm %C0,%a2", xop, plen, 3);
if (!reg_unused_after (insn, addr))
avr_asm_len ("sbiw %2,2", xop, plen, 1);
@@ -2418,17 +2667,17 @@ avr_out_lpm (rtx insn, rtx *op, int *plen)
case 4:
- avr_asm_len ("lpm %A0,%a2+" CR_TAB
- "lpm %B0,%a2+", xop, plen, -2);
+ avr_asm_len ("%4lpm %A0,%a2+" CR_TAB
+ "%4lpm %B0,%a2+", xop, plen, 2);
if (REGNO (dest) == REG_Z - 2)
- return avr_asm_len ("lpm __tmp_reg__,%a2+" CR_TAB
- "lpm %C0,%a2" CR_TAB
- "mov %D0,__tmp_reg__", xop, plen, 3);
+ return avr_asm_len ("%4lpm %5,%a2+" CR_TAB
+ "%4lpm %C0,%a2" CR_TAB
+ "mov %D0,%5", xop, plen, 3);
else
{
- avr_asm_len ("lpm %C0,%a2+" CR_TAB
- "lpm %D0,%a2", xop, plen, 2);
+ avr_asm_len ("%4lpm %C0,%a2+" CR_TAB
+ "%4lpm %D0,%a2", xop, plen, 2);
if (!reg_unused_after (insn, addr))
avr_asm_len ("sbiw %2,3", xop, plen, 1);
@@ -2444,10 +2693,10 @@ avr_out_lpm (rtx insn, rtx *op, int *plen)
gcc_assert (REG_Z == REGNO (XEXP (addr, 0))
&& n_bytes <= 4);
- avr_asm_len ("lpm %A0,%a2+", xop, plen, -1);
- if (n_bytes >= 2) avr_asm_len ("lpm %B0,%a2+", xop, plen, 1);
- if (n_bytes >= 3) avr_asm_len ("lpm %C0,%a2+", xop, plen, 1);
- if (n_bytes >= 4) avr_asm_len ("lpm %D0,%a2+", xop, plen, 1);
+ avr_asm_len ("%4lpm %A0,%a2+", xop, plen, 1);
+ if (n_bytes >= 2) avr_asm_len ("%4lpm %B0,%a2+", xop, plen, 1);
+ if (n_bytes >= 3) avr_asm_len ("%4lpm %C0,%a2+", xop, plen, 1);
+ if (n_bytes >= 4) avr_asm_len ("%4lpm %D0,%a2+", xop, plen, 1);
break; /* POST_INC */
@@ -2457,6 +2706,81 @@ avr_out_lpm (rtx insn, rtx *op, int *plen)
}
+/* Worker function for xload_<mode> and xload_8 insns. */
+
+const char*
+avr_out_xload (rtx insn, rtx *op, int *plen)
+{
+ rtx xop[5];
+ rtx reg = op[0];
+ int n_bytes = GET_MODE_SIZE (GET_MODE (reg));
+ unsigned int regno = REGNO (reg);
+
+ if (avr_current_arch->n_segments == 1)
+ return avr_out_lpm (insn, op, plen);
+
+ xop[0] = reg;
+ xop[1] = op[1];
+ xop[2] = lpm_addr_reg_rtx;
+ xop[3] = lpm_reg_rtx;
+ xop[4] = tmp_reg_rtx;
+
+ avr_asm_len ("out __RAMPZ__,%1", xop, plen, -1);
+
+ if (1 == n_bytes)
+ {
+ if (AVR_HAVE_ELPMX)
+ return avr_asm_len ("elpm %0,%a2", xop, plen, 1);
+ else
+ return avr_asm_len ("elpm" CR_TAB
+ "mov %0,%3", xop, plen, 2);
+ }
+
+ gcc_assert (AVR_HAVE_ELPMX);
+
+ if (!reg_overlap_mentioned_p (reg, lpm_addr_reg_rtx))
+ {
+ /* Insn clobbers the Z-register so we can use post-increment. */
+
+ avr_asm_len ("elpm %A0,%a2+", xop, plen, 1);
+ if (n_bytes >= 2) avr_asm_len ("elpm %B0,%a2+", xop, plen, 1);
+ if (n_bytes >= 3) avr_asm_len ("elpm %C0,%a2+", xop, plen, 1);
+ if (n_bytes >= 4) avr_asm_len ("elpm %D0,%a2+", xop, plen, 1);
+
+ return "";
+ }
+
+ switch (n_bytes)
+ {
+ default:
+ gcc_unreachable();
+
+ case 2:
+ gcc_assert (regno == REGNO (lpm_addr_reg_rtx));
+
+ return avr_asm_len ("elpm %4,%a2+" CR_TAB
+ "elpm %B0,%a2" CR_TAB
+ "mov %A0,%4", xop, plen, 3);
+
+ case 3:
+ case 4:
+ gcc_assert (regno + 2 == REGNO (lpm_addr_reg_rtx));
+
+ avr_asm_len ("elpm %A0,%a2+" CR_TAB
+ "elpm %B0,%a2+", xop, plen, 2);
+
+ if (n_bytes == 3)
+ return avr_asm_len ("elpm %C0,%a2", xop, plen, 1);
+ else
+ return avr_asm_len ("elpm %4,%a2+" CR_TAB
+ "elpm %D0,%a2" CR_TAB
+ "mov %C0,%4", xop, plen, 3);
+ }
+
+ return "";
+}
+
+
const char *
output_movqi (rtx insn, rtx operands[], int *l)
{
@@ -2497,17 +2821,12 @@ output_movqi (rtx insn, rtx operands[], int *l)
}
else if (GET_CODE (dest) == MEM)
{
- const char *templ;
+ rtx xop[2];
- if (src == const0_rtx)
- operands[1] = zero_reg_rtx;
-
- templ = out_movqi_mr_r (insn, operands, real_l);
-
- if (!real_l)
- output_asm_insn (templ, operands);
+ xop[0] = dest;
+ xop[1] = src == const0_rtx ? zero_reg_rtx : src;
- operands[1] = src;
+ return out_movqi_mr_r (insn, xop, real_l);
}
return "";
}
@@ -2578,93 +2897,79 @@ output_movhi (rtx insn, rtx operands[], int *l)
}
else if (GET_CODE (dest) == MEM)
{
- const char *templ;
+ rtx xop[2];
- if (src == const0_rtx)
- operands[1] = zero_reg_rtx;
+ xop[0] = dest;
+ xop[1] = src == const0_rtx ? zero_reg_rtx : src;
- templ = out_movhi_mr_r (insn, operands, real_l);
-
- if (!real_l)
- output_asm_insn (templ, operands);
-
- operands[1] = src;
- return "";
+ return out_movhi_mr_r (insn, xop, real_l);
}
fatal_insn ("invalid insn:", insn);
return "";
}
-const char *
-out_movqi_r_mr (rtx insn, rtx op[], int *l)
+static const char*
+out_movqi_r_mr (rtx insn, rtx op[], int *plen)
{
rtx dest = op[0];
rtx src = op[1];
rtx x = XEXP (src, 0);
- int dummy;
-
- if (!l)
- l = &dummy;
if (CONSTANT_ADDRESS_P (x))
{
- if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
- {
- *l = 1;
- return AS2 (in,%0,__SREG__);
- }
- if (optimize > 0 && io_address_operand (x, QImode))
- {
- *l = 1;
- return AS2 (in,%0,%m1-0x20);
- }
- *l = 2;
- return AS2 (lds,%0,%m1);
+ return optimize > 0 && io_address_operand (x, QImode)
+ ? avr_asm_len ("in %0,%i1", op, plen, -1)
+ : avr_asm_len ("lds %0,%m1", op, plen, -2);
}
- /* memory access by reg+disp */
else if (GET_CODE (x) == PLUS
- && REG_P (XEXP (x,0))
- && GET_CODE (XEXP (x,1)) == CONST_INT)
+ && REG_P (XEXP (x, 0))
+ && CONST_INT_P (XEXP (x, 1)))
{
- if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (src))) >= 63)
- {
- int disp = INTVAL (XEXP (x,1));
- if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("incorrect insn:",insn);
+ /* memory access by reg+disp */
- if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
- return *l = 3, (AS2 (adiw,r28,%o1-63) CR_TAB
- AS2 (ldd,%0,Y+63) CR_TAB
- AS2 (sbiw,r28,%o1-63));
+ int disp = INTVAL (XEXP (x, 1));
+
+ if (disp - GET_MODE_SIZE (GET_MODE (src)) >= 63)
+ {
+ if (REGNO (XEXP (x, 0)) != REG_Y)
+ fatal_insn ("incorrect insn:",insn);
- return *l = 5, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
- AS2 (sbci,r29,hi8(-%o1)) CR_TAB
- AS2 (ld,%0,Y) CR_TAB
- AS2 (subi,r28,lo8(%o1)) CR_TAB
- AS2 (sbci,r29,hi8(%o1)));
- }
- else if (REGNO (XEXP (x,0)) == REG_X)
- {
- /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
- it but I have this situation with extremal optimizing options. */
- if (reg_overlap_mentioned_p (dest, XEXP (x,0))
- || reg_unused_after (insn, XEXP (x,0)))
- return *l = 2, (AS2 (adiw,r26,%o1) CR_TAB
- AS2 (ld,%0,X));
-
- return *l = 3, (AS2 (adiw,r26,%o1) CR_TAB
- AS2 (ld,%0,X) CR_TAB
- AS2 (sbiw,r26,%o1));
- }
- *l = 1;
- return AS2 (ldd,%0,%1);
+ if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
+ return avr_asm_len ("adiw r28,%o1-63" CR_TAB
+ "ldd %0,Y+63" CR_TAB
+ "sbiw r28,%o1-63", op, plen, -3);
+
+ return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB
+ "sbci r29,hi8(-%o1)" CR_TAB
+ "ld %0,Y" CR_TAB
+ "subi r28,lo8(%o1)" CR_TAB
+ "sbci r29,hi8(%o1)", op, plen, -5);
+ }
+ else if (REGNO (XEXP (x, 0)) == REG_X)
+ {
+ /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
+ it but I have this situation with extremal optimizing options. */
+
+ avr_asm_len ("adiw r26,%o1" CR_TAB
+ "ld %0,X", op, plen, -2);
+
+ if (!reg_overlap_mentioned_p (dest, XEXP (x,0))
+ && !reg_unused_after (insn, XEXP (x,0)))
+ {
+ avr_asm_len ("sbiw r26,%o1", op, plen, 1);
+ }
+
+ return "";
+ }
+
+ return avr_asm_len ("ldd %0,%1", op, plen, -1);
}
- *l = 1;
- return AS2 (ld,%0,%1);
+
+ return avr_asm_len ("ld %0,%1", op, plen, -1);
}
-const char *
-out_movhi_r_mr (rtx insn, rtx op[], int *l)
+static const char*
+out_movhi_r_mr (rtx insn, rtx op[], int *plen)
{
rtx dest = op[0];
rtx src = op[1];
@@ -2674,39 +2979,25 @@ out_movhi_r_mr (rtx insn, rtx op[], int *l)
/* "volatile" forces reading low byte first, even if less efficient,
for correct operation with 16-bit I/O registers. */
int mem_volatile_p = MEM_VOLATILE_P (src);
- int tmp;
-
- if (!l)
- l = &tmp;
if (reg_base > 0)
{
if (reg_dest == reg_base) /* R = (R) */
- {
- *l = 3;
- return (AS2 (ld,__tmp_reg__,%1+) CR_TAB
- AS2 (ld,%B0,%1) CR_TAB
- AS2 (mov,%A0,__tmp_reg__));
- }
- else if (reg_base == REG_X) /* (R26) */
- {
- if (reg_unused_after (insn, base))
- {
- *l = 2;
- return (AS2 (ld,%A0,X+) CR_TAB
- AS2 (ld,%B0,X));
- }
- *l = 3;
- return (AS2 (ld,%A0,X+) CR_TAB
- AS2 (ld,%B0,X) CR_TAB
- AS2 (sbiw,r26,1));
- }
- else /* (R) */
- {
- *l = 2;
- return (AS2 (ld,%A0,%1) CR_TAB
- AS2 (ldd,%B0,%1+1));
- }
+ return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB
+ "ld %B0,%1" CR_TAB
+ "mov %A0,__tmp_reg__", op, plen, -3);
+
+ if (reg_base != REG_X)
+ return avr_asm_len ("ld %A0,%1" CR_TAB
+ "ldd %B0,%1+1", op, plen, -2);
+
+ avr_asm_len ("ld %A0,X+" CR_TAB
+ "ld %B0,X", op, plen, -2);
+
+ if (!reg_unused_after (insn, base))
+ avr_asm_len ("sbiw r26,1", op, plen, 1);
+
+ return "";
}
else if (GET_CODE (base) == PLUS) /* (R + i) */
{
@@ -2714,109 +3005,90 @@ out_movhi_r_mr (rtx insn, rtx op[], int *l)
int reg_base = true_regnum (XEXP (base, 0));
if (disp > MAX_LD_OFFSET (GET_MODE (src)))
- {
- if (REGNO (XEXP (base, 0)) != REG_Y)
- fatal_insn ("incorrect insn:",insn);
-
- if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
- return *l = 4, (AS2 (adiw,r28,%o1-62) CR_TAB
- AS2 (ldd,%A0,Y+62) CR_TAB
- AS2 (ldd,%B0,Y+63) CR_TAB
- AS2 (sbiw,r28,%o1-62));
+ {
+ if (REGNO (XEXP (base, 0)) != REG_Y)
+ fatal_insn ("incorrect insn:",insn);
+
+ return disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))
+ ? avr_asm_len ("adiw r28,%o1-62" CR_TAB
+ "ldd %A0,Y+62" CR_TAB
+ "ldd %B0,Y+63" CR_TAB
+ "sbiw r28,%o1-62", op, plen, -4)
+
+ : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB
+ "sbci r29,hi8(-%o1)" CR_TAB
+ "ld %A0,Y" CR_TAB
+ "ldd %B0,Y+1" CR_TAB
+ "subi r28,lo8(%o1)" CR_TAB
+ "sbci r29,hi8(%o1)", op, plen, -6);
+ }
+
+ /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
+ it but I have this situation with extremal
+ optimization options. */
- return *l = 6, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
- AS2 (sbci,r29,hi8(-%o1)) CR_TAB
- AS2 (ld,%A0,Y) CR_TAB
- AS2 (ldd,%B0,Y+1) CR_TAB
- AS2 (subi,r28,lo8(%o1)) CR_TAB
- AS2 (sbci,r29,hi8(%o1)));
- }
if (reg_base == REG_X)
- {
- /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
- it but I have this situation with extremal
- optimization options. */
-
- *l = 4;
- if (reg_base == reg_dest)
- return (AS2 (adiw,r26,%o1) CR_TAB
- AS2 (ld,__tmp_reg__,X+) CR_TAB
- AS2 (ld,%B0,X) CR_TAB
- AS2 (mov,%A0,__tmp_reg__));
+ return reg_base == reg_dest
+ ? avr_asm_len ("adiw r26,%o1" CR_TAB
+ "ld __tmp_reg__,X+" CR_TAB
+ "ld %B0,X" CR_TAB
+ "mov %A0,__tmp_reg__", op, plen, -4)
- return (AS2 (adiw,r26,%o1) CR_TAB
- AS2 (ld,%A0,X+) CR_TAB
- AS2 (ld,%B0,X) CR_TAB
- AS2 (sbiw,r26,%o1+1));
- }
+ : avr_asm_len ("adiw r26,%o1" CR_TAB
+ "ld %A0,X+" CR_TAB
+ "ld %B0,X" CR_TAB
+ "sbiw r26,%o1+1", op, plen, -4);
- if (reg_base == reg_dest)
- {
- *l = 3;
- return (AS2 (ldd,__tmp_reg__,%A1) CR_TAB
- AS2 (ldd,%B0,%B1) CR_TAB
- AS2 (mov,%A0,__tmp_reg__));
- }
-
- *l = 2;
- return (AS2 (ldd,%A0,%A1) CR_TAB
- AS2 (ldd,%B0,%B1));
+ return reg_base == reg_dest
+ ? avr_asm_len ("ldd __tmp_reg__,%A1" CR_TAB
+ "ldd %B0,%B1" CR_TAB
+ "mov %A0,__tmp_reg__", op, plen, -3)
+
+ : avr_asm_len ("ldd %A0,%A1" CR_TAB
+ "ldd %B0,%B1", op, plen, -2);
}
else if (GET_CODE (base) == PRE_DEC) /* (--R) */
{
if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
- fatal_insn ("incorrect insn:", insn);
-
- if (mem_volatile_p)
- {
- if (REGNO (XEXP (base, 0)) == REG_X)
- {
- *l = 4;
- return (AS2 (sbiw,r26,2) CR_TAB
- AS2 (ld,%A0,X+) CR_TAB
- AS2 (ld,%B0,X) CR_TAB
- AS2 (sbiw,r26,1));
- }
- else
- {
- *l = 3;
- return (AS2 (sbiw,%r1,2) CR_TAB
- AS2 (ld,%A0,%p1) CR_TAB
- AS2 (ldd,%B0,%p1+1));
- }
- }
+ fatal_insn ("incorrect insn:", insn);
- *l = 2;
- return (AS2 (ld,%B0,%1) CR_TAB
- AS2 (ld,%A0,%1));
+ if (!mem_volatile_p)
+ return avr_asm_len ("ld %B0,%1" CR_TAB
+ "ld %A0,%1", op, plen, -2);
+
+ return REGNO (XEXP (base, 0)) == REG_X
+ ? avr_asm_len ("sbiw r26,2" CR_TAB
+ "ld %A0,X+" CR_TAB
+ "ld %B0,X" CR_TAB
+ "sbiw r26,1", op, plen, -4)
+
+ : avr_asm_len ("sbiw %r1,2" CR_TAB
+ "ld %A0,%p1" CR_TAB
+ "ldd %B0,%p1+1", op, plen, -3);
}
else if (GET_CODE (base) == POST_INC) /* (R++) */
{
if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
- fatal_insn ("incorrect insn:", insn);
+ fatal_insn ("incorrect insn:", insn);
- *l = 2;
- return (AS2 (ld,%A0,%1) CR_TAB
- AS2 (ld,%B0,%1));
+ return avr_asm_len ("ld %A0,%1" CR_TAB
+ "ld %B0,%1", op, plen, -2);
}
else if (CONSTANT_ADDRESS_P (base))
{
- if (optimize > 0 && io_address_operand (base, HImode))
- {
- *l = 2;
- return (AS2 (in,%A0,%m1-0x20) CR_TAB
- AS2 (in,%B0,%m1+1-0x20));
- }
- *l = 4;
- return (AS2 (lds,%A0,%m1) CR_TAB
- AS2 (lds,%B0,%m1+1));
+ return optimize > 0 && io_address_operand (base, HImode)
+ ? avr_asm_len ("in %A0,%i1" CR_TAB
+ "in %B0,%i1+1", op, plen, -2)
+
+ : avr_asm_len ("lds %A0,%m1" CR_TAB
+ "lds %B0,%m1+1", op, plen, -4);
}
fatal_insn ("unknown move insn:",insn);
return "";
}
-const char *
+static const char*
out_movsi_r_mr (rtx insn, rtx op[], int *l)
{
rtx dest = op[0];
@@ -2977,7 +3249,7 @@ out_movsi_r_mr (rtx insn, rtx op[], int *l)
return "";
}
-const char *
+static const char*
out_movsi_mr_r (rtx insn, rtx op[], int *l)
{
rtx dest = op[0];
@@ -3182,34 +3454,10 @@ output_movsisf (rtx insn, rtx operands[], int *l)
AS2 (mov,%D0,%D1));
}
}
- else if (CONST_INT_P (src)
- || CONST_DOUBLE_P (src))
- {
- return output_reload_insisf (operands, NULL_RTX, real_l);
- }
else if (CONSTANT_P (src))
{
- if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
- {
- *l = 4;
- return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
- AS2 (ldi,%B0,hi8(%1)) CR_TAB
- AS2 (ldi,%C0,hlo8(%1)) CR_TAB
- AS2 (ldi,%D0,hhi8(%1)));
- }
- /* Last resort, better than loading from memory. */
- *l = 10;
- return (AS2 (mov,__tmp_reg__,r31) CR_TAB
- AS2 (ldi,r31,lo8(%1)) CR_TAB
- AS2 (mov,%A0,r31) CR_TAB
- AS2 (ldi,r31,hi8(%1)) CR_TAB
- AS2 (mov,%B0,r31) CR_TAB
- AS2 (ldi,r31,hlo8(%1)) CR_TAB
- AS2 (mov,%C0,r31) CR_TAB
- AS2 (ldi,r31,hhi8(%1)) CR_TAB
- AS2 (mov,%D0,r31) CR_TAB
- AS2 (mov,r31,__tmp_reg__));
- }
+ return output_reload_insisf (operands, NULL_RTX, real_l);
+ }
else if (GET_CODE (src) == MEM)
return out_movsi_r_mr (insn, operands, real_l); /* mov r,m */
}
@@ -3496,41 +3744,21 @@ avr_out_movpsi (rtx insn, rtx *op, int *plen)
return avr_asm_len ("mov %C0,%C1", op, plen, 1);
}
}
- else if (CONST_INT_P (src))
- {
- return avr_out_reload_inpsi (op, NULL_RTX, plen);
- }
else if (CONSTANT_P (src))
{
- if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
- {
- return avr_asm_len ("ldi %A0,lo8(%1)" CR_TAB
- "ldi %B0,hi8(%1)" CR_TAB
- "ldi %C0,hh8(%1)", op, plen, -3);
- }
-
- /* Last resort, better than loading from memory. */
- return avr_asm_len ("mov __tmp_reg__,r31" CR_TAB
- "ldi r31,lo8(%1)" CR_TAB
- "mov %A0,r31" CR_TAB
- "ldi r31,hi8(%1)" CR_TAB
- "mov %B0,r31" CR_TAB
- "ldi r31,hh8(%1)" CR_TAB
- "mov %C0,r31" CR_TAB
- "mov r31,__tmp_reg__", op, plen, -8);
+ return avr_out_reload_inpsi (op, NULL_RTX, plen);
}
else if (MEM_P (src))
return avr_out_load_psi (insn, op, plen); /* mov r,m */
}
else if (MEM_P (dest))
{
- if (src == CONST0_RTX (GET_MODE (dest)))
- op[1] = zero_reg_rtx;
-
- avr_out_store_psi (insn, op, plen);
+ rtx xop[2];
+
+ xop[0] = dest;
+ xop[1] = src == CONST0_RTX (GET_MODE (dest)) ? zero_reg_rtx : src;
- op[1] = src;
- return "";
+ return avr_out_store_psi (insn, xop, plen);
}
fatal_insn ("invalid insn:", insn);
@@ -3538,88 +3766,71 @@ avr_out_movpsi (rtx insn, rtx *op, int *plen)
}
-const char *
-out_movqi_mr_r (rtx insn, rtx op[], int *l)
+static const char*
+out_movqi_mr_r (rtx insn, rtx op[], int *plen)
{
rtx dest = op[0];
rtx src = op[1];
rtx x = XEXP (dest, 0);
- int dummy;
-
- if (!l)
- l = &dummy;
if (CONSTANT_ADDRESS_P (x))
{
- if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
- {
- *l = 1;
- return AS2 (out,__SREG__,%1);
- }
- if (optimize > 0 && io_address_operand (x, QImode))
- {
- *l = 1;
- return AS2 (out,%m0-0x20,%1);
- }
- *l = 2;
- return AS2 (sts,%m0,%1);
+ return optimize > 0 && io_address_operand (x, QImode)
+ ? avr_asm_len ("out %i0,%1", op, plen, -1)
+ : avr_asm_len ("sts %m0,%1", op, plen, -2);
}
- /* memory access by reg+disp */
- else if (GET_CODE (x) == PLUS
- && REG_P (XEXP (x,0))
- && GET_CODE (XEXP (x,1)) == CONST_INT)
+ else if (GET_CODE (x) == PLUS
+ && REG_P (XEXP (x, 0))
+ && CONST_INT_P (XEXP (x, 1)))
{
- if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (dest))) >= 63)
- {
- int disp = INTVAL (XEXP (x,1));
- if (REGNO (XEXP (x,0)) != REG_Y)
- fatal_insn ("incorrect insn:",insn);
+ /* memory access by reg+disp */
- if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
- return *l = 3, (AS2 (adiw,r28,%o0-63) CR_TAB
- AS2 (std,Y+63,%1) CR_TAB
- AS2 (sbiw,r28,%o0-63));
+ int disp = INTVAL (XEXP (x, 1));
- return *l = 5, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
- AS2 (sbci,r29,hi8(-%o0)) CR_TAB
- AS2 (st,Y,%1) CR_TAB
- AS2 (subi,r28,lo8(%o0)) CR_TAB
- AS2 (sbci,r29,hi8(%o0)));
- }
+ if (disp - GET_MODE_SIZE (GET_MODE (dest)) >= 63)
+ {
+ if (REGNO (XEXP (x, 0)) != REG_Y)
+ fatal_insn ("incorrect insn:",insn);
+
+ if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+ return avr_asm_len ("adiw r28,%o0-63" CR_TAB
+ "std Y+63,%1" CR_TAB
+ "sbiw r28,%o0-63", op, plen, -3);
+
+ return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB
+ "sbci r29,hi8(-%o0)" CR_TAB
+ "st Y,%1" CR_TAB
+ "subi r28,lo8(%o0)" CR_TAB
+ "sbci r29,hi8(%o0)", op, plen, -5);
+ }
else if (REGNO (XEXP (x,0)) == REG_X)
- {
- if (reg_overlap_mentioned_p (src, XEXP (x, 0)))
- {
- if (reg_unused_after (insn, XEXP (x,0)))
- return *l = 3, (AS2 (mov,__tmp_reg__,%1) CR_TAB
- AS2 (adiw,r26,%o0) CR_TAB
- AS2 (st,X,__tmp_reg__));
-
- return *l = 4, (AS2 (mov,__tmp_reg__,%1) CR_TAB
- AS2 (adiw,r26,%o0) CR_TAB
- AS2 (st,X,__tmp_reg__) CR_TAB
- AS2 (sbiw,r26,%o0));
- }
- else
- {
- if (reg_unused_after (insn, XEXP (x,0)))
- return *l = 2, (AS2 (adiw,r26,%o0) CR_TAB
- AS2 (st,X,%1));
+ {
+ if (reg_overlap_mentioned_p (src, XEXP (x, 0)))
+ {
+ avr_asm_len ("mov __tmp_reg__,%1" CR_TAB
+ "adiw r26,%o0" CR_TAB
+ "st X,__tmp_reg__", op, plen, -3);
+ }
+ else
+ {
+ avr_asm_len ("adiw r26,%o0" CR_TAB
+ "st X,%1", op, plen, -2);
+ }
+
+ if (!reg_unused_after (insn, XEXP (x,0)))
+ avr_asm_len ("sbiw r26,%o0", op, plen, 1);
- return *l = 3, (AS2 (adiw,r26,%o0) CR_TAB
- AS2 (st,X,%1) CR_TAB
- AS2 (sbiw,r26,%o0));
- }
- }
- *l = 1;
- return AS2 (std,%0,%1);
+ return "";
+ }
+
+ return avr_asm_len ("std %0,%1", op, plen, 1);
}
- *l = 1;
- return AS2 (st,%0,%1);
+
+ return avr_asm_len ("st %0,%1", op, plen, 1);
}
-const char *
-out_movhi_mr_r (rtx insn, rtx op[], int *l)
+static const char*
+out_movhi_mr_r (rtx insn, rtx op[], int *plen)
{
rtx dest = op[0];
rtx src = op[1];
@@ -3629,127 +3840,103 @@ out_movhi_mr_r (rtx insn, rtx op[], int *l)
/* "volatile" forces writing high byte first, even if less efficient,
for correct operation with 16-bit I/O registers. */
int mem_volatile_p = MEM_VOLATILE_P (dest);
- int tmp;
- if (!l)
- l = &tmp;
if (CONSTANT_ADDRESS_P (base))
- {
- if (optimize > 0 && io_address_operand (base, HImode))
- {
- *l = 2;
- return (AS2 (out,%m0+1-0x20,%B1) CR_TAB
- AS2 (out,%m0-0x20,%A1));
- }
- return *l = 4, (AS2 (sts,%m0+1,%B1) CR_TAB
- AS2 (sts,%m0,%A1));
- }
+ return optimize > 0 && io_address_operand (base, HImode)
+ ? avr_asm_len ("out %i0+1,%B1" CR_TAB
+ "out %i0,%A1", op, plen, -2)
+
+ : avr_asm_len ("sts %m0+1,%B1" CR_TAB
+ "sts %m0,%A1", op, plen, -4);
+
if (reg_base > 0)
{
- if (reg_base == REG_X)
- {
- if (reg_src == REG_X)
- {
- /* "st X+,r26" and "st -X,r26" are undefined. */
- if (!mem_volatile_p && reg_unused_after (insn, src))
- return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
- AS2 (st,X,r26) CR_TAB
- AS2 (adiw,r26,1) CR_TAB
- AS2 (st,X,__tmp_reg__));
- else
- return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
- AS2 (adiw,r26,1) CR_TAB
- AS2 (st,X,__tmp_reg__) CR_TAB
- AS2 (sbiw,r26,1) CR_TAB
- AS2 (st,X,r26));
- }
- else
- {
- if (!mem_volatile_p && reg_unused_after (insn, base))
- return *l=2, (AS2 (st,X+,%A1) CR_TAB
- AS2 (st,X,%B1));
- else
- return *l=3, (AS2 (adiw,r26,1) CR_TAB
- AS2 (st,X,%B1) CR_TAB
- AS2 (st,-X,%A1));
- }
- }
- else
- return *l=2, (AS2 (std,%0+1,%B1) CR_TAB
- AS2 (st,%0,%A1));
+ if (reg_base != REG_X)
+ return avr_asm_len ("std %0+1,%B1" CR_TAB
+ "st %0,%A1", op, plen, -2);
+
+ if (reg_src == REG_X)
+ /* "st X+,r26" and "st -X,r26" are undefined. */
+ return !mem_volatile_p && reg_unused_after (insn, src)
+ ? avr_asm_len ("mov __tmp_reg__,r27" CR_TAB
+ "st X,r26" CR_TAB
+ "adiw r26,1" CR_TAB
+ "st X,__tmp_reg__", op, plen, -4)
+
+ : avr_asm_len ("mov __tmp_reg__,r27" CR_TAB
+ "adiw r26,1" CR_TAB
+ "st X,__tmp_reg__" CR_TAB
+ "sbiw r26,1" CR_TAB
+ "st X,r26", op, plen, -5);
+
+ return !mem_volatile_p && reg_unused_after (insn, base)
+ ? avr_asm_len ("st X+,%A1" CR_TAB
+ "st X,%B1", op, plen, -2)
+ : avr_asm_len ("adiw r26,1" CR_TAB
+ "st X,%B1" CR_TAB
+ "st -X,%A1", op, plen, -3);
}
else if (GET_CODE (base) == PLUS)
{
int disp = INTVAL (XEXP (base, 1));
reg_base = REGNO (XEXP (base, 0));
if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
- {
- if (reg_base != REG_Y)
- fatal_insn ("incorrect insn:",insn);
-
- if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
- return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
- AS2 (std,Y+63,%B1) CR_TAB
- AS2 (std,Y+62,%A1) CR_TAB
- AS2 (sbiw,r28,%o0-62));
-
- return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
- AS2 (sbci,r29,hi8(-%o0)) CR_TAB
- AS2 (std,Y+1,%B1) CR_TAB
- AS2 (st,Y,%A1) CR_TAB
- AS2 (subi,r28,lo8(%o0)) CR_TAB
- AS2 (sbci,r29,hi8(%o0)));
- }
- if (reg_base == REG_X)
- {
- /* (X + d) = R */
- if (reg_src == REG_X)
- {
- *l = 7;
- return (AS2 (mov,__tmp_reg__,r26) CR_TAB
- AS2 (mov,__zero_reg__,r27) CR_TAB
- AS2 (adiw,r26,%o0+1) CR_TAB
- AS2 (st,X,__zero_reg__) CR_TAB
- AS2 (st,-X,__tmp_reg__) CR_TAB
- AS1 (clr,__zero_reg__) CR_TAB
- AS2 (sbiw,r26,%o0));
- }
- *l = 4;
- return (AS2 (adiw,r26,%o0+1) CR_TAB
- AS2 (st,X,%B1) CR_TAB
- AS2 (st,-X,%A1) CR_TAB
- AS2 (sbiw,r26,%o0));
- }
- return *l=2, (AS2 (std,%B0,%B1) CR_TAB
- AS2 (std,%A0,%A1));
+ {
+ if (reg_base != REG_Y)
+ fatal_insn ("incorrect insn:",insn);
+
+ return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))
+ ? avr_asm_len ("adiw r28,%o0-62" CR_TAB
+ "std Y+63,%B1" CR_TAB
+ "std Y+62,%A1" CR_TAB
+ "sbiw r28,%o0-62", op, plen, -4)
+
+ : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB
+ "sbci r29,hi8(-%o0)" CR_TAB
+ "std Y+1,%B1" CR_TAB
+ "st Y,%A1" CR_TAB
+ "subi r28,lo8(%o0)" CR_TAB
+ "sbci r29,hi8(%o0)", op, plen, -6);
+ }
+
+ if (reg_base != REG_X)
+ return avr_asm_len ("std %B0,%B1" CR_TAB
+ "std %A0,%A1", op, plen, -2);
+ /* (X + d) = R */
+ return reg_src == REG_X
+ ? avr_asm_len ("mov __tmp_reg__,r26" CR_TAB
+ "mov __zero_reg__,r27" CR_TAB
+ "adiw r26,%o0+1" CR_TAB
+ "st X,__zero_reg__" CR_TAB
+ "st -X,__tmp_reg__" CR_TAB
+ "clr __zero_reg__" CR_TAB
+ "sbiw r26,%o0", op, plen, -7)
+
+ : avr_asm_len ("adiw r26,%o0+1" CR_TAB
+ "st X,%B1" CR_TAB
+ "st -X,%A1" CR_TAB
+ "sbiw r26,%o0", op, plen, -4);
}
else if (GET_CODE (base) == PRE_DEC) /* (--R) */
- return *l=2, (AS2 (st,%0,%B1) CR_TAB
- AS2 (st,%0,%A1));
+ {
+ return avr_asm_len ("st %0,%B1" CR_TAB
+ "st %0,%A1", op, plen, -2);
+ }
else if (GET_CODE (base) == POST_INC) /* (R++) */
{
- if (mem_volatile_p)
- {
- if (REGNO (XEXP (base, 0)) == REG_X)
- {
- *l = 4;
- return (AS2 (adiw,r26,1) CR_TAB
- AS2 (st,X,%B1) CR_TAB
- AS2 (st,-X,%A1) CR_TAB
- AS2 (adiw,r26,2));
- }
- else
- {
- *l = 3;
- return (AS2 (std,%p0+1,%B1) CR_TAB
- AS2 (st,%p0,%A1) CR_TAB
- AS2 (adiw,%r0,2));
- }
- }
+ if (!mem_volatile_p)
+ return avr_asm_len ("st %0,%A1" CR_TAB
+ "st %0,%B1", op, plen, -2);
+
+ return REGNO (XEXP (base, 0)) == REG_X
+ ? avr_asm_len ("adiw r26,1" CR_TAB
+ "st X,%B1" CR_TAB
+ "st -X,%A1" CR_TAB
+ "adiw r26,2", op, plen, -4)
- *l = 2;
- return (AS2 (st,%0,%A1) CR_TAB
- AS2 (st,%0,%B1));
+ : avr_asm_len ("std %p0+1,%B1" CR_TAB
+ "st %p0,%A1" CR_TAB
+ "adiw %r0,2", op, plen, -3);
}
fatal_insn ("unknown move insn:",insn);
return "";
@@ -4044,29 +4231,33 @@ avr_out_tstsi (rtx insn, rtx *op, int *plen)
}
-/* Generate asm equivalent for various shifts.
- Shift count is a CONST_INT, MEM or REG.
- This only handles cases that are not already
- carefully hand-optimized in ?sh??i3_out. */
+/* Generate asm equivalent for various shifts. This only handles cases
+ that are not already carefully hand-optimized in ?sh??i3_out.
+
+ OPERANDS[0] resp. %0 in TEMPL is the operand to be shifted.
+ OPERANDS[2] is the shift count as CONST_INT, MEM or REG.
+ OPERANDS[3] is a QImode scratch register from LD regs if
+ available and SCRATCH, otherwise (no scratch available)
+
+ TEMPL is an assembler template that shifts by one position.
+ T_LEN is the length of this template. */
void
out_shift_with_cnt (const char *templ, rtx insn, rtx operands[],
- int *len, int t_len)
+ int *plen, int t_len)
{
- rtx op[10];
- char str[500];
- int second_label = 1;
- int saved_in_tmp = 0;
- int use_zero_reg = 0;
+ bool second_label = true;
+ bool saved_in_tmp = false;
+ bool use_zero_reg = false;
+ rtx op[5];
op[0] = operands[0];
op[1] = operands[1];
op[2] = operands[2];
op[3] = operands[3];
- str[0] = 0;
- if (len)
- *len = 1;
+ if (plen)
+ *plen = 0;
if (CONST_INT_P (operands[2]))
{
@@ -4076,118 +4267,90 @@ out_shift_with_cnt (const char *templ, rtx insn, rtx operands[],
int max_len = 10; /* If larger than this, always use a loop. */
if (count <= 0)
- {
- if (len)
- *len = 0;
- return;
- }
+ return;
if (count < 8 && !scratch)
- use_zero_reg = 1;
+ use_zero_reg = true;
if (optimize_size)
- max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5));
+ max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5));
if (t_len * count <= max_len)
- {
- /* Output shifts inline with no loop - faster. */
- if (len)
- *len = t_len * count;
- else
- {
- while (count-- > 0)
- output_asm_insn (templ, op);
- }
+ {
+ /* Output shifts inline with no loop - faster. */
+
+ while (count-- > 0)
+ avr_asm_len (templ, op, plen, t_len);
- return;
- }
+ return;
+ }
if (scratch)
- {
- if (!len)
- strcat (str, AS2 (ldi,%3,%2));
- }
+ {
+ avr_asm_len ("ldi %3,%2", op, plen, 1);
+ }
else if (use_zero_reg)
- {
- /* Hack to save one word: use __zero_reg__ as loop counter.
- Set one bit, then shift in a loop until it is 0 again. */
+ {
+ /* Hack to save one word: use __zero_reg__ as loop counter.
+ Set one bit, then shift in a loop until it is 0 again. */
- op[3] = zero_reg_rtx;
- if (len)
- *len = 2;
- else
- strcat (str, ("set" CR_TAB
- AS2 (bld,%3,%2-1)));
- }
+ op[3] = zero_reg_rtx;
+
+ avr_asm_len ("set" CR_TAB
+ "bld %3,%2-1", op, plen, 2);
+ }
else
- {
- /* No scratch register available, use one from LD_REGS (saved in
- __tmp_reg__) that doesn't overlap with registers to shift. */
+ {
+ /* No scratch register available, use one from LD_REGS (saved in
+ __tmp_reg__) that doesn't overlap with registers to shift. */
- op[3] = all_regs_rtx[((REGNO (operands[0]) - 1) & 15) + 16];
- op[4] = tmp_reg_rtx;
- saved_in_tmp = 1;
+ op[3] = all_regs_rtx[((REGNO (op[0]) - 1) & 15) + 16];
+ op[4] = tmp_reg_rtx;
+ saved_in_tmp = true;
- if (len)
- *len = 3; /* Includes "mov %3,%4" after the loop. */
- else
- strcat (str, (AS2 (mov,%4,%3) CR_TAB
- AS2 (ldi,%3,%2)));
- }
+ avr_asm_len ("mov %4,%3" CR_TAB
+ "ldi %3,%2", op, plen, 2);
+ }
- second_label = 0;
+ second_label = false;
}
- else if (GET_CODE (operands[2]) == MEM)
+ else if (MEM_P (op[2]))
{
- rtx op_mov[10];
+ rtx op_mov[2];
- op[3] = op_mov[0] = tmp_reg_rtx;
+ op_mov[0] = op[3] = tmp_reg_rtx;
op_mov[1] = op[2];
- if (len)
- out_movqi_r_mr (insn, op_mov, len);
- else
- output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
+ out_movqi_r_mr (insn, op_mov, plen);
}
- else if (register_operand (operands[2], QImode))
+ else if (register_operand (op[2], QImode))
{
- if (reg_unused_after (insn, operands[2])
- && !reg_overlap_mentioned_p (operands[0], operands[2]))
+ op[3] = op[2];
+
+ if (!reg_unused_after (insn, op[2])
+ || reg_overlap_mentioned_p (op[0], op[2]))
{
- op[3] = op[2];
+ op[3] = tmp_reg_rtx;
+ avr_asm_len ("mov %3,%2", op, plen, 1);
}
- else
- {
- op[3] = tmp_reg_rtx;
- if (!len)
- strcat (str, (AS2 (mov,%3,%2) CR_TAB));
- }
}
else
fatal_insn ("bad shift insn:", insn);
if (second_label)
- {
- if (len)
- ++*len;
- else
- strcat (str, AS1 (rjmp,2f));
- }
+ avr_asm_len ("rjmp 2f", op, plen, 1);
- if (len)
- *len += t_len + 2; /* template + dec + brXX */
- else
- {
- strcat (str, "\n1:\t");
- strcat (str, templ);
- strcat (str, second_label ? "\n2:\t" : "\n\t");
- strcat (str, use_zero_reg ? AS1 (lsr,%3) : AS1 (dec,%3));
- strcat (str, CR_TAB);
- strcat (str, second_label ? AS1 (brpl,1b) : AS1 (brne,1b));
- if (saved_in_tmp)
- strcat (str, (CR_TAB AS2 (mov,%3,%4)));
- output_asm_insn (str, op);
- }
+ avr_asm_len ("1:", op, plen, 0);
+ avr_asm_len (templ, op, plen, t_len);
+
+ if (second_label)
+ avr_asm_len ("2:", op, plen, 0);
+
+ avr_asm_len (use_zero_reg ? "lsr %3" : "dec %3", op, plen, 1);
+ avr_asm_len (second_label ? "brpl 1b" : "brne 1b", op, plen, 1);
+
+ if (saved_in_tmp)
+ avr_asm_len ("mov %3,%4", op, plen, 1);
}
@@ -5652,7 +5815,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
bool ld_reg_p = test_hard_reg_class (LD_REGS, reg8);
op[0] = reg8;
- op[1] = GEN_INT (val8);
+ op[1] = gen_int_mode (val8, QImode);
/* To get usable cc0 no low-bytes must have been skipped. */
@@ -6201,7 +6364,9 @@ adjust_insn_length (rtx insn, int len)
case ADJUST_LEN_MOV16: output_movhi (insn, op, &len); break;
case ADJUST_LEN_MOV24: avr_out_movpsi (insn, op, &len); break;
case ADJUST_LEN_MOV32: output_movsisf (insn, op, &len); break;
-
+ case ADJUST_LEN_MOVMEM: avr_out_movmem (insn, op, &len); break;
+ case ADJUST_LEN_XLOAD: avr_out_xload (insn, op, &len); break;
+
case ADJUST_LEN_TSTHI: avr_out_tsthi (insn, op, &len); break;
case ADJUST_LEN_TSTPSI: avr_out_tstpsi (insn, op, &len); break;
case ADJUST_LEN_TSTSI: avr_out_tstsi (insn, op, &len); break;
@@ -6346,6 +6511,49 @@ _reg_unused_after (rtx insn, rtx reg)
return 1;
}
+
+/* Return RTX that represents the lower 16 bits of a constant address.
+ Unfortunately, simplify_gen_subreg does not handle this case. */
+
+static rtx
+avr_const_address_lo16 (rtx x)
+{
+ rtx lo16;
+
+ switch (GET_CODE (x))
+ {
+ default:
+ break;
+
+ case CONST:
+ if (PLUS == GET_CODE (XEXP (x, 0))
+ && SYMBOL_REF == GET_CODE (XEXP (XEXP (x, 0), 0))
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1)))
+ {
+ HOST_WIDE_INT offset = INTVAL (XEXP (XEXP (x, 0), 1));
+ const char *name = XSTR (XEXP (XEXP (x, 0), 0), 0);
+
+ lo16 = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
+ lo16 = gen_rtx_CONST (Pmode, plus_constant (lo16, offset));
+
+ return lo16;
+ }
+
+ break;
+
+ case SYMBOL_REF:
+ {
+ const char *name = XSTR (x, 0);
+
+ return gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
+ }
+ }
+
+ avr_edump ("\n%?: %r\n", x);
+ gcc_unreachable();
+}
+
+
/* Target hook for assembling integer objects. The AVR version needs
special handling for references to certain labels. */
@@ -6358,11 +6566,30 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
fputs ("\t.word\tgs(", asm_out_file);
output_addr_const (asm_out_file, x);
fputs (")\n", asm_out_file);
+
return true;
}
+ else if (GET_MODE (x) == PSImode)
+ {
+ default_assemble_integer (avr_const_address_lo16 (x),
+ GET_MODE_SIZE (HImode), aligned_p);
+
+ fputs ("\t.warning\t\"assembling 24-bit address needs binutils extension for hh8(",
+ asm_out_file);
+ output_addr_const (asm_out_file, x);
+ fputs (")\"\n", asm_out_file);
+
+ fputs ("\t.byte\t0\t" ASM_COMMENT_START " hh8(", asm_out_file);
+ output_addr_const (asm_out_file, x);
+ fputs (")\n", asm_out_file);
+
+ return true;
+ }
+
return default_assemble_integer (x, size, aligned_p);
}
+
/* Worker function for ASM_DECLARE_FUNCTION_NAME. */
void
@@ -6518,6 +6745,7 @@ avr_attribute_table[] =
Return non-zero if DECL is data that must end up in Flash and
zero if the data lives in RAM (.bss, .data, .rodata, ...).
+ Return 2 if DECL is located in 24-bit flash address-space
Return 1 if DECL is located in 16-bit flash address-space
Return -1 if attribute `progmem' occurs in DECL or ATTRIBUTES
Return 0 otherwise */
@@ -6530,6 +6758,9 @@ avr_progmem_p (tree decl, tree attributes)
if (TREE_CODE (decl) != VAR_DECL)
return 0;
+ if (avr_decl_pgmx_p (decl))
+ return 2;
+
if (avr_decl_pgm_p (decl))
return 1;
@@ -6745,11 +6976,23 @@ avr_output_bss_section_asm_op (const void *data)
}
+/* Unnamed section callback for progmem*.data sections. */
+
+static void
+avr_output_progmem_section_asm_op (const void *data)
+{
+ fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n",
+ (const char*) data);
+}
+
+
/* Implement `TARGET_ASM_INIT_SECTIONS'. */
static void
avr_asm_init_sections (void)
{
+ unsigned int n;
+
/* Set up a section for jump tables. Alignment is handled by
ASM_OUTPUT_BEFORE_CASE_LABEL. */
@@ -6768,9 +7011,12 @@ avr_asm_init_sections (void)
",\"ax\",@progbits");
}
- progmem_section
- = get_unnamed_section (0, output_section_asm_op,
- "\t.section\t.progmem.data,\"a\",@progbits");
+ for (n = 0; n < sizeof (progmem_section) / sizeof (*progmem_section); n++)
+ {
+ progmem_section[n]
+ = get_unnamed_section (0, avr_output_progmem_section_asm_op,
+ progmem_section_prefix[n]);
+ }
/* Override section callbacks to keep track of `avr_need_clear_bss_p'
resp. `avr_need_copy_data_p'. */
@@ -6849,8 +7095,9 @@ avr_asm_named_section (const char *name, unsigned int flags, tree decl)
{
if (flags & AVR_SECTION_PROGMEM)
{
+ int segment = (flags & AVR_SECTION_PROGMEM) / SECTION_MACH_DEP - 1;
const char *old_prefix = ".rodata";
- const char *new_prefix = ".progmem.data";
+ const char *new_prefix = progmem_section_prefix[segment];
const char *sname = new_prefix;
if (STR_PREFIX_P (name, old_prefix))
@@ -6877,6 +7124,7 @@ avr_asm_named_section (const char *name, unsigned int flags, tree decl)
static unsigned int
avr_section_type_flags (tree decl, const char *name, int reloc)
{
+ int prog;
unsigned int flags = default_section_type_flags (decl, name, reloc);
if (STR_PREFIX_P (name, ".noinit"))
@@ -6890,11 +7138,16 @@ avr_section_type_flags (tree decl, const char *name, int reloc)
}
if (decl && DECL_P (decl)
- && avr_progmem_p (decl, DECL_ATTRIBUTES (decl)))
+ && (prog = avr_progmem_p (decl, DECL_ATTRIBUTES (decl)), prog))
{
+ int segment = 0;
+
+ if (prog == 1)
+ segment = avr_pgm_segment (TYPE_ADDR_SPACE (TREE_TYPE (decl)));
+
flags &= ~SECTION_WRITE;
flags &= ~SECTION_BSS;
- flags |= AVR_SECTION_PROGMEM;
+ flags |= (1 + segment % avr_current_arch->n_segments) * SECTION_MACH_DEP;
}
return flags;
@@ -6930,16 +7183,25 @@ avr_encode_section_info (tree decl, rtx rtl,
static section *
avr_asm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
{
+ int prog;
+
section * sect = default_elf_select_section (decl, reloc, align);
if (decl && DECL_P (decl)
- && avr_progmem_p (decl, DECL_ATTRIBUTES (decl)))
+ && (prog = avr_progmem_p (decl, DECL_ATTRIBUTES (decl)), prog))
{
+ int segment = 0;
+
+ if (prog == 1)
+ segment = avr_pgm_segment (TYPE_ADDR_SPACE (TREE_TYPE (decl)));
+
+ segment %= avr_current_arch->n_segments;
+
if (sect->common.flags & SECTION_NAMED)
{
const char * name = sect->named.name;
const char * old_prefix = ".rodata";
- const char * new_prefix = ".progmem.data";
+ const char * new_prefix = progmem_section_prefix[segment];
if (STR_PREFIX_P (name, old_prefix))
{
@@ -6950,31 +7212,38 @@ avr_asm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
}
}
- return progmem_section;
+ return progmem_section[segment];
}
return sect;
}
/* Implement `TARGET_ASM_FILE_START'. */
-/* Outputs some appropriate text to go at the start of an assembler
- file. */
+/* Outputs some text at the start of each assembler file. */
static void
avr_file_start (void)
{
+ int sfr_offset = avr_current_arch->sfr_offset;
+
if (avr_current_arch->asm_only)
error ("MCU %qs supported for assembler only", avr_current_device->name);
default_file_start ();
-/* fprintf (asm_out_file, "\t.arch %s\n", avr_current_device->name);*/
- fputs ("__SREG__ = 0x3f\n"
- "__SP_H__ = 0x3e\n"
- "__SP_L__ = 0x3d\n", asm_out_file);
-
- fputs ("__tmp_reg__ = 0\n"
- "__zero_reg__ = 1\n", asm_out_file);
+ fprintf (asm_out_file,
+ "__SREG__ = 0x%02x\n"
+ "__SP_H__ = 0x%02x\n"
+ "__SP_L__ = 0x%02x\n"
+ "__RAMPZ__ = 0x%02x\n"
+ "__tmp_reg__ = %d\n"
+ "__zero_reg__ = %d\n",
+ -sfr_offset + SREG_ADDR,
+ -sfr_offset + SP_ADDR + 1,
+ -sfr_offset + SP_ADDR,
+ -sfr_offset + RAMPZ_ADDR,
+ TMP_REGNO,
+ ZERO_REGNO);
}
@@ -8644,7 +8913,7 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
xop[1] = src;
xop[2] = clobber_reg;
- if (n >= 2)
+ if (n >= 2 + (avr_current_arch->n_segments > 1))
avr_asm_len ("clr %0", xop, len, 1);
else
avr_asm_len (asm_code[n][ldreg_p], xop, len, ldreg_p ? 1 : 2);
@@ -8820,7 +9089,9 @@ const char *
output_reload_insisf (rtx *op, rtx clobber_reg, int *len)
{
if (AVR_HAVE_MOVW
- && !test_hard_reg_class (LD_REGS, op[0]))
+ && !test_hard_reg_class (LD_REGS, op[0])
+ && (CONST_INT_P (op[1])
+ || CONST_DOUBLE_P (op[1])))
{
int len_clr, len_noclr;
@@ -8954,8 +9225,8 @@ const char *
avr_out_sbxx_branch (rtx insn, rtx operands[])
{
enum rtx_code comp = GET_CODE (operands[0]);
- int long_jump = (get_attr_length (insn) >= 4);
- int reverse = long_jump || jump_over_one_insn_p (insn, operands[3]);
+ bool long_jump = get_attr_length (insn) >= 4;
+ bool reverse = long_jump || jump_over_one_insn_p (insn, operands[3]);
if (comp == GE)
comp = EQ;
@@ -8965,49 +9236,61 @@ avr_out_sbxx_branch (rtx insn, rtx operands[])
if (reverse)
comp = reverse_condition (comp);
- if (GET_CODE (operands[1]) == CONST_INT)
+ switch (GET_CODE (operands[1]))
{
- if (INTVAL (operands[1]) < 0x40)
- {
- if (comp == EQ)
- output_asm_insn (AS2 (sbis,%m1-0x20,%2), operands);
- else
- output_asm_insn (AS2 (sbic,%m1-0x20,%2), operands);
- }
+ default:
+ gcc_unreachable();
+
+ case CONST_INT:
+
+ if (low_io_address_operand (operands[1], QImode))
+ {
+ if (comp == EQ)
+ output_asm_insn ("sbis %i1,%2", operands);
+ else
+ output_asm_insn ("sbic %i1,%2", operands);
+ }
else
- {
- output_asm_insn (AS2 (in,__tmp_reg__,%m1-0x20), operands);
- if (comp == EQ)
- output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands);
- else
- output_asm_insn (AS2 (sbrc,__tmp_reg__,%2), operands);
- }
- }
- else /* GET_CODE (operands[1]) == REG */
- {
+ {
+ output_asm_insn ("in __tmp_reg__,%i1", operands);
+ if (comp == EQ)
+ output_asm_insn ("sbrs __tmp_reg__,%2", operands);
+ else
+ output_asm_insn ("sbrc __tmp_reg__,%2", operands);
+ }
+
+ break; /* CONST_INT */
+
+ case REG:
+
if (GET_MODE (operands[1]) == QImode)
- {
- if (comp == EQ)
- output_asm_insn (AS2 (sbrs,%1,%2), operands);
- else
- output_asm_insn (AS2 (sbrc,%1,%2), operands);
- }
- else /* HImode or SImode */
- {
- static char buf[] = "sbrc %A1,0";
- int bit_nr = INTVAL (operands[2]);
- buf[3] = (comp == EQ) ? 's' : 'c';
- buf[6] = 'A' + (bit_nr >> 3);
- buf[9] = '0' + (bit_nr & 7);
- output_asm_insn (buf, operands);
- }
- }
+ {
+ if (comp == EQ)
+ output_asm_insn ("sbrs %1,%2", operands);
+ else
+ output_asm_insn ("sbrc %1,%2", operands);
+ }
+ else /* HImode, PSImode or SImode */
+ {
+ static char buf[] = "sbrc %A1,0";
+ unsigned int bit_nr = UINTVAL (operands[2]);
+
+ buf[3] = (comp == EQ) ? 's' : 'c';
+ buf[6] = 'A' + (bit_nr / 8);
+ buf[9] = '0' + (bit_nr % 8);
+ output_asm_insn (buf, operands);
+ }
+
+ break; /* REG */
+ } /* switch */
if (long_jump)
- return (AS1 (rjmp,.+4) CR_TAB
- AS1 (jmp,%x3));
+ return ("rjmp .+4" CR_TAB
+ "jmp %x3");
+
if (!reverse)
- return AS1 (rjmp,%x3);
+ return "rjmp %x3";
+
return "";
}
@@ -9055,18 +9338,18 @@ avr_case_values_threshold (void)
/* Implement `TARGET_ADDR_SPACE_ADDRESS_MODE'. */
static enum machine_mode
-avr_addr_space_address_mode (addr_space_t as ATTRIBUTE_UNUSED)
+avr_addr_space_address_mode (addr_space_t as)
{
- return HImode;
+ return as == ADDR_SPACE_PGMX ? PSImode : HImode;
}
/* Implement `TARGET_ADDR_SPACE_POINTER_MODE'. */
static enum machine_mode
-avr_addr_space_pointer_mode (addr_space_t as ATTRIBUTE_UNUSED)
+avr_addr_space_pointer_mode (addr_space_t as)
{
- return HImode;
+ return as == ADDR_SPACE_PGMX ? PSImode : HImode;
}
@@ -9111,6 +9394,11 @@ avr_addr_space_legitimate_address_p (enum machine_mode mode, rtx x,
return avr_legitimate_address_p (mode, x, strict);
case ADDR_SPACE_PGM:
+ case ADDR_SPACE_PGM1:
+ case ADDR_SPACE_PGM2:
+ case ADDR_SPACE_PGM3:
+ case ADDR_SPACE_PGM4:
+ case ADDR_SPACE_PGM5:
switch (GET_CODE (x))
{
@@ -9119,8 +9407,7 @@ avr_addr_space_legitimate_address_p (enum machine_mode mode, rtx x,
break;
case POST_INC:
- ok = (!avr_load_libgcc_p (x)
- && avr_reg_ok_for_pgm_addr (XEXP (x, 0), strict));
+ ok = avr_reg_ok_for_pgm_addr (XEXP (x, 0), strict);
break;
default:
@@ -9128,6 +9415,24 @@ avr_addr_space_legitimate_address_p (enum machine_mode mode, rtx x,
}
break; /* PGM */
+
+ case ADDR_SPACE_PGMX:
+ if (REG_P (x))
+ ok = (!strict
+ && can_create_pseudo_p());
+
+ if (LO_SUM == GET_CODE (x))
+ {
+ rtx hi = XEXP (x, 0);
+ rtx lo = XEXP (x, 1);
+
+ ok = (REG_P (hi)
+ && (!strict || REGNO (hi) < FIRST_PSEUDO_REGISTER)
+ && REG_P (lo)
+ && REGNO (lo) == REG_Z);
+ }
+
+ break; /* PGMX */
}
if (avr_log.legitimate_address_p)
@@ -9177,10 +9482,60 @@ avr_addr_space_legitimize_address (rtx x, rtx old_x,
static rtx
avr_addr_space_convert (rtx src, tree type_from, tree type_to)
{
+ addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (type_from));
+ addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type_to));
+
if (avr_log.progmem)
avr_edump ("\n%!: op = %r\nfrom = %t\nto = %t\n",
src, type_from, type_to);
+ if (as_from != ADDR_SPACE_PGMX
+ && as_to == ADDR_SPACE_PGMX)
+ {
+ rtx new_src;
+ int n_segments = avr_current_arch->n_segments;
+ RTX_CODE code = GET_CODE (src);
+
+ if (CONST == code
+ && PLUS == GET_CODE (XEXP (src, 0))
+ && SYMBOL_REF == GET_CODE (XEXP (XEXP (src, 0), 0))
+ && CONST_INT_P (XEXP (XEXP (src, 0), 1)))
+ {
+ HOST_WIDE_INT offset = INTVAL (XEXP (XEXP (src, 0), 1));
+ const char *name = XSTR (XEXP (XEXP (src, 0), 0), 0);
+
+ new_src = gen_rtx_SYMBOL_REF (PSImode, ggc_strdup (name));
+ new_src = gen_rtx_CONST (PSImode,
+ plus_constant (new_src, offset));
+ return new_src;
+ }
+
+ if (SYMBOL_REF == code)
+ {
+ const char *name = XSTR (src, 0);
+
+ return gen_rtx_SYMBOL_REF (PSImode, ggc_strdup (name));
+ }
+
+ src = force_reg (Pmode, src);
+
+ if (ADDR_SPACE_GENERIC_P (as_from)
+ || as_from == ADDR_SPACE_PGM
+ || n_segments == 1)
+ {
+ return gen_rtx_ZERO_EXTEND (PSImode, src);
+ }
+ else
+ {
+ int segment = avr_pgm_segment (as_from) % n_segments;
+
+ new_src = gen_reg_rtx (PSImode);
+ emit_insn (gen_n_extendhipsi2 (new_src, GEN_INT (segment), src));
+
+ return new_src;
+ }
+ }
+
return src;
}
@@ -9188,13 +9543,242 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to)
/* Implement `TARGET_ADDR_SPACE_SUBSET_P'. */
static bool
-avr_addr_space_subset_p (addr_space_t subset ATTRIBUTE_UNUSED,
- addr_space_t superset ATTRIBUTE_UNUSED)
+avr_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
+{
+ if (subset == ADDR_SPACE_PGMX
+ && superset != ADDR_SPACE_PGMX)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+/* Worker function for movmemhi insn.
+ XOP[0] Destination as MEM:BLK
+ XOP[1] Source " "
+ XOP[2] # Bytes to copy
+
+ Return TRUE if the expansion is accomplished.
+ Return FALSE if the operand compination is not supported. */
+
+bool
+avr_emit_movmemhi (rtx *xop)
{
+ HOST_WIDE_INT count;
+ enum machine_mode loop_mode;
+ addr_space_t as = MEM_ADDR_SPACE (xop[1]);
+ rtx loop_reg, addr0, addr1, a_src, a_dest, insn, xas, reg_x;
+ rtx a_hi8 = NULL_RTX;
+
+ if (avr_mem_pgm_p (xop[0]))
+ return false;
+
+ if (!CONST_INT_P (xop[2]))
+ return false;
+
+ count = INTVAL (xop[2]);
+ if (count <= 0)
+ return false;
+
+ a_src = XEXP (xop[1], 0);
+ a_dest = XEXP (xop[0], 0);
+
+ /* See if constant fits in 8 bits. */
+
+ loop_mode = (count <= 0x100) ? QImode : HImode;
+
+ if (PSImode == GET_MODE (a_src))
+ {
+ addr1 = simplify_gen_subreg (HImode, a_src, PSImode, 0);
+ a_hi8 = simplify_gen_subreg (QImode, a_src, PSImode, 2);
+ }
+ else
+ {
+ int seg = avr_pgm_segment (as);
+
+ addr1 = a_src;
+
+ if (seg > 0
+ && seg % avr_current_arch->n_segments > 0)
+ {
+ a_hi8 = GEN_INT (seg % avr_current_arch->n_segments);
+ }
+ }
+
+ if (a_hi8
+ && avr_current_arch->n_segments > 1)
+ {
+ emit_move_insn (rampz_rtx, a_hi8 = copy_to_mode_reg (QImode, a_hi8));
+ }
+ else if (!ADDR_SPACE_GENERIC_P (as))
+ {
+ as = ADDR_SPACE_PGM;
+ }
+
+ xas = GEN_INT (as);
+
+ /* Create loop counter register */
+
+ loop_reg = copy_to_mode_reg (loop_mode, gen_int_mode (count, loop_mode));
+
+ /* Copy pointers into new pseudos - they will be changed */
+
+ addr0 = copy_to_mode_reg (HImode, a_dest);
+ addr1 = copy_to_mode_reg (HImode, addr1);
+
+ /* FIXME: Register allocator might come up with spill fails if it is left
+ on its own. Thus, we allocate the pointer registers by hand. */
+
+ emit_move_insn (lpm_addr_reg_rtx, addr1);
+ addr1 = lpm_addr_reg_rtx;
+
+ reg_x = gen_rtx_REG (HImode, REG_X);
+ emit_move_insn (reg_x, addr0);
+ addr0 = reg_x;
+
+ /* FIXME: Register allocator does a bad job and might spill address
+ register(s) inside the loop leading to additional move instruction
+ to/from stack which could clobber tmp_reg. Thus, do *not* emit
+ load and store as seperate insns. Instead, we perform the copy
+ by means of one monolithic insn. */
+
+ if (ADDR_SPACE_GENERIC_P (as))
+ {
+ rtx (*fun) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx)
+ = QImode == loop_mode ? gen_movmem_qi : gen_movmem_hi;
+
+ insn = fun (addr0, addr1, xas, loop_reg,
+ addr0, addr1, tmp_reg_rtx, loop_reg);
+ }
+ else if (as == ADDR_SPACE_PGM)
+ {
+ rtx (*fun) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx)
+ = QImode == loop_mode ? gen_movmem_qi : gen_movmem_hi;
+
+ insn = fun (addr0, addr1, xas, loop_reg, addr0, addr1,
+ AVR_HAVE_LPMX ? tmp_reg_rtx : lpm_reg_rtx, loop_reg);
+ }
+ else
+ {
+ rtx (*fun) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx)
+ = QImode == loop_mode ? gen_movmem_qi_elpm : gen_movmem_hi_elpm;
+
+ insn = fun (addr0, addr1, xas, loop_reg, addr0, addr1,
+ AVR_HAVE_ELPMX ? tmp_reg_rtx : lpm_reg_rtx, loop_reg,
+ a_hi8, a_hi8, GEN_INT (RAMPZ_ADDR));
+ }
+
+ set_mem_addr_space (SET_SRC (XVECEXP (insn, 0, 0)), as);
+ emit_insn (insn);
+
return true;
}
+/* Print assembler for movmem_qi, movmem_hi insns...
+ $0, $4 : & dest
+ $1, $5 : & src
+ $2 : Address Space
+ $3, $7 : Loop register
+ $6 : Scratch register
+
+ ...and movmem_qi_elpm, movmem_hi_elpm insns.
+
+ $8, $9 : hh8 (& src)
+ $10 : RAMPZ_ADDR
+*/
+
+const char*
+avr_out_movmem (rtx insn ATTRIBUTE_UNUSED, rtx *xop, int *plen)
+{
+ addr_space_t as = (addr_space_t) INTVAL (xop[2]);
+ enum machine_mode loop_mode = GET_MODE (xop[3]);
+
+ bool sbiw_p = test_hard_reg_class (ADDW_REGS, xop[3]);
+
+ gcc_assert (REG_X == REGNO (xop[0])
+ && REG_Z == REGNO (xop[1]));
+
+ if (plen)
+ *plen = 0;
+
+ /* Loop label */
+
+ avr_asm_len ("0:", xop, plen, 0);
+
+ /* Load with post-increment */
+
+ switch (as)
+ {
+ default:
+ gcc_unreachable();
+
+ case ADDR_SPACE_GENERIC:
+
+ avr_asm_len ("ld %6,%a1+", xop, plen, 1);
+ break;
+
+ case ADDR_SPACE_PGM:
+
+ if (AVR_HAVE_LPMX)
+ avr_asm_len ("lpm %6,%a1+", xop, plen, 1);
+ else
+ avr_asm_len ("lpm" CR_TAB
+ "adiw %1,1", xop, plen, 2);
+ break;
+
+ case ADDR_SPACE_PGM1:
+ case ADDR_SPACE_PGM2:
+ case ADDR_SPACE_PGM3:
+ case ADDR_SPACE_PGM4:
+ case ADDR_SPACE_PGM5:
+ case ADDR_SPACE_PGMX:
+
+ if (AVR_HAVE_ELPMX)
+ avr_asm_len ("elpm %6,%a1+", xop, plen, 1);
+ else
+ avr_asm_len ("elpm" CR_TAB
+ "adiw %1,1", xop, plen, 2);
+
+ if (as == ADDR_SPACE_PGMX
+ && !AVR_HAVE_ELPMX)
+ {
+ avr_asm_len ("adc %8,__zero_reg__" CR_TAB
+ "out __RAMPZ__,%8", xop, plen, 2);
+ }
+
+ break;
+ }
+
+ /* Store with post-increment */
+
+ avr_asm_len ("st %a0+,%6", xop, plen, 1);
+
+ /* Decrement loop-counter and set Z-flag */
+
+ if (QImode == loop_mode)
+ {
+ avr_asm_len ("dec %3", xop, plen, 1);
+ }
+ else if (sbiw_p)
+ {
+ avr_asm_len ("sbiw %3,1", xop, plen, 1);
+ }
+ else
+ {
+ avr_asm_len ("subi %A3,1" CR_TAB
+ "sbci %B3,0", xop, plen, 2);
+ }
+
+ /* Loop until zero */
+
+ return avr_asm_len ("brne 0b", xop, plen, 1);
+}
+
+
+
/* Helper for __builtin_avr_delay_cycles */
static void
diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h
index 24a687b309b..96133b8da28 100644
--- a/gcc/config/avr/avr.h
+++ b/gcc/config/avr/avr.h
@@ -23,7 +23,8 @@ along with GCC; see the file COPYING3. If not see
/* Names to predefine in the preprocessor for this target machine. */
-struct base_arch_s {
+struct base_arch_s
+{
/* Assembler only. */
int asm_only;
@@ -54,6 +55,13 @@ struct base_arch_s {
/* Default start of data section address for architecture. */
int default_data_section_start;
+ /* Offset between SFR address and RAM address:
+ SFR-address = RAM-address - sfr_offset */
+ int sfr_offset;
+
+ /* Number of 64k segments in the flash. */
+ int n_segments;
+
const char *const macro;
/* Architecture name. */
@@ -131,6 +139,8 @@ extern const struct base_arch_s avr_arch_types[];
#define AVR_HAVE_MUL (avr_current_arch->have_mul)
#define AVR_HAVE_MOVW (avr_current_arch->have_movw_lpmx)
#define AVR_HAVE_LPMX (avr_current_arch->have_movw_lpmx)
+#define AVR_HAVE_ELPM (avr_current_arch->have_elpm)
+#define AVR_HAVE_ELPMX (avr_current_arch->have_elpmx)
#define AVR_HAVE_RAMPZ (avr_current_arch->have_elpm)
#define AVR_HAVE_EIJMP_EICALL (avr_current_arch->have_eijmp_eicall)
#define AVR_HAVE_8BIT_SP (avr_current_device->short_sp || TARGET_TINY_STACK)
@@ -393,6 +403,12 @@ typedef struct avr_args {
#define ADDR_SPACE_PGM 1
+#define ADDR_SPACE_PGM1 2
+#define ADDR_SPACE_PGM2 3
+#define ADDR_SPACE_PGM3 4
+#define ADDR_SPACE_PGM4 5
+#define ADDR_SPACE_PGM5 6
+#define ADDR_SPACE_PGMX 7
#define REGISTER_TARGET_PRAGMAS() \
do { \
@@ -645,3 +661,5 @@ struct GTY(()) machine_function
#define PUSH_ROUNDING(X) (X)
#define ACCUMULATE_OUTGOING_ARGS avr_accumulate_outgoing_args()
+
+#define INIT_EXPANDERS avr_init_expanders()
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 78ffe866bbc..67420ce9dab 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -28,6 +28,8 @@
;; j Branch condition.
;; k Reverse branch condition.
;;..m..Constant Direct Data memory address.
+;; i Print the SFR address quivalent of a CONST_INT RAM address.
+;; The resulting addres is suitable to be used in IN/OUT.
;; o Displacement for (mem (plus (reg) (const_int))) operands.
;; p POST_INC or PRE_DEC address as a pointer (X, Y, Z)
;; r POST_INC or PRE_DEC address as a register (r26, r28, r30)
@@ -45,13 +47,17 @@
(LPM_REGNO 0) ; implicit target register of LPM
(TMP_REGNO 0) ; temporary register r0
(ZERO_REGNO 1) ; zero register r1
-
- (SREG_ADDR 0x5F)
- (RAMPZ_ADDR 0x5B)
+
+ ;; RAM addresses of some SFRs common to all Devices.
+
+ (SREG_ADDR 0x5F) ; Status Register
+ (SP_ADDR 0x5D) ; Stack Pointer
+ (RAMPZ_ADDR 0x5B) ; Address' high part when loading via ELPM
])
(define_c_enum "unspec"
[UNSPEC_STRLEN
+ UNSPEC_MOVMEM
UNSPEC_INDEX_JMP
UNSPEC_FMUL
UNSPEC_FMULS
@@ -128,6 +134,7 @@
"out_bitop, out_plus, out_plus_noclobber, addto_sp,
tsthi, tstpsi, tstsi, compare, call,
mov8, mov16, mov24, mov32, reload_in16, reload_in24, reload_in32,
+ xload, movmem,
ashlqi, ashrqi, lshrqi,
ashlhi, ashrhi, lshrhi,
ashlsi, ashrsi, lshrsi,
@@ -137,15 +144,14 @@
;; Flavours of instruction set architecture (ISA), used in enabled attribute
-;; mov: ISA has no MOVW
-;; movw: ISA has MOVW
-;; rjmp: ISA has no CALL/JMP
-;; jmp: ISA has CALL/JMP
-;; ijmp: ISA has no EICALL/EIJMP
-;; eijmp: ISA has EICALL/EIJMP
+;; mov : ISA has no MOVW movw : ISA has MOVW
+;; rjmp : ISA has no CALL/JMP jmp : ISA has CALL/JMP
+;; ijmp : ISA has no EICALL/EIJMP eijmp : ISA has EICALL/EIJMP
+;; lpm : ISA has no LPMX lpmx : ISA has LPMX
+;; elpm : ISA has ELPM but no ELPMX elpmx : ISA has ELPMX
(define_attr "isa"
- "mov,movw, rjmp,jmp, ijmp,eijmp,
+ "mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx,
standard"
(const_string "standard"))
@@ -176,6 +182,22 @@
(and (eq_attr "isa" "eijmp")
(match_test "AVR_HAVE_EIJMP_EICALL"))
(const_int 1)
+
+ (and (eq_attr "isa" "lpm")
+ (match_test "!AVR_HAVE_LPMX"))
+ (const_int 1)
+
+ (and (eq_attr "isa" "lpmx")
+ (match_test "AVR_HAVE_LPMX"))
+ (const_int 1)
+
+ (and (eq_attr "isa" "elpm")
+ (match_test "AVR_HAVE_ELPM && !AVR_HAVE_ELPMX"))
+ (const_int 1)
+
+ (and (eq_attr "isa" "elpmx")
+ (match_test "AVR_HAVE_ELPMX"))
+ (const_int 1)
] (const_int 0)))
@@ -243,12 +265,10 @@
;; even though its function is identical to that in builtins.c
(define_expand "nonlocal_goto"
- [
- (use (match_operand 0 "general_operand"))
- (use (match_operand 1 "general_operand"))
- (use (match_operand 2 "general_operand"))
- (use (match_operand 3 "general_operand"))
- ]
+ [(use (match_operand 0 "general_operand"))
+ (use (match_operand 1 "general_operand"))
+ (use (match_operand 2 "general_operand"))
+ (use (match_operand 3 "general_operand"))]
""
{
rtx r_label = copy_to_reg (operands[1]);
@@ -333,7 +353,7 @@
set_mem_addr_space (operands[1], ADDR_SPACE_PGM);
})
-(define_insn "*load.<mode>.libgcc"
+(define_insn "load_<mode>_libgcc"
[(set (reg:MOVMODE 22)
(match_operand:MOVMODE 0 "memory_operand" "m,m"))]
"avr_load_libgcc_p (operands[0])
@@ -348,6 +368,135 @@
(set_attr "cc" "clobber")])
+(define_insn_and_split "xload8_A"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (match_operand:QI 1 "memory_operand" "m"))
+ (clobber (reg:HI REG_Z))]
+ "can_create_pseudo_p()
+ && avr_mem_pgmx_p (operands[1])
+ && REG_P (XEXP (operands[1], 0))"
+ { gcc_unreachable(); }
+ "&& 1"
+ [(clobber (const_int 0))]
+ {
+ rtx insn, addr = XEXP (operands[1], 0);
+ rtx hi8 = gen_reg_rtx (QImode);
+ rtx reg_z = gen_rtx_REG (HImode, REG_Z);
+
+ emit_move_insn (reg_z, simplify_gen_subreg (HImode, addr, PSImode, 0));
+ emit_move_insn (hi8, simplify_gen_subreg (QImode, addr, PSImode, 2));
+
+ insn = emit_insn (gen_xload_8 (operands[0], hi8));
+ set_mem_addr_space (SET_SRC (single_set (insn)),
+ MEM_ADDR_SPACE (operands[1]));
+ DONE;
+ })
+
+(define_insn_and_split "xload<mode>_A"
+ [(set (match_operand:MOVMODE 0 "register_operand" "=r")
+ (match_operand:MOVMODE 1 "memory_operand" "m"))
+ (clobber (reg:QI 21))
+ (clobber (reg:HI REG_Z))]
+ "QImode != <MODE>mode
+ && can_create_pseudo_p()
+ && avr_mem_pgmx_p (operands[1])
+ && REG_P (XEXP (operands[1], 0))"
+ { gcc_unreachable(); }
+ "&& 1"
+ [(clobber (const_int 0))]
+ {
+ rtx addr = XEXP (operands[1], 0);
+ rtx reg_z = gen_rtx_REG (HImode, REG_Z);
+ rtx addr_hi8 = simplify_gen_subreg (QImode, addr, PSImode, 2);
+ addr_space_t as = MEM_ADDR_SPACE (operands[1]);
+ rtx hi8, insn;
+
+ emit_move_insn (reg_z, simplify_gen_subreg (HImode, addr, PSImode, 0));
+
+ if (avr_xload_libgcc_p (<MODE>mode))
+ {
+ emit_move_insn (gen_rtx_REG (QImode, 21), addr_hi8);
+ insn = emit_insn (gen_xload_<mode>_libgcc ());
+ emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, 22));
+ }
+ else if (avr_current_arch->n_segments == 1
+ && GET_MODE_SIZE (<MODE>mode) > 2
+ && !AVR_HAVE_LPMX)
+ {
+ rtx src = gen_rtx_MEM (<MODE>mode, reg_z);
+
+ as = ADDR_SPACE_PGM;
+ insn = emit_insn (gen_load_<mode>_libgcc (src));
+ emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, 22));
+ }
+ else
+ {
+ hi8 = gen_reg_rtx (QImode);
+ emit_move_insn (hi8, addr_hi8);
+ insn = emit_insn (gen_xload_<mode> (operands[0], hi8));
+ }
+
+ set_mem_addr_space (SET_SRC (single_set (insn)), as);
+
+ DONE;
+ })
+
+;; Move value from address space pgmx to a register
+;; These insns must be prior to respective generic move insn.
+
+(define_insn "xload_8"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (mem:QI (lo_sum:PSI (match_operand:QI 1 "register_operand" "r")
+ (reg:HI REG_Z))))]
+ ""
+ {
+ return avr_out_xload (insn, operands, NULL);
+ }
+ [(set_attr "adjust_len" "xload")
+ (set_attr "cc" "clobber")])
+
+;; "xload_hi_libgcc"
+;; "xload_psi_libgcc"
+;; "xload_si_libgcc"
+;; "xload_sf_libgcc"
+(define_insn "xload_<mode>_libgcc"
+ [(set (reg:MOVMODE 22)
+ (mem:MOVMODE (lo_sum:PSI (reg:QI 21)
+ (reg:HI REG_Z))))
+ (clobber (reg:QI 21))
+ (clobber (reg:HI REG_Z))]
+ "<MODE>mode != QImode
+ && avr_xload_libgcc_p (<MODE>mode)"
+ {
+ rtx x_bytes = GEN_INT (GET_MODE_SIZE (<MODE>mode));
+
+ /* Devices with ELPM* also have CALL. */
+
+ output_asm_insn ("call __xload_%0", &x_bytes);
+ return "";
+ }
+ [(set_attr "length" "2")
+ (set_attr "cc" "clobber")])
+
+;; "xload_hi"
+;; "xload_psi"
+;; "xload_si"
+;; "xload_sf"
+(define_insn "xload_<mode>"
+ [(set (match_operand:MOVMODE 0 "register_operand" "=r")
+ (mem:MOVMODE (lo_sum:PSI (match_operand:QI 1 "register_operand" "r")
+ (reg:HI REG_Z))))
+ (clobber (scratch:HI))
+ (clobber (reg:HI REG_Z))]
+ "<MODE>mode != QImode
+ && !avr_xload_libgcc_p (<MODE>mode)"
+ {
+ return avr_out_xload (insn, operands, NULL);
+ }
+ [(set_attr "adjust_len" "xload")
+ (set_attr "cc" "clobber")])
+
+
;; General move expanders
;; "movqi"
@@ -375,6 +524,21 @@
operands[1] = src = copy_to_mode_reg (<MODE>mode, src);
}
+ if (avr_mem_pgmx_p (src))
+ {
+ rtx addr = XEXP (src, 0);
+
+ if (!REG_P (addr))
+ src = replace_equiv_address (src, copy_to_mode_reg (PSImode, addr));
+
+ if (QImode == <MODE>mode)
+ emit_insn (gen_xload8_A (dest, src));
+ else
+ emit_insn (gen_xload<mode>_A (dest, src));
+
+ DONE;
+ }
+
if (avr_load_libgcc_p (src))
{
/* For the small devices, do loads per libgcc call. */
@@ -673,171 +837,164 @@
;;=========================================================================
;; move string (like memcpy)
-;; implement as RTL loop
(define_expand "movmemhi"
[(parallel [(set (match_operand:BLK 0 "memory_operand" "")
- (match_operand:BLK 1 "memory_operand" ""))
- (use (match_operand:HI 2 "const_int_operand" ""))
- (use (match_operand:HI 3 "const_int_operand" ""))])]
+ (match_operand:BLK 1 "memory_operand" ""))
+ (use (match_operand:HI 2 "const_int_operand" ""))
+ (use (match_operand:HI 3 "const_int_operand" ""))])]
""
- "{
- int prob;
- HOST_WIDE_INT count;
- enum machine_mode mode;
- rtx label = gen_label_rtx ();
- rtx loop_reg;
- rtx jump, src;
-
- /* Copy pointers into new psuedos - they will be changed. */
- rtx addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
- rtx addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
-
- /* Create rtx for tmp register - we use this as scratch. */
- rtx tmp_reg_rtx = gen_rtx_REG (QImode, TMP_REGNO);
-
- if (avr_mem_pgm_p (operands[0]))
- DONE;
-
- if (GET_CODE (operands[2]) != CONST_INT)
+ {
+ if (avr_emit_movmemhi (operands))
+ DONE;
+
FAIL;
+ })
- count = INTVAL (operands[2]);
- if (count <= 0)
- FAIL;
+(define_mode_attr MOVMEM_r_d [(QI "r")
+ (HI "d")])
+
+;; $0, $4 : & dest
+;; $1, $5 : & src
+;; $2 : Address Space
+;; $3, $7 : Loop register
+;; $6 : Scratch register
+
+;; "movmem_qi"
+;; "movmem_hi"
+(define_insn "movmem_<mode>"
+ [(set (mem:BLK (match_operand:HI 0 "register_operand" "x"))
+ (mem:BLK (match_operand:HI 1 "register_operand" "z")))
+ (unspec [(match_operand:QI 2 "const_int_operand" "LP")]
+ UNSPEC_MOVMEM)
+ (use (match_operand:QIHI 3 "register_operand" "<MOVMEM_r_d>"))
+ (clobber (match_operand:HI 4 "register_operand" "=0"))
+ (clobber (match_operand:HI 5 "register_operand" "=1"))
+ (clobber (match_operand:QI 6 "register_operand" "=&r"))
+ (clobber (match_operand:QIHI 7 "register_operand" "=3"))]
+ ""
+ {
+ return avr_out_movmem (insn, operands, NULL);
+ }
+ [(set_attr "adjust_len" "movmem")
+ (set_attr "cc" "clobber")])
+
+;; Ditto and
+;; $8, $9 : hh8 (& src)
+;; $10 : RAMPZ_ADDR
+
+;; "movmem_qi_elpm"
+;; "movmem_hi_elpm"
+(define_insn "movmem_<mode>_elpm"
+ [(set (mem:BLK (match_operand:HI 0 "register_operand" "x"))
+ (mem:BLK (lo_sum:PSI (match_operand:QI 8 "register_operand" "r")
+ (match_operand:HI 1 "register_operand" "z"))))
+ (unspec [(match_operand:QI 2 "const_int_operand" "n")]
+ UNSPEC_MOVMEM)
+ (use (match_operand:QIHI 3 "register_operand" "<MOVMEM_r_d>"))
+ (clobber (match_operand:HI 4 "register_operand" "=0"))
+ (clobber (match_operand:HI 5 "register_operand" "=1"))
+ (clobber (match_operand:QI 6 "register_operand" "=&r"))
+ (clobber (match_operand:QIHI 7 "register_operand" "=3"))
+ (clobber (match_operand:QI 9 "register_operand" "=8"))
+ (clobber (mem:QI (match_operand:QI 10 "io_address_operand" "n")))]
+ ""
+ {
+ return avr_out_movmem (insn, operands, NULL);
+ }
+ [(set_attr "adjust_len" "movmem")
+ (set_attr "cc" "clobber")])
- /* Work out branch probability for latter use. */
- prob = REG_BR_PROB_BASE - REG_BR_PROB_BASE / count;
-
- /* See if constant fit 8 bits. */
- mode = (count < 0x100) ? QImode : HImode;
- /* Create loop counter register. */
- loop_reg = copy_to_mode_reg (mode, gen_int_mode (count, mode));
-
- /* Now create RTL code for move loop. */
- /* Label at top of loop. */
- emit_label (label);
-
- /* Move one byte into scratch and inc pointer. */
- src = gen_rtx_MEM (QImode, addr1);
- set_mem_addr_space (src, MEM_ADDR_SPACE (operands[1]));
- emit_move_insn (tmp_reg_rtx, src);
- emit_move_insn (addr1, gen_rtx_PLUS (Pmode, addr1, const1_rtx));
-
- /* Move to mem and inc pointer. */
- emit_move_insn (gen_rtx_MEM (QImode, addr0), tmp_reg_rtx);
- emit_move_insn (addr0, gen_rtx_PLUS (Pmode, addr0, const1_rtx));
-
- /* Decrement count. */
- emit_move_insn (loop_reg, gen_rtx_PLUS (mode, loop_reg, constm1_rtx));
-
- /* Compare with zero and jump if not equal. */
- emit_cmp_and_jump_insns (loop_reg, const0_rtx, NE, NULL_RTX, mode, 1,
- label);
- /* Set jump probability based on loop count. */
- jump = get_last_insn ();
- add_reg_note (jump, REG_BR_PROB, GEN_INT (prob));
- DONE;
-}")
-;; =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2
+;; =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2 =%2
;; memset (%0, %2, %1)
(define_expand "setmemhi"
[(parallel [(set (match_operand:BLK 0 "memory_operand" "")
- (match_operand 2 "const_int_operand" ""))
- (use (match_operand:HI 1 "const_int_operand" ""))
- (use (match_operand:HI 3 "const_int_operand" "n"))
- (clobber (match_scratch:HI 4 ""))
- (clobber (match_dup 5))])]
+ (match_operand 2 "const_int_operand" ""))
+ (use (match_operand:HI 1 "const_int_operand" ""))
+ (use (match_operand:HI 3 "const_int_operand" ""))
+ (clobber (match_scratch:HI 4 ""))
+ (clobber (match_dup 5))])]
""
- "{
- rtx addr0;
- enum machine_mode mode;
+ {
+ rtx addr0;
+ enum machine_mode mode;
- /* If value to set is not zero, use the library routine. */
- if (operands[2] != const0_rtx)
- FAIL;
+ /* If value to set is not zero, use the library routine. */
+ if (operands[2] != const0_rtx)
+ FAIL;
- if (!CONST_INT_P (operands[1]))
- FAIL;
+ if (!CONST_INT_P (operands[1]))
+ FAIL;
+
+ mode = u8_operand (operands[1], VOIDmode) ? QImode : HImode;
+ operands[5] = gen_rtx_SCRATCH (mode);
+ operands[1] = copy_to_mode_reg (mode,
+ gen_int_mode (INTVAL (operands[1]), mode));
+ addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+ operands[0] = gen_rtx_MEM (BLKmode, addr0);
+ })
- mode = u8_operand (operands[1], VOIDmode) ? QImode : HImode;
- operands[5] = gen_rtx_SCRATCH (mode);
- operands[1] = copy_to_mode_reg (mode,
- gen_int_mode (INTVAL (operands[1]), mode));
- addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
- operands[0] = gen_rtx_MEM (BLKmode, addr0);
-}")
(define_insn "*clrmemqi"
[(set (mem:BLK (match_operand:HI 0 "register_operand" "e"))
- (const_int 0))
+ (const_int 0))
(use (match_operand:QI 1 "register_operand" "r"))
(use (match_operand:QI 2 "const_int_operand" "n"))
(clobber (match_scratch:HI 3 "=0"))
(clobber (match_scratch:QI 4 "=&1"))]
""
- "st %a0+,__zero_reg__
- dec %1
- brne .-6"
+ "0:\;st %a0+,__zero_reg__\;dec %1\;brne 0b"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
+
(define_insn "*clrmemhi"
[(set (mem:BLK (match_operand:HI 0 "register_operand" "e,e"))
- (const_int 0))
+ (const_int 0))
(use (match_operand:HI 1 "register_operand" "!w,d"))
(use (match_operand:HI 2 "const_int_operand" "n,n"))
(clobber (match_scratch:HI 3 "=0,0"))
(clobber (match_scratch:HI 4 "=&1,&1"))]
""
- "*{
- if (which_alternative==0)
- return (AS2 (st,%a0+,__zero_reg__) CR_TAB
- AS2 (sbiw,%A1,1) CR_TAB
- AS1 (brne,.-6));
- else
- return (AS2 (st,%a0+,__zero_reg__) CR_TAB
- AS2 (subi,%A1,1) CR_TAB
- AS2 (sbci,%B1,0) CR_TAB
- AS1 (brne,.-8));
-}"
+ "@
+ 0:\;st %a0+,__zero_reg__\;sbiw %A1,1\;brne 0b
+ 0:\;st %a0+,__zero_reg__\;subi %A1,1\;sbci %B1,0\;brne 0b"
[(set_attr "length" "3,4")
(set_attr "cc" "clobber,clobber")])
(define_expand "strlenhi"
- [(set (match_dup 4)
- (unspec:HI [(match_operand:BLK 1 "memory_operand" "")
- (match_operand:QI 2 "const_int_operand" "")
- (match_operand:HI 3 "immediate_operand" "")]
- UNSPEC_STRLEN))
- (set (match_dup 4) (plus:HI (match_dup 4)
- (const_int -1)))
- (set (match_operand:HI 0 "register_operand" "")
- (minus:HI (match_dup 4)
- (match_dup 5)))]
- ""
- "{
- rtx addr;
- if (operands[2] != const0_rtx)
- FAIL;
- addr = copy_to_mode_reg (Pmode, XEXP (operands[1],0));
- operands[1] = gen_rtx_MEM (BLKmode, addr);
- operands[5] = addr;
- operands[4] = gen_reg_rtx (HImode);
-}")
+ [(set (match_dup 4)
+ (unspec:HI [(match_operand:BLK 1 "memory_operand" "")
+ (match_operand:QI 2 "const_int_operand" "")
+ (match_operand:HI 3 "immediate_operand" "")]
+ UNSPEC_STRLEN))
+ (set (match_dup 4)
+ (plus:HI (match_dup 4)
+ (const_int -1)))
+ (set (match_operand:HI 0 "register_operand" "")
+ (minus:HI (match_dup 4)
+ (match_dup 5)))]
+ ""
+ {
+ rtx addr;
+ if (operands[2] != const0_rtx)
+ FAIL;
+ addr = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
+ operands[1] = gen_rtx_MEM (BLKmode, addr);
+ operands[5] = addr;
+ operands[4] = gen_reg_rtx (HImode);
+ })
(define_insn "*strlenhi"
- [(set (match_operand:HI 0 "register_operand" "=e")
- (unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "%0"))
- (const_int 0)
- (match_operand:HI 2 "immediate_operand" "i")]
- UNSPEC_STRLEN))]
- ""
- "ld __tmp_reg__,%a0+
- tst __tmp_reg__
- brne .-6"
+ [(set (match_operand:HI 0 "register_operand" "=e")
+ (unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "0"))
+ (const_int 0)
+ (match_operand:HI 2 "immediate_operand" "i")]
+ UNSPEC_STRLEN))]
+ ""
+ "0:\;ld __tmp_reg__,%a0+\;tst __tmp_reg__\;brne 0b"
[(set_attr "length" "3")
(set_attr "cc" "clobber")])
@@ -4503,25 +4660,25 @@
(define_insn "*cbi"
[(set (mem:QI (match_operand 0 "low_io_address_operand" "n"))
- (and:QI (mem:QI (match_dup 0))
- (match_operand:QI 1 "single_zero_operand" "n")))]
- "(optimize > 0)"
-{
- operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff));
- return AS2 (cbi,%m0-0x20,%2);
-}
+ (and:QI (mem:QI (match_dup 0))
+ (match_operand:QI 1 "single_zero_operand" "n")))]
+ "optimize > 0"
+ {
+ operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff));
+ return "cbi %i0,%2";
+ }
[(set_attr "length" "1")
(set_attr "cc" "none")])
(define_insn "*sbi"
[(set (mem:QI (match_operand 0 "low_io_address_operand" "n"))
- (ior:QI (mem:QI (match_dup 0))
- (match_operand:QI 1 "single_one_operand" "n")))]
- "(optimize > 0)"
-{
- operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
- return AS2 (sbi,%m0-0x20,%2);
-}
+ (ior:QI (mem:QI (match_dup 0))
+ (match_operand:QI 1 "single_one_operand" "n")))]
+ "optimize > 0"
+ {
+ operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
+ return "sbi %i0,%2";
+ }
[(set_attr "length" "1")
(set_attr "cc" "none")])
@@ -5480,9 +5637,9 @@
(match_operand:QI 2 "nonmemory_operand" "L,P,r"))]
""
"@
- cbi %m0-0x20,%1
- sbi %m0-0x20,%1
- sbrc %2,0\;sbi %m0-0x20,%1\;sbrs %2,0\;cbi %m0-0x20,%1"
+ cbi %i0,%1
+ sbi %i0,%1
+ sbrc %2,0\;sbi %i0,%1\;sbrs %2,0\;cbi %i0,%1"
[(set_attr "length" "1,1,4")
(set_attr "cc" "none")])
@@ -5492,7 +5649,7 @@
(match_operand:QI 1 "const_0_to_7_operand" "n"))
(not:QI (match_operand:QI 2 "register_operand" "r")))]
""
- "sbrs %2,0\;sbi %m0-0x20,%1\;sbrc %2,0\;cbi %m0-0x20,%1"
+ "sbrs %2,0\;sbi %i0,%1\;sbrc %2,0\;cbi %i0,%1"
[(set_attr "length" "4")
(set_attr "cc" "none")])
diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md
index 9f595cbfb29..fff34b58464 100644
--- a/gcc/config/avr/predicates.md
+++ b/gcc/config/avr/predicates.md
@@ -63,10 +63,11 @@
(match_test "!avr_mem_pgm_p (op)")))
;; Return 1 if OP is an "ordinary" general operand, i.e. a general
-;; operand whose load is not handled by a libgcc call.
+;; operand whose load is not handled by a libgcc call or ELPM.
(define_predicate "nox_general_operand"
(and (match_operand 0 "general_operand")
- (match_test "!avr_load_libgcc_p (op)")))
+ (not (match_test "avr_load_libgcc_p (op)"))
+ (not (match_test "avr_mem_pgmx_p (op)"))))
;; Return 1 if OP is the zero constant for MODE.
(define_predicate "const0_operand"
diff --git a/gcc/config/cris/cris-protos.h b/gcc/config/cris/cris-protos.h
index 291981d5707..545f821ac0f 100644
--- a/gcc/config/cris/cris-protos.h
+++ b/gcc/config/cris/cris-protos.h
@@ -65,5 +65,3 @@ extern int cris_fatal (char *);
extern int cris_initial_elimination_offset (int, int);
extern void cris_init_expanders (void);
-
-extern bool cris_function_value_regno_p (const unsigned int);
diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c
index 06568023051..de9e26984ea 100644
--- a/gcc/config/cris/cris.c
+++ b/gcc/config/cris/cris.c
@@ -153,6 +153,7 @@ static void cris_trampoline_init (rtx, tree, rtx);
static rtx cris_function_value(const_tree, const_tree, bool);
static rtx cris_libcall_value (enum machine_mode, const_rtx);
+static bool cris_function_value_regno_p (const unsigned int);
/* This is the parsed result of the "-max-stack-stackframe=" option. If
it (still) is zero, then there was no such option given. */
@@ -252,6 +253,8 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
#define TARGET_FUNCTION_VALUE cris_function_value
#undef TARGET_LIBCALL_VALUE
#define TARGET_LIBCALL_VALUE cris_libcall_value
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P cris_function_value_regno_p
struct gcc_target targetm = TARGET_INITIALIZER;
@@ -3931,7 +3934,7 @@ cris_libcall_value (enum machine_mode mode,
/* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the
time being. */
-bool
+static bool
cris_function_value_regno_p (const unsigned int regno)
{
return (regno == CRIS_FIRST_ARG_REG);
diff --git a/gcc/config/cris/cris.h b/gcc/config/cris/cris.h
index 5a6ebda2e48..ff0be0041f0 100644
--- a/gcc/config/cris/cris.h
+++ b/gcc/config/cris/cris.h
@@ -712,12 +712,6 @@ struct cum_args {int regs;};
&& (REGNO) < CRIS_FIRST_ARG_REG + (CRIS_MAX_ARGS_IN_REGS))
-/* Node: Scalar Return */
-
-#define FUNCTION_VALUE_REGNO_P(N) cris_function_value_regno_p (N)
-
-
-
/* Node: Aggregate Return */
#define CRIS_STRUCT_VALUE_REGNUM ((CRIS_FIRST_ARG_REG) - 1)
diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h
index 0c8f2769abe..7ae751972f9 100644
--- a/gcc/config/darwin.h
+++ b/gcc/config/darwin.h
@@ -395,6 +395,11 @@ extern GTY(()) int darwin_ms_struct;
%{Zforce_cpusubtype_ALL:-force_cpusubtype_ALL} \
%{static}"
+/* Default ASM_DEBUG_SPEC. Darwin's as cannot currently produce dwarf
+ debugging data. */
+
+#define ASM_DEBUG_SPEC "%{g*:%{!g0:%{!gdwarf*:--gstabs}}}"
+
/* We still allow output of STABS. */
#define DBX_DEBUGGING_INFO 1
diff --git a/gcc/config/darwin9.h b/gcc/config/darwin9.h
index 483a7e5269c..92429cae57c 100644
--- a/gcc/config/darwin9.h
+++ b/gcc/config/darwin9.h
@@ -41,6 +41,12 @@ along with GCC; see the file COPYING3. If not see
%{mdynamic-no-pic: %n'-mdynamic-no-pic' overrides '-pie', '-fpie' or '-fPIE'; \
:-pie}}"
+/* Only ask as for debug data if the debug style is stabs (since as doesn't
+ yet generate dwarf.) */
+
+#undef ASM_DEBUG_SPEC
+#define ASM_DEBUG_SPEC "%{g*:%{!g0:%{gstabs:--gstabs}}}"
+
#undef ASM_OUTPUT_ALIGNED_COMMON
#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
do { \
diff --git a/gcc/config/host-linux.c b/gcc/config/host-linux.c
index ec6105577a6..94b7a0b89a7 100644
--- a/gcc/config/host-linux.c
+++ b/gcc/config/host-linux.c
@@ -86,6 +86,10 @@
# define TRY_EMPTY_VM_SPACE 0x40000000
#elif defined(__ARM_EABI__)
# define TRY_EMPTY_VM_SPACE 0x60000000
+#elif defined(__mips__) && defined(__LP64__)
+# define TRY_EMPTY_VM_SPACE 0x8000000000
+#elif defined(__mips__)
+# define TRY_EMPTY_VM_SPACE 0x60000000
#else
# define TRY_EMPTY_VM_SPACE 0
#endif
diff --git a/gcc/config/i386/emmintrin.h b/gcc/config/i386/emmintrin.h
index fe4cd6abaea..07ac9f3d8ae 100644
--- a/gcc/config/i386/emmintrin.h
+++ b/gcc/config/i386/emmintrin.h
@@ -1418,6 +1418,14 @@ _mm_stream_si32 (int *__A, int __B)
__builtin_ia32_movnti (__A, __B);
}
+#ifdef __x86_64__
+extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_stream_si64 (long long int *__A, long long int __B)
+{
+ __builtin_ia32_movnti64 (__A, __B);
+}
+#endif
+
extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_stream_si128 (__m128i *__A, __m128i __B)
{
diff --git a/gcc/config/i386/i386-builtin-types.def b/gcc/config/i386/i386-builtin-types.def
index 79fb1427787..d00b05341b9 100644
--- a/gcc/config/i386/i386-builtin-types.def
+++ b/gcc/config/i386/i386-builtin-types.def
@@ -111,6 +111,7 @@ DEF_POINTER_TYPE (PDOUBLE, DOUBLE)
DEF_POINTER_TYPE (PFLOAT, FLOAT)
DEF_POINTER_TYPE (PUSHORT, USHORT)
DEF_POINTER_TYPE (PINT, INT)
+DEF_POINTER_TYPE (PLONGLONG, LONGLONG)
DEF_POINTER_TYPE (PULONGLONG, ULONGLONG)
DEF_POINTER_TYPE (PUNSIGNED, UNSIGNED)
@@ -357,6 +358,7 @@ DEF_FUNCTION_TYPE (VOID, PDOUBLE, V4DF)
DEF_FUNCTION_TYPE (VOID, PFLOAT, V4SF)
DEF_FUNCTION_TYPE (VOID, PFLOAT, V8SF)
DEF_FUNCTION_TYPE (VOID, PINT, INT)
+DEF_FUNCTION_TYPE (VOID, PLONGLONG, LONGLONG)
DEF_FUNCTION_TYPE (VOID, PULONGLONG, ULONGLONG)
DEF_FUNCTION_TYPE (VOID, PV2SI, V2SI)
DEF_FUNCTION_TYPE (VOID, PV2DI, V2DI)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 691c89a9d28..34368203cd9 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -1783,18 +1783,18 @@ struct processor_costs atom_cost = {
/* stringop_algs for memcpy.
SSE loops works best on Atom, but fall back into non-SSE unrolled loop variant
if that fails. */
- {{{libcall, {{4096, sse_loop}, {4096, unrolled_loop}, {-1, libcall}}}, /* Known alignment. */
- {libcall, {{4096, sse_loop}, {4096, unrolled_loop}, {-1, libcall}}}},
- {{libcall, {{-1, libcall}}}, /* Unknown alignment. */
- {libcall, {{2048, sse_loop}, {2048, unrolled_loop},
+ {{{libcall, {{4096, unrolled_loop}, {-1, libcall}}}, /* Known alignment. */
+ {libcall, {{4096, unrolled_loop}, {-1, libcall}}}},
+ {{libcall, {{2048, unrolled_loop}, {-1, libcall}}}, /* Unknown alignment. */
+ {libcall, {{2048, unrolled_loop},
{-1, libcall}}}}},
/* stringop_algs for memset. */
- {{{libcall, {{4096, sse_loop}, {4096, unrolled_loop}, {-1, libcall}}}, /* Known alignment. */
- {libcall, {{4096, sse_loop}, {4096, unrolled_loop}, {-1, libcall}}}},
- {{libcall, {{1024, sse_loop}, {1024, unrolled_loop}, /* Unknown alignment. */
+ {{{libcall, {{4096, unrolled_loop}, {-1, libcall}}}, /* Known alignment. */
+ {libcall, {{4096, unrolled_loop}, {-1, libcall}}}},
+ {{libcall, {{1024, unrolled_loop}, /* Unknown alignment. */
{-1, libcall}}},
- {libcall, {{2048, sse_loop}, {2048, unrolled_loop},
+ {libcall, {{2048, unrolled_loop},
{-1, libcall}}}}},
1, /* scalar_stmt_cost. */
1, /* scalar load_cost. */
@@ -19619,8 +19619,12 @@ ix86_expand_int_vcond (rtx operands[])
cop0 = operands[4];
cop1 = operands[5];
- /* XOP supports all of the comparisons on all vector int types. */
- if (!TARGET_XOP)
+ /* XOP supports all of the comparisons on all 128-bit vector int types. */
+ if (TARGET_XOP
+ && (mode == V16QImode || mode == V8HImode
+ || mode == V4SImode || mode == V2DImode))
+ ;
+ else
{
/* Canonicalize the comparison to EQ, GT, GTU. */
switch (code)
@@ -21149,20 +21153,25 @@ expand_set_or_movmem_via_loop_with_iter (rtx destmem, rtx srcmem,
top_label = gen_label_rtx ();
out_label = gen_label_rtx ();
- if (!reuse_iter)
- iter = gen_reg_rtx (iter_mode);
-
size = expand_simple_binop (iter_mode, AND, count, piece_size_mask,
- NULL, 1, OPTAB_DIRECT);
- /* Those two should combine. */
- if (piece_size == const1_rtx)
+ NULL, 1, OPTAB_DIRECT);
+ if (!reuse_iter)
+ {
+ iter = gen_reg_rtx (iter_mode);
+ /* Those two should combine. */
+ if (piece_size == const1_rtx)
+ {
+ emit_cmp_and_jump_insns (size, const0_rtx, EQ, NULL_RTX, iter_mode,
+ true, out_label);
+ predict_jump (REG_BR_PROB_BASE * 10 / 100);
+ }
+ emit_move_insn (iter, const0_rtx);
+ }
+ else
{
- emit_cmp_and_jump_insns (size, const0_rtx, EQ, NULL_RTX, iter_mode,
+ emit_cmp_and_jump_insns (iter, size, GE, NULL_RTX, iter_mode,
true, out_label);
- predict_jump (REG_BR_PROB_BASE * 10 / 100);
}
- if (!reuse_iter)
- emit_move_insn (iter, const0_rtx);
emit_label (top_label);
@@ -21460,7 +21469,7 @@ expand_movmem_epilogue (rtx destmem, rtx srcmem,
gcc_assert (remainder_size == 0);
return;
}
- if (max_size > 8)
+ if (max_size > 16)
{
count = expand_simple_binop (GET_MODE (count), AND, count, GEN_INT (max_size - 1),
count, 1, OPTAB_DIRECT);
@@ -21475,6 +21484,25 @@ expand_movmem_epilogue (rtx destmem, rtx srcmem,
*/
if (TARGET_SINGLE_STRINGOP)
{
+ if (max_size > 8)
+ {
+ rtx label = ix86_expand_aligntest (count, 8, true);
+ if (TARGET_64BIT)
+ {
+ src = change_address (srcmem, DImode, srcptr);
+ dest = change_address (destmem, DImode, destptr);
+ emit_insn (gen_strmov (destptr, dest, srcptr, src));
+ }
+ else
+ {
+ src = change_address (srcmem, SImode, srcptr);
+ dest = change_address (destmem, SImode, destptr);
+ emit_insn (gen_strmov (destptr, dest, srcptr, src));
+ emit_insn (gen_strmov (destptr, dest, srcptr, src));
+ }
+ emit_label (label);
+ LABEL_NUSES (label) = 1;
+ }
if (max_size > 4)
{
rtx label = ix86_expand_aligntest (count, 4, true);
@@ -21508,6 +21536,35 @@ expand_movmem_epilogue (rtx destmem, rtx srcmem,
rtx offset = force_reg (Pmode, const0_rtx);
rtx tmp;
+ if (max_size > 8)
+ {
+ rtx label = ix86_expand_aligntest (count, 8, true);
+ if (TARGET_64BIT)
+ {
+ src = change_address (srcmem, DImode, srcptr);
+ dest = change_address (destmem, DImode, destptr);
+ emit_move_insn (dest, src);
+ tmp = expand_simple_binop (Pmode, PLUS, offset, GEN_INT (8), NULL,
+ true, OPTAB_LIB_WIDEN);
+ }
+ else
+ {
+ src = change_address (srcmem, SImode, srcptr);
+ dest = change_address (destmem, SImode, destptr);
+ emit_move_insn (dest, src);
+ tmp = expand_simple_binop (Pmode, PLUS, offset, GEN_INT (4), NULL,
+ true, OPTAB_LIB_WIDEN);
+ if (tmp != offset)
+ emit_move_insn (offset, tmp);
+ tmp = expand_simple_binop (Pmode, PLUS, offset, GEN_INT (4), NULL,
+ true, OPTAB_LIB_WIDEN);
+ emit_move_insn (dest, src);
+ }
+ if (tmp != offset)
+ emit_move_insn (offset, tmp);
+ emit_label (label);
+ LABEL_NUSES (label) = 1;
+ }
if (max_size > 4)
{
rtx label = ix86_expand_aligntest (count, 4, true);
@@ -21588,17 +21645,28 @@ expand_setmem_epilogue (rtx destmem, rtx destptr, rtx promoted_to_vector_value,
Remaining part we'll move using Pmode and narrower modes. */
if (promoted_to_vector_value)
- while (remainder_size >= 16)
- {
- if (GET_MODE (destmem) != move_mode)
- destmem = adjust_automodify_address_nv (destmem, move_mode,
- destptr, offset);
- emit_strset (destmem, promoted_to_vector_value, destptr,
- move_mode, offset);
-
- offset += 16;
- remainder_size -= 16;
- }
+ {
+ if (promoted_to_vector_value)
+ {
+ if (max_size >= GET_MODE_SIZE (V4SImode))
+ move_mode = V4SImode;
+ else if (max_size >= GET_MODE_SIZE (DImode))
+ move_mode = DImode;
+ }
+ while (remainder_size >= GET_MODE_SIZE (move_mode))
+ {
+ if (GET_MODE (destmem) != move_mode)
+ destmem = adjust_automodify_address_nv (destmem, move_mode,
+ destptr, offset);
+ emit_strset (destmem,
+ promoted_to_vector_value,
+ destptr,
+ move_mode, offset);
+
+ offset += GET_MODE_SIZE (move_mode);
+ remainder_size -= GET_MODE_SIZE (move_mode);
+ }
+ }
/* Move the remaining part of epilogue - its size might be
a size of the widest mode. */
@@ -22022,10 +22090,11 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size, bool memset,
|| (memset
? fixed_regs[AX_REG] : fixed_regs[SI_REG]));
-#define ALG_USABLE_P(alg) (rep_prefix_usable \
- || (alg != rep_prefix_1_byte \
- && alg != rep_prefix_4_byte \
- && alg != rep_prefix_8_byte))
+#define ALG_USABLE_P(alg) ((rep_prefix_usable \
+ || (alg != rep_prefix_1_byte \
+ && alg != rep_prefix_4_byte \
+ && alg != rep_prefix_8_byte)) \
+ && (TARGET_SSE2 || alg != sse_loop))
const struct processor_costs *cost;
/* Even if the string operation call is cold, we still might spend a lot
@@ -22037,6 +22106,9 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size, bool memset,
else
optimize_for_speed = true;
+ if (!optimize)
+ return (rep_prefix_usable ? rep_prefix_1_byte : libcall);
+
cost = optimize_for_speed ? ix86_cost : &ix86_size_cost;
*dynamic_check = -1;
@@ -22049,10 +22121,10 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size, bool memset,
/* rep; movq or rep; movl is the smallest variant. */
else if (!optimize_for_speed)
{
- if (!count || (count & 3))
- return rep_prefix_usable ? rep_prefix_1_byte : loop_1_byte;
+ if (!count || (count & 3) || memset)
+ return rep_prefix_usable ? rep_prefix_1_byte : libcall;
else
- return rep_prefix_usable ? rep_prefix_4_byte : loop;
+ return rep_prefix_usable ? rep_prefix_4_byte : libcall;
}
/* Very tiny blocks are best handled via the loop, REP is expensive to setup.
*/
@@ -22106,13 +22178,11 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size, bool memset,
int max = -1;
enum stringop_alg alg;
int i;
- bool any_alg_usable_p = true;
bool only_libcall_fits = true;
for (i = 0; i < MAX_STRINGOP_ALGS; i++)
{
enum stringop_alg candidate = algs->size[i].alg;
- any_alg_usable_p = any_alg_usable_p && ALG_USABLE_P (candidate);
if (candidate != libcall && candidate
&& ALG_USABLE_P (candidate))
@@ -22124,7 +22194,7 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size, bool memset,
/* If there aren't any usable algorithms, then recursing on
smaller sizes isn't going to find anything. Just return the
simple byte-at-a-time copy loop. */
- if (!any_alg_usable_p || only_libcall_fits)
+ if (only_libcall_fits)
{
/* Pick something reasonable. */
if (TARGET_INLINE_STRINGOPS_DYNAMICALLY)
@@ -22253,7 +22323,7 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
int dynamic_check;
bool need_zero_guard = false;
bool align_unknown;
- int unroll_factor;
+ unsigned int unroll_factor;
enum machine_mode move_mode;
rtx loop_iter = NULL_RTX;
int dst_offset, src_offset;
@@ -22316,14 +22386,28 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
case unrolled_loop:
need_zero_guard = true;
move_mode = Pmode;
- unroll_factor = TARGET_64BIT ? 4 : 2;
+ unroll_factor = 1;
+ /* Select maximal available 1,2 or 4 unroll factor.
+ In 32bit we can not afford to use 4 registers inside the loop. */
+ if (!count)
+ unroll_factor = TARGET_64BIT ? 4 : 2;
+ else
+ while (GET_MODE_SIZE (move_mode) * unroll_factor * 2 < count
+ && unroll_factor < (TARGET_64BIT ? 4 :2))
+ unroll_factor *= 2;
size_needed = GET_MODE_SIZE (move_mode) * unroll_factor;
break;
case sse_loop:
need_zero_guard = true;
/* Use SSE instructions, if possible. */
- move_mode = align_unknown ? DImode : V4SImode;
- unroll_factor = TARGET_64BIT ? 4 : 2;
+ move_mode = V4SImode;
+ /* Select maximal available 1,2 or 4 unroll factor. */
+ if (!count)
+ unroll_factor = 4;
+ else
+ while (GET_MODE_SIZE (move_mode) * unroll_factor * 2 < count
+ && unroll_factor < 4)
+ unroll_factor *= 2;
size_needed = GET_MODE_SIZE (move_mode) * unroll_factor;
break;
case rep_prefix_8_byte:
@@ -22568,7 +22652,13 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
if (alg == sse_loop || alg == unrolled_loop)
{
rtx tmp;
- if (align_unknown && unroll_factor > 1)
+ int remainder_size = epilogue_size_needed;
+
+ /* We may not need the epilgoue loop at all when the count is known
+ and alignment is not adjusted. */
+ if (count && desired_align <= align)
+ remainder_size = count % epilogue_size_needed;
+ if (remainder_size > 31)
{
/* Reduce epilogue's size by creating not-unrolled loop. If we won't
do this, we can have very big epilogue - when alignment is statically
@@ -22710,7 +22800,7 @@ promote_duplicated_reg_to_size (rtx val, int size_needed, int desired_align, int
{
rtx promoted_val = NULL_RTX;
- if (size_needed > 8 || (desired_align > align && desired_align > 8))
+ if (size_needed > 8)
{
/* We want to promote to vector register, so we expect that at least SSE
is available. */
@@ -22724,7 +22814,7 @@ promote_duplicated_reg_to_size (rtx val, int size_needed, int desired_align, int
else
promoted_val = promote_duplicated_reg (V4SImode, val);
}
- else if (size_needed > 4 || (desired_align > align && desired_align > 4))
+ else if (size_needed > 4)
{
gcc_assert (TARGET_64BIT);
promoted_val = promote_duplicated_reg (DImode, val);
@@ -22764,6 +22854,7 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
unsigned int unroll_factor;
enum machine_mode move_mode;
rtx loop_iter = NULL_RTX;
+ bool early_jump = false;
if (CONST_INT_P (align_exp))
align = INTVAL (align_exp);
@@ -22783,7 +22874,7 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
/* Step 0: Decide on preferred algorithm, desired alignment and
size of chunks to be copied by main loop. */
- align_unknown = CONST_INT_P (align_exp) && INTVAL (align_exp) > 0;
+ align_unknown = !(CONST_INT_P (align_exp) && INTVAL (align_exp) > 0);
alg = decide_alg (count, expected_size, true, &dynamic_check, align_unknown);
desired_align = decide_alignment (align, alg, expected_size);
unroll_factor = 1;
@@ -22813,9 +22904,12 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
move_mode = Pmode;
unroll_factor = 1;
/* Select maximal available 1,2 or 4 unroll factor. */
- while (GET_MODE_SIZE (move_mode) * unroll_factor * 2 < count
- && unroll_factor < 4)
- unroll_factor *= 2;
+ if (!count)
+ unroll_factor = 4;
+ else
+ while (GET_MODE_SIZE (move_mode) * unroll_factor * 2 < count
+ && unroll_factor < 4)
+ unroll_factor *= 2;
size_needed = GET_MODE_SIZE (move_mode) * unroll_factor;
break;
case sse_loop:
@@ -22823,9 +22917,12 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
move_mode = TARGET_64BIT ? V2DImode : V4SImode;
unroll_factor = 1;
/* Select maximal available 1,2 or 4 unroll factor. */
- while (GET_MODE_SIZE (move_mode) * unroll_factor * 2 < count
- && unroll_factor < 4)
- unroll_factor *= 2;
+ if (!count)
+ unroll_factor = 4;
+ else
+ while (GET_MODE_SIZE (move_mode) * unroll_factor * 2 < count
+ && unroll_factor < 4)
+ unroll_factor *= 2;
size_needed = GET_MODE_SIZE (move_mode) * unroll_factor;
break;
case rep_prefix_8_byte:
@@ -22904,6 +23001,7 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
emit_move_insn (loop_iter, const0_rtx);
}
label = gen_label_rtx ();
+ early_jump = true;
emit_cmp_and_jump_insns (count_exp,
GEN_INT (epilogue_size_needed),
LTU, 0, counter_mode (count_exp), 1, label);
@@ -23016,7 +23114,7 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
vec_promoted_val =
promote_duplicated_reg_to_size (gpr_promoted_val,
GET_MODE_SIZE (move_mode),
- desired_align, align);
+ GET_MODE_SIZE (move_mode), align);
loop_iter = expand_set_or_movmem_via_loop_with_iter (dst, NULL, destreg,
NULL, vec_promoted_val, count_exp,
loop_iter, move_mode, unroll_factor,
@@ -23065,21 +23163,26 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
LABEL_NUSES (label) = 1;
/* We can not rely on fact that promoved value is known. */
vec_promoted_val = 0;
- gpr_promoted_val = 0;
+ if (early_jump)
+ gpr_promoted_val = 0;
}
epilogue:
if (alg == unrolled_loop || alg == sse_loop)
{
rtx tmp;
- if (align_unknown && unroll_factor > 1
- && epilogue_size_needed >= GET_MODE_SIZE (move_mode)
- && vec_promoted_val)
+ int remainder_size = epilogue_size_needed;
+ if (count && desired_align <= align)
+ remainder_size = count % epilogue_size_needed;
+ /* We may not need the epilgoue loop at all when the count is known
+ and alignment is not adjusted. */
+ if (remainder_size > 31
+ && (alg == sse_loop ? vec_promoted_val : gpr_promoted_val))
{
/* Reduce epilogue's size by creating not-unrolled loop. If we won't
do this, we can have very big epilogue - when alignment is statically
unknown we'll have the epilogue byte by byte which may be very slow. */
loop_iter = expand_set_or_movmem_via_loop_with_iter (dst, NULL, destreg,
- NULL, vec_promoted_val, count_exp,
+ NULL, (alg == sse_loop ? vec_promoted_val : gpr_promoted_val), count_exp,
loop_iter, move_mode, 1,
expected_size, false);
dst = change_address (dst, BLKmode, destreg);
@@ -23090,17 +23193,14 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
if (tmp != destreg)
emit_move_insn (destreg, tmp);
}
- if (count_exp == const0_rtx)
+ if (count_exp == const0_rtx || epilogue_size_needed <= 1)
;
- else if (!gpr_promoted_val && epilogue_size_needed > 1)
+ else if (!gpr_promoted_val)
expand_setmem_epilogue_via_loop (dst, destreg, val_exp, count_exp,
epilogue_size_needed);
else
- {
- if (epilogue_size_needed > 1)
- expand_setmem_epilogue (dst, destreg, vec_promoted_val, gpr_promoted_val,
- val_exp, count_exp, epilogue_size_needed);
- }
+ expand_setmem_epilogue (dst, destreg, vec_promoted_val, gpr_promoted_val,
+ val_exp, count_exp, epilogue_size_needed);
if (jump_around_label)
emit_label (jump_around_label);
return true;
@@ -25245,6 +25345,7 @@ enum ix86_builtins
IX86_BUILTIN_CVTTPS2DQ,
IX86_BUILTIN_MOVNTI,
+ IX86_BUILTIN_MOVNTI64,
IX86_BUILTIN_MOVNTPD,
IX86_BUILTIN_MOVNTDQ,
@@ -26318,7 +26419,7 @@ static const struct builtin_description bdesc_special_args[] =
/* SSE or 3DNow!A */
{ OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_sse_sfence, "__builtin_ia32_sfence", IX86_BUILTIN_SFENCE, UNKNOWN, (int) VOID_FTYPE_VOID },
- { OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_sse_movntdi, "__builtin_ia32_movntq", IX86_BUILTIN_MOVNTQ, UNKNOWN, (int) VOID_FTYPE_PULONGLONG_ULONGLONG },
+ { OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_sse_movntq, "__builtin_ia32_movntq", IX86_BUILTIN_MOVNTQ, UNKNOWN, (int) VOID_FTYPE_PULONGLONG_ULONGLONG },
/* SSE2 */
{ OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_lfence, "__builtin_ia32_lfence", IX86_BUILTIN_LFENCE, UNKNOWN, (int) VOID_FTYPE_VOID },
@@ -26327,7 +26428,8 @@ static const struct builtin_description bdesc_special_args[] =
{ OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_movdqu, "__builtin_ia32_storedqu", IX86_BUILTIN_STOREDQU, UNKNOWN, (int) VOID_FTYPE_PCHAR_V16QI },
{ OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_movntv2df, "__builtin_ia32_movntpd", IX86_BUILTIN_MOVNTPD, UNKNOWN, (int) VOID_FTYPE_PDOUBLE_V2DF },
{ OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_movntv2di, "__builtin_ia32_movntdq", IX86_BUILTIN_MOVNTDQ, UNKNOWN, (int) VOID_FTYPE_PV2DI_V2DI },
- { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_movntsi, "__builtin_ia32_movnti", IX86_BUILTIN_MOVNTI, UNKNOWN, (int) VOID_FTYPE_PINT_INT },
+ { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_movntisi, "__builtin_ia32_movnti", IX86_BUILTIN_MOVNTI, UNKNOWN, (int) VOID_FTYPE_PINT_INT },
+ { OPTION_MASK_ISA_SSE2 | OPTION_MASK_ISA_64BIT, CODE_FOR_sse2_movntidi, "__builtin_ia32_movnti64", IX86_BUILTIN_MOVNTI64, UNKNOWN, (int) VOID_FTYPE_PLONGLONG_LONGLONG },
{ OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_movupd, "__builtin_ia32_loadupd", IX86_BUILTIN_LOADUPD, UNKNOWN, (int) V2DF_FTYPE_PCDOUBLE },
{ OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_movdqu, "__builtin_ia32_loaddqu", IX86_BUILTIN_LOADDQU, UNKNOWN, (int) V16QI_FTYPE_PCCHAR },
@@ -29313,6 +29415,7 @@ ix86_expand_special_args_builtin (const struct builtin_description *d,
case VOID_FTYPE_PFLOAT_V4SF:
case VOID_FTYPE_PDOUBLE_V4DF:
case VOID_FTYPE_PDOUBLE_V2DF:
+ case VOID_FTYPE_PLONGLONG_LONGLONG:
case VOID_FTYPE_PULONGLONG_ULONGLONG:
case VOID_FTYPE_PINT_INT:
nargs = 1;
@@ -29914,7 +30017,7 @@ rdrand_step:
icode = CODE_FOR_avx2_gatherdiv8sf;
goto gather_gen;
case IX86_BUILTIN_GATHERALTSIV4DI:
- icode = CODE_FOR_avx2_gathersiv4df;
+ icode = CODE_FOR_avx2_gathersiv4di;
goto gather_gen;
case IX86_BUILTIN_GATHERALTDIV8SI:
icode = CODE_FOR_avx2_gatherdiv8si;
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index bc602532304..912c17229a2 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -115,6 +115,7 @@
UNSPEC_FIX_NOTRUNC
UNSPEC_MASKMOV
UNSPEC_MOVMSK
+ UNSPEC_MOVNTQ
UNSPEC_MOVNT
UNSPEC_MOVU
UNSPEC_RCP
diff --git a/gcc/config/i386/i386elf.h b/gcc/config/i386/i386elf.h
index 179c601738d..1bf3feb7479 100644
--- a/gcc/config/i386/i386elf.h
+++ b/gcc/config/i386/i386elf.h
@@ -20,10 +20,6 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-/* Use stabs instead of DWARF debug format. */
-#undef PREFERRED_DEBUGGING_TYPE
-#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
-
/* The ELF ABI for the i386 says that records and unions are returned
in memory. */
diff --git a/gcc/config/i386/mmx.md b/gcc/config/i386/mmx.md
index f76834e5ab2..7fa072eb6fe 100644
--- a/gcc/config/i386/mmx.md
+++ b/gcc/config/i386/mmx.md
@@ -329,10 +329,10 @@
DONE;
})
-(define_insn "sse_movntdi"
+(define_insn "sse_movntq"
[(set (match_operand:DI 0 "memory_operand" "=m")
(unspec:DI [(match_operand:DI 1 "register_operand" "y")]
- UNSPEC_MOVNT))]
+ UNSPEC_MOVNTQ))]
"TARGET_SSE || TARGET_3DNOW_A"
"movntq\t{%1, %0|%0, %1}"
[(set_attr "type" "mmxmov")
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index b8e821de90e..89559966f0e 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -573,15 +573,15 @@
(set_attr "prefix" "maybe_vex")
(set_attr "mode" "<sseinsnmode>")])
-(define_insn "sse2_movntsi"
- [(set (match_operand:SI 0 "memory_operand" "=m")
- (unspec:SI [(match_operand:SI 1 "register_operand" "r")]
- UNSPEC_MOVNT))]
+(define_insn "sse2_movnti<mode>"
+ [(set (match_operand:SWI48 0 "memory_operand" "=m")
+ (unspec:SWI48 [(match_operand:SWI48 1 "register_operand" "r")]
+ UNSPEC_MOVNT))]
"TARGET_SSE2"
"movnti\t{%1, %0|%0, %1}"
[(set_attr "type" "ssemov")
(set_attr "prefix_data16" "0")
- (set_attr "mode" "V2DF")])
+ (set_attr "mode" "<MODE>")])
(define_insn "<sse>_movnt<mode>"
[(set (match_operand:VF 0 "memory_operand" "=m")
@@ -614,8 +614,9 @@
;; Modes handled by storent patterns.
(define_mode_iterator STORENT_MODE
- [(SI "TARGET_SSE2") (SF "TARGET_SSE4A") (DF "TARGET_SSE4A")
- (V2DI "TARGET_SSE2")
+ [(DI "TARGET_SSE2 && TARGET_64BIT") (SI "TARGET_SSE2")
+ (SF "TARGET_SSE4A") (DF "TARGET_SSE4A")
+ (V4DI "TARGET_AVX") (V2DI "TARGET_SSE2")
(V8SF "TARGET_AVX") V4SF
(V4DF "TARGET_AVX") (V2DF "TARGET_SSE2")])
@@ -9962,17 +9963,32 @@
{
rtx tmp0, tmp1;
- tmp0 = gen_reg_rtx (<MODE>mode);
- tmp1 = gen_reg_rtx (<MODE>mode);
+ if (<MODE>mode == V2DFmode
+ && TARGET_AVX && !TARGET_PREFER_AVX128)
+ {
+ rtx tmp2 = gen_reg_rtx (V4DFmode);
- emit_insn
- (gen_<sse4_1>_round<ssemodesuffix><avxsizesuffix> (tmp0, operands[1],
- operands[3]));
- emit_insn
- (gen_<sse4_1>_round<ssemodesuffix><avxsizesuffix> (tmp1, operands[2],
- operands[3]));
- emit_insn
- (gen_vec_pack_sfix_trunc_<mode> (operands[0], tmp0, tmp1));
+ tmp0 = gen_reg_rtx (V4DFmode);
+ tmp1 = force_reg (V2DFmode, operands[1]);
+
+ emit_insn (gen_avx_vec_concatv4df (tmp0, tmp1, operands[2]));
+ emit_insn (gen_avx_roundpd256 (tmp2, tmp0, operands[3]));
+ emit_insn (gen_fix_truncv4dfv4si2 (operands[0], tmp2));
+ }
+ else
+ {
+ tmp0 = gen_reg_rtx (<MODE>mode);
+ tmp1 = gen_reg_rtx (<MODE>mode);
+
+ emit_insn
+ (gen_<sse4_1>_round<ssemodesuffix><avxsizesuffix> (tmp0, operands[1],
+ operands[3]));
+ emit_insn
+ (gen_<sse4_1>_round<ssemodesuffix><avxsizesuffix> (tmp1, operands[2],
+ operands[3]));
+ emit_insn
+ (gen_vec_pack_sfix_trunc_<mode> (operands[0], tmp0, tmp1));
+ }
DONE;
})
@@ -10053,14 +10069,29 @@
{
rtx tmp0, tmp1;
- tmp0 = gen_reg_rtx (<MODE>mode);
- tmp1 = gen_reg_rtx (<MODE>mode);
+ if (<MODE>mode == V2DFmode
+ && TARGET_AVX && !TARGET_PREFER_AVX128)
+ {
+ rtx tmp2 = gen_reg_rtx (V4DFmode);
- emit_insn (gen_round<mode>2 (tmp0, operands[1]));
- emit_insn (gen_round<mode>2 (tmp1, operands[2]));
+ tmp0 = gen_reg_rtx (V4DFmode);
+ tmp1 = force_reg (V2DFmode, operands[1]);
- emit_insn
- (gen_vec_pack_sfix_trunc_<mode> (operands[0], tmp0, tmp1));
+ emit_insn (gen_avx_vec_concatv4df (tmp0, tmp1, operands[2]));
+ emit_insn (gen_roundv4df2 (tmp2, tmp0));
+ emit_insn (gen_fix_truncv4dfv4si2 (operands[0], tmp2));
+ }
+ else
+ {
+ tmp0 = gen_reg_rtx (<MODE>mode);
+ tmp1 = gen_reg_rtx (<MODE>mode);
+
+ emit_insn (gen_round<mode>2 (tmp0, operands[1]));
+ emit_insn (gen_round<mode>2 (tmp1, operands[2]));
+
+ emit_insn
+ (gen_vec_pack_sfix_trunc_<mode> (operands[0], tmp0, tmp1));
+ }
DONE;
})
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index ff72e28a35c..75e73bda2a1 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -11218,9 +11218,13 @@ mips_init_libfuncs (void)
}
/* The MIPS16 ISA does not have an encoding for "sync", so we rely
- on an external non-MIPS16 routine to implement __sync_synchronize. */
+ on an external non-MIPS16 routine to implement __sync_synchronize.
+ Similarly for the rest of the ll/sc libfuncs. */
if (TARGET_MIPS16)
- synchronize_libfunc = init_one_libfunc ("__sync_synchronize");
+ {
+ synchronize_libfunc = init_one_libfunc ("__sync_synchronize");
+ init_sync_libfuncs (UNITS_PER_WORD);
+ }
}
/* Build up a multi-insn sequence that loads label TARGET into $AT. */
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 4436ed0e205..f01353b8942 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -17244,16 +17244,16 @@ rs6000_post_atomic_barrier (enum memmodel model)
which to shift and mask. */
static rtx
-rs6000_adjust_atomic_subword (rtx mem, rtx *pshift, rtx *pmask)
+rs6000_adjust_atomic_subword (rtx orig_mem, rtx *pshift, rtx *pmask)
{
- rtx addr, align, shift, mask;
+ rtx addr, align, shift, mask, mem;
HOST_WIDE_INT shift_mask;
- enum machine_mode mode = GET_MODE (mem);
+ enum machine_mode mode = GET_MODE (orig_mem);
/* For smaller modes, we have to implement this via SImode. */
shift_mask = (mode == QImode ? 0x18 : 0x10);
- addr = XEXP (mem, 0);
+ addr = XEXP (orig_mem, 0);
addr = force_reg (GET_MODE (addr), addr);
/* Aligned memory containing subword. Generate a new memory. We
@@ -17262,7 +17262,9 @@ rs6000_adjust_atomic_subword (rtx mem, rtx *pshift, rtx *pmask)
align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-4),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
mem = gen_rtx_MEM (SImode, align);
- MEM_VOLATILE_P (mem) = 1;
+ MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (orig_mem);
+ if (MEM_ALIAS_SET (orig_mem) == ALIAS_SET_MEMORY_BARRIER)
+ set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
/* Shift amount for subword relative to aligned word. */
shift = gen_reg_rtx (SImode);
@@ -17339,12 +17341,12 @@ rs6000_expand_atomic_compare_and_swap (rtx operands[])
/* Shift and mask OLDVAL into position with the word. */
oldval = convert_modes (SImode, mode, oldval, 1);
oldval = expand_simple_binop (SImode, ASHIFT, oldval, shift,
- oldval, 1, OPTAB_LIB_WIDEN);
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
/* Shift and mask NEWVAL into position within the word. */
newval = convert_modes (SImode, mode, newval, 1);
newval = expand_simple_binop (SImode, ASHIFT, newval, shift,
- newval, 1, OPTAB_LIB_WIDEN);
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
/* Prepare to adjust the return value. */
retval = gen_reg_rtx (SImode);
@@ -17432,7 +17434,7 @@ rs6000_expand_atomic_exchange (rtx operands[])
/* Shift and mask VAL into position with the word. */
val = convert_modes (SImode, mode, val, 1);
val = expand_simple_binop (SImode, ASHIFT, val, shift,
- val, 1, OPTAB_LIB_WIDEN);
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
/* Prepare to adjust the return value. */
retval = gen_reg_rtx (SImode);
@@ -17485,7 +17487,7 @@ rs6000_expand_atomic_op (enum rtx_code code, rtx mem, rtx val,
/* Shift and mask VAL into position with the word. */
val = convert_modes (SImode, mode, val, 1);
val = expand_simple_binop (SImode, ASHIFT, val, shift,
- val, 1, OPTAB_LIB_WIDEN);
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
switch (code)
{
@@ -25782,7 +25784,7 @@ rs6000_xcoff_section_type_flags (tree decl, const char *name, int reloc)
unsigned int flags = default_section_type_flags (decl, name, reloc);
/* Align to at least UNIT size. */
- if (flags & SECTION_CODE)
+ if (flags & SECTION_CODE || !decl)
align = MIN_UNITS_PER_WORD;
else
/* Increase alignment of large objects if not already stricter. */
diff --git a/gcc/configure b/gcc/configure
index d8654121837..6bffb8f24ad 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -7597,17 +7597,7 @@ else
RANLIB="$ac_cv_prog_RANLIB"
fi
-case "${host}" in
-*-*-darwin*)
- # By default, the Darwin ranlib will not treat common symbols as
- # definitions when building the archive table of contents. Other
- # ranlibs do that; pass an option to the Darwin ranlib that makes
- # it behave similarly.
- ranlib_flags="-c"
- ;;
-*)
- ranlib_flags=""
-esac
+ranlib_flags=""
# Find a good install program. We prefer a C program (faster),
@@ -18087,7 +18077,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 18090 "configure"
+#line 18080 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -18193,7 +18183,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 18196 "configure"
+#line 18186 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
diff --git a/gcc/configure.ac b/gcc/configure.ac
index af5b748b0f5..12492ff1fe5 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -847,17 +847,7 @@ esac
gcc_AC_PROG_LN_S
ACX_PROG_LN($LN_S)
AC_PROG_RANLIB
-case "${host}" in
-*-*-darwin*)
- # By default, the Darwin ranlib will not treat common symbols as
- # definitions when building the archive table of contents. Other
- # ranlibs do that; pass an option to the Darwin ranlib that makes
- # it behave similarly.
- ranlib_flags="-c"
- ;;
-*)
- ranlib_flags=""
-esac
+ranlib_flags=""
AC_SUBST(ranlib_flags)
gcc_AC_PROG_INSTALL
diff --git a/gcc/coverage.c b/gcc/coverage.c
index 520652b1e71..65ceba22783 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -657,9 +657,8 @@ coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum)
}
/* Build a coverage variable of TYPE for function FN_DECL. If COUNTER
- >= 0 it is a counter array, and thus local. Otherwise it is the
- function structure and needs to be globalized. All cases must be
- in the same comdat group as FN_DECL. */
+ >= 0 it is a counter array, otherwise it is the function structure.
+ Propagate appropriate linkage and visibility from the function decl. */
static tree
build_var (tree fn_decl, tree type, int counter)
@@ -668,29 +667,29 @@ build_var (tree fn_decl, tree type, int counter)
tree fn_name = DECL_ASSEMBLER_NAME (fn_decl);
char *buf = (char *)alloca (IDENTIFIER_LENGTH (fn_name) + 10);
- if (counter >= 0)
- TREE_STATIC (var) = 1;
- else
- {
- TREE_PUBLIC (var) = TREE_PUBLIC (fn_decl);
- TREE_STATIC (var) = TREE_STATIC (fn_decl);
- }
- TREE_ADDRESSABLE (var) = 1;
- DECL_ALIGN (var) = TYPE_ALIGN (type);
-
if (counter < 0)
sprintf (buf, "__gcov__%s", IDENTIFIER_POINTER (fn_name));
else
sprintf (buf, "__gcov%u_%s", counter, IDENTIFIER_POINTER (fn_name));
DECL_NAME (var) = get_identifier (buf);
-
- /* Initialize assembler name so we can stream out. */
+ TREE_STATIC (var) = 1;
+ TREE_ADDRESSABLE (var) = 1;
+ DECL_ALIGN (var) = TYPE_ALIGN (type);
+ DECL_WEAK (var) = DECL_WEAK (fn_decl);
+ TREE_PUBLIC (var)
+ = TREE_PUBLIC (fn_decl) && (counter < 0 || DECL_WEAK (fn_decl));
+ if (DECL_ONE_ONLY (fn_decl))
+ make_decl_one_only (var, DECL_COMDAT_GROUP (fn_decl));
+
if (TREE_PUBLIC (var))
- DECL_ASSEMBLER_NAME (var);
+ {
+ DECL_VISIBILITY (var) = DECL_VISIBILITY (fn_decl);
+ DECL_VISIBILITY_SPECIFIED (var)
+ = DECL_VISIBILITY_SPECIFIED (fn_decl);
- DECL_WEAK (var) = TREE_PUBLIC (var) && DECL_WEAK (fn_decl);
- DECL_COMDAT (var) = DECL_COMDAT (fn_decl);
- DECL_COMDAT_GROUP (var) = DECL_COMDAT_GROUP (fn_decl);
+ /* Initialize assembler name so we can stream out. */
+ DECL_ASSEMBLER_NAME (var);
+ }
return var;
}
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4e5b26523e1..c08314449bf 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,68 @@
+2011-11-20 Jason Merrill <jason@redhat.com>
+
+ * pt.c (tsubst_pack_expansion): Fix SFINAE.
+
+ PR c++/48322
+ * cp-tree.h (PACK_EXPANSION_EXTRA_ARGS): New.
+ * cp-tree.def (EXPR_PACK_EXPANSION): Add an operand for it.
+ * pt.c (tsubst_pack_expansion): Set and use it.
+ (iterative_hash_template_arg): Hash it.
+ (template_args_equal): Compare it.
+ (comp_template_args_with_info): Handle nulls.
+ * tree.c (cp_walk_subtrees): Walk it.
+ * typeck.c (structural_comptypes): Compare it.
+ * ptree.c (cxx_print_type): Print it.
+
+ * pt.c (type_unification_real): Set input_location
+ during default arg instantiation.
+
+2011-11-20 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/51230
+ * pt.c (unify_inconsistency): Handle non-type parameters better.
+ * error.c (dump_expr): Handle TEMPLATE_TEMPLATE_PARM.
+
+2011-11-20 Dodji Seketeli <dodji@redhat.com>
+
+ PR c++/51194
+ * pt.c (lookup_template_class_1): Go out early if the type of the
+ template is error_mark_node.
+
+2011-11-19 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/51216
+ * semantics.c (potential_constant_expression_1): Handle IF_STMT,
+ DO_STMT, FOR_STMT, and WHILE_STMT.
+
+2011-11-18 Fabien Chêne <fabien@gcc.gnu.org>
+
+ PR c++/51188
+ * search.c (lookup_field_1): Handle USING_DECLs for the storted
+ case.
+
+2011-11-18 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/51150
+ * pt.c (tsubst_copy_and_build): Handle FIX_TRUNC_EXPR.
+
+2011-11-18 Dodji Seketeli <dodji@redhat.com>
+
+ PR c++/51191
+ * pt.c (primary_template_instantiation_p): Don't forget to
+ consider alias declarations.
+
+2011-11-17 Jason Merrill <jason@redhat.com>
+
+ PR c++/51186
+ * decl.c (grokdeclarator): Improve C++98 trailing return diagnostic.
+
+ N3203
+ * class.c (add_implicitly_declared_members): Update move
+ conditions.
+
+ PR c++/51137
+ * class.c (build_base_path): Don't do calculation in templates.
+
2011-11-15 Torvald Riegel <triegel@redhat.com>
* parser.c (cp_parser_transaction_expression): Require parentheses
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 4a291acca8a..cb0e683c597 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -304,8 +304,13 @@ build_base_path (enum tree_code code,
virtual_access = (v_binfo && fixed_type_p <= 0);
/* Don't bother with the calculations inside sizeof; they'll ICE if the
- source type is incomplete and the pointer value doesn't matter. */
- if (cp_unevaluated_operand != 0)
+ source type is incomplete and the pointer value doesn't matter. In a
+ template (even in fold_non_dependent_expr), we don't have vtables set
+ up properly yet, and the value doesn't matter there either; we're just
+ interested in the result of overload resolution. */
+ if (cp_unevaluated_operand != 0
+ || (current_function_decl
+ && uses_template_parms (current_function_decl)))
{
expr = build_nop (ptr_target_type, expr);
if (!want_pointer)
@@ -359,11 +364,6 @@ build_base_path (enum tree_code code,
V_BINFO. That offset is an entry in D_BINFO's vtable. */
tree v_offset;
- /* In a constructor template, current_in_charge_parm isn't set,
- and we might end up here via fold_non_dependent_expr. */
- if (fixed_type_p < 0 && !(cfun && current_in_charge_parm))
- fixed_type_p = 0;
-
if (fixed_type_p < 0 && in_base_initializer)
{
/* In a base member initializer, we cannot rely on the
@@ -2721,6 +2721,13 @@ add_implicitly_declared_members (tree t,
int cant_have_const_cctor,
int cant_have_const_assignment)
{
+ bool move_ok = false;
+
+ if (cxx_dialect >= cxx0x && !CLASSTYPE_DESTRUCTORS (t)
+ && !TYPE_HAS_COPY_CTOR (t) && !TYPE_HAS_COPY_ASSIGN (t)
+ && !type_has_move_constructor (t) && !type_has_move_assign (t))
+ move_ok = true;
+
/* Destructor. */
if (!CLASSTYPE_DESTRUCTORS (t))
{
@@ -2758,7 +2765,7 @@ add_implicitly_declared_members (tree t,
TYPE_HAS_COPY_CTOR (t) = 1;
TYPE_HAS_CONST_COPY_CTOR (t) = !cant_have_const_cctor;
CLASSTYPE_LAZY_COPY_CTOR (t) = 1;
- if (cxx_dialect >= cxx0x && !type_has_move_constructor (t))
+ if (move_ok)
CLASSTYPE_LAZY_MOVE_CTOR (t) = 1;
}
@@ -2771,7 +2778,7 @@ add_implicitly_declared_members (tree t,
TYPE_HAS_COPY_ASSIGN (t) = 1;
TYPE_HAS_CONST_COPY_ASSIGN (t) = !cant_have_const_assignment;
CLASSTYPE_LAZY_COPY_ASSIGN (t) = 1;
- if (cxx_dialect >= cxx0x && !type_has_move_assign (t))
+ if (move_ok)
CLASSTYPE_LAZY_MOVE_ASSIGN (t) = 1;
}
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 4eec9f97c7d..5fc5496ef9e 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -419,7 +419,7 @@ DEFTREECODE (TYPE_PACK_EXPANSION, "type_pack_expansion", tcc_type, 0)
EXPR_PACK_EXPANSION plays precisely the same role as TYPE_PACK_EXPANSION,
but will be used for expressions. */
-DEFTREECODE (EXPR_PACK_EXPANSION, "expr_pack_expansion", tcc_expression, 2)
+DEFTREECODE (EXPR_PACK_EXPANSION, "expr_pack_expansion", tcc_expression, 3)
/* Selects the Ith parameter out of an argument pack. This node will
be used when instantiating pack expansions; see
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index fe50e34e7d9..3f4f4081f38 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2813,7 +2813,14 @@ extern void decl_shadowed_for_var_insert (tree, tree);
#define PACK_EXPANSION_PARAMETER_PACKS(NODE) \
*(TREE_CODE (NODE) == EXPR_PACK_EXPANSION \
? &TREE_OPERAND (NODE, 1) \
- : &TREE_CHAIN (TYPE_PACK_EXPANSION_CHECK (NODE)))
+ : &TYPE_MINVAL (TYPE_PACK_EXPANSION_CHECK (NODE)))
+
+/* Any additional template args to be applied when substituting into
+ the pattern, set by tsubst_pack_expansion for partial instantiations. */
+#define PACK_EXPANSION_EXTRA_ARGS(NODE) \
+ *(TREE_CODE (NODE) == TYPE_PACK_EXPANSION \
+ ? &TYPE_MAXVAL (NODE) \
+ : &TREE_OPERAND ((NODE), 2))
/* Determine if this is an argument pack. */
#define ARGUMENT_PACK_P(NODE) \
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index d744da85f3e..b77963b72df 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -9126,12 +9126,12 @@ grokdeclarator (const cp_declarator *declarator,
if (!declarator->u.function.late_return_type)
{
error ("%qs function uses %<auto%> type specifier without"
- " late return type", name);
+ " trailing return type", name);
return error_mark_node;
}
else if (!is_auto (type))
{
- error ("%qs function with late return type has"
+ error ("%qs function with trailing return type has"
" %qT as its type rather than plain %<auto%>",
name, type);
return error_mark_node;
@@ -9139,8 +9139,14 @@ grokdeclarator (const cp_declarator *declarator,
}
else if (declarator->u.function.late_return_type)
{
- error ("%qs function with late return type not declared"
- " with %<auto%> type specifier", name);
+ if (cxx_dialect < cxx0x)
+ /* Not using maybe_warn_cpp0x because this should
+ always be an error. */
+ error ("trailing return type only available with "
+ "-std=c++11 or -std=gnu++11");
+ else
+ error ("%qs function with trailing return type not "
+ "declared with %<auto%> type specifier", name);
return error_mark_node;
}
}
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 602cb75236a..4940a783353 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -2406,6 +2406,7 @@ dump_expr (tree t, int flags)
break;
case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
case BOUND_TEMPLATE_TEMPLATE_PARM:
dump_type (t, flags);
break;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 97380260ae4..2ba26b206bd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1534,7 +1534,8 @@ iterative_hash_template_arg (tree arg, hashval_t val)
case TYPE_PACK_EXPANSION:
case EXPR_PACK_EXPANSION:
- return iterative_hash_template_arg (PACK_EXPANSION_PATTERN (arg), val);
+ val = iterative_hash_template_arg (PACK_EXPANSION_PATTERN (arg), val);
+ return iterative_hash_template_arg (PACK_EXPANSION_EXTRA_ARGS (arg), val);
case TYPE_ARGUMENT_PACK:
case NONTYPE_ARGUMENT_PACK:
@@ -2870,7 +2871,7 @@ primary_template_instantiation_p (const_tree t)
return DECL_LANG_SPECIFIC (t)
&& DECL_TEMPLATE_INSTANTIATION (t)
&& PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t));
- else if (CLASS_TYPE_P (t))
+ else if (CLASS_TYPE_P (t) && !TYPE_DECL_ALIAS_P (TYPE_NAME (t)))
return CLASSTYPE_TEMPLATE_INSTANTIATION (t)
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t));
else if (TYPE_P (t)
@@ -5501,7 +5502,7 @@ unify_inconsistency (bool explain_p, tree parm, tree first, tree second)
{
if (explain_p)
inform (input_location,
- " deduced conflicting types for parameter %qT (%qT and %qT)",
+ " conflicting deductions for parameter %qE (%qE and %qE)",
parm, first, second);
return 1;
}
@@ -6902,9 +6903,11 @@ template_args_equal (tree ot, tree nt)
/* For member templates */
return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
else if (PACK_EXPANSION_P (ot))
- return PACK_EXPANSION_P (nt)
- && template_args_equal (PACK_EXPANSION_PATTERN (ot),
- PACK_EXPANSION_PATTERN (nt));
+ return (PACK_EXPANSION_P (nt)
+ && template_args_equal (PACK_EXPANSION_PATTERN (ot),
+ PACK_EXPANSION_PATTERN (nt))
+ && template_args_equal (PACK_EXPANSION_EXTRA_ARGS (ot),
+ PACK_EXPANSION_EXTRA_ARGS (nt)));
else if (ARGUMENT_PACK_P (ot))
{
int i, len;
@@ -6954,6 +6957,12 @@ comp_template_args_with_info (tree oldargs, tree newargs,
{
int i;
+ if (oldargs == newargs)
+ return 1;
+
+ if (!oldargs || !newargs)
+ return 0;
+
if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs))
return 0;
@@ -7270,6 +7279,12 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
int is_dependent_type;
int use_partial_inst_tmpl = false;
+ if (template_type == error_mark_node)
+ /* An error occured while building the template TEMPL, and a
+ diagnostic has most certainly been emitted for that
+ already. Let's propagate that error. */
+ return error_mark_node;
+
gen_tmpl = most_general_template (templ);
parmlist = DECL_TEMPLATE_PARMS (gen_tmpl);
parm_depth = TMPL_PARMS_DEPTH (parmlist);
@@ -9235,13 +9250,21 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
tree pattern;
tree pack, packs = NULL_TREE;
bool unsubstituted_packs = false;
+ bool real_packs = false;
+ int missing_level = 0;
int i, len = -1;
tree result;
htab_t saved_local_specializations = NULL;
+ int levels;
gcc_assert (PACK_EXPANSION_P (t));
pattern = PACK_EXPANSION_PATTERN (t);
+ /* Add in any args remembered from an earlier partial instantiation. */
+ args = add_to_template_args (PACK_EXPANSION_EXTRA_ARGS (t), args);
+
+ levels = TMPL_ARGS_DEPTH (args);
+
/* Determine the argument packs that will instantiate the parameter
packs used in the expansion expression. While we're at it,
compute the number of arguments to be expanded and make sure it
@@ -9252,6 +9275,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
tree parm_pack = TREE_VALUE (pack);
tree arg_pack = NULL_TREE;
tree orig_arg = NULL_TREE;
+ int level = 0;
if (TREE_CODE (parm_pack) == BASES)
{
@@ -9284,10 +9308,9 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
}
else
{
- int level, idx, levels;
+ int idx;
template_parm_level_and_index (parm_pack, &level, &idx);
- levels = TMPL_ARGS_DEPTH (args);
if (level <= levels)
arg_pack = TMPL_ARG (args, level, idx);
}
@@ -9327,7 +9350,9 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
len = my_len;
else if (len != my_len)
{
- if (TREE_CODE (t) == TYPE_PACK_EXPANSION)
+ if (!(complain & tf_error))
+ /* Fail quietly. */;
+ else if (TREE_CODE (t) == TYPE_PACK_EXPANSION)
error ("mismatched argument pack lengths while expanding "
"%<%T%>",
pattern);
@@ -9338,6 +9363,13 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
return error_mark_node;
}
+ if (TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack)) == 1
+ && PACK_EXPANSION_P (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg_pack),
+ 0)))
+ /* This isn't a real argument pack yet. */;
+ else
+ real_packs = true;
+
/* Keep track of the parameter packs and their corresponding
argument packs. */
packs = tree_cons (parm_pack, arg_pack, packs);
@@ -9345,25 +9377,57 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
}
else
{
- /* We can't substitute for this parameter pack. */
+ /* We can't substitute for this parameter pack. We use a flag as
+ well as the missing_level counter because function parameter
+ packs don't have a level. */
unsubstituted_packs = true;
- break;
+ if (!missing_level || missing_level > level)
+ missing_level = level;
}
}
/* We cannot expand this expansion expression, because we don't have
- all of the argument packs we need. Substitute into the pattern
- and return a PACK_EXPANSION_*. The caller will need to deal with
- that. */
+ all of the argument packs we need. */
if (unsubstituted_packs)
{
- tree new_pat;
- if (TREE_CODE (t) == EXPR_PACK_EXPANSION)
- new_pat = tsubst_expr (pattern, args, complain, in_decl,
- /*integral_constant_expression_p=*/false);
+ if (real_packs)
+ {
+ /* We got some full packs, but we can't substitute them in until we
+ have values for all the packs. So remember these until then. */
+ tree save_args;
+
+ t = make_pack_expansion (pattern);
+
+ /* The call to add_to_template_args above assumes no overlap
+ between saved args and new args, so prune away any fake
+ args, i.e. those that satisfied arg_from_parm_pack_p above. */
+ if (missing_level && levels >= missing_level)
+ {
+ gcc_assert (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args)
+ && missing_level > 1);
+ TREE_VEC_LENGTH (args) = missing_level - 1;
+ save_args = copy_node (args);
+ TREE_VEC_LENGTH (args) = levels;
+ }
+ else
+ save_args = args;
+
+ PACK_EXPANSION_EXTRA_ARGS (t) = save_args;
+ }
else
- new_pat = tsubst (pattern, args, complain, in_decl);
- return make_pack_expansion (new_pat);
+ {
+ /* There were no real arguments, we're just replacing a parameter
+ pack with another version of itself. Substitute into the
+ pattern and return a PACK_EXPANSION_*. The caller will need to
+ deal with that. */
+ if (TREE_CODE (t) == EXPR_PACK_EXPANSION)
+ t = tsubst_expr (pattern, args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+ else
+ t = tsubst (pattern, args, complain, in_decl);
+ t = make_pack_expansion (t);
+ }
+ return t;
}
/* We could not find any argument packs that work. */
@@ -13387,6 +13451,10 @@ tsubst_copy_and_build (tree t,
return build_x_unary_op (TREE_CODE (t), RECUR (TREE_OPERAND (t, 0)),
complain);
+ case FIX_TRUNC_EXPR:
+ return cp_build_unary_op (FIX_TRUNC_EXPR, RECUR (TREE_OPERAND (t, 0)),
+ 0, complain);
+
case ADDR_EXPR:
op1 = TREE_OPERAND (t, 0);
if (TREE_CODE (op1) == LABEL_DECL)
@@ -15208,9 +15276,13 @@ type_unification_real (tree tparms,
{
tree parm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
tree arg = TREE_PURPOSE (TREE_VEC_ELT (tparms, i));
+ location_t save_loc = input_location;
+ if (DECL_P (parm))
+ input_location = DECL_SOURCE_LOCATION (parm);
arg = tsubst_template_arg (arg, targs, complain, NULL_TREE);
arg = convert_template_argument (parm, arg, targs, complain,
i, NULL_TREE);
+ input_location = save_loc;
if (arg == error_mark_node)
return 1;
else
diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c
index fb05e136045..a66e695c1f7 100644
--- a/gcc/cp/ptree.c
+++ b/gcc/cp/ptree.c
@@ -104,6 +104,10 @@ cxx_print_type (FILE *file, tree node, int indent)
indent + 4);
return;
+ case TYPE_PACK_EXPANSION:
+ print_node (file, "args", PACK_EXPANSION_EXTRA_ARGS (node), indent + 4);
+ return;
+
default:
return;
}
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 9f308e29d79..3894c685884 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -436,6 +436,14 @@ lookup_field_1 (tree type, tree name, bool want_type)
field = fields[i++];
while (i < hi && DECL_NAME (fields[i]) == name);
}
+
+ if (field)
+ {
+ field = strip_using_decl (field);
+ if (is_overloaded_fn (field))
+ field = NULL_TREE;
+ }
+
return field;
}
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f70bdb377b5..fe685fa1527 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -8178,6 +8178,10 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
case EXPR_STMT:
case BIND_EXPR:
case TRANSACTION_EXPR:
+ case IF_STMT:
+ case DO_STMT:
+ case FOR_STMT:
+ case WHILE_STMT:
if (flags & tf_error)
error ("expression %qE is not a constant-expression", t);
return false;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 841029f3385..d206fd2ec24 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2993,11 +2993,13 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
case TYPE_PACK_EXPANSION:
WALK_SUBTREE (TREE_TYPE (*tp));
+ WALK_SUBTREE (PACK_EXPANSION_EXTRA_ARGS (*tp));
*walk_subtrees_p = 0;
break;
case EXPR_PACK_EXPANSION:
WALK_SUBTREE (TREE_OPERAND (*tp, 0));
+ WALK_SUBTREE (PACK_EXPANSION_EXTRA_ARGS (*tp));
*walk_subtrees_p = 0;
break;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index b8d4c10c8ca..a23e27491d8 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1329,8 +1329,10 @@ structural_comptypes (tree t1, tree t2, int strict)
break;
case TYPE_PACK_EXPANSION:
- return same_type_p (PACK_EXPANSION_PATTERN (t1),
- PACK_EXPANSION_PATTERN (t2));
+ return (same_type_p (PACK_EXPANSION_PATTERN (t1),
+ PACK_EXPANSION_PATTERN (t2))
+ && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1),
+ PACK_EXPANSION_EXTRA_ARGS (t2)));
case DECLTYPE_TYPE:
if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
diff --git a/gcc/cprop.c b/gcc/cprop.c
index 9ee1efb1af6..01f40f0bc72 100644
--- a/gcc/cprop.c
+++ b/gcc/cprop.c
@@ -116,6 +116,11 @@ static struct hash_table_d set_hash_table;
/* Array of implicit set patterns indexed by basic block index. */
static rtx *implicit_sets;
+/* Array of indexes of expressions for implicit set patterns indexed by basic
+ block index. In other words, implicit_set_indexes[i] is the bitmap_index
+ of the expression whose RTX is implicit_sets[i]. */
+static int *implicit_set_indexes;
+
/* Bitmap containing one bit for each register in the program.
Used when performing GCSE to track which registers have been set since
the start or end of the basic block while traversing that block. */
@@ -177,10 +182,12 @@ hash_set (int regno, int hash_table_size)
/* Insert assignment DEST:=SET from INSN in the hash table.
DEST is a register and SET is a register or a suitable constant.
If the assignment is already present in the table, record it as
- the last occurrence in INSN's basic block. */
+ the last occurrence in INSN's basic block.
+ IMPLICIT is true if it's an implicit set, false otherwise. */
static void
-insert_set_in_table (rtx dest, rtx src, rtx insn, struct hash_table_d *table)
+insert_set_in_table (rtx dest, rtx src, rtx insn, struct hash_table_d *table,
+ bool implicit)
{
bool found = false;
unsigned int hash;
@@ -243,6 +250,10 @@ insert_set_in_table (rtx dest, rtx src, rtx insn, struct hash_table_d *table)
cur_occr->next = cur_expr->avail_occr;
cur_expr->avail_occr = cur_occr;
}
+
+ /* Record bitmap_index of the implicit set in implicit_set_indexes. */
+ if (implicit)
+ implicit_set_indexes[BLOCK_FOR_INSN(insn)->index] = cur_expr->bitmap_index;
}
/* Determine whether the rtx X should be treated as a constant for CPROP.
@@ -255,10 +266,11 @@ cprop_constant_p (const_rtx x)
return CONSTANT_P (x) && (GET_CODE (x) != CONST || shared_const_p (x));
}
-/* Scan SET present in INSN and add an entry to the hash TABLE. */
+/* Scan SET present in INSN and add an entry to the hash TABLE.
+ IMPLICIT is true if it's an implicit set, false otherwise. */
static void
-hash_scan_set (rtx set, rtx insn, struct hash_table_d *table)
+hash_scan_set (rtx set, rtx insn, struct hash_table_d *table, bool implicit)
{
rtx src = SET_SRC (set);
rtx dest = SET_DEST (set);
@@ -294,7 +306,7 @@ hash_scan_set (rtx set, rtx insn, struct hash_table_d *table)
&& ! HARD_REGISTER_P (src)
&& reg_available_p (src, insn))
|| cprop_constant_p (src))
- insert_set_in_table (dest, src, insn, table);
+ insert_set_in_table (dest, src, insn, table, implicit);
}
}
@@ -310,14 +322,14 @@ hash_scan_insn (rtx insn, struct hash_table_d *table)
what's been modified. */
if (GET_CODE (pat) == SET)
- hash_scan_set (pat, insn, table);
+ hash_scan_set (pat, insn, table, false);
else if (GET_CODE (pat) == PARALLEL)
for (i = 0; i < XVECLEN (pat, 0); i++)
{
rtx x = XVECEXP (pat, 0, i);
if (GET_CODE (x) == SET)
- hash_scan_set (x, insn, table);
+ hash_scan_set (x, insn, table, false);
}
}
@@ -421,7 +433,7 @@ compute_hash_table_work (struct hash_table_d *table)
/* Insert implicit sets in the hash table, pretending they appear as
insns at the head of the basic block. */
if (implicit_sets[bb->index] != NULL_RTX)
- hash_scan_set (implicit_sets[bb->index], BB_HEAD (bb), table);
+ hash_scan_set (implicit_sets[bb->index], BB_HEAD (bb), table, true);
}
FREE_REG_SET (reg_set_bitmap);
@@ -633,8 +645,22 @@ compute_local_properties (sbitmap *kill, sbitmap *comp,
static void
compute_cprop_data (void)
{
+ basic_block bb;
+
compute_local_properties (cprop_kill, cprop_avloc, &set_hash_table);
compute_available (cprop_avloc, cprop_kill, cprop_avout, cprop_avin);
+
+ /* Merge implicit sets into CPROP_AVIN. They are always available at the
+ entry of their basic block. We need to do this because 1) implicit sets
+ aren't recorded for the local pass so they cannot be propagated within
+ their basic block by this pass and 2) the global pass would otherwise
+ propagate them only in the successors of their basic block. */
+ FOR_EACH_BB (bb)
+ {
+ int index = implicit_set_indexes[bb->index];
+ if (index != -1)
+ SET_BIT (cprop_avin[bb->index], index);
+ }
}
/* Copy/constant propagation. */
@@ -1727,6 +1753,7 @@ is_too_expensive (const char *pass)
static int
one_cprop_pass (void)
{
+ int i;
int changed = 0;
/* Return if there's nothing to do, or it is too expensive. */
@@ -1774,6 +1801,11 @@ one_cprop_pass (void)
if (changed)
df_analyze ();
+ /* Initialize implicit_set_indexes array. */
+ implicit_set_indexes = XNEWVEC (int, last_basic_block);
+ for (i = 0; i < last_basic_block; i++)
+ implicit_set_indexes[i] = -1;
+
alloc_hash_table (&set_hash_table);
compute_hash_table (&set_hash_table);
@@ -1791,6 +1823,9 @@ one_cprop_pass (void)
alloc_cprop_mem (last_basic_block, set_hash_table.n_elems);
compute_cprop_data ();
+ free (implicit_set_indexes);
+ implicit_set_indexes = NULL;
+
/* Allocate vars to track sets of regs. */
reg_set_bitmap = ALLOC_REG_SET (NULL);
@@ -1820,6 +1855,11 @@ one_cprop_pass (void)
FREE_REG_SET (reg_set_bitmap);
free_cprop_mem ();
}
+ else
+ {
+ free (implicit_set_indexes);
+ implicit_set_indexes = NULL;
+ }
free_hash_table (&set_hash_table);
obstack_free (&cprop_obstack, NULL);
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 15238c1b39e..de483a3d354 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9384,6 +9384,7 @@ v2df __builtin_ia32_loadlpd (v2df, double const *)
int __builtin_ia32_movmskpd (v2df)
int __builtin_ia32_pmovmskb128 (v16qi)
void __builtin_ia32_movnti (int *, int)
+void __builtin_ia32_movnti64 (long long int *, long long int)
void __builtin_ia32_movntpd (double *, v2df)
void __builtin_ia32_movntdq (v2df *, v2df)
v4si __builtin_ia32_pshufd (v4si, int)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 73f874f152c..7cc255c5c6e 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -12809,6 +12809,15 @@ Improved versions of k8, opteron and athlon64 with SSE3 instruction set support.
AMD Family 10h core based CPUs with x86-64 instruction set support. (This
supersets MMX, SSE, SSE2, SSE3, SSE4A, 3DNow!, enhanced 3DNow!, ABM and 64-bit
instruction set extensions.)
+@item bdver1
+AMD Family 15h core based CPUs with x86-64 instruction set support. (This
+supersets FMA4, AVX, XOP, LWP, AES, PCL_MUL, CX16, MMX, SSE, SSE2, SSE3, SSE4A,
+SSSE3, SSE4.1, SSE4.2, 3DNow!, enhanced 3DNow!, ABM and 64-bit
+instruction set extensions.)
+@item btver1
+AMD Family 14h core based CPUs with x86-64 instruction set support. (This
+supersets MMX, SSE, SSE2, SSE3, SSSE3, SSE4A, CX16, ABM and 64-bit
+instruction set extensions.)
@item winchip-c6
IDT Winchip C6 CPU, dealt in same way as i486 with additional MMX instruction
set support.
diff --git a/gcc/expmed.c b/gcc/expmed.c
index b3e6d6d1816..ea42e9cd52a 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -557,9 +557,18 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
0)
: (int) i * BITS_PER_WORD);
rtx value_word = operand_subword_force (value, wordnum, fieldmode);
-
- if (!store_bit_field_1 (op0, MIN (BITS_PER_WORD,
- bitsize - i * BITS_PER_WORD),
+ unsigned HOST_WIDE_INT new_bitsize =
+ MIN (BITS_PER_WORD, bitsize - i * BITS_PER_WORD);
+
+ /* If the remaining chunk doesn't have full wordsize we have
+ to make sure that for big endian machines the higher order
+ bits are used. */
+ if (new_bitsize < BITS_PER_WORD && BYTES_BIG_ENDIAN)
+ value_word = extract_bit_field (value_word, new_bitsize, 0,
+ true, false, NULL_RTX,
+ BLKmode, word_mode);
+
+ if (!store_bit_field_1 (op0, new_bitsize,
bitnum + bit_offset,
bitregion_start, bitregion_end,
word_mode,
diff --git a/gcc/expr.c b/gcc/expr.c
index 84cfe5c23ee..8d3a0f671a8 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -9740,11 +9740,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER)
/* If the field is volatile, we always want an aligned
- access. Only do this if the access is not already naturally
+ access. Do this in following two situations:
+ 1. the access is not already naturally
aligned, otherwise "normal" (non-bitfield) volatile fields
- become non-addressable. */
+ become non-addressable.
+ 2. the bitsize is narrower than the access size. Need
+ to extract bitfields from the access. */
|| (volatilep && flag_strict_volatile_bitfields > 0
- && (bitpos % GET_MODE_ALIGNMENT (mode) != 0))
+ && (bitpos % GET_MODE_ALIGNMENT (mode) != 0
+ || (mode1 != BLKmode
+ && bitsize < GET_MODE_SIZE (mode1) * BITS_PER_UNIT)))
/* If the field isn't aligned enough to fetch as a memref,
fetch it as a bit field. */
|| (mode1 != BLKmode
diff --git a/gcc/expr.h b/gcc/expr.h
index 2cc8152c740..4b923a53e66 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -254,7 +254,6 @@ extern void expand_builtin_setjmp_receiver (rtx);
extern rtx expand_builtin_saveregs (void);
extern void expand_builtin_trap (void);
extern rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
-extern void expand_builtin_mem_thread_fence (enum memmodel);
/* Functions from expr.c: */
diff --git a/gcc/final.c b/gcc/final.c
index cc3a199692e..60df6fa70a6 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -3585,7 +3585,7 @@ output_addr_const (FILE *file, rtx x)
break;
case CONST_INT:
- fprint_w (file, INTVAL (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
break;
case CONST:
@@ -3741,33 +3741,6 @@ sprint_ul_rev (char *s, unsigned long value)
return i;
}
-/* Write a signed HOST_WIDE_INT as decimal to a file, fast. */
-
-void
-fprint_w (FILE *f, HOST_WIDE_INT value)
-{
- /* python says: len(str(2**64)) == 20 */
- char s[20];
- int i;
-
- if (value >= 0)
- i = sprint_ul_rev (s, (unsigned long) value);
- else
- {
- /* Cast to long long to output max negative correctly! */
- i = sprint_ul_rev (s, ((unsigned long long) value) * -1);
- putc('-', f);
- }
-
- /* It's probably too small to bother with string reversal and fputs. */
- do
- {
- i--;
- putc (s[i], f);
- }
- while (i != 0);
-}
-
/* Write an unsigned long as decimal to a file, fast. */
void
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 167573b17b3..e590377265e 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -14157,7 +14157,8 @@ fold_checksum_tree (const_tree expr, struct md5_ctx *ctx, htab_t ht)
}
}
md5_process_bytes (expr, tree_size (expr), ctx);
- fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
+ if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
+ fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
if (TREE_CODE_CLASS (code) != tcc_type
&& TREE_CODE_CLASS (code) != tcc_declaration
&& code != TREE_LIST
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 01abd74f890..83974b51ca0 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,63 @@
+2011-11-19 Tobias Burnus <burnus@net-b.de>
+
+ PR fortran/51207
+ * class.c (gfc_find_derived_vtab): Mark __def_init as PARAMETER
+ and hence as TREE_READONLY; add subroutine attribute to
+ __copy_ procedure.
+
+ PR fortran/50640
+ * trans.h (GFC_DECL_PUSH_TOPLEVEL): New DECL_LANG_FLAG_7.
+ * trans-decl.c (gfc_get_symbol_decl): Mark __def_init and vtab as
+ GFC_DECL_PUSH_TOPLEVEL.
+ (gfc_generate_function_code): If GFC_DECL_PUSH_TOPLEVEL, push it there.
+ (build_function_decl): Push __copy_ procedure to the toplevel.
+
+2011-11-16 Tobias Burnus <burnus@net-b.de>
+
+ PR fortran/39427
+ PR fortran/37829
+ * decl.c (match_data_constant, match_data_constant, variable_decl,
+ gfc_match_decl_type_spec, access_attr_decl,
+ check_extended_derived_type, gfc_match_derived_decl,
+ gfc_match_derived_decl, gfc_match_derived_decl) Modified to deal
+ with DT constructors.
+ * gfortran.h (gfc_find_dt_in_generic,
+ gfc_convert_to_structure_constructor): New function prototypes.
+ * interface.c (check_interface0, check_interface1,
+ gfc_search_interface): Ignore DT constructors in generic list.
+ * match.h (gfc_match_structure_constructor): Update prototype.
+ * match.c (match_derived_type_spec): Ensure that one uses the DT
+ not the generic function.
+ * module.c (MOD_VERSION): Bump.
+ (dt_lower_string, dt_upper_string): New functions.
+ (find_use_name_n, find_use_operator, compare_true_names,
+ find_true_name, add_true_name, fix_mio_expr, load_needed,
+ read_module, write_dt_extensions, write_symbol): Changes to deal with
+ different symtree vs. sym names.
+ (create_derived_type): Create also generic procedure.
+ * parse.c (gfc_fixup_sibling_symbols): Don't regard DT and generic
+ function as the same.
+ * primary.c (gfc_convert_to_structure_constructor): New function.
+ (gfc_match_structure_constructor): Restructured; calls
+ gfc_convert_to_structure_constructor.
+ (build_actual_constructor, gfc_match_rvalue): Update for DT generic
+ functions.
+ * resolve.c (resolve_formal_arglist, resolve_structure_cons,
+ is_illegal_recursion, resolve_generic_f, resolve_variable,
+ resolve_fl_variable_derived, resolve_fl_derived0,
+ resolve_symbol): Handle DT and DT generic constructors.
+ * symbol.c (gfc_use_derived, gfc_undo_symbols,
+ gen_special_c_interop_ptr, gen_cptr_param,
+ generate_isocbinding_symbol, gfc_get_derived_super_type): Handle
+ derived-types, which are hidden in the generic type.
+ (gfc_find_dt_in_generic): New function
+ * trans-array.c (gfc_conv_array_initializer): Replace FL_PARAMETER
+ expr by actual value.
+ * trans-decl.c (gfc_get_module_backend_decl, gfc_trans_use_stmts):
+ Ensure that we use the DT and not the generic function.
+ * trans-types.c (gfc_get_derived_type): Ensure that we use the DT
+ and not the generic procedure.
+
2011-11-14 Tobias Burnus <burnus@net-b.de>
PR fortran/51073
diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c
index dc76ad158bb..bcb2d0b76bc 100644
--- a/gcc/fortran/class.c
+++ b/gcc/fortran/class.c
@@ -522,7 +522,7 @@ gfc_find_derived_vtab (gfc_symbol *derived)
def_init->attr.target = 1;
def_init->attr.save = SAVE_IMPLICIT;
def_init->attr.access = ACCESS_PUBLIC;
- def_init->attr.flavor = FL_VARIABLE;
+ def_init->attr.flavor = FL_PARAMETER;
gfc_set_sym_referenced (def_init);
def_init->ts.type = BT_DERIVED;
def_init->ts.u.derived = derived;
@@ -552,6 +552,7 @@ gfc_find_derived_vtab (gfc_symbol *derived)
gfc_get_symbol (name, sub_ns, &copy);
sub_ns->proc_name = copy;
copy->attr.flavor = FL_PROCEDURE;
+ copy->attr.subroutine = 1;
copy->attr.if_source = IFSRC_DECL;
if (ns->proc_name->attr.flavor == FL_MODULE)
copy->module = ns->proc_name->name;
diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c
index 2dd38b9485e..3e553a38143 100644
--- a/gcc/fortran/decl.c
+++ b/gcc/fortran/decl.c
@@ -323,7 +323,7 @@ static match
match_data_constant (gfc_expr **result)
{
char name[GFC_MAX_SYMBOL_LEN + 1];
- gfc_symbol *sym;
+ gfc_symbol *sym, *dt_sym = NULL;
gfc_expr *expr;
match m;
locus old_loc;
@@ -366,15 +366,19 @@ match_data_constant (gfc_expr **result)
if (gfc_find_symbol (name, NULL, 1, &sym))
return MATCH_ERROR;
+ if (sym && sym->attr.generic)
+ dt_sym = gfc_find_dt_in_generic (sym);
+
if (sym == NULL
- || (sym->attr.flavor != FL_PARAMETER && sym->attr.flavor != FL_DERIVED))
+ || (sym->attr.flavor != FL_PARAMETER
+ && (!dt_sym || dt_sym->attr.flavor != FL_DERIVED)))
{
gfc_error ("Symbol '%s' must be a PARAMETER in DATA statement at %C",
name);
return MATCH_ERROR;
}
- else if (sym->attr.flavor == FL_DERIVED)
- return gfc_match_structure_constructor (sym, result, false);
+ else if (dt_sym && dt_sym->attr.flavor == FL_DERIVED)
+ return gfc_match_structure_constructor (dt_sym, result);
/* Check to see if the value is an initialization array expression. */
if (sym->value->expr_type == EXPR_ARRAY)
@@ -1954,10 +1958,10 @@ variable_decl (int elem)
st = gfc_find_symtree (gfc_current_ns->sym_root, current_ts.u.derived->name);
if (!(current_ts.u.derived->attr.imported
&& st != NULL
- && st->n.sym == current_ts.u.derived)
+ && gfc_find_dt_in_generic (st->n.sym) == current_ts.u.derived)
&& !gfc_current_ns->has_import_set)
{
- gfc_error ("the type of '%s' at %C has not been declared within the "
+ gfc_error ("The type of '%s' at %C has not been declared within the "
"interface", name);
m = MATCH_ERROR;
goto cleanup;
@@ -2501,10 +2505,11 @@ match
gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
{
char name[GFC_MAX_SYMBOL_LEN + 1];
- gfc_symbol *sym;
+ gfc_symbol *sym, *dt_sym;
match m;
char c;
bool seen_deferred_kind, matched_type;
+ const char *dt_name;
/* A belt and braces check that the typespec is correctly being treated
as a deferred characteristic association. */
@@ -2668,40 +2673,96 @@ gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
ts->u.derived = NULL;
if (gfc_current_state () != COMP_INTERFACE
&& !gfc_find_symbol (name, NULL, 1, &sym) && sym)
- ts->u.derived = sym;
+ {
+ sym = gfc_find_dt_in_generic (sym);
+ ts->u.derived = sym;
+ }
return MATCH_YES;
}
/* Search for the name but allow the components to be defined later. If
type = -1, this typespec has been seen in a function declaration but
- the type could not be accessed at that point. */
+ the type could not be accessed at that point. The actual derived type is
+ stored in a symtree with the first letter of the name captialized; the
+ symtree with the all lower-case name contains the associated
+ generic function. */
+ dt_name = gfc_get_string ("%c%s",
+ (char) TOUPPER ((unsigned char) name[0]),
+ (const char*)&name[1]);
sym = NULL;
- if (ts->kind != -1 && gfc_get_ha_symbol (name, &sym))
+ dt_sym = NULL;
+ if (ts->kind != -1)
{
- gfc_error ("Type name '%s' at %C is ambiguous", name);
- return MATCH_ERROR;
+ gfc_get_ha_symbol (name, &sym);
+ if (sym->generic && gfc_find_symbol (dt_name, NULL, 0, &dt_sym))
+ {
+ gfc_error ("Type name '%s' at %C is ambiguous", name);
+ return MATCH_ERROR;
+ }
+ if (sym->generic && !dt_sym)
+ dt_sym = gfc_find_dt_in_generic (sym);
}
else if (ts->kind == -1)
{
int iface = gfc_state_stack->previous->state != COMP_INTERFACE
|| gfc_current_ns->has_import_set;
- if (gfc_find_symbol (name, NULL, iface, &sym))
+ gfc_find_symbol (name, NULL, iface, &sym);
+ if (sym && sym->generic && gfc_find_symbol (dt_name, NULL, 1, &dt_sym))
{
gfc_error ("Type name '%s' at %C is ambiguous", name);
return MATCH_ERROR;
}
+ if (sym && sym->generic && !dt_sym)
+ dt_sym = gfc_find_dt_in_generic (sym);
ts->kind = 0;
if (sym == NULL)
return MATCH_NO;
}
- if (sym->attr.flavor != FL_DERIVED
- && gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
- return MATCH_ERROR;
+ if ((sym->attr.flavor != FL_UNKNOWN
+ && !(sym->attr.flavor == FL_PROCEDURE && sym->attr.generic))
+ || sym->attr.subroutine)
+ {
+ gfc_error ("Type name '%s' at %C conflicts with previously declared "
+ "entity at %L, which has the same name", name,
+ &sym->declared_at);
+ return MATCH_ERROR;
+ }
gfc_set_sym_referenced (sym);
- ts->u.derived = sym;
+ if (!sym->attr.generic
+ && gfc_add_generic (&sym->attr, sym->name, NULL) == FAILURE)
+ return MATCH_ERROR;
+
+ if (!sym->attr.function
+ && gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE)
+ return MATCH_ERROR;
+
+ if (!dt_sym)
+ {
+ gfc_interface *intr, *head;
+
+ /* Use upper case to save the actual derived-type symbol. */
+ gfc_get_symbol (dt_name, NULL, &dt_sym);
+ dt_sym->name = gfc_get_string (sym->name);
+ head = sym->generic;
+ intr = gfc_get_interface ();
+ intr->sym = dt_sym;
+ intr->where = gfc_current_locus;
+ intr->next = head;
+ sym->generic = intr;
+ sym->attr.if_source = IFSRC_DECL;
+ }
+
+ gfc_set_sym_referenced (dt_sym);
+
+ if (dt_sym->attr.flavor != FL_DERIVED
+ && gfc_add_flavor (&dt_sym->attr, FL_DERIVED, sym->name, NULL)
+ == FAILURE)
+ return MATCH_ERROR;
+
+ ts->u.derived = dt_sym;
return MATCH_YES;
@@ -3053,6 +3114,20 @@ gfc_match_import (void)
sym->refs++;
sym->attr.imported = 1;
+ if (sym->attr.generic && (sym = gfc_find_dt_in_generic (sym)))
+ {
+ /* The actual derived type is stored in a symtree with the first
+ letter of the name captialized; the symtree with the all
+ lower-case name contains the associated generic function. */
+ st = gfc_new_symtree (&gfc_current_ns->sym_root,
+ gfc_get_string ("%c%s",
+ (char) TOUPPER ((unsigned char) sym->name[0]),
+ &sym->name[1]));
+ st->n.sym = sym;
+ sym->refs++;
+ sym->attr.imported = 1;
+ }
+
goto next_item;
case MATCH_NO:
@@ -6475,7 +6550,7 @@ access_attr_decl (gfc_statement st)
char name[GFC_MAX_SYMBOL_LEN + 1];
interface_type type;
gfc_user_op *uop;
- gfc_symbol *sym;
+ gfc_symbol *sym, *dt_sym;
gfc_intrinsic_op op;
match m;
@@ -6505,6 +6580,13 @@ access_attr_decl (gfc_statement st)
sym->name, NULL) == FAILURE)
return MATCH_ERROR;
+ if (sym->attr.generic && (dt_sym = gfc_find_dt_in_generic (sym))
+ && gfc_add_access (&dt_sym->attr,
+ (st == ST_PUBLIC) ? ACCESS_PUBLIC
+ : ACCESS_PRIVATE,
+ sym->name, NULL) == FAILURE)
+ return MATCH_ERROR;
+
break;
case INTERFACE_INTRINSIC_OP:
@@ -7175,6 +7257,8 @@ check_extended_derived_type (char *name)
return NULL;
}
+ extended = gfc_find_dt_in_generic (extended);
+
if (extended->attr.flavor != FL_DERIVED)
{
gfc_error ("'%s' in EXTENDS expression at %C is not a "
@@ -7277,11 +7361,12 @@ gfc_match_derived_decl (void)
char name[GFC_MAX_SYMBOL_LEN + 1];
char parent[GFC_MAX_SYMBOL_LEN + 1];
symbol_attribute attr;
- gfc_symbol *sym;
+ gfc_symbol *sym, *gensym;
gfc_symbol *extended;
match m;
match is_type_attr_spec = MATCH_NO;
bool seen_attr = false;
+ gfc_interface *intr = NULL, *head;
if (gfc_current_state () == COMP_DERIVED)
return MATCH_NO;
@@ -7327,16 +7412,50 @@ gfc_match_derived_decl (void)
return MATCH_ERROR;
}
- if (gfc_get_symbol (name, NULL, &sym))
+ if (gfc_get_symbol (name, NULL, &gensym))
return MATCH_ERROR;
- if (sym->ts.type != BT_UNKNOWN)
+ if (!gensym->attr.generic && gensym->ts.type != BT_UNKNOWN)
{
gfc_error ("Derived type name '%s' at %C already has a basic type "
- "of %s", sym->name, gfc_typename (&sym->ts));
+ "of %s", gensym->name, gfc_typename (&gensym->ts));
+ return MATCH_ERROR;
+ }
+
+ if (!gensym->attr.generic
+ && gfc_add_generic (&gensym->attr, gensym->name, NULL) == FAILURE)
+ return MATCH_ERROR;
+
+ if (!gensym->attr.function
+ && gfc_add_function (&gensym->attr, gensym->name, NULL) == FAILURE)
+ return MATCH_ERROR;
+
+ sym = gfc_find_dt_in_generic (gensym);
+
+ if (sym && (sym->components != NULL || sym->attr.zero_comp))
+ {
+ gfc_error ("Derived type definition of '%s' at %C has already been "
+ "defined", sym->name);
return MATCH_ERROR;
}
+ if (!sym)
+ {
+ /* Use upper case to save the actual derived-type symbol. */
+ gfc_get_symbol (gfc_get_string ("%c%s",
+ (char) TOUPPER ((unsigned char) gensym->name[0]),
+ &gensym->name[1]), NULL, &sym);
+ sym->name = gfc_get_string (gensym->name);
+ head = gensym->generic;
+ intr = gfc_get_interface ();
+ intr->sym = sym;
+ intr->where = gfc_current_locus;
+ intr->sym->declared_at = gfc_current_locus;
+ intr->next = head;
+ gensym->generic = intr;
+ gensym->attr.if_source = IFSRC_DECL;
+ }
+
/* The symbol may already have the derived attribute without the
components. The ways this can happen is via a function
definition, an INTRINSIC statement or a subtype in another
@@ -7346,16 +7465,18 @@ gfc_match_derived_decl (void)
&& gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
return MATCH_ERROR;
- if (sym->components != NULL || sym->attr.zero_comp)
- {
- gfc_error ("Derived type definition of '%s' at %C has already been "
- "defined", sym->name);
- return MATCH_ERROR;
- }
-
if (attr.access != ACCESS_UNKNOWN
&& gfc_add_access (&sym->attr, attr.access, sym->name, NULL) == FAILURE)
return MATCH_ERROR;
+ else if (sym->attr.access == ACCESS_UNKNOWN
+ && gensym->attr.access != ACCESS_UNKNOWN
+ && gfc_add_access (&sym->attr, gensym->attr.access, sym->name, NULL)
+ == FAILURE)
+ return MATCH_ERROR;
+
+ if (sym->attr.access != ACCESS_UNKNOWN
+ && gensym->attr.access == ACCESS_UNKNOWN)
+ gensym->attr.access = sym->attr.access;
/* See if the derived type was labeled as bind(c). */
if (attr.is_bind_c != 0)
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 17ebd58e50f..372c056d3d1 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -2630,6 +2630,7 @@ gfc_try gfc_check_symbol_typed (gfc_symbol*, gfc_namespace*, bool, locus);
gfc_namespace* gfc_find_proc_namespace (gfc_namespace*);
bool gfc_is_associate_pointer (gfc_symbol*);
+gfc_symbol * gfc_find_dt_in_generic (gfc_symbol *);
/* intrinsic.c -- true if working in an init-expr, false otherwise. */
extern bool gfc_init_expr_flag;
@@ -2874,6 +2875,9 @@ match gfc_match_rvalue (gfc_expr **);
match gfc_match_varspec (gfc_expr*, int, bool, bool);
int gfc_check_digit (char, int);
bool gfc_is_function_return_value (gfc_symbol *, gfc_namespace *);
+gfc_try gfc_convert_to_structure_constructor (gfc_expr *, gfc_symbol *,
+ gfc_expr **,
+ gfc_actual_arglist **, bool);
/* trans.c */
void gfc_generate_code (gfc_namespace *);
diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c
index 90d98c759dd..6d2acce378a 100644
--- a/gcc/fortran/interface.c
+++ b/gcc/fortran/interface.c
@@ -1262,8 +1262,9 @@ check_interface0 (gfc_interface *p, const char *interface_name)
{
/* Make sure all symbols in the interface have been defined as
functions or subroutines. */
- if ((!p->sym->attr.function && !p->sym->attr.subroutine)
- || !p->sym->attr.if_source)
+ if (((!p->sym->attr.function && !p->sym->attr.subroutine)
+ || !p->sym->attr.if_source)
+ && p->sym->attr.flavor != FL_DERIVED)
{
if (p->sym->attr.external)
gfc_error ("Procedure '%s' in %s at %L has no explicit interface",
@@ -1276,11 +1277,18 @@ check_interface0 (gfc_interface *p, const char *interface_name)
}
/* Verify that procedures are either all SUBROUTINEs or all FUNCTIONs. */
- if ((psave->sym->attr.function && !p->sym->attr.function)
+ if ((psave->sym->attr.function && !p->sym->attr.function
+ && p->sym->attr.flavor != FL_DERIVED)
|| (psave->sym->attr.subroutine && !p->sym->attr.subroutine))
{
- gfc_error ("In %s at %L procedures must be either all SUBROUTINEs"
- " or all FUNCTIONs", interface_name, &p->sym->declared_at);
+ if (p->sym->attr.flavor != FL_DERIVED)
+ gfc_error ("In %s at %L procedures must be either all SUBROUTINEs"
+ " or all FUNCTIONs", interface_name,
+ &p->sym->declared_at);
+ else
+ gfc_error ("In %s at %L procedures must be all FUNCTIONs as the "
+ "generic name is also the name of a derived type",
+ interface_name, &p->sym->declared_at);
return 1;
}
@@ -1336,8 +1344,10 @@ check_interface1 (gfc_interface *p, gfc_interface *q0,
if (p->sym->name == q->sym->name && p->sym->module == q->sym->module)
continue;
- if (gfc_compare_interfaces (p->sym, q->sym, q->sym->name, generic_flag,
- 0, NULL, 0))
+ if (p->sym->attr.flavor != FL_DERIVED
+ && q->sym->attr.flavor != FL_DERIVED
+ && gfc_compare_interfaces (p->sym, q->sym, q->sym->name,
+ generic_flag, 0, NULL, 0))
{
if (referenced)
gfc_error ("Ambiguous interfaces '%s' and '%s' in %s at %L",
@@ -3019,6 +3029,8 @@ gfc_search_interface (gfc_interface *intr, int sub_flag,
for (; intr; intr = intr->next)
{
+ if (intr->sym->attr.flavor == FL_DERIVED)
+ continue;
if (sub_flag && intr->sym->attr.function)
continue;
if (!sub_flag && intr->sym->attr.subroutine)
diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c
index 4ea98b61017..fbafe82cc66 100644
--- a/gcc/fortran/match.c
+++ b/gcc/fortran/match.c
@@ -1920,6 +1920,9 @@ match_derived_type_spec (gfc_typespec *ts)
gfc_find_symbol (name, NULL, 1, &derived);
+ if (derived && derived->attr.flavor == FL_PROCEDURE && derived->attr.generic)
+ derived = gfc_find_dt_in_generic (derived);
+
if (derived && derived->attr.flavor == FL_DERIVED)
{
ts->type = BT_DERIVED;
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index 0d841044b98..df18074c58a 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -206,7 +206,7 @@ match gfc_match_bind_c (gfc_symbol *, bool);
match gfc_get_type_attr_spec (symbol_attribute *, char*);
/* primary.c. */
-match gfc_match_structure_constructor (gfc_symbol *, gfc_expr **, bool);
+match gfc_match_structure_constructor (gfc_symbol *, gfc_expr **);
match gfc_match_variable (gfc_expr **, int);
match gfc_match_equiv_variable (gfc_expr **);
match gfc_match_actual_arglist (int, gfc_actual_arglist **);
diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c
index 62f759876d3..7c28e8bb97c 100644
--- a/gcc/fortran/module.c
+++ b/gcc/fortran/module.c
@@ -80,7 +80,7 @@ along with GCC; see the file COPYING3. If not see
/* Don't put any single quote (') in MOD_VERSION,
if yout want it to be recognized. */
-#define MOD_VERSION "7"
+#define MOD_VERSION "8"
/* Structure that describes a position within a module file. */
@@ -429,6 +429,34 @@ resolve_fixups (fixup_t *f, void *gp)
}
+/* Convert a string such that it starts with a lower-case character. Used
+ to convert the symtree name of a derived-type to the symbol name or to
+ the name of the associated generic function. */
+
+const char *
+dt_lower_string (const char *name)
+{
+ if (name[0] != (char) TOLOWER ((unsigned char) name[0]))
+ return gfc_get_string ("%c%s", (char) TOLOWER ((unsigned char) name[0]),
+ &name[1]);
+ return gfc_get_string (name);
+}
+
+
+/* Convert a string such that it starts with an upper-case character. Used to
+ return the symtree-name for a derived type; the symbol name itself and the
+ symtree/symbol name of the associated generic function start with a lower-
+ case character. */
+
+const char *
+dt_upper_string (const char *name)
+{
+ if (name[0] != (char) TOUPPER ((unsigned char) name[0]))
+ return gfc_get_string ("%c%s", (char) TOUPPER ((unsigned char) name[0]),
+ &name[1]);
+ return gfc_get_string (name);
+}
+
/* Call here during module reading when we know what pointer to
associate with an integer. Any fixups that exist are resolved at
this time. */
@@ -699,12 +727,18 @@ static const char *
find_use_name_n (const char *name, int *inst, bool interface)
{
gfc_use_rename *u;
+ const char *low_name = NULL;
int i;
+ /* For derived types. */
+ if (name[0] != (char) TOLOWER ((unsigned char) name[0]))
+ low_name = dt_lower_string (name);
+
i = 0;
for (u = gfc_rename_list; u; u = u->next)
{
- if (strcmp (u->use_name, name) != 0
+ if ((!low_name && strcmp (u->use_name, name) != 0)
+ || (low_name && strcmp (u->use_name, low_name) != 0)
|| (u->op == INTRINSIC_USER && !interface)
|| (u->op != INTRINSIC_USER && interface))
continue;
@@ -723,6 +757,13 @@ find_use_name_n (const char *name, int *inst, bool interface)
u->found = 1;
+ if (low_name)
+ {
+ if (u->local_name[0] == '\0')
+ return name;
+ return dt_upper_string (u->local_name);
+ }
+
return (u->local_name[0] != '\0') ? u->local_name : name;
}
@@ -780,6 +821,7 @@ find_use_operator (gfc_intrinsic_op op)
typedef struct true_name
{
BBT_HEADER (true_name);
+ const char *name;
gfc_symbol *sym;
}
true_name;
@@ -803,7 +845,7 @@ compare_true_names (void *_t1, void *_t2)
if (c != 0)
return c;
- return strcmp (t1->sym->name, t2->sym->name);
+ return strcmp (t1->name, t2->name);
}
@@ -817,7 +859,7 @@ find_true_name (const char *name, const char *module)
gfc_symbol sym;
int c;
- sym.name = gfc_get_string (name);
+ t.name = gfc_get_string (name);
if (module != NULL)
sym.module = gfc_get_string (module);
else
@@ -847,6 +889,10 @@ add_true_name (gfc_symbol *sym)
t = XCNEW (true_name);
t->sym = sym;
+ if (sym->attr.flavor == FL_DERIVED)
+ t->name = dt_upper_string (sym->name);
+ else
+ t->name = sym->name;
gfc_insert_bbt (&true_name_root, t, compare_true_names);
}
@@ -858,13 +904,19 @@ add_true_name (gfc_symbol *sym)
static void
build_tnt (gfc_symtree *st)
{
+ const char *name;
if (st == NULL)
return;
build_tnt (st->left);
build_tnt (st->right);
- if (find_true_name (st->n.sym->name, st->n.sym->module) != NULL)
+ if (st->n.sym->attr.flavor == FL_DERIVED)
+ name = dt_upper_string (st->n.sym->name);
+ else
+ name = st->n.sym->name;
+
+ if (find_true_name (name, st->n.sym->module) != NULL)
return;
add_true_name (st->n.sym);
@@ -2986,8 +3038,12 @@ fix_mio_expr (gfc_expr *e)
namespace to see if the required, non-contained symbol is available
yet. If so, the latter should be written. */
if (e->symtree->n.sym && check_unique_name (e->symtree->name))
- ns_st = gfc_find_symtree (gfc_current_ns->sym_root,
- e->symtree->n.sym->name);
+ {
+ const char *name = e->symtree->n.sym->name;
+ if (e->symtree->n.sym->attr.flavor == FL_DERIVED)
+ name = dt_upper_string (name);
+ ns_st = gfc_find_symtree (gfc_current_ns->sym_root, name);
+ }
/* On the other hand, if the existing symbol is the module name or the
new symbol is a dummy argument, do not do the promotion. */
@@ -4205,6 +4261,7 @@ load_needed (pointer_info *p)
1, &ns->proc_name);
sym = gfc_new_symbol (p->u.rsym.true_name, ns);
+ sym->name = dt_lower_string (p->u.rsym.true_name);
sym->module = gfc_get_string (p->u.rsym.module);
strcpy (sym->binding_label, p->u.rsym.binding_label);
@@ -4497,6 +4554,7 @@ read_module (void)
{
info->u.rsym.sym = gfc_new_symbol (info->u.rsym.true_name,
gfc_current_ns);
+ info->u.rsym.sym->name = dt_lower_string (info->u.rsym.true_name);
sym = info->u.rsym.sym;
sym->module = gfc_get_string (info->u.rsym.module);
@@ -4835,7 +4893,7 @@ write_dt_extensions (gfc_symtree *st)
return;
mio_lparen ();
- mio_pool_string (&st->n.sym->name);
+ mio_pool_string (&st->name);
if (st->n.sym->module != NULL)
mio_pool_string (&st->n.sym->module);
else
@@ -4870,7 +4928,15 @@ write_symbol (int n, gfc_symbol *sym)
gfc_internal_error ("write_symbol(): bad module symbol '%s'", sym->name);
mio_integer (&n);
- mio_pool_string (&sym->name);
+
+ if (sym->attr.flavor == FL_DERIVED)
+ {
+ const char *name;
+ name = dt_upper_string (sym->name);
+ mio_pool_string (&name);
+ }
+ else
+ mio_pool_string (&sym->name);
mio_pool_string (&sym->module);
if (sym->attr.is_bind_c || sym->attr.is_iso_c)
@@ -5566,7 +5632,8 @@ create_derived_type (const char *name, const char *modname,
intmod_id module, int id)
{
gfc_symtree *tmp_symtree;
- gfc_symbol *sym;
+ gfc_symbol *sym, *dt_sym;
+ gfc_interface *intr, *head;
tmp_symtree = gfc_find_symtree (gfc_current_ns->sym_root, name);
if (tmp_symtree != NULL)
@@ -5579,18 +5646,35 @@ create_derived_type (const char *name, const char *modname,
gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree, false);
sym = tmp_symtree->n.sym;
-
sym->module = gfc_get_string (modname);
sym->from_intmod = module;
sym->intmod_sym_id = id;
- sym->attr.flavor = FL_DERIVED;
- sym->attr.private_comp = 1;
- sym->attr.zero_comp = 1;
- sym->attr.use_assoc = 1;
+ sym->attr.flavor = FL_PROCEDURE;
+ sym->attr.function = 1;
+ sym->attr.generic = 1;
+
+ gfc_get_sym_tree (dt_upper_string (sym->name),
+ gfc_current_ns, &tmp_symtree, false);
+ dt_sym = tmp_symtree->n.sym;
+ dt_sym->name = gfc_get_string (sym->name);
+ dt_sym->attr.flavor = FL_DERIVED;
+ dt_sym->attr.private_comp = 1;
+ dt_sym->attr.zero_comp = 1;
+ dt_sym->attr.use_assoc = 1;
+ dt_sym->module = gfc_get_string (modname);
+ dt_sym->from_intmod = module;
+ dt_sym->intmod_sym_id = id;
+
+ head = sym->generic;
+ intr = gfc_get_interface ();
+ intr->sym = dt_sym;
+ intr->where = gfc_current_locus;
+ intr->next = head;
+ sym->generic = intr;
+ sym->attr.if_source = IFSRC_DECL;
}
-
/* USE the ISO_FORTRAN_ENV intrinsic module. */
static void
diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c
index 24d8960d06b..7d91645207b 100644
--- a/gcc/fortran/parse.c
+++ b/gcc/fortran/parse.c
@@ -3881,6 +3881,12 @@ gfc_fixup_sibling_symbols (gfc_symbol *sym, gfc_namespace *siblings)
if (!st || (st->n.sym->attr.dummy && ns == st->n.sym->ns))
goto fixup_contained;
+ if ((st->n.sym->attr.flavor == FL_DERIVED
+ && sym->attr.generic && sym->attr.function)
+ ||(sym->attr.flavor == FL_DERIVED
+ && st->n.sym->attr.generic && st->n.sym->attr.function))
+ goto fixup_contained;
+
old_sym = st->n.sym;
if (old_sym->ns == ns
&& !old_sym->attr.contained
diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c
index 23dc0b66400..0f67ec78282 100644
--- a/gcc/fortran/primary.c
+++ b/gcc/fortran/primary.c
@@ -2315,171 +2315,162 @@ build_actual_constructor (gfc_structure_ctor_component **comp_head,
return SUCCESS;
}
-match
-gfc_match_structure_constructor (gfc_symbol *sym, gfc_expr **result,
- bool parent)
+
+gfc_try
+gfc_convert_to_structure_constructor (gfc_expr *e, gfc_symbol *sym, gfc_expr **cexpr,
+ gfc_actual_arglist **arglist,
+ bool parent)
{
+ gfc_actual_arglist *actual;
gfc_structure_ctor_component *comp_tail, *comp_head, *comp_iter;
gfc_constructor_base ctor_head = NULL;
gfc_component *comp; /* Is set NULL when named component is first seen */
- gfc_expr *e;
- locus where;
- match m;
const char* last_name = NULL;
+ locus old_locus;
+ gfc_expr *expr;
- comp_tail = comp_head = NULL;
-
- if (!parent && gfc_match_char ('(') != MATCH_YES)
- goto syntax;
-
- where = gfc_current_locus;
+ expr = parent ? *cexpr : e;
+ old_locus = gfc_current_locus;
+ if (parent)
+ ; /* gfc_current_locus = *arglist->expr ? ->where;*/
+ else
+ gfc_current_locus = expr->where;
- gfc_find_component (sym, NULL, false, true);
+ comp_tail = comp_head = NULL;
- /* Check that we're not about to construct an ABSTRACT type. */
if (!parent && sym->attr.abstract)
{
- gfc_error ("Can't construct ABSTRACT type '%s' at %C", sym->name);
- return MATCH_ERROR;
+ gfc_error ("Can't construct ABSTRACT type '%s' at %L",
+ sym->name, &expr->where);
+ goto cleanup;
}
- /* Match the component list and store it in a list together with the
- corresponding component names. Check for empty argument list first. */
- if (gfc_match_char (')') != MATCH_YES)
+ comp = sym->components;
+ actual = parent ? *arglist : expr->value.function.actual;
+ for ( ; actual; )
{
- comp = sym->components;
- do
- {
- gfc_component *this_comp = NULL;
-
- if (comp == sym->components && sym->attr.extension
- && comp->ts.type == BT_DERIVED
- && comp->ts.u.derived->attr.zero_comp)
- /* Skip empty parents. */
- comp = comp->next;
+ gfc_component *this_comp = NULL;
- if (!comp_head)
- comp_tail = comp_head = gfc_get_structure_ctor_component ();
- else
- {
- comp_tail->next = gfc_get_structure_ctor_component ();
- comp_tail = comp_tail->next;
- }
- comp_tail->name = XCNEWVEC (char, GFC_MAX_SYMBOL_LEN + 1);
- comp_tail->val = NULL;
- comp_tail->where = gfc_current_locus;
+ if (!comp_head)
+ comp_tail = comp_head = gfc_get_structure_ctor_component ();
+ else
+ {
+ comp_tail->next = gfc_get_structure_ctor_component ();
+ comp_tail = comp_tail->next;
+ }
+ if (actual->name)
+ {
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Structure"
+ " constructor with named arguments at %C")
+ == FAILURE)
+ goto cleanup;
- /* Try matching a component name. */
- if (gfc_match_name (comp_tail->name) == MATCH_YES
- && gfc_match_char ('=') == MATCH_YES)
+ comp_tail->name = xstrdup (actual->name);
+ last_name = comp_tail->name;
+ comp = NULL;
+ }
+ else
+ {
+ /* Components without name are not allowed after the first named
+ component initializer! */
+ if (!comp)
{
- if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Structure"
- " constructor with named arguments at %C")
- == FAILURE)
- goto cleanup;
-
- last_name = comp_tail->name;
- comp = NULL;
+ if (last_name)
+ gfc_error ("Component initializer without name after component"
+ " named %s at %L!", last_name,
+ actual->expr ? &actual->expr->where
+ : &gfc_current_locus);
+ else
+ gfc_error ("Too many components in structure constructor at "
+ "%L!", actual->expr ? &actual->expr->where
+ : &gfc_current_locus);
+ goto cleanup;
}
- else
- {
- /* Components without name are not allowed after the first named
- component initializer! */
- if (!comp)
- {
- if (last_name)
- gfc_error ("Component initializer without name after"
- " component named %s at %C!", last_name);
- else if (!parent)
- gfc_error ("Too many components in structure constructor at"
- " %C!");
- goto cleanup;
- }
- gfc_current_locus = comp_tail->where;
- strncpy (comp_tail->name, comp->name, GFC_MAX_SYMBOL_LEN + 1);
- }
+ comp_tail->name = xstrdup (comp->name);
+ }
- /* Find the current component in the structure definition and check
+ /* Find the current component in the structure definition and check
its access is not private. */
- if (comp)
- this_comp = gfc_find_component (sym, comp->name, false, false);
- else
- {
- this_comp = gfc_find_component (sym,
- (const char *)comp_tail->name,
- false, false);
- comp = NULL; /* Reset needed! */
- }
-
- /* Here we can check if a component name is given which does not
- correspond to any component of the defined structure. */
- if (!this_comp)
- goto cleanup;
+ if (comp)
+ this_comp = gfc_find_component (sym, comp->name, false, false);
+ else
+ {
+ this_comp = gfc_find_component (sym, (const char *)comp_tail->name,
+ false, false);
+ comp = NULL; /* Reset needed! */
+ }
- /* Check if this component is already given a value. */
- for (comp_iter = comp_head; comp_iter != comp_tail;
- comp_iter = comp_iter->next)
- {
- gcc_assert (comp_iter);
- if (!strcmp (comp_iter->name, comp_tail->name))
- {
- gfc_error ("Component '%s' is initialized twice in the"
- " structure constructor at %C!", comp_tail->name);
- goto cleanup;
- }
- }
+ /* Here we can check if a component name is given which does not
+ correspond to any component of the defined structure. */
+ if (!this_comp)
+ goto cleanup;
- /* Match the current initializer expression. */
- if (this_comp->attr.proc_pointer)
- gfc_matching_procptr_assignment = 1;
- m = gfc_match_expr (&comp_tail->val);
- gfc_matching_procptr_assignment = 0;
- if (m == MATCH_NO)
- goto syntax;
- if (m == MATCH_ERROR)
- goto cleanup;
+ comp_tail->val = actual->expr;
+ if (actual->expr != NULL)
+ comp_tail->where = actual->expr->where;
+ actual->expr = NULL;
- /* F2008, R457/C725, for PURE C1283. */
- if (this_comp->attr.pointer && gfc_is_coindexed (comp_tail->val))
+ /* Check if this component is already given a value. */
+ for (comp_iter = comp_head; comp_iter != comp_tail;
+ comp_iter = comp_iter->next)
+ {
+ gcc_assert (comp_iter);
+ if (!strcmp (comp_iter->name, comp_tail->name))
{
- gfc_error ("Coindexed expression to pointer component '%s' in "
- "structure constructor at %C!", comp_tail->name);
+ gfc_error ("Component '%s' is initialized twice in the structure"
+ " constructor at %L!", comp_tail->name,
+ comp_tail->val ? &comp_tail->where
+ : &gfc_current_locus);
goto cleanup;
- }
+ }
+ }
+ /* F2008, R457/C725, for PURE C1283. */
+ if (this_comp->attr.pointer && comp_tail->val
+ && gfc_is_coindexed (comp_tail->val))
+ {
+ gfc_error ("Coindexed expression to pointer component '%s' in "
+ "structure constructor at %L!", comp_tail->name,
+ &comp_tail->where);
+ goto cleanup;
+ }
- /* If not explicitly a parent constructor, gather up the components
- and build one. */
- if (comp && comp == sym->components
- && sym->attr.extension
- && (comp_tail->val->ts.type != BT_DERIVED
- ||
- comp_tail->val->ts.u.derived != this_comp->ts.u.derived))
- {
- gfc_current_locus = where;
- gfc_free_expr (comp_tail->val);
- comp_tail->val = NULL;
+ /* If not explicitly a parent constructor, gather up the components
+ and build one. */
+ if (comp && comp == sym->components
+ && sym->attr.extension
+ && comp_tail->val
+ && (comp_tail->val->ts.type != BT_DERIVED
+ ||
+ comp_tail->val->ts.u.derived != this_comp->ts.u.derived))
+ {
+ gfc_try m;
+ gfc_actual_arglist *arg_null = NULL;
- m = gfc_match_structure_constructor (comp->ts.u.derived,
- &comp_tail->val, true);
- if (m == MATCH_NO)
- goto syntax;
- if (m == MATCH_ERROR)
- goto cleanup;
- }
+ actual->expr = comp_tail->val;
+ comp_tail->val = NULL;
- if (comp)
- comp = comp->next;
+ m = gfc_convert_to_structure_constructor (NULL,
+ comp->ts.u.derived, &comp_tail->val,
+ comp->ts.u.derived->attr.zero_comp
+ ? &arg_null : &actual, true);
+ if (m == FAILURE)
+ goto cleanup;
- if (parent && !comp)
- break;
- }
+ if (comp->ts.u.derived->attr.zero_comp)
+ {
+ comp = comp->next;
+ continue;
+ }
+ }
- while (gfc_match_char (',') == MATCH_YES);
+ if (comp)
+ comp = comp->next;
+ if (parent && !comp)
+ break;
- if (!parent && gfc_match_char (')') != MATCH_YES)
- goto syntax;
+ actual = actual->next;
}
if (build_actual_constructor (&comp_head, &ctor_head, sym) == FAILURE)
@@ -2488,9 +2479,8 @@ gfc_match_structure_constructor (gfc_symbol *sym, gfc_expr **result,
/* No component should be left, as this should have caused an error in the
loop constructing the component-list (name that does not correspond to any
component in the structure definition). */
- if (comp_head)
+ if (comp_head && sym->attr.extension)
{
- gcc_assert (sym->attr.extension);
for (comp_iter = comp_head; comp_iter; comp_iter = comp_iter->next)
{
gfc_error ("component '%s' at %L has already been set by a "
@@ -2499,18 +2489,33 @@ gfc_match_structure_constructor (gfc_symbol *sym, gfc_expr **result,
}
goto cleanup;
}
+ else
+ gcc_assert (!comp_head);
- e = gfc_get_structure_constructor_expr (BT_DERIVED, 0, &where);
- e->ts.u.derived = sym;
- e->value.constructor = ctor_head;
+ if (parent)
+ {
+ expr = gfc_get_structure_constructor_expr (BT_DERIVED, 0, &gfc_current_locus);
+ expr->ts.u.derived = sym;
+ expr->value.constructor = ctor_head;
+ *cexpr = expr;
+ }
+ else
+ {
+ expr->ts.u.derived = sym;
+ expr->ts.kind = 0;
+ expr->ts.type = BT_DERIVED;
+ expr->value.constructor = ctor_head;
+ expr->expr_type = EXPR_STRUCTURE;
+ }
- *result = e;
- return MATCH_YES;
+ gfc_current_locus = old_locus;
+ if (parent)
+ *arglist = actual;
+ return SUCCESS;
-syntax:
- gfc_error ("Syntax error in structure constructor at %C");
+ cleanup:
+ gfc_current_locus = old_locus;
-cleanup:
for (comp_iter = comp_head; comp_iter; )
{
gfc_structure_ctor_component *next = comp_iter->next;
@@ -2518,7 +2523,45 @@ cleanup:
comp_iter = next;
}
gfc_constructor_free (ctor_head);
- return MATCH_ERROR;
+
+ return FAILURE;
+}
+
+
+match
+gfc_match_structure_constructor (gfc_symbol *sym, gfc_expr **result)
+{
+ match m;
+ gfc_expr *e;
+ gfc_symtree *symtree;
+
+ gfc_get_sym_tree (sym->name, NULL, &symtree, false); /* Can't fail */
+
+ e = gfc_get_expr ();
+ e->symtree = symtree;
+ e->expr_type = EXPR_FUNCTION;
+
+ gcc_assert (sym->attr.flavor == FL_DERIVED
+ && symtree->n.sym->attr.flavor == FL_PROCEDURE);
+ e->value.function.esym = sym;
+ e->symtree->n.sym->attr.generic = 1;
+
+ m = gfc_match_actual_arglist (0, &e->value.function.actual);
+ if (m != MATCH_YES)
+ {
+ gfc_free_expr (e);
+ return m;
+ }
+
+ if (gfc_convert_to_structure_constructor (e, sym, NULL, NULL, false)
+ != SUCCESS)
+ {
+ gfc_free_expr (e);
+ return MATCH_ERROR;
+ }
+
+ *result = e;
+ return MATCH_YES;
}
@@ -2715,7 +2758,7 @@ gfc_match_rvalue (gfc_expr **result)
if (sym == NULL)
m = MATCH_ERROR;
else
- m = gfc_match_structure_constructor (sym, &e, false);
+ goto generic_function;
break;
/* If we're here, then the name is known to be the name of a
@@ -2989,6 +3032,12 @@ gfc_match_rvalue (gfc_expr **result)
e->symtree = symtree;
e->expr_type = EXPR_FUNCTION;
+ if (sym->attr.flavor == FL_DERIVED)
+ {
+ e->value.function.esym = sym;
+ e->symtree->n.sym->attr.generic = 1;
+ }
+
m = gfc_match_actual_arglist (0, &e->value.function.actual);
break;
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index d96b33225ed..94c21bedf8d 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -454,7 +454,8 @@ resolve_formal_arglist (gfc_symbol *proc)
static void
find_arglists (gfc_symbol *sym)
{
- if (sym->attr.if_source == IFSRC_UNKNOWN || sym->ns != gfc_current_ns)
+ if (sym->attr.if_source == IFSRC_UNKNOWN || sym->ns != gfc_current_ns
+ || sym->attr.flavor == FL_DERIVED)
return;
resolve_formal_arglist (sym);
@@ -967,13 +968,6 @@ resolve_structure_cons (gfc_expr *expr, int init)
resolve_fl_derived0 (expr->ts.u.derived);
cons = gfc_constructor_first (expr->value.constructor);
- /* A constructor may have references if it is the result of substituting a
- parameter variable. In this case we just pull out the component we
- want. */
- if (expr->ref)
- comp = expr->ref->u.c.sym->components;
- else
- comp = expr->ts.u.derived->components;
/* See if the user is trying to invoke a structure constructor for one of
the iso_c_binding derived types. */
@@ -992,6 +986,14 @@ resolve_structure_cons (gfc_expr *expr, int init)
&& cons->expr && cons->expr->expr_type == EXPR_NULL)
return SUCCESS;
+ /* A constructor may have references if it is the result of substituting a
+ parameter variable. In this case we just pull out the component we
+ want. */
+ if (expr->ref)
+ comp = expr->ref->u.c.sym->components;
+ else
+ comp = expr->ts.u.derived->components;
+
for (; comp && cons; comp = comp->next, cons = gfc_constructor_next (cons))
{
int rank;
@@ -1401,7 +1403,8 @@ is_illegal_recursion (gfc_symbol* sym, gfc_namespace* context)
gfc_symbol* context_proc;
gfc_namespace* real_context;
- if (sym->attr.flavor == FL_PROGRAM)
+ if (sym->attr.flavor == FL_PROGRAM
+ || sym->attr.flavor == FL_DERIVED)
return false;
gcc_assert (sym->attr.flavor == FL_PROCEDURE);
@@ -2323,6 +2326,7 @@ resolve_generic_f (gfc_expr *expr)
{
gfc_symbol *sym;
match m;
+ gfc_interface *intr = NULL;
sym = expr->symtree->n.sym;
@@ -2335,6 +2339,11 @@ resolve_generic_f (gfc_expr *expr)
return FAILURE;
generic:
+ if (!intr)
+ for (intr = sym->generic; intr; intr = intr->next)
+ if (intr->sym->attr.flavor == FL_DERIVED)
+ break;
+
if (sym->ns->parent == NULL)
break;
gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym);
@@ -2347,16 +2356,25 @@ generic:
/* Last ditch attempt. See if the reference is to an intrinsic
that possesses a matching interface. 14.1.2.4 */
- if (sym && !gfc_is_intrinsic (sym, 0, expr->where))
+ if (sym && !intr && !gfc_is_intrinsic (sym, 0, expr->where))
{
- gfc_error ("There is no specific function for the generic '%s' at %L",
- expr->symtree->n.sym->name, &expr->where);
+ gfc_error ("There is no specific function for the generic '%s' "
+ "at %L", expr->symtree->n.sym->name, &expr->where);
return FAILURE;
}
+ if (intr)
+ {
+ if (gfc_convert_to_structure_constructor (expr, intr->sym, NULL, NULL,
+ false) != SUCCESS)
+ return FAILURE;
+ return resolve_structure_cons (expr, 0);
+ }
+
m = gfc_intrinsic_func_interface (expr, 0);
if (m == MATCH_YES)
return SUCCESS;
+
if (m == MATCH_NO)
gfc_error ("Generic function '%s' at %L is not consistent with a "
"specific intrinsic interface", expr->symtree->n.sym->name,
@@ -5053,6 +5071,9 @@ resolve_variable (gfc_expr *e)
if (sym->assoc && !sym->attr.dimension && e->ref && e->ref->type == REF_ARRAY)
return FAILURE;
+ if (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.generic)
+ sym->ts.u.derived = gfc_find_dt_in_generic (sym->ts.u.derived);
+
/* On the other hand, the parser may not have known this is an array;
in this case, we have to add a FULL reference. */
if (sym->assoc && sym->attr.dimension && !e->ref)
@@ -10152,6 +10173,8 @@ resolve_fl_variable_derived (gfc_symbol *sym, int no_init_flag)
{
gfc_symbol *s;
gfc_find_symbol (sym->ts.u.derived->name, sym->ns, 0, &s);
+ if (s && s->attr.generic)
+ s = gfc_find_dt_in_generic (s);
if (s && s->attr.flavor != FL_DERIVED)
{
gfc_error ("The type '%s' cannot be host associated at %L "
@@ -11718,6 +11741,13 @@ resolve_fl_derived0 (gfc_symbol *sym)
}
}
+ if (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.generic)
+ c->ts.u.derived = gfc_find_dt_in_generic (c->ts.u.derived);
+ else if (c->ts.type == BT_CLASS && c->attr.class_ok
+ && CLASS_DATA (c)->ts.u.derived->attr.generic)
+ CLASS_DATA (c)->ts.u.derived
+ = gfc_find_dt_in_generic (CLASS_DATA (c)->ts.u.derived);
+
if (!sym->attr.is_class && c->ts.type == BT_DERIVED && !sym->attr.vtype
&& c->attr.pointer && c->ts.u.derived->components == NULL
&& !c->ts.u.derived->attr.zero_comp)
@@ -11788,6 +11818,23 @@ resolve_fl_derived0 (gfc_symbol *sym)
static gfc_try
resolve_fl_derived (gfc_symbol *sym)
{
+ gfc_symbol *gen_dt = NULL;
+
+ if (!sym->attr.is_class)
+ gfc_find_symbol (sym->name, sym->ns, 0, &gen_dt);
+ if (gen_dt && gen_dt->generic && gen_dt->generic->next
+ && gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Generic name '%s' of "
+ "function '%s' at %L being the same name as derived "
+ "type at %L", sym->name,
+ gen_dt->generic->sym == sym
+ ? gen_dt->generic->next->sym->name
+ : gen_dt->generic->sym->name,
+ gen_dt->generic->sym == sym
+ ? &gen_dt->generic->next->sym->declared_at
+ : &gen_dt->generic->sym->declared_at,
+ &sym->declared_at) == FAILURE)
+ return FAILURE;
+
if (sym->attr.is_class && sym->ts.u.derived == NULL)
{
/* Fix up incomplete CLASS symbols. */
@@ -12191,6 +12238,20 @@ resolve_symbol (gfc_symbol *sym)
}
}
+ if (sym->ts.type == BT_DERIVED && !sym->attr.is_iso_c
+ && sym->ts.u.derived->attr.generic)
+ {
+ sym->ts.u.derived = gfc_find_dt_in_generic (sym->ts.u.derived);
+ if (!sym->ts.u.derived)
+ {
+ gfc_error ("The derived type '%s' at %L is of type '%s', "
+ "which has not been defined", sym->name,
+ &sym->declared_at, sym->ts.u.derived->name);
+ sym->ts.type = BT_UNKNOWN;
+ return;
+ }
+ }
+
/* If the symbol is marked as bind(c), verify it's type and kind. Do not
do this for something that was implicitly typed because that is handled
in gfc_set_default_type. Handle dummy arguments and procedure
@@ -12260,7 +12321,8 @@ resolve_symbol (gfc_symbol *sym)
the type is not declared in the scope of the implicit
statement. Change the type to BT_UNKNOWN, both because it is so
and to prevent an ICE. */
- if (sym->ts.type == BT_DERIVED && sym->ts.u.derived->components == NULL
+ if (sym->ts.type == BT_DERIVED && !sym->attr.is_iso_c
+ && sym->ts.u.derived->components == NULL
&& !sym->ts.u.derived->attr.zero_comp)
{
gfc_error ("The derived type '%s' at %L is of type '%s', "
@@ -12276,22 +12338,9 @@ resolve_symbol (gfc_symbol *sym)
if (sym->ts.type == BT_DERIVED
&& sym->ts.u.derived->attr.use_assoc
&& sym->ns->proc_name
- && sym->ns->proc_name->attr.flavor == FL_MODULE)
- {
- gfc_symbol *ds;
-
- if (resolve_fl_derived (sym->ts.u.derived) == FAILURE)
- return;
-
- gfc_find_symbol (sym->ts.u.derived->name, sym->ns, 1, &ds);
- if (!ds && sym->attr.function && gfc_check_symbol_access (sym))
- {
- symtree = gfc_new_symtree (&sym->ns->sym_root,
- sym->ts.u.derived->name);
- symtree->n.sym = sym->ts.u.derived;
- sym->ts.u.derived->refs++;
- }
- }
+ && sym->ns->proc_name->attr.flavor == FL_MODULE
+ && resolve_fl_derived (sym->ts.u.derived) == FAILURE)
+ return;
/* Unless the derived-type declaration is use associated, Fortran 95
does not allow public entries of private derived types.
diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c
index 33ec706f40a..9bd6ed489f3 100644
--- a/gcc/fortran/symbol.c
+++ b/gcc/fortran/symbol.c
@@ -1949,6 +1949,9 @@ gfc_use_derived (gfc_symbol *sym)
if (!sym)
return NULL;
+ if (sym->attr.generic)
+ sym = gfc_find_dt_in_generic (sym);
+
if (sym->components != NULL || sym->attr.zero_comp)
return sym; /* Already defined. */
@@ -2880,7 +2883,15 @@ gfc_undo_symbols (void)
}
}
- gfc_delete_symtree (&p->ns->sym_root, p->name);
+ /* The derived type is saved in the symtree with the first
+ letter capitalized; the all lower-case version to the
+ derived type contains its associated generic function. */
+ if (p->attr.flavor == FL_DERIVED)
+ gfc_delete_symtree (&p->ns->sym_root, gfc_get_string ("%c%s",
+ (char) TOUPPER ((unsigned char) p->name[0]),
+ &p->name[1]));
+ else
+ gfc_delete_symtree (&p->ns->sym_root, p->name);
gfc_release_symbol (p);
continue;
@@ -3773,15 +3784,15 @@ gen_special_c_interop_ptr (int ptr_id, const char *ptr_name,
that has arg(s) of the missing type. In this case, a
regular version of the thing should have been put in the
current ns. */
+
generate_isocbinding_symbol (module_name, ptr_id == ISOCBINDING_NULL_PTR
? ISOCBINDING_PTR : ISOCBINDING_FUNPTR,
(const char *) (ptr_id == ISOCBINDING_NULL_PTR
- ? "_gfortran_iso_c_binding_c_ptr"
- : "_gfortran_iso_c_binding_c_funptr"));
-
+ ? "c_ptr"
+ : "c_funptr"));
tmp_sym->ts.u.derived =
- get_iso_c_binding_dt (ptr_id == ISOCBINDING_NULL_PTR
- ? ISOCBINDING_PTR : ISOCBINDING_FUNPTR);
+ get_iso_c_binding_dt (ptr_id == ISOCBINDING_NULL_PTR
+ ? ISOCBINDING_PTR : ISOCBINDING_FUNPTR);
}
/* Module name is some mangled version of iso_c_binding. */
@@ -3859,9 +3870,9 @@ gen_cptr_param (gfc_formal_arglist **head,
const char *c_ptr_type = NULL;
if (iso_c_sym_id == ISOCBINDING_F_PROCPOINTER)
- c_ptr_type = "_gfortran_iso_c_binding_c_funptr";
+ c_ptr_type = "c_funptr";
else
- c_ptr_type = "_gfortran_iso_c_binding_c_ptr";
+ c_ptr_type = "c_ptr";
if(c_ptr_name == NULL)
c_ptr_in = "gfc_cptr__";
@@ -4338,19 +4349,31 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
: c_interop_kinds_table[s].name;
gfc_symtree *tmp_symtree = NULL;
gfc_symbol *tmp_sym = NULL;
- gfc_dt_list **dt_list_ptr = NULL;
- gfc_component *tmp_comp = NULL;
- char comp_name[(GFC_MAX_SYMBOL_LEN * 2) + 1];
int index;
if (gfc_notification_std (std_for_isocbinding_symbol (s)) == ERROR)
return;
+
tmp_symtree = gfc_find_symtree (gfc_current_ns->sym_root, name);
- /* Already exists in this scope so don't re-add it.
- TODO: we should probably check that it's really the same symbol. */
- if (tmp_symtree != NULL)
- return;
+ /* Already exists in this scope so don't re-add it. */
+ if (tmp_symtree != NULL && (tmp_sym = tmp_symtree->n.sym) != NULL
+ && (!tmp_sym->attr.generic
+ || (tmp_sym = gfc_find_dt_in_generic (tmp_sym)) != NULL)
+ && tmp_sym->from_intmod == INTMOD_ISO_C_BINDING)
+ {
+ if (tmp_sym->attr.flavor == FL_DERIVED
+ && !get_iso_c_binding_dt (tmp_sym->intmod_sym_id))
+ {
+ gfc_dt_list *dt_list;
+ dt_list = gfc_get_dt_list ();
+ dt_list->derived = tmp_sym;
+ dt_list->next = gfc_derived_types;
+ gfc_derived_types = dt_list;
+ }
+
+ return;
+ }
/* Create the sym tree in the current ns. */
gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree, false);
@@ -4443,64 +4466,112 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
case ISOCBINDING_PTR:
case ISOCBINDING_FUNPTR:
-
- /* Initialize an integer constant expression node. */
- tmp_sym->attr.flavor = FL_DERIVED;
- tmp_sym->ts.is_c_interop = 1;
- tmp_sym->attr.is_c_interop = 1;
- tmp_sym->attr.is_iso_c = 1;
- tmp_sym->ts.is_iso_c = 1;
- tmp_sym->ts.type = BT_DERIVED;
-
- /* A derived type must have the bind attribute to be
- interoperable (J3/04-007, Section 15.2.3), even though
- the binding label is not used. */
- tmp_sym->attr.is_bind_c = 1;
-
- tmp_sym->attr.referenced = 1;
-
- tmp_sym->ts.u.derived = tmp_sym;
-
- /* Add the symbol created for the derived type to the current ns. */
- dt_list_ptr = &(gfc_derived_types);
- while (*dt_list_ptr != NULL && (*dt_list_ptr)->next != NULL)
- dt_list_ptr = &((*dt_list_ptr)->next);
-
- /* There is already at least one derived type in the list, so append
- the one we're currently building for c_ptr or c_funptr. */
- if (*dt_list_ptr != NULL)
- dt_list_ptr = &((*dt_list_ptr)->next);
- (*dt_list_ptr) = gfc_get_dt_list ();
- (*dt_list_ptr)->derived = tmp_sym;
- (*dt_list_ptr)->next = NULL;
-
- /* Set up the component of the derived type, which will be
- an integer with kind equal to c_ptr_size. Mangle the name of
- the field for the c_address to prevent the curious user from
- trying to access it from Fortran. */
- sprintf (comp_name, "__%s_%s", tmp_sym->name, "c_address");
- gfc_add_component (tmp_sym, comp_name, &tmp_comp);
- if (tmp_comp == NULL)
+ {
+ gfc_interface *intr, *head;
+ gfc_symbol *dt_sym;
+ const char *hidden_name;
+ gfc_dt_list **dt_list_ptr = NULL;
+ gfc_component *tmp_comp = NULL;
+ char comp_name[(GFC_MAX_SYMBOL_LEN * 2) + 1];
+
+ hidden_name = gfc_get_string ("%c%s",
+ (char) TOUPPER ((unsigned char) tmp_sym->name[0]),
+ &tmp_sym->name[1]);
+
+ /* Generate real derived type. */
+ tmp_symtree = gfc_find_symtree (gfc_current_ns->sym_root,
+ hidden_name);
+
+ if (tmp_symtree != NULL)
+ gcc_unreachable ();
+ gfc_get_sym_tree (hidden_name, gfc_current_ns, &tmp_symtree, false);
+ if (tmp_symtree)
+ dt_sym = tmp_symtree->n.sym;
+ else
+ gcc_unreachable ();
+
+ /* Generate an artificial generic function. */
+ dt_sym->name = gfc_get_string (tmp_sym->name);
+ head = tmp_sym->generic;
+ intr = gfc_get_interface ();
+ intr->sym = dt_sym;
+ intr->where = gfc_current_locus;
+ intr->next = head;
+ tmp_sym->generic = intr;
+
+ if (!tmp_sym->attr.generic
+ && gfc_add_generic (&tmp_sym->attr, tmp_sym->name, NULL)
+ == FAILURE)
+ return;
+
+ if (!tmp_sym->attr.function
+ && gfc_add_function (&tmp_sym->attr, tmp_sym->name, NULL)
+ == FAILURE)
+ return;
+
+ /* Say what module this symbol belongs to. */
+ dt_sym->module = gfc_get_string (mod_name);
+ dt_sym->from_intmod = INTMOD_ISO_C_BINDING;
+ dt_sym->intmod_sym_id = s;
+
+ /* Initialize an integer constant expression node. */
+ dt_sym->attr.flavor = FL_DERIVED;
+ dt_sym->ts.is_c_interop = 1;
+ dt_sym->attr.is_c_interop = 1;
+ dt_sym->attr.is_iso_c = 1;
+ dt_sym->ts.is_iso_c = 1;
+ dt_sym->ts.type = BT_DERIVED;
+
+ /* A derived type must have the bind attribute to be
+ interoperable (J3/04-007, Section 15.2.3), even though
+ the binding label is not used. */
+ dt_sym->attr.is_bind_c = 1;
+
+ dt_sym->attr.referenced = 1;
+ dt_sym->ts.u.derived = dt_sym;
+
+ /* Add the symbol created for the derived type to the current ns. */
+ dt_list_ptr = &(gfc_derived_types);
+ while (*dt_list_ptr != NULL && (*dt_list_ptr)->next != NULL)
+ dt_list_ptr = &((*dt_list_ptr)->next);
+
+ /* There is already at least one derived type in the list, so append
+ the one we're currently building for c_ptr or c_funptr. */
+ if (*dt_list_ptr != NULL)
+ dt_list_ptr = &((*dt_list_ptr)->next);
+ (*dt_list_ptr) = gfc_get_dt_list ();
+ (*dt_list_ptr)->derived = dt_sym;
+ (*dt_list_ptr)->next = NULL;
+
+ /* Set up the component of the derived type, which will be
+ an integer with kind equal to c_ptr_size. Mangle the name of
+ the field for the c_address to prevent the curious user from
+ trying to access it from Fortran. */
+ sprintf (comp_name, "__%s_%s", dt_sym->name, "c_address");
+ gfc_add_component (dt_sym, comp_name, &tmp_comp);
+ if (tmp_comp == NULL)
gfc_internal_error ("generate_isocbinding_symbol(): Unable to "
"create component for c_address");
- tmp_comp->ts.type = BT_INTEGER;
+ tmp_comp->ts.type = BT_INTEGER;
- /* Set this because the module will need to read/write this field. */
- tmp_comp->ts.f90_type = BT_INTEGER;
+ /* Set this because the module will need to read/write this field. */
+ tmp_comp->ts.f90_type = BT_INTEGER;
- /* The kinds for c_ptr and c_funptr are the same. */
- index = get_c_kind ("c_ptr", c_interop_kinds_table);
- tmp_comp->ts.kind = c_interop_kinds_table[index].value;
+ /* The kinds for c_ptr and c_funptr are the same. */
+ index = get_c_kind ("c_ptr", c_interop_kinds_table);
+ tmp_comp->ts.kind = c_interop_kinds_table[index].value;
- tmp_comp->attr.pointer = 0;
- tmp_comp->attr.dimension = 0;
+ tmp_comp->attr.pointer = 0;
+ tmp_comp->attr.dimension = 0;
- /* Mark the component as C interoperable. */
- tmp_comp->ts.is_c_interop = 1;
+ /* Mark the component as C interoperable. */
+ tmp_comp->ts.is_c_interop = 1;
+
+ /* Make it use associated (iso_c_binding module). */
+ dt_sym->attr.use_assoc = 1;
+ }
- /* Make it use associated (iso_c_binding module). */
- tmp_sym->attr.use_assoc = 1;
break;
case ISOCBINDING_NULL_PTR:
@@ -4550,21 +4621,20 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
tmp_sym->ts.u.derived =
get_iso_c_binding_dt (ISOCBINDING_FUNPTR);
- if (tmp_sym->ts.u.derived == NULL)
- {
+ if (tmp_sym->ts.u.derived == NULL)
+ {
/* Create the necessary derived type so we can continue
processing the file. */
- generate_isocbinding_symbol
+ generate_isocbinding_symbol
(mod_name, s == ISOCBINDING_FUNLOC
- ? ISOCBINDING_FUNPTR : ISOCBINDING_PTR,
- (const char *)(s == ISOCBINDING_FUNLOC
- ? "_gfortran_iso_c_binding_c_funptr"
- : "_gfortran_iso_c_binding_c_ptr"));
+ ? ISOCBINDING_FUNPTR : ISOCBINDING_PTR,
+ (const char *)(s == ISOCBINDING_FUNLOC
+ ? "c_funptr" : "c_ptr"));
tmp_sym->ts.u.derived =
- get_iso_c_binding_dt (s == ISOCBINDING_FUNLOC
- ? ISOCBINDING_FUNPTR
- : ISOCBINDING_PTR);
- }
+ get_iso_c_binding_dt (s == ISOCBINDING_FUNLOC
+ ? ISOCBINDING_FUNPTR
+ : ISOCBINDING_PTR);
+ }
/* The function result is itself (no result clause). */
tmp_sym->result = tmp_sym;
@@ -4712,6 +4782,9 @@ gfc_get_typebound_proc (gfc_typebound_proc *tb0)
gfc_symbol*
gfc_get_derived_super_type (gfc_symbol* derived)
{
+ if (derived && derived->attr.generic)
+ derived = gfc_find_dt_in_generic (derived);
+
if (!derived->attr.extension)
return NULL;
@@ -4719,6 +4792,9 @@ gfc_get_derived_super_type (gfc_symbol* derived)
gcc_assert (derived->components->ts.type == BT_DERIVED);
gcc_assert (derived->components->ts.u.derived);
+ if (derived->components->ts.u.derived->attr.generic)
+ return gfc_find_dt_in_generic (derived->components->ts.u.derived);
+
return derived->components->ts.u.derived;
}
@@ -4814,3 +4890,19 @@ gfc_is_associate_pointer (gfc_symbol* sym)
return true;
}
+
+
+gfc_symbol *
+gfc_find_dt_in_generic (gfc_symbol *sym)
+{
+ gfc_interface *intr = NULL;
+
+ if (!sym || sym->attr.flavor == FL_DERIVED)
+ return sym;
+
+ if (sym->attr.generic)
+ for (intr = (sym ? sym->generic : NULL); intr; intr = intr->next)
+ if (intr->sym->attr.flavor == FL_DERIVED)
+ break;
+ return intr ? intr->sym : NULL;
+}
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 262743d0d37..2fb2d34ae4a 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -5027,6 +5027,11 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)
tree index, range;
VEC(constructor_elt,gc) *v = NULL;
+ if (expr->expr_type == EXPR_VARIABLE
+ && expr->symtree->n.sym->attr.flavor == FL_PARAMETER
+ && expr->symtree->n.sym->value)
+ expr = expr->symtree->n.sym->value;
+
switch (expr->expr_type)
{
case EXPR_CONSTANT:
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 80e4f555d1c..fc8a9ed4e4b 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -699,6 +699,18 @@ gfc_get_module_backend_decl (gfc_symbol *sym)
}
else if (sym->attr.flavor == FL_DERIVED)
{
+ if (s && s->attr.flavor == FL_PROCEDURE)
+ {
+ gfc_interface *intr;
+ gcc_assert (s->attr.generic);
+ for (intr = s->generic; intr; intr = intr->next)
+ if (intr->sym->attr.flavor == FL_DERIVED)
+ {
+ s = intr->sym;
+ break;
+ }
+ }
+
if (!s->backend_decl)
s->backend_decl = gfc_get_derived_type (s);
gfc_copy_dt_decls_ifequal (s, sym, true);
@@ -1459,6 +1471,10 @@ gfc_get_symbol_decl (gfc_symbol * sym)
&& !sym->attr.proc_pointer)
DECL_BY_REFERENCE (decl) = 1;
+ if (sym->attr.vtab
+ || (sym->name[0] == '_' && strncmp ("__def_init", sym->name, 10) == 0))
+ GFC_DECL_PUSH_TOPLEVEL (decl) = 1;
+
return decl;
}
@@ -1879,7 +1895,8 @@ build_function_decl (gfc_symbol * sym, bool global)
/* Layout the function declaration and put it in the binding level
of the current function. */
- if (global)
+ if (global
+ || (sym->name[0] == '_' && strncmp ("__copy", sym->name, 6) == 0))
pushdecl_top_level (fndecl);
else
pushdecl (fndecl);
@@ -4035,7 +4052,18 @@ gfc_trans_use_stmts (gfc_namespace * ns)
st = gfc_find_symtree (ns->sym_root,
rent->local_name[0]
? rent->local_name : rent->use_name);
- gcc_assert (st);
+
+ /* The following can happen if a derived type is renamed. */
+ if (!st)
+ {
+ char *name;
+ name = xstrdup (rent->local_name[0]
+ ? rent->local_name : rent->use_name);
+ name[0] = (char) TOUPPER ((unsigned char) name[0]);
+ st = gfc_find_symtree (ns->sym_root, name);
+ free (name);
+ gcc_assert (st);
+ }
/* Sometimes, generic interfaces wind up being over-ruled by a
local symbol (see PR41062). */
@@ -5293,7 +5321,10 @@ gfc_generate_function_code (gfc_namespace * ns)
next = DECL_CHAIN (decl);
DECL_CHAIN (decl) = NULL_TREE;
- pushdecl (decl);
+ if (GFC_DECL_PUSH_TOPLEVEL (decl))
+ pushdecl_top_level (decl);
+ else
+ pushdecl (decl);
decl = next;
}
saved_function_decls = NULL_TREE;
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index ce607d8dbfd..3f4ebd5b7b7 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -2257,6 +2257,10 @@ gfc_get_derived_type (gfc_symbol * derived)
gfc_dt_list *dt;
gfc_namespace *ns;
+ if (derived && derived->attr.flavor == FL_PROCEDURE
+ && derived->attr.generic)
+ derived = gfc_find_dt_in_generic (derived);
+
gcc_assert (derived && derived->attr.flavor == FL_DERIVED);
/* See if it's one of the iso_c_binding derived types. */
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 22033d38d15..8fc7599473d 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -802,6 +802,7 @@ struct GTY((variable_size)) lang_decl {
#define GFC_DECL_CRAY_POINTEE(node) DECL_LANG_FLAG_4(node)
#define GFC_DECL_RESULT(node) DECL_LANG_FLAG_5(node)
#define GFC_DECL_SUBREF_ARRAY_P(node) DECL_LANG_FLAG_6(node)
+#define GFC_DECL_PUSH_TOPLEVEL(node) DECL_LANG_FLAG_7(node)
/* An array descriptor. */
#define GFC_DESCRIPTOR_TYPE_P(node) TYPE_LANG_FLAG_1(node)
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 6168d33ac05..071c6515b4c 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -2858,8 +2858,18 @@ is_gimple_ip_invariant_address (const_tree t)
return false;
op = strip_invariant_refs (TREE_OPERAND (t, 0));
+ if (!op)
+ return false;
+
+ if (TREE_CODE (op) == MEM_REF)
+ {
+ const_tree op0 = TREE_OPERAND (op, 0);
+ return (TREE_CODE (op0) == ADDR_EXPR
+ && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
+ || decl_address_ip_invariant_p (TREE_OPERAND (op0, 0))));
+ }
- return op && (CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op));
+ return CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op);
}
/* Return true if T is a GIMPLE minimal invariant. It's a restricted
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 171756be7ef..2468efd273b 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -7378,7 +7378,7 @@ expand_atomic_exchange (rtx target, rtx mem, rtx val, enum memmodel model,
if (model == MEMMODEL_SEQ_CST
|| model == MEMMODEL_RELEASE
|| model == MEMMODEL_ACQ_REL)
- expand_builtin_mem_thread_fence (model);
+ expand_mem_thread_fence (model);
create_output_operand (&ops[0], target, mode);
create_fixed_operand (&ops[1], mem);
@@ -7403,7 +7403,7 @@ expand_atomic_exchange (rtx target, rtx mem, rtx val, enum memmodel model,
if (model == MEMMODEL_SEQ_CST
|| model == MEMMODEL_RELEASE
|| model == MEMMODEL_ACQ_REL)
- expand_builtin_mem_thread_fence (model);
+ expand_mem_thread_fence (model);
addr = convert_memory_address (ptr_mode, XEXP (mem, 0));
return emit_library_call_value (libfunc, target, LCT_NORMAL,
@@ -7556,6 +7556,76 @@ expand_atomic_compare_and_swap (rtx *ptarget_bool, rtx *ptarget_oval,
return true;
}
+/* Generate asm volatile("" : : : "memory") as the memory barrier. */
+
+static void
+expand_asm_memory_barrier (void)
+{
+ rtx asm_op, clob;
+
+ asm_op = gen_rtx_ASM_OPERANDS (VOIDmode, empty_string, empty_string, 0,
+ rtvec_alloc (0), rtvec_alloc (0),
+ rtvec_alloc (0), UNKNOWN_LOCATION);
+ MEM_VOLATILE_P (asm_op) = 1;
+
+ clob = gen_rtx_SCRATCH (VOIDmode);
+ clob = gen_rtx_MEM (BLKmode, clob);
+ clob = gen_rtx_CLOBBER (VOIDmode, clob);
+
+ emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, asm_op, clob)));
+}
+
+/* This routine will either emit the mem_thread_fence pattern or issue a
+ sync_synchronize to generate a fence for memory model MEMMODEL. */
+
+#ifndef HAVE_mem_thread_fence
+# define HAVE_mem_thread_fence 0
+# define gen_mem_thread_fence(x) (gcc_unreachable (), NULL_RTX)
+#endif
+#ifndef HAVE_memory_barrier
+# define HAVE_memory_barrier 0
+# define gen_memory_barrier() (gcc_unreachable (), NULL_RTX)
+#endif
+
+void
+expand_mem_thread_fence (enum memmodel model)
+{
+ if (HAVE_mem_thread_fence)
+ emit_insn (gen_mem_thread_fence (GEN_INT (model)));
+ else if (model != MEMMODEL_RELAXED)
+ {
+ if (HAVE_memory_barrier)
+ emit_insn (gen_memory_barrier ());
+ else if (synchronize_libfunc != NULL_RTX)
+ emit_library_call (synchronize_libfunc, LCT_NORMAL, VOIDmode, 0);
+ else
+ expand_asm_memory_barrier ();
+ }
+}
+
+/* This routine will either emit the mem_signal_fence pattern or issue a
+ sync_synchronize to generate a fence for memory model MEMMODEL. */
+
+#ifndef HAVE_mem_signal_fence
+# define HAVE_mem_signal_fence 0
+# define gen_mem_signal_fence(x) (gcc_unreachable (), NULL_RTX)
+#endif
+
+void
+expand_mem_signal_fence (enum memmodel model)
+{
+ if (HAVE_mem_signal_fence)
+ emit_insn (gen_mem_signal_fence (GEN_INT (model)));
+ else if (model != MEMMODEL_RELAXED)
+ {
+ /* By default targets are coherent between a thread and the signal
+ handler running on the same thread. Thus this really becomes a
+ compiler barrier, in that stores must not be sunk past
+ (or raised above) a given point. */
+ expand_asm_memory_barrier ();
+ }
+}
+
/* This function expands the atomic load operation:
return the atomically loaded value in MEM.
@@ -7598,13 +7668,13 @@ expand_atomic_load (rtx target, rtx mem, enum memmodel model)
target = gen_reg_rtx (mode);
/* Emit the appropriate barrier before the load. */
- expand_builtin_mem_thread_fence (model);
+ expand_mem_thread_fence (model);
emit_move_insn (target, mem);
/* For SEQ_CST, also emit a barrier after the load. */
if (model == MEMMODEL_SEQ_CST)
- expand_builtin_mem_thread_fence (model);
+ expand_mem_thread_fence (model);
return target;
}
@@ -7645,7 +7715,7 @@ expand_atomic_store (rtx mem, rtx val, enum memmodel model, bool use_release)
{
/* lock_release is only a release barrier. */
if (model == MEMMODEL_SEQ_CST)
- expand_builtin_mem_thread_fence (model);
+ expand_mem_thread_fence (model);
return const0_rtx;
}
}
@@ -7665,13 +7735,13 @@ expand_atomic_store (rtx mem, rtx val, enum memmodel model, bool use_release)
/* If there is no mem_store, default to a move with barriers */
if (model == MEMMODEL_SEQ_CST || model == MEMMODEL_RELEASE)
- expand_builtin_mem_thread_fence (model);
+ expand_mem_thread_fence (model);
emit_move_insn (mem, val);
/* For SEQ_CST, also emit a barrier after the load. */
if (model == MEMMODEL_SEQ_CST)
- expand_builtin_mem_thread_fence (model);
+ expand_mem_thread_fence (model);
return const0_rtx;
}
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 654d2766f40..ec13f6ff301 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -978,6 +978,10 @@ extern bool can_atomic_exchange_p (enum machine_mode, bool);
extern bool expand_atomic_compare_and_swap (rtx *, rtx *, rtx, rtx, rtx, bool,
enum memmodel, enum memmodel);
+/* Generate memory barriers. */
+extern void expand_mem_thread_fence (enum memmodel);
+extern void expand_mem_signal_fence (enum memmodel);
+
/* Check whether an operation represented by the code CODE is a
convert operation that is supported by the target platform in
vector form */
diff --git a/gcc/output.h b/gcc/output.h
index e73c4a4c6bc..2cabaaa4499 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -129,7 +129,6 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
#define ATTRIBUTE_ASM_FPRINTF(m, n) ATTRIBUTE_NONNULL(m)
#endif
-extern void fprint_w (FILE *, HOST_WIDE_INT);
extern void fprint_whex (FILE *, unsigned HOST_WIDE_INT);
extern void fprint_ul (FILE *, unsigned long);
extern int sprint_ul (char *, unsigned long);
diff --git a/gcc/reorg.c b/gcc/reorg.c
index 40d73a76a71..0b90550add5 100644
--- a/gcc/reorg.c
+++ b/gcc/reorg.c
@@ -3600,9 +3600,11 @@ relax_delay_slots (rtx first)
}
}
+ /* See if we have a simple (conditional) jump that is useless. */
if (! INSN_ANNULLED_BRANCH_P (delay_insn)
- && prev_active_insn (target_label) == insn
&& ! condjump_in_parallel_p (delay_insn)
+ && prev_active_insn (target_label) == insn
+ && ! BARRIER_P (prev_nonnote_insn (target_label))
#ifdef HAVE_cc0
/* If the last insn in the delay slot sets CC0 for some insn,
various code assumes that it is in a delay slot. We could
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 53c500d82b3..5c1fb0077d6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,176 @@
+2011-11-20 Joey Ye <joey.ye@arm.com>
+
+ * gcc.dg/volatile-bitfields-1.c: New.
+
+2011-11-20 Jason Merrill <jason@redhat.com>
+
+ PR c++/48322
+ * g++.dg/cpp0x/variadic120.C: New.
+ * g++.dg/cpp0x/sfinae26.C: Adjust.
+
+ * g++.dg/cpp0x/sfinae11.C: Adjust.
+ * g++.dg/cpp0x/sfinae26.C: Adjust.
+ * g++.dg/template/unify11.C: Adjust.
+
+2011-11-20 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/51230
+ * g++.dg/template/error46.C: New.
+
+2011-11-20 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/51235
+ * gcc.target/i386/pr51235.c: New test.
+
+ PR target/51236
+ * gcc.target/i386/pr51236.c: New test.
+
+2011-11-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/discr32.adb: New test.
+ * gnat.dg/discr32_pkg.ads: New helper.
+
+2011-11-20 Nathan Sidwell <nathan@acm.org>
+
+ PR gcov-profile/51113
+ * gcc.misc-tests/gcov-13.c: Check gcovpart-13b coverage
+ * gcc.misc-tests/gcov-16.c: New.
+ * gcc.misc-tests/gcov-17.c: New.
+ * g++.dg/gcov/gcov-8.C: New.
+ * g++.dg/gcov/gcov-9.C: New.
+ * g++.dg/gcov/gcov-10.C: New.
+
+2011-11-20 Dodji Seketeli <dodji@redhat.com>
+
+ PR c++/51194
+ * g++.dg/cpp0x/alias-decl-15.C: New test.
+
+2011-11-19 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/51216
+ * g++.dg/cpp0x/pr51216.C: New.
+
+2011-11-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc.dg/delay-slot-2.c: New test.
+
+2011-11-18 Joseph Myers <joseph@codesourcery.com>
+
+ * gcc.dg/cpp/assert4.c: Test __linux__, not __gnu_linux__.
+
+2011-11-18 Fabien Chêne <fabien@gcc.gnu.org>
+
+ PR c++/51188
+ * g++.dg/lookup/using46.C: New.
+ * g++.dg/lookup/using47.C: New.
+ * g++.dg/lookup/using48.C: New.
+ * g++.dg/lookup/using49.C: New.
+ * g++.dg/lookup/using50.C: New.
+
+2011-11-18 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+ * gcc.c-torture/compile/pr44707.c: Do not assume assembler
+ supports /* ... */ comments.
+
+2011-11-18 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/51150
+ * g++.dg/cpp0x/pr51150.C: New.
+
+2011-11-18 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/50605
+ * g++.dg/ipa/pr50605.C: New test.
+
+2011-11-18 Dodji Seketeli <dodji@redhat.com>
+
+ PR c++/51191
+ * g++.dg/cpp0x/alias-decl-13.C: New test.
+
+2011-11-17 Jason Merrill <jason@redhat.com>
+
+ PR c++/51186
+ * g++.dg/cpp0x/auto27.C: New.
+ * g++.dg/cpp0x/trailing2.C: Adjust messages.
+
+2011-11-17 Andrew MacLeod <amacleod@redhat.com>
+
+ * gcc.dg/atomic-generic-aux.c (__atomic_compare_exchange): Fail if
+ memory model parameters don't match expected values.
+ * gcc.dg/atomic-generic.c: Pass specific memory model parameters to
+ __atomic_compare_exchange.
+ * gcc.dg/atomic-noinline.c: Pass specific memory model parameters to
+ __atomic_compare_exchange_n.
+ * gcc.dg/atomic-noinline-aux.c (__atomic_compare_exchange_2): Remove
+ weak/strong parameter and fail if memory models aren't correct.
+
+2011-10-17 Uros Bizjak <ubizjak@gmail.com>
+
+ * lib/gcc-simulate-thread.exp (simulate-thread): Run on all targets.
+ Look for simulate_thread_done to determine working gdb. Reduce timeout
+ to 10 seconds and fail when timeout occurs. Improve error messages.
+
+2011-11-17 Jason Merrill <jason@redhat.com>
+
+ PR c++/51137
+ * g++.dg/template/virtual2.C: New.
+
+2011-11-17 Michael Matz <matz@suse.de>
+
+ PR middle-end/50644
+ PR middle-end/50741
+ * g++.dg/tree-ssa/pr50741.C: New.
+
+2011-11-17 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * lib/gcc-simulate-thread.exp (simulate-thread): Skip on alpha*-*-*.
+
+2011-10-16 Uros Bizjak <ubizjak@gmail.com>
+
+ * gcc.dg/tm/memopt-6.c: Cleanup tmedge tree dump.
+ * gcc.dg/tm/memopt-13.c: Cleanup tmmark tree dump.
+ * g++.dg/eh/array1.C: Cleanup gimple tree dump.
+
+2011-11-16 Tobias Burnus <burnus@net-b.de>
+
+ PR fortran/39427
+ PR fortran/37829
+ * gfortran.dg/constructor_1.f90: New.
+ * gfortran.dg/constructor_2.f90: New.
+ * gfortran.dg/constructor_3.f90: New.
+ * gfortran.dg/constructor_4.f90: New.
+ * gfortran.dg/constructor_5.f90: New.
+ * gfortran.dg/constructor_6.f90: New.
+ * gfortran.dg/use_only_5.f90: New.
+ * gfortran.dg/c_ptr_tests_17.f90: New.
+ * gfortran.dg/c_ptr_tests_18.f90: New.
+ * gfortran.dg/used_types_25.f90: New.
+ * gfortran.dg/used_types_26.f90: New
+ * gfortran.dg/type_decl_3.f90: New.
+ * gfortran.dg/function_types_3.f90: Update dg-error.
+ * gfortran.dg/result_1.f90: Ditto.
+ * gfortran.dg/structure_constructor_3.f03: Ditto.
+ * gfortran.dg/structure_constructor_4.f03: Ditto.
+
+2011-10-16 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
+
+ * gcc.dg/vect/pr30858.c: Update expected output for
+ architectures with multiple vector sizes.
+
+2011-11-16 Richard Earnshaw <rearnsha@arm.com>
+ Bernd Schmidt <bernds@coudesourcery.com>
+ Sebastian Huber <sebastian.huber@embedded-brains.de>
+
+ PR target/49641
+ * gcc.target/arm/pr49641.c: New test.
+
+2011-11-16 Razya Ladelsky <razya@il.ibm.com>
+
+ PR tree-optimization/49960
+ * gcc.dg/autopar/pr49960.c: New test.
+ * gcc.dg/autopar/pr49960-1.c: New test.
+
+
2011-11-16 Tom de Vries <tom@codesourcery.com>
* gcc.dg/pr43864.c: Check for absence of 'Invalid sum' in pre tree-dump.
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-13.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-13.C
new file mode 100644
index 00000000000..8555154c634
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-13.C
@@ -0,0 +1,24 @@
+// Origin PR c++/51191
+// { dg-options "-std=c++0x" }
+
+template< class T >
+class ClassTemplate {};
+
+template< class T >
+struct Metafunction {
+ typedef T type;
+};
+
+template< class T >
+using TemplateAlias = ClassTemplate< typename Metafunction<T>::type >;
+
+using Alias = TemplateAlias<int>;
+
+template< class T >
+void f( TemplateAlias<T> );
+
+int main()
+{
+ Alias x;
+ f( x ); // { dg-error "no matching function for call to|f" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-15.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-15.C
new file mode 100644
index 00000000000..2bc9b11843d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-15.C
@@ -0,0 +1,17 @@
+// Origin PR c++/51194
+// { dg-options "-std=c++0x" }
+
+template<class U, class V> //#1
+struct foo {}; // { dg-error "provided for|foo" }
+
+template<class U, class V=char>
+struct P {};
+
+template<template<class... U> class... TT>
+struct bar {
+ template<class... Args>
+ using mem = P<TT<Args...>...>;//#2 { dg-error "wrong number of|arguments" }
+};
+
+bar<foo>::mem<int, char> b;//#3 { dg-error "invalid type" }
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto27.C b/gcc/testsuite/g++.dg/cpp0x/auto27.C
new file mode 100644
index 00000000000..c1041df54b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/auto27.C
@@ -0,0 +1,6 @@
+// PR c++/51186
+
+auto main()->int // { dg-error "std=" "" { target c++98 } }
+ // { dg-error "auto" "" { target c++98 } 3 }
+ // { dg-error "no type" "" { target c++98 } 3 }
+{ }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr51150.C b/gcc/testsuite/g++.dg/cpp0x/pr51150.C
new file mode 100644
index 00000000000..37eb166b43e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr51150.C
@@ -0,0 +1,20 @@
+// PR c++/51150
+// { dg-options "-std=c++0x" }
+
+struct Clock {
+ double Now();
+};
+template <class T> void Foo(Clock* clock) {
+ const int now = clock->Now();
+}
+
+template void Foo<float>(Clock*);
+
+template <class T> void Boo(int val) {
+ const int now1 = (double)(val);
+ const int now2 = const_cast<double>(val); // { dg-error "invalid" }
+ const int now3 = static_cast<double>(val);
+ const int now4 = reinterpret_cast<double>(val); // { dg-error "invalid" }
+}
+
+template void Boo<float>(int);
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr51216.C b/gcc/testsuite/g++.dg/cpp0x/pr51216.C
new file mode 100644
index 00000000000..4bdd071475e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr51216.C
@@ -0,0 +1,10 @@
+// PR c++/51216
+// { dg-options "-std=c++0x" }
+
+void foo()
+{
+ int i = ({ if (1) ; }); // { dg-error "ignored" }
+ int j = ({ for (;;) ; }); // { dg-error "ignored" }
+ int k = ({ while (1) ; }); // { dg-error "ignored" }
+ int l = ({ do { } while (1); }); // { dg-error "ignored" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
index 25902cbd65e..2e8408d8f4d 100644
--- a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
@@ -12,7 +12,8 @@ inline void f1( T& x ) noexcept( noexcept( declval<T&>().foo() ) ) // { dg-error
}
template< class T,
- bool Noexcept = noexcept( declval<T&>().foo() )
+ bool Noexcept = noexcept( declval<T&>().foo() ) // { dg-error "no member|not convert" }
+
>
inline void f2( T& x ) noexcept( Noexcept )
{
@@ -51,7 +52,6 @@ int main()
// static_assert( noexcept( f3(y) ), "shall be ill-formed(OK)." );
noexcept( f1(z) ); // { dg-message "required" }
- static_assert( noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match|could not convert" }
- // { dg-error "no member" "" { target *-*-* } 54 }
+ static_assert( noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match" }
noexcept( f3(z) ); // { dg-message "required" }
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae26.C b/gcc/testsuite/g++.dg/cpp0x/sfinae26.C
index 42b48eb5a6b..374f9976b2c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/sfinae26.C
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae26.C
@@ -30,9 +30,9 @@ struct is_same<T, T> {
template<class... T>
struct S {
template<class... U,
- typename enable_if<and_<is_same<T, U>...>::value>::type*& = enabler
+ typename enable_if<and_<is_same<T, U>...>::value>::type*& = enabler // { dg-error "no type" }
>
- S(U...){} // { dg-error "no type named 'type'" }
+ S(U...){}
};
S<bool> s(0); // { dg-error "no match" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae30.C b/gcc/testsuite/g++.dg/cpp0x/sfinae30.C
new file mode 100644
index 00000000000..6fcf5f75609
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae30.C
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++11 } }
+
+template <class... T> struct tuple;
+template <class T> struct tuple<T> { T t; };
+
+template <class T, class U> struct pair;
+template<> struct pair<int,double> { };
+
+template <class... Ts>
+struct A
+{
+ template <class... Us,
+ class V = tuple<pair<Ts,Us>...> >
+ static void f(Us...)
+ {
+ V v;
+ }
+ template <class U>
+ static void f(bool);
+};
+
+int main()
+{
+ A<int,float>::f<double>(1.0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing2.C b/gcc/testsuite/g++.dg/cpp0x/trailing2.C
index e45204fe715..5f5af22947f 100644
--- a/gcc/testsuite/g++.dg/cpp0x/trailing2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/trailing2.C
@@ -3,14 +3,14 @@
// { dg-options "-std=c++0x" }
auto f1 () -> int;
-auto f2 (); // { dg-error "without late return type" }
-int f3 () -> int; // { dg-error "late return type" }
-auto *f4 () -> int; // { dg-error "late return type" }
+auto f2 (); // { dg-error "without trailing return type" }
+int f3 () -> int; // { dg-error "trailing return type" }
+auto *f4 () -> int; // { dg-error "trailing return type" }
struct A
{
auto f5 () const -> int;
- auto f6 (); // { dg-error "without late return type" }
- int f7 () -> int; // { dg-error "late return type" }
- auto *f8 () -> int; // { dg-error "late return type" }
+ auto f6 (); // { dg-error "without trailing return type" }
+ int f7 () -> int; // { dg-error "trailing return type" }
+ auto *f8 () -> int; // { dg-error "trailing return type" }
};
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic120.C b/gcc/testsuite/g++.dg/cpp0x/variadic120.C
new file mode 100644
index 00000000000..e26ee4e9abe
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic120.C
@@ -0,0 +1,24 @@
+// PR c++/48322
+// { dg-do compile { target c++11 } }
+
+template <class... T> struct tuple;
+template <class T> struct tuple<T> { T t; };
+
+template <class T, class U> struct pair;
+template<> struct pair<int,double> { };
+
+template <class... Ts>
+struct A
+{
+ template <class... Us,
+ class V = tuple<pair<Ts,Us>...> >
+ static void f()
+ {
+ V v;
+ }
+};
+
+int main()
+{
+ A<int>::f<double>();
+}
diff --git a/gcc/testsuite/g++.dg/debug/using6.C b/gcc/testsuite/g++.dg/debug/using6.C
new file mode 100644
index 00000000000..8f73d37ffa0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/using6.C
@@ -0,0 +1,22 @@
+// PR c++/51189
+// { dg-do compile }
+
+struct A
+{
+ int i1, i2, i3, i4, i5, i6;
+};
+
+struct B : A
+{
+ using A::i1;
+ using A::i2;
+ using A::i3;
+ using A::i4;
+ using A::i5;
+ using A::i6;
+};
+
+struct C : B
+{
+ using B::i1;
+};
diff --git a/gcc/testsuite/g++.dg/eh/array1.C b/gcc/testsuite/g++.dg/eh/array1.C
index 157450a9592..43e5bc02449 100644
--- a/gcc/testsuite/g++.dg/eh/array1.C
+++ b/gcc/testsuite/g++.dg/eh/array1.C
@@ -1,7 +1,6 @@
// Test that we have one EH cleanup region for the whole array
// rather than one for each element.
-// { dg-options -fdump-tree-gimple }
-// { dg-final { scan-tree-dump-times "catch" 1 "gimple" } }
+// { dg-options "-fdump-tree-gimple" }
struct A
{
@@ -13,3 +12,6 @@ void f()
{
A a[10] = { };
}
+
+// { dg-final { scan-tree-dump-times "catch" 1 "gimple" } }
+// { dg-final { cleanup-tree-dump "gimple" } }
diff --git a/gcc/testsuite/g++.dg/gcov/gcov-10.C b/gcc/testsuite/g++.dg/gcov/gcov-10.C
new file mode 100644
index 00000000000..4c91be94ee4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/gcov-10.C
@@ -0,0 +1,20 @@
+/* Ensure PIC sequence used for comdat functions */
+
+/* { dg-options "-fprofile-arcs -ftest-coverage -fpic" } */
+/* { dg-do run { target native } } */
+/* { dg-require-effective-target fpic } */
+
+inline int __attribute__ ((noinline)) Foo ()
+{
+ static int x[1];
+
+ return x[0]++; /* count (1) */
+}
+
+int main ()
+{
+ Foo (); /* count (1) */
+ return 0; /* count (1) */
+}
+
+/* { dg-final { run-gcov gcov-10.C } } */
diff --git a/gcc/testsuite/g++.dg/gcov/gcov-11.C b/gcc/testsuite/g++.dg/gcov/gcov-11.C
new file mode 100644
index 00000000000..fa0890206f3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/gcov-11.C
@@ -0,0 +1,42 @@
+/* Check that unexecuted exception processing regions are shown
+ distinct from unexecuted normal regions. */
+
+/* { dg-options "-fprofile-arcs -ftest-coverage" } */
+/* { dg-do run { target native } } */
+
+void Baz (int i)
+{
+ if (i)
+ throw 1;
+}
+
+void Boz () throw ()
+{
+}
+
+int main ()
+{
+ try
+ {
+ Baz (0); /* count (1) */
+ Baz (0); /* count (1) */
+ }
+ catch (...)
+ {
+ Boz (); /* count (=====) */
+ }
+
+ try
+ {
+ Baz (1); /* count (1) */
+ Baz (0); /* count (#####) */
+ }
+ catch (...)
+ {
+ Boz (); /* count (1) */
+ }
+
+ return 0; /* count (1) */
+}
+
+/* { dg-final { run-gcov gcov-11.C } } */
diff --git a/gcc/testsuite/g++.dg/gcov/gcov-8.C b/gcc/testsuite/g++.dg/gcov/gcov-8.C
new file mode 100644
index 00000000000..25e265e9c98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/gcov-8.C
@@ -0,0 +1,13 @@
+/* { dg-options "-fprofile-arcs -fvisibility=hidden" } */
+/* { dg-require-visibility "" } */
+
+struct __attribute__((visibility ("hidden"))) X
+{
+ void Fink ();
+};
+
+void X::Fink ()
+{
+}
+
+/* { dg-final { scan-assembler "\\.hidden\t__gcov___ZN1X4FinkEv" } } */
diff --git a/gcc/testsuite/g++.dg/gcov/gcov-9.C b/gcc/testsuite/g++.dg/gcov/gcov-9.C
new file mode 100644
index 00000000000..e8d5ad8b0a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/gcov-9.C
@@ -0,0 +1,15 @@
+/* { dg-options "-fprofile-arcs -fvisibility-inlines-hidden" } */
+/* { dg-require-visibility "" } */
+
+inline void Boo ()
+{
+}
+
+extern "C" void (*Foo ()) ()
+{
+ return Boo;
+}
+
+/* { dg-final { scan-assembler "\\.hidden\t__gcov___Z3Boov" } } */
+/* { dg-final { scan-assembler "__gcov__Foo:" } } */
+/* { dg-final { scan-assembler-not "\\.hidden\t__gcov__Foo" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/pr50605.C b/gcc/testsuite/g++.dg/ipa/pr50605.C
new file mode 100644
index 00000000000..4910a37f8f2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr50605.C
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-early-inlining" } */
+
+class A
+{
+public:
+ int a;
+ void *stuff;
+};
+
+class B
+{
+public:
+ int b;
+ void *other_stuff;
+ A array[50];
+};
+
+extern B gb;
+
+int process_A (A *a)
+{
+ return a->a;
+}
+
+int process_A_complex (A *a)
+{
+ return process_A (a+3);
+}
+
+int process_B (B *b)
+{
+ return process_A_complex (&b->array[0]);
+}
+
+int foo (void)
+{
+ return process_B (&gb);
+}
+
diff --git a/gcc/testsuite/g++.dg/lookup/using46.C b/gcc/testsuite/g++.dg/lookup/using46.C
new file mode 100644
index 00000000000..6f0f5bca090
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using46.C
@@ -0,0 +1,62 @@
+// PR c++/51141
+// { dg-do compile }
+// { dg-options "-fpermissive -w -Werror" }
+
+typedef int size_t;
+template < size_t, size_t > struct AlignedBuffer {};
+
+template < typename > class VectorBufferBase
+{
+public:
+ allocateBuffer (size_t) {
+ }
+ buffer () {
+ }
+ *m_buffer;
+ size_t m_capacity;
+};
+
+template < typename T, size_t > class VectorBuffer:VectorBufferBase < T >
+{
+ typedef VectorBufferBase < T > Base;
+
+public:
+ VectorBuffer () {
+ }
+ allocateBuffer (size_t) {
+ m_capacity = 0;
+ }
+ Base::buffer;
+ Base::m_buffer;
+ Base::m_capacity;
+ size_t m_inlineBufferSize;
+
+ AlignedBuffer < 0, __alignof__ (T) > m_inlineBuffer;
+};
+
+template < typename T, size_t > class Vector
+{
+ typedef VectorBuffer < T,
+ 0 > Buffer;
+public:
+ void shrinkCapacity (size_t);
+
+ clear () {
+ shrinkCapacity (0);
+ }
+ Buffer m_buffer;
+};
+
+template < typename T, size_t inlineCapacity > void Vector < T,
+ inlineCapacity >::shrinkCapacity (size_t)
+{
+ m_buffer.allocateBuffer (0);
+}
+
+struct PatternDisjunction;
+struct YarrPattern {
+ reset () {
+ m_disjunctions.clear ();
+ }
+ Vector < PatternDisjunction *, 0 > m_disjunctions;
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using47.C b/gcc/testsuite/g++.dg/lookup/using47.C
new file mode 100644
index 00000000000..c81864705c4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using47.C
@@ -0,0 +1,29 @@
+// PR c++/51152
+// { dg-do compile }
+
+struct A
+{
+ int a;
+};
+
+struct B
+{
+ int b1;
+ int b2;
+ A b3;
+};
+
+struct C : B
+{
+ typedef int R;
+ typedef int S;
+ typedef int T;
+ using B::b1;
+ using B::b2;
+ using B::b3;
+ void f()
+ {
+ b3.a;
+ b3.~A();
+ }
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using48.C b/gcc/testsuite/g++.dg/lookup/using48.C
new file mode 100644
index 00000000000..e6dc3fab77c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using48.C
@@ -0,0 +1,23 @@
+// PR c++/51190
+// { dg-do compile }
+
+struct A
+{
+ int i;
+};
+
+template<typename> struct B
+{
+ A* p;
+};
+
+template<typename T> struct C : B<T>
+{
+ using B<T>::p;
+
+ C() { p->i; }
+
+ int i1, i2, i3, i4, i5;
+};
+
+C<A> c;
diff --git a/gcc/testsuite/g++.dg/lookup/using49.C b/gcc/testsuite/g++.dg/lookup/using49.C
new file mode 100644
index 00000000000..391476ac472
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using49.C
@@ -0,0 +1,20 @@
+// PR c++/51188
+// { dg-do compile }
+
+#include <utility>
+class XBase {
+public:
+ virtual ~XBase() = 0;
+ enum ImpMode { Imp1, Imp2, Imp3 };
+};
+class X : public XBase {
+ class XBlock {};
+ using XBase::ImpMode;
+ using XBase::Imp3;
+ using XBase::Imp1;
+ using XBase::Imp2;
+ int _XBlocked;
+ std::pair<int,int> getImp(void) const {
+ return (std::make_pair(0, static_cast<int>(X::Imp1)));
+ }
+};
diff --git a/gcc/testsuite/g++.dg/template/error46.C b/gcc/testsuite/g++.dg/template/error46.C
new file mode 100644
index 00000000000..0f4bdafb8a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/error46.C
@@ -0,0 +1,11 @@
+// PR c++/51230
+
+template<int> struct A {};
+
+template<int N> void foo(A<N>, A<N>); // { dg-message "template" }
+
+void bar()
+{
+ foo(A<0>(), A<1>()); // { dg-error "no matching" }
+}
+// { dg-message "candidate|parameter 'N' ('0' and '1')" { target *-*-* } 9 }
diff --git a/gcc/testsuite/g++.dg/template/unify11.C b/gcc/testsuite/g++.dg/template/unify11.C
index 25606dc4af8..85bdbbc940a 100644
--- a/gcc/testsuite/g++.dg/template/unify11.C
+++ b/gcc/testsuite/g++.dg/template/unify11.C
@@ -6,9 +6,10 @@ struct A
{
};
-template <typename S, typename T, typename U, typename S::v = &S::v::s>
+template <typename S, typename T, typename U,
+ typename S::v = &S::v::s> // { dg-error "is not a" }
typename S::A
-foo (S c, T t, U u) // { dg-message "note" }
+foo (S c, T t, U u)
{
}
@@ -20,8 +21,7 @@ struct B
C (U t)
{
A a;
- A b = foo (this, a, t); // { dg-error "(no matching function|is not a)" }
- // { dg-message "candidate" "candidate note" { target *-*-* } 23 }
+ A b = foo (this, a, t); // { dg-error "no matching function" }
}
} c;
B () : c (A ())
diff --git a/gcc/testsuite/g++.dg/template/virtual2.C b/gcc/testsuite/g++.dg/template/virtual2.C
new file mode 100644
index 00000000000..83b7ed6beae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/virtual2.C
@@ -0,0 +1,11 @@
+// PR c++/51137
+
+struct A {};
+
+template<int> struct B : virtual A
+{
+ void foo()
+ {
+ (new A(*this))->A::~A();
+ }
+};
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr50741.C b/gcc/testsuite/g++.dg/tree-ssa/pr50741.C
new file mode 100644
index 00000000000..843a7be4a7b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr50741.C
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -g" } */
+/* PR middle-end/50741 */
+
+struct PublishLo
+{
+ const char *functionName;
+ ~PublishLo();
+};
+struct A { A(); };
+A::A()
+{
+ static PublishLo _rL_53 = {__FUNCTION__};
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr44707.c b/gcc/testsuite/gcc.c-torture/compile/pr44707.c
index 9031f0042c9..d5d39fc83c8 100644
--- a/gcc/testsuite/gcc.c-torture/compile/pr44707.c
+++ b/gcc/testsuite/gcc.c-torture/compile/pr44707.c
@@ -9,6 +9,6 @@ foo (void)
int e3 = v.b;
int e4 = v.c;
int e5 = v.d;
- __asm__ volatile ("/* %0 %1 %2 %3 %4 */" : : "nro" (e1), "nro" (e2), "nro" (e3), "nro" (e4), "nro" (e5));
+ __asm__ volatile ("" : : "nro" (e1), "nro" (e2), "nro" (e3), "nro" (e4), "nro" (e5));
}
diff --git a/gcc/testsuite/gcc.dg/atomic-generic-aux.c b/gcc/testsuite/gcc.dg/atomic-generic-aux.c
index a6b552a5dfd..2f4cb2a88f7 100644
--- a/gcc/testsuite/gcc.dg/atomic-generic-aux.c
+++ b/gcc/testsuite/gcc.dg/atomic-generic-aux.c
@@ -19,17 +19,30 @@ __atomic_exchange (size_t size, void *obj, void *val, void *ret, int model)
}
+/* Note that the external version of this routine has the boolean weak/strong
+ parameter removed. This is required by teh external library. */
bool
-__atomic_compare_exchange (size_t size, void *obj, void *expected,
+__atomic_compare_exchange (size_t size, void *obj, void *expected,
void *desired, int model1, int model2)
{
+ bool ret;
if (!memcmp (obj, expected, size))
{
memcpy (obj, desired, size);
- return true;
+ ret = true;
}
- memcpy (expected, obj, size);
- return false;
+ else
+ {
+ memcpy (expected, obj, size);
+ ret = false;
+ }
+
+ /* Make sure the parameters have been properly adjusted for the external
+ function call (no weak/strong parameter. */
+ if (model1 != __ATOMIC_SEQ_CST || model2 != __ATOMIC_ACQUIRE)
+ ret = !ret;
+
+ return ret;
}
diff --git a/gcc/testsuite/gcc.dg/atomic-generic.c b/gcc/testsuite/gcc.dg/atomic-generic.c
index 8a5528c3653..d77e97dbf8a 100644
--- a/gcc/testsuite/gcc.dg/atomic-generic.c
+++ b/gcc/testsuite/gcc.dg/atomic-generic.c
@@ -41,12 +41,12 @@ main ()
if (memcmp (&b, &ones, size))
abort ();
- if (!__atomic_compare_exchange (&a, &b, &zero, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
+ if (!__atomic_compare_exchange (&a, &b, &zero, false, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE))
abort();
if (memcmp (&a, &zero, size))
abort ();
- if (__atomic_compare_exchange (&a, &b, &ones, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
+ if (__atomic_compare_exchange (&a, &b, &ones, false, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE))
abort();
if (memcmp (&b, &zero, size))
abort ();
diff --git a/gcc/testsuite/gcc.dg/atomic-noinline-aux.c b/gcc/testsuite/gcc.dg/atomic-noinline-aux.c
index b05460e469b..deab7ae1de3 100644
--- a/gcc/testsuite/gcc.dg/atomic-noinline-aux.c
+++ b/gcc/testsuite/gcc.dg/atomic-noinline-aux.c
@@ -30,9 +30,15 @@ __atomic_store_1 (char *p, char v, int i)
*p = 1;
}
-int __atomic_compare_exchange_2 (short *p, short *a, short b, int x, int y, int z)
+int __atomic_compare_exchange_2 (short *p, short *a, short b, int y, int z)
{
- *p = 1;
+ /* Fail if the memory models aren't correct as that will indicate the external
+ call has failed to remove the weak/strong parameter as required by the
+ library. */
+ if (y != __ATOMIC_SEQ_CST || z != __ATOMIC_ACQUIRE)
+ *p = 0;
+ else
+ *p = 1;
}
char __atomic_fetch_add_1 (char *p, char v, int i)
diff --git a/gcc/testsuite/gcc.dg/atomic-noinline.c b/gcc/testsuite/gcc.dg/atomic-noinline.c
index eb0866e549e..626254d8a9a 100644
--- a/gcc/testsuite/gcc.dg/atomic-noinline.c
+++ b/gcc/testsuite/gcc.dg/atomic-noinline.c
@@ -31,7 +31,7 @@ main ()
if (ac != 1)
abort ();
- __atomic_compare_exchange_n (&as, &bs, cs, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ __atomic_compare_exchange_n (&as, &bs, cs, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
if (as != 1)
abort ();
diff --git a/gcc/testsuite/gcc.dg/autopar/pr49960-1.c b/gcc/testsuite/gcc.dg/autopar/pr49960-1.c
new file mode 100644
index 00000000000..ac9d5678499
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/autopar/pr49960-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-parallelize-loops=4 -fdump-tree-parloops-details -fdump-tree-optimized" } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int main()
+{
+ unsigned int x, y, idx, H = 1024, W = 1024;
+
+ int * tmps = (int *)malloc(H*W*sizeof(int));
+
+ /* This loop gets parallelized even though output dependences exist
+ between writes to 'tmps' that prevent parallelization.
+ For example: tmps[1] = 1, ..., tmps[1] = 17. */
+
+ for(x = 1; x < H; x++)
+ {
+ for(y = 1; y < W; y++)
+ {
+ idx = x*W+y;
+ tmps[idx % 4096] = idx;
+ }
+ }
+
+ for(x = 1; x < 8; x++)
+ printf("tmps[%d]=%d\n", x, tmps[x]);
+
+ return 0;
+}
+/* Check that no loop gets parallelized. */
+
+/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 0 "parloops" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "parloops" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/autopar/pr49960.c b/gcc/testsuite/gcc.dg/autopar/pr49960.c
new file mode 100644
index 00000000000..1f3482f170d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/autopar/pr49960.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-parallelize-loops=4 -fdump-tree-parloops-details -fdump-tree-optimized" } */
+
+#include <stdio.h>
+#define MB 100
+#define NA 450
+#define MA 400
+
+int T[MA][MB],A[MA][NA],B[MB][NA];
+void MRTRBR(int MA_1, int NA_1, int MB_1)
+{
+ int i,j, t,k;
+
+ /* The outer most loop is not parallel because for different k's there
+ is write-write dependency for T[i][j]. */
+
+ /* The two inner loops don't get parallelized due to low number of
+ iterations. */
+
+ for (k = 3; k < NA_1; k++)
+ for (i = 3; i < MA_1; i++)
+ for (j = 3; j < MB_1; j++)
+ {
+ t = T[i][j];
+ T[i][j] = t+2+A[i][k]*B[j][k];
+ }
+}
+void main ()
+{
+ int j,i;
+
+ for (i = 3; i < MA; i++)
+ for (j = 3; j < MB; j++)
+ T[i][j] = (i>j?i:j);
+
+ MRTRBR (MA,NA,MB);
+
+ for (i = MA-1; i < MA; i++)
+ for (j = MB-10; j < MB; j++)
+ printf ("i %d j %d T[i][j] = %d\n",i,j,T[i][j]);
+}
+
+
+/* Check that the outer most loop doesn't get parallelized (thus no loop gets parallelized) */
+
+/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 0 "parloops" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "parloops" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/cpp/assert4.c b/gcc/testsuite/gcc.dg/cpp/assert4.c
index a05ef130206..514195313b3 100644
--- a/gcc/testsuite/gcc.dg/cpp/assert4.c
+++ b/gcc/testsuite/gcc.dg/cpp/assert4.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003, 2006, 2008 Free Software Foundation, Inc.
+/* Copyright (C) 2003, 2006, 2008, 2009, 2011 Free Software Foundation, Inc.
Test builtin preprocessor assertions.
By Kaveh Ghazi <ghazi@caip.rutgers.edu>. */
@@ -7,7 +7,7 @@
/* Check for #system assertions. */
-#if defined __gnu_linux__
+#if defined __linux__
# if !#system(linux) || !#system(unix) || !#system(posix)
# error
# endif
diff --git a/gcc/testsuite/gcc.dg/delay-slot-2.c b/gcc/testsuite/gcc.dg/delay-slot-2.c
new file mode 100644
index 00000000000..79faf81c798
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/delay-slot-2.c
@@ -0,0 +1,116 @@
+/* PR rtl-optimization/51187 */
+/* Reported by Jurij Smakov <jurij@wooyd.org> */
+
+/* { dg-do compile } */
+/* { dg-options "-g -O2" } */
+
+extern int printf (__const char *__restrict __format, ...);
+extern void print_c_condition (const char *);
+
+enum decision_type
+{
+ DT_num_insns,
+ DT_mode, DT_code, DT_veclen,
+ DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe,
+ DT_const_int,
+ DT_veclen_ge, DT_dup, DT_pred, DT_c_test,
+ DT_accept_op, DT_accept_insn
+};
+
+struct decision_test
+{
+ struct decision_test *next;
+ enum decision_type type;
+
+ union
+ {
+ int num_insns;
+
+ struct
+ {
+ const char *name;
+ } pred;
+
+ const char *c_test;
+ int veclen;
+ int dup;
+ long intval;
+ int opno;
+
+ struct {
+ int code_number;
+ int lineno;
+ int num_clobbers_to_add;
+ } insn;
+ } u;
+};
+
+enum routine_type {
+ RECOG, SPLIT, PEEPHOLE2
+};
+
+void
+write_cond (struct decision_test *p, int depth,
+ enum routine_type subroutine_type)
+{
+ switch (p->type)
+ {
+ case DT_num_insns:
+ printf ("peep2_current_count >= %d", p->u.num_insns);
+ break;
+
+ case DT_code:
+ printf ("GET_CODE (x%d) == ", depth);
+ break;
+
+ case DT_veclen:
+ printf ("XVECLEN (x%d, 0) == %d", depth, p->u.veclen);
+ break;
+
+ case DT_elt_zero_int:
+ printf ("XINT (x%d, 0) == %d", depth, (int) p->u.intval);
+ break;
+
+ case DT_elt_one_int:
+ printf ("XINT (x%d, 1) == %d", depth, (int) p->u.intval);
+ break;
+
+ case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
+ printf ("XWINT (x%d, 0) == ", depth);
+ print_host_wide_int (p->u.intval);
+ break;
+
+ case DT_const_int:
+ printf ("x%d == const_int_rtx[MAX_SAVED_CONST_INT + (%d)]",
+ depth, (int) p->u.intval);
+ break;
+
+ case DT_veclen_ge:
+ printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen);
+ break;
+
+ case DT_dup:
+ printf ("rtx_equal_p (x%d, operands[%d])", depth, p->u.dup);
+ break;
+
+ case DT_pred:
+ printf ("%s (x%d)", p->u.pred.name, depth);
+ break;
+
+ case DT_c_test:
+ print_c_condition (p->u.c_test);
+ break;
+
+ case DT_accept_insn:
+ ((void)(__builtin_expect(!(subroutine_type == RECOG), 0) ? __builtin_unreachable(), 0 : 0));
+ ((void)(__builtin_expect(!(p->u.insn.num_clobbers_to_add), 0) ? __builtin_unreachable(), 0 : 0));
+ printf ("pnum_clobbers != NULL");
+ break;
+
+ default:
+ __builtin_unreachable();
+ }
+}
+
+/* { dg-final { scan-assembler "printf" } } */
diff --git a/gcc/testsuite/gcc.dg/tm/memopt-13.c b/gcc/testsuite/gcc.dg/tm/memopt-13.c
index 6e93b7feaea..381e682bca0 100644
--- a/gcc/testsuite/gcc.dg/tm/memopt-13.c
+++ b/gcc/testsuite/gcc.dg/tm/memopt-13.c
@@ -13,3 +13,4 @@ void f()
}
/* { dg-final { scan-tree-dump-times "memmoveRtWt \\\(&large_global," 1 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
diff --git a/gcc/testsuite/gcc.dg/tm/memopt-6.c b/gcc/testsuite/gcc.dg/tm/memopt-6.c
index f4343736772..496ce2dd3e8 100644
--- a/gcc/testsuite/gcc.dg/tm/memopt-6.c
+++ b/gcc/testsuite/gcc.dg/tm/memopt-6.c
@@ -18,3 +18,4 @@ int f()
}
/* { dg-final { scan-tree-dump-times "memmoveRtWt \\\(&lala, &lacopy" 1 "tmedge" } } */
+/* { dg-final { cleanup-tree-dump "tmedge" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr30858.c b/gcc/testsuite/gcc.dg/vect/pr30858.c
index 0af2f8e9a91..0e7f7e10d4d 100644
--- a/gcc/testsuite/gcc.dg/vect/pr30858.c
+++ b/gcc/testsuite/gcc.dg/vect/pr30858.c
@@ -11,5 +11,5 @@ foo (int ko)
}
/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" } } */
-/* { dg-final { scan-tree-dump-times "Unknown def-use cycle pattern." 1 "vect" } } */
+/* { dg-final { scan-tree-dump "Unknown def-use cycle pattern." "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/volatile-bitfields-1.c b/gcc/testsuite/gcc.dg/volatile-bitfields-1.c
new file mode 100644
index 00000000000..6adda27fea4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/volatile-bitfields-1.c
@@ -0,0 +1,23 @@
+/* { dg-options "-fstrict-volatile-bitfields" } */
+/* { dg-do run } */
+
+extern int puts(const char *);
+extern void abort(void) __attribute__((noreturn));
+
+typedef struct {
+ volatile unsigned short a:8, b:8;
+} BitStruct;
+
+BitStruct bits = {1, 2};
+
+void check(int i, int j)
+{
+ if (i != 1 || j != 2) puts("FAIL"), abort();
+}
+
+int main ()
+{
+ check(bits.a, bits.b);
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.misc-tests/gcov-13.c b/gcc/testsuite/gcc.misc-tests/gcov-13.c
index 605d4d4b382..14be8f9e103 100644
--- a/gcc/testsuite/gcc.misc-tests/gcov-13.c
+++ b/gcc/testsuite/gcc.misc-tests/gcov-13.c
@@ -16,3 +16,4 @@ int main ()
}
/* { dg-final { run-gcov { -a gcov-13.c } } } */
+/* { dg-final { run-gcov { -a gcovpart-13b.c } } } */
diff --git a/gcc/testsuite/gcc.misc-tests/gcov-16.c b/gcc/testsuite/gcc.misc-tests/gcov-16.c
new file mode 100644
index 00000000000..b05c4a064e8
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/gcov-16.c
@@ -0,0 +1,11 @@
+/* Test visibility is copied */
+
+/* { dg-options "-fprofile-arcs -fvisibility=hidden" } */
+/* { dg-require-visibility "" } */
+/* { dg-require-weak "" } */
+
+void Foo ()
+{
+}
+
+ /* { dg-final { scan-assembler "\\.hidden\t__gcov__Foo" } } */
diff --git a/gcc/testsuite/gcc.misc-tests/gcov-17.c b/gcc/testsuite/gcc.misc-tests/gcov-17.c
new file mode 100644
index 00000000000..66f50f27477
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/gcov-17.c
@@ -0,0 +1,11 @@
+/* Test visibility is copied */
+
+/* { dg-options "-fprofile-arcs" } */
+/* { dg-require-visibility "" } */
+/* { dg-require-weak "" } */
+
+void __attribute__ ((visibility ("hidden"), weak)) Foo ()
+{
+}
+
+/* { dg-final { scan-assembler "\\.hidden\t__gcov__Foo" } } */
diff --git a/gcc/testsuite/gcc.target/arm/pr49641.c b/gcc/testsuite/gcc.target/arm/pr49641.c
new file mode 100644
index 00000000000..7f9b3769c1a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr49641.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-mthumb -O2" } */
+/* { dg-require-effective-target arm_thumb1_ok } */
+/* { dg-final { scan-assembler-not "stmia\[\\t \]*r3!\[^\\n]*r3" } } */
+typedef struct {
+ void *t1, *t2, *t3;
+} z;
+extern volatile int y;
+static inline void foo(z *x) {
+ x->t1 = &x->t2;
+ x->t2 = ((void *)0);
+ x->t3 = &x->t1;
+}
+extern z v;
+void bar (void) {
+ y = 0;
+ foo(&v);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr51235.c b/gcc/testsuite/gcc.target/i386/pr51235.c
new file mode 100644
index 00000000000..c99d5c0e733
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr51235.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O -ftree-vectorize -mxop -mavx2" } */
+
+void *foo (int count, void **list)
+{
+ void *minaddr = list[0];
+ int i;
+
+ for (i = 1; i < count; i++)
+ {
+ void *addr = list[i];
+ if (addr < minaddr)
+ minaddr = addr;
+ }
+
+ return minaddr;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr51236.c b/gcc/testsuite/gcc.target/i386/pr51236.c
new file mode 100644
index 00000000000..63bfaeeb0eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr51236.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O -ftree-vectorize -mavx2" } */
+
+long foo (long *p, int i)
+{
+ long x = 0;
+
+ while (--i)
+ x ^= p[i];
+
+ return x;
+}
diff --git a/gcc/testsuite/gfortran.dg/c_ptr_tests_17.f90 b/gcc/testsuite/gfortran.dg/c_ptr_tests_17.f90
new file mode 100644
index 00000000000..9bbd0dd41ad
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c_ptr_tests_17.f90
@@ -0,0 +1,88 @@
+! { dg-do compile }
+!
+! PR fortran/37829
+!
+! Contributed by James Van Buskirk and Jerry DeLisle.
+!
+! Fix derived-type loading with ISO_BIND_C's C_PTR/C_FUNPTR.
+
+module m3
+ use ISO_C_BINDING
+ implicit none
+ private
+
+ public kill_C_PTR
+ interface
+ function kill_C_PTR() bind(C)
+ import
+ implicit none
+ type(C_PTR) kill_C_PTR
+ end function kill_C_PTR
+ end interface
+
+ public kill_C_FUNPTR
+ interface
+ function kill_C_FUNPTR() bind(C)
+ import
+ implicit none
+ type(C_FUNPTR) kill_C_FUNPTR
+ end function kill_C_FUNPTR
+ end interface
+end module m3
+
+module m1
+ use m3
+end module m1
+
+program X
+ use m1
+ use ISO_C_BINDING
+ implicit none
+ type(C_PTR) cp
+ type(C_FUNPTR) fp
+ integer(C_INT),target :: i
+ interface
+ function fun() bind(C)
+ use ISO_C_BINDING
+ implicit none
+ real(C_FLOAT) fun
+ end function fun
+ end interface
+
+ cp = C_NULL_PTR
+ cp = C_LOC(i)
+ fp = C_NULL_FUNPTR
+ fp = C_FUNLOC(fun)
+end program X
+
+function fun() bind(C)
+ use ISO_C_BINDING
+ implicit none
+ real(C_FLOAT) fun
+ fun = 1.0
+end function fun
+
+function kill_C_PTR() bind(C)
+ use ISO_C_BINDING
+ implicit none
+ type(C_PTR) kill_C_PTR
+ integer(C_INT), pointer :: p
+ allocate(p)
+ kill_C_PTR = C_LOC(p)
+end function kill_C_PTR
+
+function kill_C_FUNPTR() bind(C)
+ use ISO_C_BINDING
+ implicit none
+ type(C_FUNPTR) kill_C_FUNPTR
+ interface
+ function fun() bind(C)
+ use ISO_C_BINDING
+ implicit none
+ real(C_FLOAT) fun
+ end function fun
+ end interface
+ kill_C_FUNPTR = C_FUNLOC(fun)
+end function kill_C_FUNPTR
+
+! { dg-final { cleanup-modules "m3 m1" } }
diff --git a/gcc/testsuite/gfortran.dg/c_ptr_tests_18.f90 b/gcc/testsuite/gfortran.dg/c_ptr_tests_18.f90
new file mode 100644
index 00000000000..6239516ec2e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/c_ptr_tests_18.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+!
+! PR fortran/37829
+! PR fortran/45190
+!
+! Contributed by Mat Cross
+!
+! Fix derived-type loading with ISO_BIND_C's C_PTR/C_FUNPTR.
+
+MODULE NAG_J_TYPES
+ USE ISO_C_BINDING, ONLY : C_PTR
+ IMPLICIT NONE
+ TYPE :: NAG_IMAGE
+ INTEGER :: WIDTH, HEIGHT, PXFMT, NCHAN
+ TYPE (C_PTR) :: PIXELS
+ END TYPE NAG_IMAGE
+END MODULE NAG_J_TYPES
+program cfpointerstress
+ use nag_j_types
+ use iso_c_binding
+ implicit none
+ type(nag_image),pointer :: img
+ type(C_PTR) :: ptr
+ real, pointer :: r
+ allocate(r)
+ allocate(img)
+ r = 12
+ ptr = c_loc(img)
+ write(*,*) 'C_ASSOCIATED =', C_ASSOCIATED(ptr)
+ call c_f_pointer(ptr, img)
+ write(*,*) 'ASSOCIATED =', associated(img)
+ deallocate(r)
+end program cfpointerstress
+
+! { dg-final { cleanup-modules "nag_j_types" } }
diff --git a/gcc/testsuite/gfortran.dg/constructor_1.f90 b/gcc/testsuite/gfortran.dg/constructor_1.f90
new file mode 100644
index 00000000000..e8fe03ac38c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/constructor_1.f90
@@ -0,0 +1,42 @@
+! { dg-do compile }
+!
+! PR fortran/39427
+!
+! Check constructor functionality.
+!
+! Contributed by Damian Rouson.
+!
+module mycomplex_module
+ private
+ public :: mycomplex
+ type mycomplex
+! private
+ real :: argument, modulus
+ end type
+ interface mycomplex
+ module procedure complex_to_mycomplex, two_reals_to_mycomplex
+ end interface
+! :
+ contains
+ type(mycomplex) function complex_to_mycomplex(c)
+ complex, intent(in) :: c
+! :
+ end function complex_to_mycomplex
+ type(mycomplex) function two_reals_to_mycomplex(x,y)
+ real, intent(in) :: x
+ real, intent(in), optional :: y
+! :
+ end function two_reals_to_mycomplex
+! :
+ end module mycomplex_module
+! :
+program myuse
+ use mycomplex_module
+ type(mycomplex) :: a, b, c
+! :
+ a = mycomplex(argument=5.6, modulus=1.0) ! The structure constructor
+ c = mycomplex(x=0.0, y=1.0) ! A function reference
+ c = mycomplex(0.0, 1.0) ! A function reference
+end program myuse
+
+! { dg-final { cleanup-modules "mycomplex_module" } }
diff --git a/gcc/testsuite/gfortran.dg/constructor_2.f90 b/gcc/testsuite/gfortran.dg/constructor_2.f90
new file mode 100644
index 00000000000..0e3d8af29f3
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/constructor_2.f90
@@ -0,0 +1,73 @@
+! { dg-do run }
+!
+! PR fortran/39427
+!
+module foo_module
+ interface foo
+ procedure constructor
+ end interface
+
+ type foo
+ integer :: bar
+ end type
+contains
+ type(foo) function constructor()
+ constructor%bar = 1
+ end function
+
+ subroutine test_foo()
+ type(foo) :: f
+ f = foo()
+ if (f%bar /= 1) call abort ()
+ f = foo(2)
+ if (f%bar /= 2) call abort ()
+ end subroutine test_foo
+end module foo_module
+
+
+! Same as foo_module but order
+! of INTERFACE and TYPE reversed
+module bar_module
+ type bar
+ integer :: bar
+ end type
+
+ interface bar
+ procedure constructor
+ end interface
+contains
+ type(bar) function constructor()
+ constructor%bar = 3
+ end function
+
+ subroutine test_bar()
+ type(bar) :: f
+ f = bar()
+ if (f%bar /= 3) call abort ()
+ f = bar(4)
+ if (f%bar /= 4) call abort ()
+ end subroutine test_bar
+end module bar_module
+
+program main
+ use foo_module
+ use bar_module
+ implicit none
+
+ type(foo) :: f
+ type(bar) :: b
+
+ call test_foo()
+ f = foo()
+ if (f%bar /= 1) call abort ()
+ f = foo(2)
+ if (f%bar /= 2) call abort ()
+
+ call test_bar()
+ b = bar()
+ if (b%bar /= 3) call abort ()
+ b = bar(4)
+ if (b%bar /= 4) call abort ()
+end program main
+
+! { dg-final { cleanup-tree-dump "foo_module bar_module" } }
diff --git a/gcc/testsuite/gfortran.dg/constructor_3.f90 b/gcc/testsuite/gfortran.dg/constructor_3.f90
new file mode 100644
index 00000000000..4015090bced
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/constructor_3.f90
@@ -0,0 +1,47 @@
+! { dg-do run }
+!
+! PR fortran/39427
+!
+! Check constructor functionality.
+!
+!
+module m
+ interface cons
+ procedure cons42
+ end interface cons
+contains
+ integer function cons42()
+ cons42 = 42
+ end function cons42
+end module m
+
+
+module m2
+ type cons
+ integer :: j = -1
+ end type cons
+ interface cons
+ procedure consT
+ end interface cons
+contains
+ type(cons) function consT(k)
+ integer :: k
+ consT%j = k**2
+ end function consT
+end module m2
+
+
+use m
+use m2, only: cons
+implicit none
+type(cons) :: x
+integer :: k
+x = cons(3)
+k = cons()
+if (x%j /= 9) call abort ()
+if (k /= 42) call abort ()
+!print *, x%j
+!print *, k
+end
+
+! { dg-final { cleanup-modules "m m2" } }
diff --git a/gcc/testsuite/gfortran.dg/constructor_4.f90 b/gcc/testsuite/gfortran.dg/constructor_4.f90
new file mode 100644
index 00000000000..34dfba80c27
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/constructor_4.f90
@@ -0,0 +1,33 @@
+! { dg-do compile }
+! { dg-options "-std=f95" }
+!
+! PR fortran/39427
+!
+! Check constructor functionality.
+!
+!
+module m
+ type t ! { dg-error "the same name as derived type" }
+ integer :: x
+ end type t
+ interface t
+ module procedure f
+ end interface t
+contains
+ function f() ! { dg-error "the same name as derived type" }
+ type(t) :: f
+ end function
+end module
+
+module m2
+ interface t2
+ module procedure f2
+ end interface t2
+ type t2 ! { dg-error "the same name as derived type" }
+ integer :: x2
+ end type t2
+contains
+ function f2() ! { dg-error "the same name as derived type" }
+ type(t2) :: f2
+ end function
+end module
diff --git a/gcc/testsuite/gfortran.dg/constructor_5.f90 b/gcc/testsuite/gfortran.dg/constructor_5.f90
new file mode 100644
index 00000000000..ab9c9f2f5e3
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/constructor_5.f90
@@ -0,0 +1,34 @@
+! { dg-do compile }
+!
+! PR fortran/39427
+!
+! Check constructor functionality.
+!
+!
+module m
+ type t
+ integer :: x
+ end type t
+ interface t
+ module procedure f
+ end interface t
+contains
+ function f()
+ type(t) :: f
+ end function
+end module
+
+module m2
+ interface t2
+ module procedure f2
+ end interface t2
+ type t2
+ integer :: x2
+ end type t2
+contains
+ function f2()
+ type(t2) :: f2
+ end function
+end module
+
+! { dg-final { cleanup-modules "m m2" } }
diff --git a/gcc/testsuite/gfortran.dg/constructor_6.f90 b/gcc/testsuite/gfortran.dg/constructor_6.f90
new file mode 100644
index 00000000000..00b99f2eba6
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/constructor_6.f90
@@ -0,0 +1,171 @@
+! { dg-do run }
+!
+! PR fortran/39427
+!
+! Contributed by Norman S. Clerman (in PR fortran/45155)
+!
+! Constructor test case
+!
+!
+module test_cnt
+ integer, public, save :: my_test_cnt = 0
+end module test_cnt
+
+module Rational
+ use test_cnt
+ implicit none
+ private
+
+ type, public :: rational_t
+ integer :: n = 0, id = 1
+ contains
+ procedure, nopass :: Construct_rational_t
+ procedure :: Print_rational_t
+ procedure, private :: Rational_t_init
+ generic :: Rational_t => Construct_rational_t
+ generic :: print => Print_rational_t
+ end type rational_t
+
+contains
+
+ function Construct_rational_t (message_) result (return_type)
+ character (*), intent (in) :: message_
+ type (rational_t) :: return_type
+
+! print *, trim (message_)
+ if (my_test_cnt /= 1) call abort()
+ my_test_cnt = my_test_cnt + 1
+ call return_type % Rational_t_init
+
+ end function Construct_rational_t
+
+ subroutine Print_rational_t (this_)
+ class (rational_t), intent (in) :: this_
+
+! print *, "n, id", this_% n, this_% id
+ if (my_test_cnt == 0) then
+ if (this_% n /= 0 .or. this_% id /= 1) call abort ()
+ else if (my_test_cnt == 2) then
+ if (this_% n /= 10 .or. this_% id /= 0) call abort ()
+ else
+ call abort ()
+ end if
+ my_test_cnt = my_test_cnt + 1
+ end subroutine Print_rational_t
+
+ subroutine Rational_t_init (this_)
+ class (rational_t), intent (in out) :: this_
+
+ this_% n = 10
+ this_% id = 0
+
+ end subroutine Rational_t_init
+
+end module Rational
+
+module Temp_node
+ use test_cnt
+ implicit none
+ private
+
+ real, parameter :: NOMINAL_TEMP = 20.0
+
+ type, public :: temp_node_t
+ real :: temperature = NOMINAL_TEMP
+ integer :: id = 1
+ contains
+ procedure :: Print_temp_node_t
+ procedure, private :: Temp_node_t_init
+ generic :: Print => Print_temp_node_t
+ end type temp_node_t
+
+ interface temp_node_t
+ module procedure Construct_temp_node_t
+ end interface
+
+contains
+
+ function Construct_temp_node_t (message_) result (return_type)
+ character (*), intent (in) :: message_
+ type (temp_node_t) :: return_type
+
+ !print *, trim (message_)
+ if (my_test_cnt /= 4) call abort()
+ my_test_cnt = my_test_cnt + 1
+ call return_type % Temp_node_t_init
+
+ end function Construct_temp_node_t
+
+ subroutine Print_temp_node_t (this_)
+ class (temp_node_t), intent (in) :: this_
+
+! print *, "temp, id", this_% temperature, this_% id
+ if (my_test_cnt == 3) then
+ if (this_% temperature /= 20 .or. this_% id /= 1) call abort ()
+ else if (my_test_cnt == 5) then
+ if (this_% temperature /= 10 .or. this_% id /= 0) call abort ()
+ else
+ call abort ()
+ end if
+ my_test_cnt = my_test_cnt + 1
+ end subroutine Print_temp_node_t
+
+ subroutine Temp_node_t_init (this_)
+ class (temp_node_t), intent (in out) :: this_
+
+ this_% temperature = 10.0
+ this_% id = 0
+
+ end subroutine Temp_node_t_init
+
+end module Temp_node
+
+program Struct_over
+ use test_cnt
+ use Rational, only : rational_t
+ use Temp_node, only : temp_node_t
+
+ implicit none
+
+ type (rational_t) :: sample_rational_t
+ type (temp_node_t) :: sample_temp_node_t
+
+! print *, "rational_t"
+! print *, "----------"
+! print *, ""
+!
+! print *, "after declaration"
+ if (my_test_cnt /= 0) call abort()
+ call sample_rational_t % print
+
+ if (my_test_cnt /= 1) call abort()
+
+ sample_rational_t = sample_rational_t % rational_t ("using override")
+ if (my_test_cnt /= 2) call abort()
+! print *, "after override"
+ ! call print (sample_rational_t)
+ ! call sample_rational_t % print ()
+ call sample_rational_t % print
+
+ if (my_test_cnt /= 3) call abort()
+
+! print *, "sample_t"
+! print *, "--------"
+! print *, ""
+!
+! print *, "after declaration"
+ call sample_temp_node_t % print
+
+ if (my_test_cnt /= 4) call abort()
+
+ sample_temp_node_t = temp_node_t ("using override")
+ if (my_test_cnt /= 5) call abort()
+! print *, "after override"
+ ! call print (sample_rational_t)
+ ! call sample_rational_t % print ()
+ call sample_temp_node_t % print
+ if (my_test_cnt /= 6) call abort()
+
+end program Struct_over
+
+! { dg-final { cleanup-modules "test_cnt rational temp_node" } }
diff --git a/gcc/testsuite/gfortran.dg/function_types_3.f90 b/gcc/testsuite/gfortran.dg/function_types_3.f90
index 8d00f5f7f1e..49d5d5f561b 100644
--- a/gcc/testsuite/gfortran.dg/function_types_3.f90
+++ b/gcc/testsuite/gfortran.dg/function_types_3.f90
@@ -14,6 +14,6 @@ end
! PR 50403: SIGSEGV in gfc_use_derived
-type(f) function f() ! { dg-error "conflicts with DERIVED attribute|is not accessible" }
+type(f) function f() ! { dg-error "Type name 'f' at .1. conflicts with previously declared entity|The type for function 'f' at .1. is not accessible" }
f=110 ! { dg-error "Unclassifiable statement" }
end
diff --git a/gcc/testsuite/gfortran.dg/result_1.f90 b/gcc/testsuite/gfortran.dg/result_1.f90
index 162ffaf5857..96d2a1febe5 100644
--- a/gcc/testsuite/gfortran.dg/result_1.f90
+++ b/gcc/testsuite/gfortran.dg/result_1.f90
@@ -14,5 +14,10 @@ namelist /s/ a,b,c ! { dg-error "attribute conflicts" }
end function
function h() result(t)
-type t ! { dg-error "attribute conflicts" }
+type t ! { dg-error "GENERIC attribute conflicts with RESULT attribute" }
+end type t ! { dg-error "Expecting END FUNCTION statement" }
+end function
+
+function i() result(t)
+type t ! { dg-error "GENERIC attribute conflicts with RESULT attribute" }
end function
diff --git a/gcc/testsuite/gfortran.dg/structure_constructor_3.f03 b/gcc/testsuite/gfortran.dg/structure_constructor_3.f03
index aa5934951c4..5fb7d612d0e 100644
--- a/gcc/testsuite/gfortran.dg/structure_constructor_3.f03
+++ b/gcc/testsuite/gfortran.dg/structure_constructor_3.f03
@@ -13,6 +13,6 @@ PROGRAM test
TYPE(basics_t) :: basics
- basics = basics_t (i=42, 1.5) ! { dg-error "without name after" }
+ basics = basics_t (i=42, 1.5) ! { dg-error "Missing keyword name" }
END PROGRAM test
diff --git a/gcc/testsuite/gfortran.dg/structure_constructor_4.f03 b/gcc/testsuite/gfortran.dg/structure_constructor_4.f03
index 647be5fbb7d..8a5aaa7a23f 100644
--- a/gcc/testsuite/gfortran.dg/structure_constructor_4.f03
+++ b/gcc/testsuite/gfortran.dg/structure_constructor_4.f03
@@ -14,6 +14,6 @@ PROGRAM test
TYPE(basics_t) :: basics
basics = basics_t (42, r=1.5, i=15) ! { dg-error "'i' is initialized twice" }
- basics = basics_t (42, r=1., r=-2.) ! { dg-error "'r' is initialized twice" }
+ basics = basics_t (42, r=1., r=-2.) ! { dg-error "has already appeared in the current argument list" }
END PROGRAM test
diff --git a/gcc/testsuite/gfortran.dg/type_decl_3.f90 b/gcc/testsuite/gfortran.dg/type_decl_3.f90
new file mode 100644
index 00000000000..a3fc54ad326
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/type_decl_3.f90
@@ -0,0 +1,7 @@
+! { dg-do compile }
+!
+! PR fortran/39427
+!
+ subroutine t(x) ! { dg-error "conflicts with previously declared entity" }
+ type(t) :: x ! { dg-error "conflicts with previously declared entity" }
+ end subroutine t
diff --git a/gcc/testsuite/gfortran.dg/use_only_5.f90 b/gcc/testsuite/gfortran.dg/use_only_5.f90
new file mode 100644
index 00000000000..56d33f42750
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/use_only_5.f90
@@ -0,0 +1,38 @@
+! { dg-do compile }
+!
+! PR fortran/39427
+!
+! Test case was failing with the initial version of the
+! constructor patch.
+!
+! Based on the Fortran XML library FoX
+
+module m_common_attrs
+ implicit none
+ private
+
+ type dict_item
+ integer, allocatable :: i(:)
+ end type dict_item
+
+ type dictionary_t
+ private
+ type(dict_item), pointer :: d => null()
+ end type dictionary_t
+
+ public :: dictionary_t
+ public :: get_prefix_by_index
+
+contains
+ pure function get_prefix_by_index(dict) result(prefix)
+ type(dictionary_t), intent(in) :: dict
+ character(len=size(dict%d%i)) :: prefix
+ end function get_prefix_by_index
+end module m_common_attrs
+
+module m_common_namespaces
+ use m_common_attrs, only: dictionary_t
+ use m_common_attrs, only: get_prefix_by_index
+end module m_common_namespaces
+
+! { dg-final { cleanup-modules "m_common_attrs m_common_namespaces" } }
diff --git a/gcc/testsuite/gfortran.dg/used_types_25.f90 b/gcc/testsuite/gfortran.dg/used_types_25.f90
new file mode 100644
index 00000000000..35ac8c75b86
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/used_types_25.f90
@@ -0,0 +1,17 @@
+! { dg-do compile }
+!
+! Created to check this ambiguity when
+! constructors were added. Cf. PR fortran/39427
+
+module m
+ type t
+ end type t
+end module m
+
+use m
+ type t ! { dg-error "Derived type definition of 't' at .1. has already been defined" }
+ end type t ! { dg-error "Expecting END PROGRAM statement" }
+end
+
+! { dg-final { cleanup-modules "m" } }
+
diff --git a/gcc/testsuite/gfortran.dg/used_types_26.f90 b/gcc/testsuite/gfortran.dg/used_types_26.f90
new file mode 100644
index 00000000000..2c0437f63e1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/used_types_26.f90
@@ -0,0 +1,22 @@
+! { dg-do compile }
+!
+! Check for ambiguity.
+!
+! Added as part of the constructor work (PR fortran/39427).
+!
+ module m
+ type t
+ end type t
+ end module m
+
+ module m2
+ type t
+ end type t
+ end module m2
+
+ use m
+ use m2
+ type(t) :: x ! { dg-error "Type name 't' at .1. is ambiguous" }
+ end
+
+! { dg-final { cleanup-modules "m m2" } }
diff --git a/gcc/testsuite/gnat.dg/discr32.adb b/gcc/testsuite/gnat.dg/discr32.adb
new file mode 100644
index 00000000000..830a6dfd59a
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/discr32.adb
@@ -0,0 +1,21 @@
+-- { dg-do run }
+-- { dg-options "-gnatws" }
+
+with Discr32_Pkg; use Discr32_Pkg;
+
+procedure Discr32 is
+begin
+
+ if R1'Object_Size /= 32 then
+ raise Program_Error;
+ end if;
+
+ if R2'Object_Size /= R'Object_Size then
+ raise Program_Error;
+ end if;
+
+ if R3'Object_Size /= 64 then
+ raise Program_Error;
+ end if;
+
+end;
diff --git a/gcc/testsuite/gnat.dg/discr32_pkg.ads b/gcc/testsuite/gnat.dg/discr32_pkg.ads
new file mode 100644
index 00000000000..f1761e4b5e5
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/discr32_pkg.ads
@@ -0,0 +1,24 @@
+package Discr32_Pkg is
+
+ type Enum is (One, Two, Three);
+
+ type R (D : Enum) is record
+ case D is
+ when One => B : Boolean;
+ when Two => I : Integer;
+ when Three => F : Float;
+ end case;
+ end record;
+
+ for R use record
+ D at 0 range 0 .. 1;
+ B at 1 range 0 .. 0;
+ I at 4 range 0 .. 31 + 128;
+-- F at 4 range 0 .. 31;
+ end record;
+
+ subtype R1 is R (One);
+ subtype R2 is R (Two);
+ subtype R3 is R (Three);
+
+end Discr32_Pkg;
diff --git a/gcc/testsuite/lib/gcc-simulate-thread.exp b/gcc/testsuite/lib/gcc-simulate-thread.exp
index 1fea404a9c7..9be5da317b9 100644
--- a/gcc/testsuite/lib/gcc-simulate-thread.exp
+++ b/gcc/testsuite/lib/gcc-simulate-thread.exp
@@ -22,15 +22,6 @@
# Call 'fail' if a given test printed "FAIL:", otherwise call 'pass'.
proc simulate-thread { args } {
-
- # ??? Exit immediately if this is alpha*-*-linux* target, single-stepping
- # executable between ldl_l and stl_c insns in gdb breaks LL/SC chaining.
- if { [istarget alpha*-*-linux*] } { return }
-
- # GNU gdb 6.3 on powerpc-darwin also on these (and expect does not appear
- # to be able to terminate them).
- if { [istarget powerpc*-*-darwin*] } { return }
-
if { ![isnative] || [is_remote target] } { return }
if { [llength $args] == 1 } {
@@ -54,35 +45,39 @@ proc simulate-thread { args } {
return
}
+ set message "thread simulation test"
+
send_log "Spawning: $gdb_name -nx -nw -quiet -x $cmd_file ./$exec_file\n"
set res [remote_spawn target "$gdb_name -nx -nw -x $cmd_file ./$exec_file"]
if { $res < 0 || $res == "" } {
- unsupported "$testcase"
+ unsupported "$testcase $message"
return
}
set gdb_worked 0
- remote_expect target [timeout_value] {
+
+ # Set timeout to 10 seconds due to huge amount of generated log.
+ remote_expect target 10 {
# Too old GDB
-re "Unhandled dwarf expression|Error in sourced command file" {
- unsupported "$testcase"
+ unsupported "$testcase $message"
remote_close target
return
}
-re "FAIL:" {
- fail "$testcase"
+ fail "$testcase $message"
remote_close target
return
}
- # If the gdb output contained simulate_thread_main, assume
+ # If the gdb output contained simulate_thread_done, assume
# that at the very least, we had a working gdb that was able
- # to break in simulate_thread_main.
- -re "simulate_thread_main" {
+ # to break in simulate_thread_done.
+ -re "simulate_thread_done" {
set gdb_worked 1
exp_continue
}
timeout {
- unsupported "$testcase"
+ fail "$testcase $message"
remote_close target
return
}
@@ -90,10 +85,10 @@ proc simulate-thread { args } {
remote_close target
if {$gdb_worked} {
- pass "$testcase"
+ pass "$testcase $message"
} else {
- # Fail in the absence of a sane GDB.
- fail "$testcase"
+ # Unsupported in the absence of a sane GDB.
+ unsupported "$testcase $message"
}
return
}
diff --git a/gcc/tracer.c b/gcc/tracer.c
index d3523b985b1..602e7580d99 100644
--- a/gcc/tracer.c
+++ b/gcc/tracer.c
@@ -90,10 +90,19 @@ bb_seen_p (basic_block bb)
static bool
ignore_bb_p (const_basic_block bb)
{
+ gimple g;
+
if (bb->index < NUM_FIXED_BLOCKS)
return true;
if (optimize_bb_for_size_p (bb))
return true;
+
+ /* A transaction is a single entry multiple exit region. It must be
+ duplicated in its entirety or not at all. */
+ g = last_stmt (CONST_CAST_BB (bb));
+ if (g && gimple_code (g) == GIMPLE_TRANSACTION)
+ return true;
+
return false;
}
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index 89d123d65e9..565bf57b752 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -1389,13 +1389,30 @@ initialize_data_dependence_relation (struct data_reference *a,
the data dependence tests, just initialize the ddr and return. */
if (operand_equal_p (DR_REF (a), DR_REF (b), 0))
{
+ if (loop_nest
+ && !object_address_invariant_in_loop_p (VEC_index (loop_p, loop_nest, 0),
+ DR_BASE_OBJECT (a)))
+ {
+ DDR_ARE_DEPENDENT (res) = chrec_dont_know;
+ return res;
+ }
DDR_AFFINE_P (res) = true;
DDR_ARE_DEPENDENT (res) = NULL_TREE;
DDR_SUBSCRIPTS (res) = VEC_alloc (subscript_p, heap, DR_NUM_DIMENSIONS (a));
DDR_LOOP_NEST (res) = loop_nest;
DDR_INNER_LOOP (res) = 0;
DDR_SELF_REFERENCE (res) = true;
- compute_self_dependence (res);
+ for (i = 0; i < DR_NUM_DIMENSIONS (a); i++)
+ {
+ struct subscript *subscript;
+
+ subscript = XNEW (struct subscript);
+ SUB_CONFLICTS_IN_A (subscript) = conflict_fn_not_known ();
+ SUB_CONFLICTS_IN_B (subscript) = conflict_fn_not_known ();
+ SUB_LAST_CONFLICT (subscript) = chrec_dont_know;
+ SUB_DISTANCE (subscript) = chrec_dont_know;
+ VEC_safe_push (subscript_p, heap, DDR_SUBSCRIPTS (res), subscript);
+ }
return res;
}
@@ -4040,8 +4057,7 @@ compute_affine_dependence (struct data_dependence_relation *ddr,
}
/* Analyze only when the dependence relation is not yet known. */
- if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE
- && !DDR_SELF_REFERENCE (ddr))
+ if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE)
{
dependence_stats.num_dependence_tests++;
@@ -4122,31 +4138,11 @@ compute_affine_dependence (struct data_dependence_relation *ddr,
void
compute_self_dependence (struct data_dependence_relation *ddr)
{
- unsigned int i;
- struct subscript *subscript;
-
if (DDR_ARE_DEPENDENT (ddr) != NULL_TREE)
return;
- for (i = 0; VEC_iterate (subscript_p, DDR_SUBSCRIPTS (ddr), i, subscript);
- i++)
- {
- if (SUB_CONFLICTS_IN_A (subscript))
- free_conflict_function (SUB_CONFLICTS_IN_A (subscript));
- if (SUB_CONFLICTS_IN_B (subscript))
- free_conflict_function (SUB_CONFLICTS_IN_B (subscript));
-
- /* The accessed index overlaps for each iteration. */
- SUB_CONFLICTS_IN_A (subscript)
- = conflict_fn (1, affine_fn_cst (integer_zero_node));
- SUB_CONFLICTS_IN_B (subscript)
- = conflict_fn (1, affine_fn_cst (integer_zero_node));
- SUB_LAST_CONFLICT (subscript) = chrec_dont_know;
- }
-
- /* The distance vector is the zero vector. */
- save_dist_v (ddr, lambda_vector_new (DDR_NB_LOOPS (ddr)));
- save_dir_v (ddr, lambda_vector_new (DDR_NB_LOOPS (ddr)));
+ if (DDR_LOOP_NEST (ddr))
+ compute_affine_dependence (ddr, VEC_index (loop_p, DDR_LOOP_NEST (ddr), 0));
}
/* Compute in DEPENDENCE_RELATIONS the data dependence graph for all
@@ -4179,7 +4175,8 @@ compute_all_dependences (VEC (data_reference_p, heap) *datarefs,
{
ddr = initialize_data_dependence_relation (a, a, loop_nest);
VEC_safe_push (ddr_p, heap, *dependence_relations, ddr);
- compute_self_dependence (ddr);
+ if (loop_nest)
+ compute_affine_dependence (ddr, VEC_index (loop_p, loop_nest, 0));
}
}
diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c
index 4de45001e67..45060f70eb0 100644
--- a/gcc/tree-outof-ssa.c
+++ b/gcc/tree-outof-ssa.c
@@ -1021,6 +1021,8 @@ insert_backedge_copies (void)
basic_block bb;
gimple_stmt_iterator gsi;
+ mark_dfs_back_edges ();
+
FOR_EACH_BB (bb)
{
/* Mark block as possibly needing calculation of UIDs. */
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index 2a2c13393fe..b8a056ebdac 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -374,7 +374,8 @@ mark_all_vars_used_1 (tree *tp, int *walk_subtrees, void *data)
eliminated as unused. */
if (TREE_CODE (t) == VAR_DECL)
{
- if (data != NULL && bitmap_clear_bit ((bitmap) data, DECL_UID (t)))
+ if (data != NULL && bitmap_clear_bit ((bitmap) data, DECL_UID (t))
+ && DECL_CONTEXT (t) == current_function_decl)
mark_all_vars_used (&DECL_INITIAL (t), data);
set_is_used (t);
}
@@ -836,7 +837,8 @@ remove_unused_locals (void)
if (TREE_CODE (var) == VAR_DECL
&& is_global_var (var)
&& var_ann (var) != NULL
- && is_used_p (var))
+ && is_used_p (var)
+ && DECL_CONTEXT (var) == current_function_decl)
mark_all_vars_used (&DECL_INITIAL (var), global_unused_vars);
num = VEC_length (tree, cfun->local_decls);