diff options
Diffstat (limited to 'gcc')
120 files changed, 4326 insertions, 1706 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a29383083b3..67a4645a87a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,376 @@ +2014-04-28 Richard Biener <rguenther@suse.de> + + * tree-vrp.c (vrp_var_may_overflow): Remove. + (vrp_visit_phi_node): Rather than bumping to +-INF possibly + with overflow immediately bump to one before that value and + let iteration figure out overflow status. + +2014-04-28 Richard Biener <rguenther@suse.de> + + * configure.ac: Do valgrind header checks unconditionally. + Add --enable-valgrind-annotations. + * system.h: Guard valgrind header inclusion with + ENABLE_VALGRIND_ANNOTATIONS instead of ENABLE_VALGRIND_CHECKING. + * alloc-pool.c (pool_alloc, pool_free): Use + ENABLE_VALGRIND_ANNOTATIONS instead of ENABLE_VALGRIND_CHECKING + to guard possibly dead code. + * config.in: Regenerated. + * configure: Likewise. + +2014-04-28 Jeff Law <law@redhat.com> + + PR tree-optimization/60902 + * tree-ssa-threadedge.c + (record_temporary_equivalences_from_stmts_at_dest): Only iterate + over real defs when invalidating outputs from statements that do not + produce useful outputs for threading. + +2014-04-28 Richard Biener <rguenther@suse.de> + + PR tree-optimization/60979 + * graphite-scop-detection.c (scopdet_basic_block_info): Reject + SCOPs that end in a block with a successor with abnormal + predecessors. + +2014-04-28 Richard Biener <rguenther@suse.de> + + * tree-pass.h (execute_pass_list): Adjust prototype. + * passes.c (pass_manager::execute_early_local_passes): + Adjust. + (do_per_function): Change callback signature, push all actual + work to the callbals. + (do_per_function_toporder): Likewise. + (execute_function_dump): Adjust. + (execute_function_todo): Likewise. + (clear_last_verified): Likewise. + (verify_curr_properties): Likewise. + (update_properties_after_pass): Likewise. + (execute_pass_list_1): Split out from ... + (execute_pass_list): ... here. Adjust. + (execute_ipa_pass_list): Likewise. + * cgraphunit.c (cgraph_add_new_function): Adjust. + (analyze_function): Likewise. + (expand_function): Likewise. + * cgraph.c (release_function_body): Free dominance info + here instead of asserting it was magically freed elsewhere. + +2014-04-28 Eric Botcazou <ebotcazou@adacore.com> + + * configure.ac: Tweak GAS check for LEON instructions on SPARC. + * configure: Regenerate. + * config/sparc/sparc.opt (muser-mode): New option. + * config/sparc/sync.md (atomic_compare_and_swap<mode>_1): Do not enable + for LEON3. + (atomic_compare_and_swap_leon3_1): New instruction for LEON3. + * doc/invoke.texi (SPARC options): Document -muser-mode. + +2014-04-27 Richard Sandiford <rdsandiford@googlemail.com> + + * cselib.c (find_slot_memmode): Delete. + (cselib_hasher): Change compare_type to a struct. + (cselib_hasher::equal): Update accordingly. Don't expect wrapped + constants. + (preserve_constants_and_equivs): Adjust for new compare_type. + (cselib_find_slot): Likewise. Take the mode of the rtx as argument. + (wrap_constant): Delete. + (cselib_lookup_mem, cselib_lookup_1): Update calls to cselib_find_slot. + +2014-04-26 Markus Trippelsdorf <markus@trippelsdorf.de> + + * doc/install.texi (Building with profile feedback): Remove + outdated sentence. + +2014-04-26 Tom de Vries <tom@codesourcery.com> + + * config/i386/i386.md (define_expand "ldexpxf3"): Fix out-of-bounds + array accesses. + +2014-04-25 Cary Coutant <ccoutant@google.com> + + PR debug/60929 + * dwarf2out.c (should_move_die_to_comdat): A type definition + can contain a subprogram definition, but don't move it to a + comdat unit. + (clone_as_declaration): Copy DW_AT_abstract_origin attribute. + (generate_skeleton_bottom_up): Remove DW_AT_object_pointer attribute + from original DIE. + (clone_tree_hash): Rename to... + (clone_tree_partial): ...this; change callers. Copy + DW_TAG_subprogram DIEs as declarations. + (copy_decls_walk): Don't copy children of a declaration into a + type unit. + +2014-04-25 H.J. Lu <hongjiu.lu@intel.com> + + PR target/60969 + * config/i386/i386.md (*movsf_internal): Set MODE to SI for + alternative 12. + +2014-04-25 Jiong Wang <jiong.wang@arm.com> + + * config/arm/predicates.md (call_insn_operand): Add long_call check. + * config/arm/arm.md (sibcall, sibcall_value): Force the address to + reg for long_call. + * config/arm/arm.c (arm_function_ok_for_sibcall): Remove long_call + restriction. + +2014-04-25 Kyrylo Tkachov <kyrylo.tkachov@arm.com> + + * config/arm/arm.c (arm_cortex_a8_tune): Initialise + T16-related fields. + +2014-04-25 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR tree-optimization/60930 + * gimple-ssa-strength-reduction.c (create_mul_imm_cand): Reject + creating a multiply candidate by folding two constant + multiplicands when the result overflows. + +2014-04-25 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/60960 + * tree-vect-generic.c (expand_vector_operation): Only call + expand_vector_divmod if type's mode satisfies VECTOR_MODE_P. + +2014-04-25 Tom de Vries <tom@codesourcery.com> + + * expr.c (clobber_reg_mode): New function. + * expr.h (clobber_reg): New function. + +2014-04-25 Tom de Vries <tom@codesourcery.com> + + * rtlanal.c (find_all_hard_reg_sets): Note INSN_CALL_FUNCTION_USAGE + clobbers. + +2014-04-25 Radovan Obradovic <robradovic@mips.com> + Tom de Vries <tom@codesourcery.com> + + * rtlanal.c (find_all_hard_reg_sets): Add bool implicit parameter and + handle. + * rtl.h (find_all_hard_reg_sets): Add bool parameter. + * haifa-sched.c (recompute_todo_spec, check_clobbered_conditions): Add + new argument to find_all_hard_reg_sets call. + +2014-04-25 Kyrylo Tkachov <kyrylo.tkachov@arm.com> + + * config/arm/aarch-common.c (aarch_rev16_shright_mask_imm_p): + Use HOST_WIDE_INT_C for mask literal. + (aarch_rev16_shleft_mask_imm_p): Likewise. + +2014-04-25 Eric Botcazou <ebotcazou@adacore.com> + + PR target/60941 + * config/sparc/sparc.md (ashlsi3_extend): Delete. + +2014-04-25 Marc Glisse <marc.glisse@inria.fr> + + PR preprocessor/56540 + * config/i386/i386-c.c (ix86_target_macros): Define + __SIZEOF_FLOAT80__ and __SIZEOF_FLOAT128__. + +2014-04-25 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * configure.ac (tga_func): Remove. + (LIB_TLS_SPEC): Remove. + * configure: Regenerate. + * config.in: Regenerate. + * config/sol2.h (LIB_SPEC): Don't use LIB_TLS_SPEC. + +2014-04-25 Richard Biener <rguenther@suse.de> + + PR ipa/60912 + * tree-ssa-structalias.c (ipa_pta_execute): Compute direct + call stmt use/clobber sets during stmt walk instead of + walking the possibly incomplete set of caller edges. + +2014-04-25 Richard Biener <rguenther@suse.de> + + PR ipa/60911 + * passes.c (apply_ipa_transforms): Inline into only caller ... + (execute_one_pass): ... here. Properly bring in function + bodies for nodes we want to apply IPA transforms to. + +2014-04-24 Cong Hou <congh@google.com> + + PR tree-optimization/60896 + * tree-vect-patterns.c (vect_recog_dot_prod_pattern): Pick up + all statements in PATTERN_DEF_SEQ in recognized widen-mult pattern. + (vect_mark_pattern_stmts): Set the def type of all statements in + PATTERN_DEF_SEQ as vect_internal_def. + +2014-04-24 Michael Meissner <meissner@linux.vnet.ibm.com> + + * doc/extend.texi (PowerPC Built-in Functions): Document new + powerpc extended divide, bcd, pack/unpack 128-bit, builtin + functions. + (PowerPC AltiVec/VSX Built-in Functions): Likewise. + + * config/rs6000/predicates.md (const_0_to_3_operand): New + predicate to match 0..3 integer constants. + + * config/rs6000/rs6000-builtin.def (BU_DFP_MISC_1): Add new macros + to support adding miscellaneous builtin functions. + (BU_DFP_MISC_2): Likewise. + (BU_P7_MISC_1): Likewise. + (BU_P7_MISC_2): Likewise. + (BU_P8V_MISC_3): Likewise. + (BU_MISC_1): Likewise. + (BU_MISC_2): Likewise. + (DIVWE): Add extended divide builtin functions. + (DIVWEO): Likewise. + (DIVWEU): Likewise. + (DIVWEUO): Likewise. + (DIVDE): Likewise. + (DIVDEO): Likewise. + (DIVDEU): Likewise. + (DIVDEUO): Likewise. + (DXEX): Add decimal floating-point builtin functions. + (DXEXQ): Likewise. + (DDEDPD): Likewise. + (DDEDPDQ): Likewise. + (DENBCD): Likewise. + (DENBCDQ): Likewise. + (DIEX): Likewise. + (DIEXQ): Likewise. + (DSCLI): Likewise. + (DSCLIQ): Likewise. + (DSCRI): Likewise. + (DSCRIQ): Likewise. + (CDTBCD): Add new BCD builtin functions. + (CBCDTD): Likewise. + (ADDG6S): Likewise. + (BCDADD): Likewise. + (BCDADD_LT): Likewise. + (BCDADD_EQ): Likewise. + (BCDADD_GT): Likewise. + (BCDADD_OV): Likewise. + (BCDSUB): Likewise. + (BCDSUB_LT): Likewise. + (BCDSUB_EQ): Likewise. + (BCDSUB_GT): Likewise. + (BCDSUB_OV): Likewise. + (PACK_TD): Add new pack/unpack 128-bit type builtin functions. + (UNPACK_TD): Likewise. + (PACK_TF): Likewise. + (UNPACK_TF): Likewise. + (UNPACK_TF_0): Likewise. + (UNPACK_TF_1): Likewise. + (PACK_V1TI): Likewise. + (UNPACK_V1TI): Likewise. + + * config/rs6000/rs6000.c (rs6000_builtin_mask_calculate): Add + support for decimal floating point builtin functions. + (rs6000_expand_ternop_builtin): Add checks for the new builtin + functions that take constant arguments. + (rs6000_invalid_builtin): Add decimal floating point builtin + support. + (rs6000_init_builtins): Setup long double, _Decimal64, and + _Decimal128 types for new builtin functions. + (builtin_function_type): Set the unsigned flags appropriately for + the new builtin functions. + (rs6000_opt_masks): Add support for decimal floating point builtin + functions. + + * config/rs6000/rs6000.h (RS6000_BTM_DFP): Add support for decimal + floating point builtin functions. + (RS6000_BTM_COMMON): Likewise. + (RS6000_BTI_long_double): Likewise. + (RS6000_BTI_dfloat64): Likewise. + (RS6000_BTI_dfloat128): Likewise. + (long_double_type_internal_node): Likewise. + (dfloat64_type_internal_node): Likewise. + (dfloat128_type_internal_node): Likewise. + + * config/rs6000/altivec.h (UNSPEC_BCDADD): Add support for ISA + 2.07 bcd arithmetic instructions. + (UNSPEC_BCDSUB): Likewise. + (UNSPEC_BCD_OVERFLOW): Likewise. + (UNSPEC_BCD_ADD_SUB): Likewise. + (bcd_add_sub): Likewise. + (BCD_TEST): Likewise. + (bcd<bcd_add_sub>): Likewise. + (bcd<bcd_add_sub>_test): Likewise. + (bcd<bcd_add_sub>_test2): Likewise. + (bcd<bcd_add_sub>_<code>): Likewise. + (peephole2 for combined bcd ops): Likewise. + + * config/rs6000/dfp.md (UNSPEC_DDEDPD): Add support for new + decimal floating point builtin functions. + (UNSPEC_DENBCD): Likewise. + (UNSPEC_DXEX): Likewise. + (UNSPEC_DIEX): Likewise. + (UNSPEC_DSCLI): Likewise. + (UNSPEC_DSCRI): Likewise. + (D64_D128): Likewise. + (dfp_suffix): Likewise. + (dfp_ddedpd_<mode>): Likewise. + (dfp_denbcd_<mode>): Likewise. + (dfp_dxex_<mode>): Likewise. + (dfp_diex_<mode>): Likewise. + (dfp_dscli_<mode>): Likewise. + (dfp_dscri_<mode>): Likewise. + + * config/rs6000/rs6000.md (UNSPEC_ADDG6S): Add support for new BCD + builtin functions. + (UNSPEC_CDTBCD): Likewise. + (UNSPEC_CBCDTD): Likewise. + (UNSPEC_DIVE): Add support for new extended divide builtin + functions. + (UNSPEC_DIVEO): Likewise. + (UNSPEC_DIVEU): Likewise. + (UNSPEC_DIVEUO): Likewise. + (UNSPEC_UNPACK_128BIT): Add support for new builtin functions to + pack/unpack 128-bit types. + (UNSPEC_PACK_128BIT): Likewise. + (idiv_ldiv): New mode attribute to set the 32/64-bit divide type. + (udiv<mode>3): Use idiv_ldiv mode attribute. + (div<mode>3): Likewise. + (addg6s): Add new BCD builtin functions. + (cdtbcd): Likewise. + (cbcdtd): Likewise. + (UNSPEC_DIV_EXTEND): Add support for new extended divide + instructions. + (div_extend): Likewise. + (div<div_extend>_<mode>"): Likewise. + (FP128_64): Add support for new builtin functions to pack/unpack + 128-bit types. + (unpack<mode>): Likewise. + (unpacktf_0): Likewise. + (unpacktf_1): Likewise. + (unpack<mode>_dm): Likewise. + (unpack<mode>_nodm): Likewise. + (pack<mode>): Likewise. + (unpackv1ti): Likewise. + (packv1ti): Likewise. + +2014-04-24 Vishnu K S <Vishnu.k_s@atmel.com> + + * gcc/config/avr/avr.c: Add comment on why -fdelete-null-pointer-checks + is disabled. + +2014-04-24 Jakub Jelinek <jakub@redhat.com> + + * tree.h (OMP_CLAUSE_LINEAR_GIMPLE_SEQ): Define. + * gimplify.c (omp_is_private): Change last argument's type to int. + Only diagnose lastprivate if the simd argument is 1, only diagnose + linear if the simd argument is 2. + (gimplify_omp_for): Adjust omp_is_private callers. When adding + lastprivate or private, add the clause to OMP_FOR_CLAUSES. Pass + GOVD_EXPLICIT to omp_add_variable. For simd with collapse == 1 + create OMP_CLAUSE_LINEAR rather than OMP_CLAUSE_PRIVATE for var. + If var != decl and decl is in OMP_CLAUSE_LINEAR, gimplify decl + increment to OMP_CLAUSE_LINEAR_GIMPLE_SEQ. + * omp-low.c (scan_sharing_clauses, lower_lastprivate_clauses): Handle + OMP_CLAUSE_LINEAR_GIMPLE_SEQ. + * tree-nested.c (convert_nonlocal_omp_clauses, + convert_local_omp_clauses): Handle OMP_CLAUSE_LINEAR. + +2014-04-24 Segher Boessenkool <segher@kernel.crashing.org> + + PR target/60822 + * config/m68k/m68k.md (extendplussidi): Don't allow memory for + operand 1. + 2014-04-24 Dimitris Papavasiliou <dpapavas@gmail.com> * flag-types.h (enum ivar_visibility): Add. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index dd60d348052..2eee80b2cf1 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20140424 +20140428 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 6dc0c11ed3f..a31cd3c2f11 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,7 @@ +2014-04-26 Eric Botcazou <ebotcazou@adacore.com> + + * gnatvsn.ads (Library_Version): Bump to 4.10. + 2014-04-23 Eric Botcazou <ebotcazou@adacore.com> Revert diff --git a/gcc/ada/gnatvsn.ads b/gcc/ada/gnatvsn.ads index d1f95621b98..a0155fe7cb9 100644 --- a/gcc/ada/gnatvsn.ads +++ b/gcc/ada/gnatvsn.ads @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2013, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2014, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -82,7 +82,7 @@ package Gnatvsn is -- Prefix generated by binder. If it is changed, be sure to change -- GNAT.Compiler_Version.Ver_Prefix as well. - Library_Version : constant String := "4.9"; + Library_Version : constant String := "4.10"; -- Library version. This value must be updated when the compiler -- version number Gnat_Static_Version_String is updated. -- diff --git a/gcc/alloc-pool.c b/gcc/alloc-pool.c index dfb13ce55fb..87fbd8556fb 100644 --- a/gcc/alloc-pool.c +++ b/gcc/alloc-pool.c @@ -250,7 +250,7 @@ void * pool_alloc (alloc_pool pool) { alloc_pool_list header; -#ifdef ENABLE_VALGRIND_CHECKING +#ifdef ENABLE_VALGRIND_ANNOTATIONS int size; #endif @@ -265,7 +265,7 @@ pool_alloc (alloc_pool pool) } gcc_checking_assert (pool); -#ifdef ENABLE_VALGRIND_CHECKING +#ifdef ENABLE_VALGRIND_ANNOTATIONS size = pool->elt_size - offsetof (allocation_object, u.data); #endif @@ -334,7 +334,7 @@ void pool_free (alloc_pool pool, void *ptr) { alloc_pool_list header; -#if defined(ENABLE_VALGRIND_CHECKING) || defined(ENABLE_CHECKING) +#if defined(ENABLE_VALGRIND_ANNOTATIONS) || defined(ENABLE_CHECKING) int size; size = pool->elt_size - offsetof (allocation_object, u.data); #endif diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 1b466ac4b51..fb0d102eac3 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,20 @@ +2014-04-25 Marek Polacek <polacek@redhat.com> + + PR c/18079 + * c-common.c (handle_noinline_attribute): Warn if the attribute + conflicts with always_inline attribute. + (handle_always_inline_attribute): Warn if the attribute conflicts + with noinline attribute. + +2014-04-25 Marek Polacek <polacek@redhat.com> + + PR c/60156 + * c-common.c (check_main_parameter_types): Warn about variadic main. + +2014-04-24 Mike Stump <mikestump@comcast.net> + + * c.opt (Wshadow-ivar): Default to on. + 2014-04-24 Dimitris Papavasiliou <dpapavas@gmail.com> * c.opt (Wshadow-ivar, flocal-ivars, fivar-visibility): Add. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 347be6e8208..0afe2f5ab38 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -2229,6 +2229,10 @@ check_main_parameter_types (tree decl) if (argct > 0 && (argct < 2 || argct > 3)) pedwarn (input_location, OPT_Wmain, "%q+D takes only zero or two arguments", decl); + + if (stdarg_p (TREE_TYPE (decl))) + pedwarn (input_location, OPT_Wmain, + "%q+D declared as variadic function", decl); } /* vector_targets_convertible_p is used for vector pointer types. The @@ -6549,8 +6553,8 @@ handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args), { if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL) { - warning (OPT_Wattributes, "%qE attribute conflicts with attribute %s", - name, "cold"); + warning (OPT_Wattributes, "%qE attribute ignored due to conflict " + "with attribute %qs", name, "cold"); *no_add_attrs = true; } /* Most of the rest of the hot processing is done later with @@ -6577,8 +6581,8 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), { if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL) { - warning (OPT_Wattributes, "%qE attribute conflicts with attribute %s", - name, "hot"); + warning (OPT_Wattributes, "%qE attribute ignored due to conflict " + "with attribute %qs", name, "hot"); *no_add_attrs = true; } /* Most of the rest of the cold processing is done later with @@ -6651,7 +6655,16 @@ handle_noinline_attribute (tree *node, tree name, int ARG_UNUSED (flags), bool *no_add_attrs) { if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_UNINLINABLE (*node) = 1; + { + if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (*node))) + { + warning (OPT_Wattributes, "%qE attribute ignored due to conflict " + "with attribute %qs", name, "always_inline"); + *no_add_attrs = true; + } + else + DECL_UNINLINABLE (*node) = 1; + } else { warning (OPT_Wattributes, "%qE attribute ignored", name); @@ -6689,9 +6702,16 @@ handle_always_inline_attribute (tree *node, tree name, { if (TREE_CODE (*node) == FUNCTION_DECL) { - /* Set the attribute and mark it for disregarding inline - limits. */ - DECL_DISREGARD_INLINE_LIMITS (*node) = 1; + if (lookup_attribute ("noinline", DECL_ATTRIBUTES (*node))) + { + warning (OPT_Wattributes, "%qE attribute ignored due to conflict " + "with %qs attribute", name, "noinline"); + *no_add_attrs = true; + } + else + /* Set the attribute and mark it for disregarding inline + limits. */ + DECL_DISREGARD_INLINE_LIMITS (*node) = 1; } else { diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 2bc06ba7bba..94447082fb5 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -685,7 +685,7 @@ ObjC ObjC++ Var(warn_selector) Warning Warn if a selector has multiple methods Wshadow-ivar -ObjC ObjC++ Var(warn_shadow_ivar) Init(-1) Warning +ObjC ObjC++ Var(warn_shadow_ivar) Init(1) Warning Warn if a local declaration hides an instance variable Wsequence-point diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 2d182f354d5..80841af40ee 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,38 @@ +2014-04-25 Marek Polacek <polacek@redhat.com> + + PR c/18079 + * c-decl.c (diagnose_mismatched_decls): Warn for mismatched + always_inline/noinline and hot/cold attributes. + +2014-04-25 Marek Polacek <polacek@redhat.com> + + PR c/60114 + * c-parser.c (c_parser_initelt): Pass input_location to + process_init_element. + (c_parser_initval): Pass loc to process_init_element. + * c-tree.h (process_init_element): Adjust declaration. + * c-typeck.c (push_init_level): Pass input_location to + process_init_element. + (pop_init_level): Likewise. + (set_designator): Likewise. + (output_init_element): Add location_t parameter. Pass loc to + digest_init. + (output_pending_init_elements): Pass input_location to + output_init_element. + (process_init_element): Add location_t parameter. Pass loc to + output_init_element. + +2014-04-24 Prathamesh Kulkarni <bilbotheelffriend@gmail.com> + + * c-parser.c (c_parser_sizeof_expression): Reorganize slightly to + avoid goto. + +2014-04-24 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_atomic): Allow seq_cst before + atomic-clause, allow comma in between atomic-clause and + seq_cst. + 2014-04-22 Jakub Jelinek <jakub@redhat.com> PR c/59073 diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 82b882e3cd1..90808eda618 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -2099,18 +2099,38 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, /* Diagnose inline __attribute__ ((noinline)) which is silly. */ if (DECL_DECLARED_INLINE_P (newdecl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) - { - warned |= warning (OPT_Wattributes, - "inline declaration of %qD follows " - "declaration with attribute noinline", newdecl); - } + warned |= warning (OPT_Wattributes, + "inline declaration of %qD follows " + "declaration with attribute noinline", newdecl); else if (DECL_DECLARED_INLINE_P (olddecl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) - { - warned |= warning (OPT_Wattributes, - "declaration of %q+D with attribute " - "noinline follows inline declaration ", newdecl); - } + warned |= warning (OPT_Wattributes, + "declaration of %q+D with attribute " + "noinline follows inline declaration ", newdecl); + else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)) + && lookup_attribute ("always_inline", DECL_ATTRIBUTES (olddecl))) + warned |= warning (OPT_Wattributes, + "declaration of %q+D with attribute " + "%qs follows declaration with attribute %qs", + newdecl, "noinline", "always_inline"); + else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (newdecl)) + && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) + warned |= warning (OPT_Wattributes, + "declaration of %q+D with attribute " + "%qs follows declaration with attribute %qs", + newdecl, "always_inline", "noinline"); + else if (lookup_attribute ("cold", DECL_ATTRIBUTES (newdecl)) + && lookup_attribute ("hot", DECL_ATTRIBUTES (olddecl))) + warned |= warning (OPT_Wattributes, + "declaration of %q+D with attribute %qs follows " + "declaration with attribute %qs", newdecl, "cold", + "hot"); + else if (lookup_attribute ("hot", DECL_ATTRIBUTES (newdecl)) + && lookup_attribute ("cold", DECL_ATTRIBUTES (olddecl))) + warned |= warning (OPT_Wattributes, + "declaration of %q+D with attribute %qs follows " + "declaration with attribute %qs", newdecl, "hot", + "cold"); } else /* PARM_DECL, VAR_DECL */ { diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index b1770860ae7..41ae77b541e 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -4219,7 +4219,8 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) init.original_type = NULL; c_parser_error (parser, "expected identifier"); c_parser_skip_until_found (parser, CPP_COMMA, NULL); - process_init_element (init, false, braced_init_obstack); + process_init_element (input_location, init, false, + braced_init_obstack); return; } } @@ -4351,7 +4352,8 @@ c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack) init.original_type = NULL; c_parser_error (parser, "expected %<=%>"); c_parser_skip_until_found (parser, CPP_COMMA, NULL); - process_init_element (init, false, braced_init_obstack); + process_init_element (input_location, init, false, + braced_init_obstack); return; } } @@ -4372,18 +4374,19 @@ c_parser_initval (c_parser *parser, struct c_expr *after, { struct c_expr init; gcc_assert (!after || c_dialect_objc ()); + location_t loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after) init = c_parser_braced_init (parser, NULL_TREE, true); else { - location_t loc = c_parser_peek_token (parser)->location; init = c_parser_expr_no_commas (parser, after); if (init.value != NULL_TREE && TREE_CODE (init.value) != STRING_CST && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR) init = convert_lvalue_to_rvalue (loc, init, true, true); } - process_init_element (init, false, braced_init_obstack); + process_init_element (loc, init, false, braced_init_obstack); } /* Parse a compound statement (possibly a function body) (C90 6.6.2, @@ -6514,30 +6517,29 @@ c_parser_sizeof_expression (c_parser *parser) return ret; } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) + expr = c_parser_postfix_expression_after_paren_type (parser, + type_name, + expr_loc); + else { - expr = c_parser_postfix_expression_after_paren_type (parser, - type_name, - expr_loc); - goto sizeof_expr; + /* sizeof ( type-name ). */ + c_inhibit_evaluation_warnings--; + in_sizeof--; + return c_expr_sizeof_type (expr_loc, type_name); } - /* sizeof ( type-name ). */ - c_inhibit_evaluation_warnings--; - in_sizeof--; - return c_expr_sizeof_type (expr_loc, type_name); } else { expr_loc = c_parser_peek_token (parser)->location; expr = c_parser_unary_expression (parser); - sizeof_expr: - c_inhibit_evaluation_warnings--; - in_sizeof--; - mark_exp_read (expr.value); - if (TREE_CODE (expr.value) == COMPONENT_REF - && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) - error_at (expr_loc, "%<sizeof%> applied to a bit-field"); - return c_expr_sizeof_expr (expr_loc, expr); } + c_inhibit_evaluation_warnings--; + in_sizeof--; + mark_exp_read (expr.value); + if (TREE_CODE (expr.value) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) + error_at (expr_loc, "%<sizeof%> applied to a bit-field"); + return c_expr_sizeof_expr (expr_loc, expr); } /* Parse an alignof expression. */ @@ -11198,6 +11200,18 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + c_parser_consume_token (parser); + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + } + } + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); if (!strcmp (p, "read")) code = OMP_ATOMIC_READ; @@ -11212,13 +11226,21 @@ c_parser_omp_atomic (location_t loc, c_parser *parser) if (p) c_parser_consume_token (parser); } - if (c_parser_next_token_is (parser, CPP_NAME)) + if (!seq_cst) { - const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (!strcmp (p, "seq_cst")) + if (c_parser_next_token_is (parser, CPP_COMMA) + && c_parser_peek_2nd_token (parser)->type == CPP_NAME) + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_NAME)) { - seq_cst = true; - c_parser_consume_token (parser); + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + c_parser_consume_token (parser); + } } } c_parser_skip_to_pragma_eol (parser); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 85df8858dea..53768d619b7 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -612,7 +612,8 @@ extern void push_init_level (int, struct obstack *); extern struct c_expr pop_init_level (int, struct obstack *); extern void set_init_index (tree, tree, struct obstack *); extern void set_init_label (tree, struct obstack *); -extern void process_init_element (struct c_expr, bool, struct obstack *); +extern void process_init_element (location_t, struct c_expr, bool, + struct obstack *); extern tree build_compound_literal (location_t, tree, tree, bool); extern void check_compound_literal_type (location_t, struct c_type_name *); extern tree c_start_case (location_t, location_t, tree); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 886ef518be6..e4293104d7b 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -103,8 +103,8 @@ static int spelling_length (void); static char *print_spelling (char *); static void warning_init (int, const char *); static tree digest_init (location_t, tree, tree, tree, bool, bool, int); -static void output_init_element (tree, tree, bool, tree, tree, int, bool, - struct obstack *); +static void output_init_element (location_t, tree, tree, bool, tree, tree, int, + bool, struct obstack *); static void output_pending_init_elements (int, struct obstack *); static int set_designator (int, struct obstack *); static void push_range_stack (tree, struct obstack *); @@ -7182,13 +7182,15 @@ push_init_level (int implicit, struct obstack * braced_init_obstack) if ((TREE_CODE (constructor_type) == RECORD_TYPE || TREE_CODE (constructor_type) == UNION_TYPE) && constructor_fields == 0) - process_init_element (pop_init_level (1, braced_init_obstack), + process_init_element (input_location, + pop_init_level (1, braced_init_obstack), true, braced_init_obstack); else if (TREE_CODE (constructor_type) == ARRAY_TYPE && constructor_max_index && tree_int_cst_lt (constructor_max_index, constructor_index)) - process_init_element (pop_init_level (1, braced_init_obstack), + process_init_element (input_location, + pop_init_level (1, braced_init_obstack), true, braced_init_obstack); else break; @@ -7388,10 +7390,9 @@ pop_init_level (int implicit, struct obstack * braced_init_obstack) /* When we come to an explicit close brace, pop any inner levels that didn't have explicit braces. */ while (constructor_stack->implicit) - { - process_init_element (pop_init_level (1, braced_init_obstack), - true, braced_init_obstack); - } + process_init_element (input_location, + pop_init_level (1, braced_init_obstack), + true, braced_init_obstack); gcc_assert (!constructor_range_stack); } @@ -7569,10 +7570,9 @@ set_designator (int array, struct obstack * braced_init_obstack) /* Designator list starts at the level of closest explicit braces. */ while (constructor_stack->implicit) - { - process_init_element (pop_init_level (1, braced_init_obstack), - true, braced_init_obstack); - } + process_init_element (input_location, + pop_init_level (1, braced_init_obstack), + true, braced_init_obstack); constructor_designated = 1; return 0; } @@ -8194,9 +8194,9 @@ find_init_member (tree field, struct obstack * braced_init_obstack) existing initializer. */ static void -output_init_element (tree value, tree origtype, bool strict_string, tree type, - tree field, int pending, bool implicit, - struct obstack * braced_init_obstack) +output_init_element (location_t loc, tree value, tree origtype, + bool strict_string, tree type, tree field, int pending, + bool implicit, struct obstack * braced_init_obstack) { tree semantic_type = NULL_TREE; bool maybe_const = true; @@ -8294,8 +8294,8 @@ output_init_element (tree value, tree origtype, bool strict_string, tree type, if (semantic_type) value = build1 (EXCESS_PRECISION_EXPR, semantic_type, value); - value = digest_init (input_location, type, value, origtype, npc, - strict_string, require_constant_value); + value = digest_init (loc, type, value, origtype, npc, strict_string, + require_constant_value); if (value == error_mark_node) { constructor_erroneous = 1; @@ -8422,8 +8422,8 @@ output_pending_init_elements (int all, struct obstack * braced_init_obstack) { if (tree_int_cst_equal (elt->purpose, constructor_unfilled_index)) - output_init_element (elt->value, elt->origtype, true, - TREE_TYPE (constructor_type), + output_init_element (input_location, elt->value, elt->origtype, + true, TREE_TYPE (constructor_type), constructor_unfilled_index, 0, false, braced_init_obstack); else if (tree_int_cst_lt (constructor_unfilled_index, @@ -8477,8 +8477,8 @@ output_pending_init_elements (int all, struct obstack * braced_init_obstack) if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos)) { constructor_unfilled_fields = elt->purpose; - output_init_element (elt->value, elt->origtype, true, - TREE_TYPE (elt->purpose), + output_init_element (input_location, elt->value, elt->origtype, + true, TREE_TYPE (elt->purpose), elt->purpose, 0, false, braced_init_obstack); } @@ -8551,7 +8551,7 @@ output_pending_init_elements (int all, struct obstack * braced_init_obstack) existing initializer. */ void -process_init_element (struct c_expr value, bool implicit, +process_init_element (location_t loc, struct c_expr value, bool implicit, struct obstack * braced_init_obstack) { tree orig_value = value.value; @@ -8595,14 +8595,14 @@ process_init_element (struct c_expr value, bool implicit, if ((TREE_CODE (constructor_type) == RECORD_TYPE || TREE_CODE (constructor_type) == UNION_TYPE) && constructor_fields == 0) - process_init_element (pop_init_level (1, braced_init_obstack), + process_init_element (loc, pop_init_level (1, braced_init_obstack), true, braced_init_obstack); else if ((TREE_CODE (constructor_type) == ARRAY_TYPE || TREE_CODE (constructor_type) == VECTOR_TYPE) && constructor_max_index && tree_int_cst_lt (constructor_max_index, constructor_index)) - process_init_element (pop_init_level (1, braced_init_obstack), + process_init_element (loc, pop_init_level (1, braced_init_obstack), true, braced_init_obstack); else break; @@ -8680,7 +8680,7 @@ process_init_element (struct c_expr value, bool implicit, if (value.value) { push_member_name (constructor_fields); - output_init_element (value.value, value.original_type, + output_init_element (loc, value.value, value.original_type, strict_string, fieldtype, constructor_fields, 1, implicit, braced_init_obstack); @@ -8772,7 +8772,7 @@ process_init_element (struct c_expr value, bool implicit, if (value.value) { push_member_name (constructor_fields); - output_init_element (value.value, value.original_type, + output_init_element (loc, value.value, value.original_type, strict_string, fieldtype, constructor_fields, 1, implicit, braced_init_obstack); @@ -8824,7 +8824,7 @@ process_init_element (struct c_expr value, bool implicit, if (value.value) { push_array_bounds (tree_to_uhwi (constructor_index)); - output_init_element (value.value, value.original_type, + output_init_element (loc, value.value, value.original_type, strict_string, elttype, constructor_index, 1, implicit, braced_init_obstack); @@ -8859,7 +8859,7 @@ process_init_element (struct c_expr value, bool implicit, { if (TREE_CODE (value.value) == VECTOR_CST) elttype = TYPE_MAIN_VARIANT (constructor_type); - output_init_element (value.value, value.original_type, + output_init_element (loc, value.value, value.original_type, strict_string, elttype, constructor_index, 1, implicit, braced_init_obstack); @@ -8888,7 +8888,7 @@ process_init_element (struct c_expr value, bool implicit, else { if (value.value) - output_init_element (value.value, value.original_type, + output_init_element (loc, value.value, value.original_type, strict_string, constructor_type, NULL_TREE, 1, implicit, braced_init_obstack); @@ -8907,8 +8907,8 @@ process_init_element (struct c_expr value, bool implicit, while (constructor_stack != range_stack->stack) { gcc_assert (constructor_stack->implicit); - process_init_element (pop_init_level (1, - braced_init_obstack), + process_init_element (loc, + pop_init_level (1, braced_init_obstack), true, braced_init_obstack); } for (p = range_stack; @@ -8916,7 +8916,8 @@ process_init_element (struct c_expr value, bool implicit, p = p->prev) { gcc_assert (constructor_stack->implicit); - process_init_element (pop_init_level (1, braced_init_obstack), + process_init_element (loc, + pop_init_level (1, braced_init_obstack), true, braced_init_obstack); } diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 28524f85ca1..b5df572d039 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1695,8 +1695,8 @@ release_function_body (tree decl) } if (cfun->cfg) { - gcc_assert (dom_computed[0] == DOM_NONE); - gcc_assert (dom_computed[1] == DOM_NONE); + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); clear_edges (); cfun->cfg = NULL; } diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 7bf9a07cbb2..d06ce3217fd 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -520,7 +520,7 @@ cgraph_add_new_function (tree fndecl, bool lowered) push_cfun (DECL_STRUCT_FUNCTION (fndecl)); gimple_register_cfg_hooks (); bitmap_obstack_initialize (NULL); - execute_pass_list (passes->all_lowering_passes); + execute_pass_list (cfun, passes->all_lowering_passes); passes->execute_early_local_passes (); bitmap_obstack_release (NULL); pop_cfun (); @@ -658,7 +658,7 @@ analyze_function (struct cgraph_node *node) gimple_register_cfg_hooks (); bitmap_obstack_initialize (NULL); - execute_pass_list (g->get_passes ()->all_lowering_passes); + execute_pass_list (cfun, g->get_passes ()->all_lowering_passes); free_dominance_info (CDI_POST_DOMINATORS); free_dominance_info (CDI_DOMINATORS); compact_blocks (); @@ -1771,7 +1771,7 @@ expand_function (struct cgraph_node *node) /* Signal the start of passes. */ invoke_plugin_callbacks (PLUGIN_ALL_PASSES_START, NULL); - execute_pass_list (g->get_passes ()->all_passes); + execute_pass_list (cfun, g->get_passes ()->all_passes); /* Signal the end of passes. */ invoke_plugin_callbacks (PLUGIN_ALL_PASSES_END, NULL); diff --git a/gcc/config.in b/gcc/config.in index af02866dd33..c0ba36ea98b 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -172,6 +172,12 @@ #endif +/* Define to get calls to the valgrind runtime enabled. */ +#ifndef USED_FOR_TARGET +#undef ENABLE_VALGRIND_ANNOTATIONS +#endif + + /* Define if you want to run subprograms and generated programs through valgrind (a memory checker). This is extremely expensive. */ #ifndef USED_FOR_TARGET @@ -1697,12 +1703,6 @@ #endif -/* Define to the library containing __tls_get_addr/___tls_get_addr. */ -#ifndef USED_FOR_TARGET -#undef LIB_TLS_SPEC -#endif - - /* The linker hash style */ #ifndef USED_FOR_TARGET #undef LINKER_HASH_STYLE diff --git a/gcc/config/arm/aarch-common.c b/gcc/config/arm/aarch-common.c index 884d4b37fac..d31191ab9e7 100644 --- a/gcc/config/arm/aarch-common.c +++ b/gcc/config/arm/aarch-common.c @@ -195,14 +195,18 @@ bool aarch_rev16_shright_mask_imm_p (rtx val, enum machine_mode mode) { return CONST_INT_P (val) - && INTVAL (val) == trunc_int_for_mode (0xff00ff00ff00ff, mode); + && INTVAL (val) + == trunc_int_for_mode (HOST_WIDE_INT_C (0xff00ff00ff00ff), + mode); } bool aarch_rev16_shleft_mask_imm_p (rtx val, enum machine_mode mode) { return CONST_INT_P (val) - && INTVAL (val) == trunc_int_for_mode (0xff00ff00ff00ff00, mode); + && INTVAL (val) + == trunc_int_for_mode (HOST_WIDE_INT_C (0xff00ff00ff00ff00), + mode); } diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 8ca945f1a67..1e44080d601 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -1710,7 +1710,8 @@ const struct tune_params arm_cortex_a8_tune = false, /* Prefer LDRD/STRD. */ {true, true}, /* Prefer non short circuit. */ &arm_default_vec_cost, /* Vectorizer costs. */ - false /* Prefer Neon for 64-bits bitops. */ + false, /* Prefer Neon for 64-bits bitops. */ + false, false /* Prefer 32-bit encodings. */ }; const struct tune_params arm_cortex_a7_tune = @@ -6216,11 +6217,6 @@ arm_function_ok_for_sibcall (tree decl, tree exp) if (TARGET_VXWORKS_RTP && flag_pic && !targetm.binds_local_p (decl)) return false; - /* Cannot tail-call to long calls, since these are out of range of - a branch instruction. */ - if (decl && arm_is_long_call_p (decl)) - return false; - /* If we are interworking and the function is not declared static then we can't tail-call it unless we know that it exists in this compilation unit (since it might be a Thumb routine). */ diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 8a949b929fa..97753ce1e98 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -9367,8 +9367,10 @@ "TARGET_32BIT" " { - if (!REG_P (XEXP (operands[0], 0)) - && (GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)) + if ((!REG_P (XEXP (operands[0], 0)) + && GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF) + || (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF + && arm_is_long_call_p (SYMBOL_REF_DECL (XEXP (operands[0], 0))))) XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0)); if (operands[2] == NULL_RTX) @@ -9385,8 +9387,10 @@ "TARGET_32BIT" " { - if (!REG_P (XEXP (operands[1], 0)) && - (GET_CODE (XEXP (operands[1],0)) != SYMBOL_REF)) + if ((!REG_P (XEXP (operands[1], 0)) + && GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF) + || (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF + && arm_is_long_call_p (SYMBOL_REF_DECL (XEXP (operands[1], 0))))) XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0)); if (operands[3] == NULL_RTX) diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index 6273e8820c6..d74fcb31bc7 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -681,5 +681,6 @@ (match_code "reg" "0"))) (define_predicate "call_insn_operand" - (ior (match_code "symbol_ref") + (ior (and (match_code "symbol_ref") + (match_test "!arm_is_long_call_p (SYMBOL_REF_DECL (op))")) (match_operand 0 "s_register_operand"))) diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 25075b2f4b3..0fa7f6633e2 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -290,6 +290,12 @@ avr_to_int_mode (rtx x) static void avr_option_override (void) { + /* Disable -fdelete-null-pointer-checks option for AVR target. + This option compiler assumes that dereferencing of a null pointer + would halt the program. For AVR this assumption is not true and + programs can safely dereference null pointers. Changes made by this + option may not work properly for AVR. So disable this option. */ + flag_delete_null_pointer_checks = 0; /* caller-save.c looks for call-clobbered hard registers that are assigned diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c index c9977bf2b0e..2c31dc8062d 100644 --- a/gcc/config/i386/i386-c.c +++ b/gcc/config/i386/i386-c.c @@ -518,6 +518,13 @@ ix86_target_macros (void) if (TARGET_LONG_DOUBLE_128) cpp_define (parse_in, "__LONG_DOUBLE_128__"); + if (TARGET_128BIT_LONG_DOUBLE) + cpp_define (parse_in, "__SIZEOF_FLOAT80__=16"); + else + cpp_define (parse_in, "__SIZEOF_FLOAT80__=12"); + + cpp_define (parse_in, "__SIZEOF_FLOAT128__=16"); + cpp_define_formatted (parse_in, "__ATOMIC_HLE_ACQUIRE=%d", IX86_HLE_ACQUIRE); cpp_define_formatted (parse_in, "__ATOMIC_HLE_RELEASE=%d", IX86_HLE_RELEASE); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 25e2e93e317..fde0a93e68f 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -3201,7 +3201,7 @@ (const_string "1") (const_string "*"))) (set (attr "mode") - (cond [(eq_attr "alternative" "3,4,9,10,13,14,15") + (cond [(eq_attr "alternative" "3,4,9,10,12,13,14,15") (const_string "SI") (eq_attr "alternative" "11") (const_string "DI") @@ -14427,15 +14427,16 @@ "TARGET_USE_FANCY_MATH_387 && flag_unsafe_math_optimizations" { + rtx tmp1, tmp2; if (optimize_insn_for_size_p ()) FAIL; - operands[3] = gen_reg_rtx (XFmode); - operands[4] = gen_reg_rtx (XFmode); + tmp1 = gen_reg_rtx (XFmode); + tmp2 = gen_reg_rtx (XFmode); - emit_insn (gen_floatsixf2 (operands[3], operands[2])); - emit_insn (gen_fscalexf4_i387 (operands[0], operands[4], - operands[1], operands[3])); + emit_insn (gen_floatsixf2 (tmp1, operands[2])); + emit_insn (gen_fscalexf4_i387 (operands[0], tmp2, + operands[1], tmp1)); DONE; }) diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md index e61048b4d0b..72c11f592db 100644 --- a/gcc/config/m68k/m68k.md +++ b/gcc/config/m68k/m68k.md @@ -1868,9 +1868,11 @@ ;; Maybe there is a way to make that the general case, by forcing the ;; result of the SI tree to be in the lower register of the DI target +;; Don't allow memory for operand 1 as that would require an earlyclobber +;; which results in worse code (define_insn "extendplussidi" [(set (match_operand:DI 0 "register_operand" "=d") - (sign_extend:DI (plus:SI (match_operand:SI 1 "general_operand" "%rmn") + (sign_extend:DI (plus:SI (match_operand:SI 1 "general_operand" "%rn") (match_operand:SI 2 "general_operand" "rmn"))))] "" { diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md index 674cb40bf7a..a8cfcb739ea 100644 --- a/gcc/config/rs6000/altivec.md +++ b/gcc/config/rs6000/altivec.md @@ -143,6 +143,9 @@ UNSPEC_VSUBEUQM UNSPEC_VSUBECUQ UNSPEC_VBPERMQ + UNSPEC_BCDADD + UNSPEC_BCDSUB + UNSPEC_BCD_OVERFLOW ]) (define_c_enum "unspecv" @@ -3334,3 +3337,112 @@ "vbpermq %0,%1,%2" [(set_attr "length" "4") (set_attr "type" "vecsimple")]) + +;; Decimal Integer operations +(define_int_iterator UNSPEC_BCD_ADD_SUB [UNSPEC_BCDADD UNSPEC_BCDSUB]) + +(define_int_attr bcd_add_sub [(UNSPEC_BCDADD "add") + (UNSPEC_BCDSUB "sub")]) + +(define_code_iterator BCD_TEST [eq lt gt unordered]) + +(define_insn "bcd<bcd_add_sub>" + [(set (match_operand:V1TI 0 "register_operand" "") + (unspec:V1TI [(match_operand:V1TI 1 "register_operand" "") + (match_operand:V1TI 2 "register_operand" "") + (match_operand:QI 3 "const_0_to_1_operand" "")] + UNSPEC_BCD_ADD_SUB)) + (clobber (reg:CCFP 74))] + "TARGET_P8_VECTOR" + "bcd<bcd_add_sub>. %0,%1,%2,%3" + [(set_attr "length" "4") + (set_attr "type" "vecsimple")]) + +;; Use a floating point type (V2DFmode) for the compare to set CR6 so that we +;; can use the unordered test for BCD nans and add/subtracts that overflow. An +;; UNORDERED test on an integer type (like V1TImode) is not defined. The type +;; probably should be one that can go in the VMX (Altivec) registers, so we +;; can't use DDmode or DFmode. +(define_insn "*bcd<bcd_add_sub>_test" + [(set (reg:CCFP 74) + (compare:CCFP + (unspec:V2DF [(match_operand:V1TI 1 "register_operand" "v") + (match_operand:V1TI 2 "register_operand" "v") + (match_operand:QI 3 "const_0_to_1_operand" "i")] + UNSPEC_BCD_ADD_SUB) + (match_operand:V2DF 4 "zero_constant" "j"))) + (clobber (match_scratch:V1TI 0 "=v"))] + "TARGET_P8_VECTOR" + "bcd<bcd_add_sub>. %0,%1,%2,%3" + [(set_attr "length" "4") + (set_attr "type" "vecsimple")]) + +(define_insn "*bcd<bcd_add_sub>_test2" + [(set (match_operand:V1TI 0 "register_operand" "=v") + (unspec:V1TI [(match_operand:V1TI 1 "register_operand" "v") + (match_operand:V1TI 2 "register_operand" "v") + (match_operand:QI 3 "const_0_to_1_operand" "i")] + UNSPEC_BCD_ADD_SUB)) + (set (reg:CCFP 74) + (compare:CCFP + (unspec:V2DF [(match_dup 1) + (match_dup 2) + (match_dup 3)] + UNSPEC_BCD_ADD_SUB) + (match_operand:V2DF 4 "zero_constant" "j")))] + "TARGET_P8_VECTOR" + "bcd<bcd_add_sub>. %0,%1,%2,%3" + [(set_attr "length" "4") + (set_attr "type" "vecsimple")]) + +(define_expand "bcd<bcd_add_sub>_<code>" + [(parallel [(set (reg:CCFP 74) + (compare:CCFP + (unspec:V2DF [(match_operand:V1TI 1 "register_operand" "") + (match_operand:V1TI 2 "register_operand" "") + (match_operand:QI 3 "const_0_to_1_operand" "")] + UNSPEC_BCD_ADD_SUB) + (match_dup 4))) + (clobber (match_scratch:V1TI 5 ""))]) + (set (match_operand:SI 0 "register_operand" "") + (BCD_TEST:SI (reg:CCFP 74) + (const_int 0)))] + "TARGET_P8_VECTOR" +{ + operands[4] = CONST0_RTX (V2DFmode); +}) + +;; Peephole2 pattern to combine a bcdadd/bcdsub that calculates the value and +;; the bcdadd/bcdsub that tests the value. The combiner won't work since +;; CR6 is a hard coded register. Unfortunately, all of the Altivec predicate +;; support is hard coded to use the fixed register CR6 instead of creating +;; a register class for CR6. + +(define_peephole2 + [(parallel [(set (match_operand:V1TI 0 "register_operand" "") + (unspec:V1TI [(match_operand:V1TI 1 "register_operand" "") + (match_operand:V1TI 2 "register_operand" "") + (match_operand:QI 3 "const_0_to_1_operand" "")] + UNSPEC_BCD_ADD_SUB)) + (clobber (reg:CCFP 74))]) + (parallel [(set (reg:CCFP 74) + (compare:CCFP + (unspec:V2DF [(match_dup 1) + (match_dup 2) + (match_dup 3)] + UNSPEC_BCD_ADD_SUB) + (match_operand:V2DF 4 "zero_constant" ""))) + (clobber (match_operand:V1TI 5 "register_operand" ""))])] + "TARGET_P8_VECTOR" + [(parallel [(set (match_dup 0) + (unspec:V1TI [(match_dup 1) + (match_dup 2) + (match_dup 3)] + UNSPEC_BCD_ADD_SUB)) + (set (reg:CCFP 74) + (compare:CCFP + (unspec:V2DF [(match_dup 1) + (match_dup 2) + (match_dup 3)] + UNSPEC_BCD_ADD_SUB) + (match_dup 4)))])]) diff --git a/gcc/config/rs6000/dfp.md b/gcc/config/rs6000/dfp.md index 8e99bc0d787..40e27e77d23 100644 --- a/gcc/config/rs6000/dfp.md +++ b/gcc/config/rs6000/dfp.md @@ -322,3 +322,72 @@ "TARGET_DFP" "dctfixq %0,%1" [(set_attr "type" "fp")]) + + +;; Decimal builtin support + +(define_c_enum "unspec" + [UNSPEC_DDEDPD + UNSPEC_DENBCD + UNSPEC_DXEX + UNSPEC_DIEX + UNSPEC_DSCLI + UNSPEC_DSCRI]) + +(define_mode_iterator D64_D128 [DD TD]) + +(define_mode_attr dfp_suffix [(DD "") + (TD "q")]) + +(define_insn "dfp_ddedpd_<mode>" + [(set (match_operand:D64_D128 0 "gpc_reg_operand" "=d") + (unspec:D64_D128 [(match_operand:QI 1 "const_0_to_3_operand" "i") + (match_operand:D64_D128 2 "gpc_reg_operand" "d")] + UNSPEC_DDEDPD))] + "TARGET_DFP" + "ddedpd<dfp_suffix> %1,%0,%2" + [(set_attr "type" "fp")]) + +(define_insn "dfp_denbcd_<mode>" + [(set (match_operand:D64_D128 0 "gpc_reg_operand" "=d") + (unspec:D64_D128 [(match_operand:QI 1 "const_0_to_1_operand" "i") + (match_operand:D64_D128 2 "gpc_reg_operand" "d")] + UNSPEC_DENBCD))] + "TARGET_DFP" + "denbcd<dfp_suffix> %1,%0,%2" + [(set_attr "type" "fp")]) + +(define_insn "dfp_dxex_<mode>" + [(set (match_operand:D64_D128 0 "gpc_reg_operand" "=d") + (unspec:D64_D128 [(match_operand:D64_D128 1 "gpc_reg_operand" "d")] + UNSPEC_DXEX))] + "TARGET_DFP" + "dxex<dfp_suffix> %0,%1" + [(set_attr "type" "fp")]) + +(define_insn "dfp_diex_<mode>" + [(set (match_operand:D64_D128 0 "gpc_reg_operand" "=d") + (unspec:D64_D128 [(match_operand:D64_D128 1 "gpc_reg_operand" "d") + (match_operand:D64_D128 2 "gpc_reg_operand" "d")] + UNSPEC_DXEX))] + "TARGET_DFP" + "diex<dfp_suffix> %0,%1,%2" + [(set_attr "type" "fp")]) + +(define_insn "dfp_dscli_<mode>" + [(set (match_operand:D64_D128 0 "gpc_reg_operand" "=d") + (unspec:D64_D128 [(match_operand:D64_D128 1 "gpc_reg_operand" "d") + (match_operand:QI 2 "immediate_operand" "i")] + UNSPEC_DSCLI))] + "TARGET_DFP" + "dscli<dfp_suffix> %0,%1,%2" + [(set_attr "type" "fp")]) + +(define_insn "dfp_dscri_<mode>" + [(set (match_operand:D64_D128 0 "gpc_reg_operand" "=d") + (unspec:D64_D128 [(match_operand:D64_D128 1 "gpc_reg_operand" "d") + (match_operand:QI 2 "immediate_operand" "i")] + UNSPEC_DSCRI))] + "TARGET_DFP" + "dscri<dfp_suffix> %0,%1,%2" + [(set_attr "type" "fp")]) diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 2ed1d4a184d..1616b888c9c 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -171,6 +171,11 @@ (and (match_code "const_int") (match_test "IN_RANGE (INTVAL (op), 0, 1)"))) +;; Match op = 0..3. +(define_predicate "const_0_to_3_operand" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 3)"))) + ;; Match op = 2 or op = 3. (define_predicate "const_2_to_3_operand" (and (match_code "const_int") diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def index 83351691fa5..16793f501e7 100644 --- a/gcc/config/rs6000/rs6000-builtin.def +++ b/gcc/config/rs6000/rs6000-builtin.def @@ -570,6 +570,75 @@ MASK, /* MASK */ \ (ATTR | RS6000_BTC_SPECIAL), /* ATTR */ \ CODE_FOR_nothing) /* ICODE */ + + +/* Decimal floating point builtins for instructions. */ +#define BU_DFP_MISC_1(ENUM, NAME, ATTR, ICODE) \ + RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \ + "__builtin_" NAME, /* NAME */ \ + RS6000_BTM_DFP, /* MASK */ \ + (RS6000_BTC_ ## ATTR /* ATTR */ \ + | RS6000_BTC_UNARY), \ + CODE_FOR_ ## ICODE) /* ICODE */ + +#define BU_DFP_MISC_2(ENUM, NAME, ATTR, ICODE) \ + RS6000_BUILTIN_2 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \ + "__builtin_" NAME, /* NAME */ \ + RS6000_BTM_DFP, /* MASK */ \ + (RS6000_BTC_ ## ATTR /* ATTR */ \ + | RS6000_BTC_BINARY), \ + CODE_FOR_ ## ICODE) /* ICODE */ + + +/* Miscellaneous builtins for instructions added in ISA 2.06. These + instructions don't require either the DFP or VSX options, just the basic ISA + 2.06 (popcntd) enablement since they operate on general purpose + registers. */ +#define BU_P7_MISC_1(ENUM, NAME, ATTR, ICODE) \ + RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \ + "__builtin_" NAME, /* NAME */ \ + RS6000_BTM_POPCNTD, /* MASK */ \ + (RS6000_BTC_ ## ATTR /* ATTR */ \ + | RS6000_BTC_UNARY), \ + CODE_FOR_ ## ICODE) /* ICODE */ + +#define BU_P7_MISC_2(ENUM, NAME, ATTR, ICODE) \ + RS6000_BUILTIN_2 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \ + "__builtin_" NAME, /* NAME */ \ + RS6000_BTM_POPCNTD, /* MASK */ \ + (RS6000_BTC_ ## ATTR /* ATTR */ \ + | RS6000_BTC_BINARY), \ + CODE_FOR_ ## ICODE) /* ICODE */ + + +/* Miscellaneous builtins for instructions added in ISA 2.07. These + instructions do require the ISA 2.07 vector support, but they aren't vector + instructions. */ +#define BU_P8V_MISC_3(ENUM, NAME, ATTR, ICODE) \ + RS6000_BUILTIN_3 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \ + "__builtin_" NAME, /* NAME */ \ + RS6000_BTM_P8_VECTOR, /* MASK */ \ + (RS6000_BTC_ ## ATTR /* ATTR */ \ + | RS6000_BTC_TERNARY), \ + CODE_FOR_ ## ICODE) /* ICODE */ + +/* Miscellaneous builtins. */ +#define BU_MISC_1(ENUM, NAME, ATTR, ICODE) \ + RS6000_BUILTIN_2 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \ + "__builtin_" NAME, /* NAME */ \ + RS6000_BTM_ALWAYS, /* MASK */ \ + (RS6000_BTC_ ## ATTR /* ATTR */ \ + | RS6000_BTC_UNARY), \ + CODE_FOR_ ## ICODE) /* ICODE */ + +#define BU_MISC_2(ENUM, NAME, ATTR, ICODE) \ + RS6000_BUILTIN_2 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \ + "__builtin_" NAME, /* NAME */ \ + RS6000_BTM_ALWAYS, /* MASK */ \ + (RS6000_BTC_ ## ATTR /* ATTR */ \ + | RS6000_BTC_BINARY), \ + CODE_FOR_ ## ICODE) /* ICODE */ + #endif /* Insure 0 is not a legitimate index. */ @@ -1412,10 +1481,10 @@ BU_P8V_AV_2 (ORC_V4SF, "orc_v4sf", CONST, orcv4sf3) BU_P8V_AV_2 (ORC_V2DF, "orc_v2df", CONST, orcv2df3) /* 3 argument altivec instructions added in ISA 2.07. */ -BU_P8V_AV_3 (VADDEUQM, "vaddeuqm", CONST, altivec_vaddeuqm) -BU_P8V_AV_3 (VADDECUQ, "vaddecuq", CONST, altivec_vaddecuq) -BU_P8V_AV_3 (VSUBEUQM, "vsubeuqm", CONST, altivec_vsubeuqm) -BU_P8V_AV_3 (VSUBECUQ, "vsubecuq", CONST, altivec_vsubecuq) +BU_P8V_AV_3 (VADDEUQM, "vaddeuqm", CONST, altivec_vaddeuqm) +BU_P8V_AV_3 (VADDECUQ, "vaddecuq", CONST, altivec_vaddecuq) +BU_P8V_AV_3 (VSUBEUQM, "vsubeuqm", CONST, altivec_vsubeuqm) +BU_P8V_AV_3 (VSUBECUQ, "vsubecuq", CONST, altivec_vsubecuq) /* Vector comparison instructions added in ISA 2.07. */ BU_P8V_AV_2 (VCMPEQUD, "vcmpequd", CONST, vector_eqv2di) @@ -1475,6 +1544,64 @@ BU_P8V_OVERLOAD_3 (VSUBECUQ, "vsubecuq") BU_P8V_OVERLOAD_3 (VSUBEUQM, "vsubeuqm") +/* 2 argument extended divide functions added in ISA 2.06. */ +BU_P7_MISC_2 (DIVWE, "divwe", CONST, dive_si) +BU_P7_MISC_2 (DIVWEO, "divweo", CONST, diveo_si) +BU_P7_MISC_2 (DIVWEU, "divweu", CONST, diveu_si) +BU_P7_MISC_2 (DIVWEUO, "divweuo", CONST, diveuo_si) +BU_P7_MISC_2 (DIVDE, "divde", CONST, dive_di) +BU_P7_MISC_2 (DIVDEO, "divdeo", CONST, diveo_di) +BU_P7_MISC_2 (DIVDEU, "divdeu", CONST, diveu_di) +BU_P7_MISC_2 (DIVDEUO, "divdeuo", CONST, diveuo_di) + +/* 1 argument DFP (decimal floating point) functions added in ISA 2.05. */ +BU_DFP_MISC_1 (DXEX, "dxex", CONST, dfp_dxex_dd) +BU_DFP_MISC_1 (DXEXQ, "dxexq", CONST, dfp_dxex_td) + +/* 2 argument DFP (decimal floating point) functions added in ISA 2.05. */ +BU_DFP_MISC_2 (DDEDPD, "ddedpd", CONST, dfp_ddedpd_dd) +BU_DFP_MISC_2 (DDEDPDQ, "ddedpdq", CONST, dfp_ddedpd_td) +BU_DFP_MISC_2 (DENBCD, "denbcd", CONST, dfp_denbcd_dd) +BU_DFP_MISC_2 (DENBCDQ, "denbcdq", CONST, dfp_denbcd_td) +BU_DFP_MISC_2 (DIEX, "diex", CONST, dfp_diex_dd) +BU_DFP_MISC_2 (DIEXQ, "diexq", CONST, dfp_diex_td) +BU_DFP_MISC_2 (DSCLI, "dscli", CONST, dfp_dscli_dd) +BU_DFP_MISC_2 (DSCLIQ, "dscliq", CONST, dfp_dscli_td) +BU_DFP_MISC_2 (DSCRI, "dscri", CONST, dfp_dscri_dd) +BU_DFP_MISC_2 (DSCRIQ, "dscriq", CONST, dfp_dscri_td) + +/* 1 argument BCD functions added in ISA 2.06. */ +BU_P7_MISC_1 (CDTBCD, "cdtbcd", CONST, cdtbcd) +BU_P7_MISC_1 (CBCDTD, "cbcdtd", CONST, cbcdtd) + +/* 2 argument BCD functions added in ISA 2.06. */ +BU_P7_MISC_2 (ADDG6S, "addg6s", CONST, addg6s) + +/* 3 argument BCD functions added in ISA 2.07. */ +BU_P8V_MISC_3 (BCDADD, "bcdadd", CONST, bcdadd) +BU_P8V_MISC_3 (BCDADD_LT, "bcdadd_lt", CONST, bcdadd_lt) +BU_P8V_MISC_3 (BCDADD_EQ, "bcdadd_eq", CONST, bcdadd_eq) +BU_P8V_MISC_3 (BCDADD_GT, "bcdadd_gt", CONST, bcdadd_gt) +BU_P8V_MISC_3 (BCDADD_OV, "bcdadd_ov", CONST, bcdadd_unordered) +BU_P8V_MISC_3 (BCDSUB, "bcdsub", CONST, bcdsub) +BU_P8V_MISC_3 (BCDSUB_LT, "bcdsub_lt", CONST, bcdsub_lt) +BU_P8V_MISC_3 (BCDSUB_EQ, "bcdsub_eq", CONST, bcdsub_eq) +BU_P8V_MISC_3 (BCDSUB_GT, "bcdsub_gt", CONST, bcdsub_gt) +BU_P8V_MISC_3 (BCDSUB_OV, "bcdsub_ov", CONST, bcdsub_unordered) + +/* 2 argument pack/unpack 128-bit floating point types. */ +BU_DFP_MISC_2 (PACK_TD, "pack_dec128", CONST, packtd) +BU_DFP_MISC_2 (UNPACK_TD, "unpack_dec128", CONST, unpacktd) + +BU_MISC_2 (PACK_TF, "pack_longdouble", CONST, packtf) +BU_MISC_2 (UNPACK_TF, "unpack_longdouble", CONST, unpacktf) +BU_MISC_1 (UNPACK_TF_0, "longdouble_dw0", CONST, unpacktf_0) +BU_MISC_1 (UNPACK_TF_1, "longdouble_dw1", CONST, unpacktf_1) + +BU_P7_MISC_2 (PACK_V1TI, "pack_vector_int128", CONST, packv1ti) +BU_P7_MISC_2 (UNPACK_V1TI, "unpack_vector_int128", CONST, unpackv1ti) + + /* 1 argument crypto functions. */ BU_CRYPTO_1 (VSBOX, "vsbox", CONST, crypto_vsbox) diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index bab79df7760..0c983f9a105 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -3038,7 +3038,8 @@ rs6000_builtin_mask_calculate (void) | ((rs6000_cpu == PROCESSOR_CELL) ? RS6000_BTM_CELL : 0) | ((TARGET_P8_VECTOR) ? RS6000_BTM_P8_VECTOR : 0) | ((TARGET_CRYPTO) ? RS6000_BTM_CRYPTO : 0) - | ((TARGET_HTM) ? RS6000_BTM_HTM : 0)); + | ((TARGET_HTM) ? RS6000_BTM_HTM : 0) + | ((TARGET_DFP) ? RS6000_BTM_DFP : 0)); } /* Override command line options. Mostly we process the processor type and @@ -12396,7 +12397,15 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target) } } else if (icode == CODE_FOR_vsx_set_v2df - || icode == CODE_FOR_vsx_set_v2di) + || icode == CODE_FOR_vsx_set_v2di + || icode == CODE_FOR_bcdadd + || icode == CODE_FOR_bcdadd_lt + || icode == CODE_FOR_bcdadd_eq + || icode == CODE_FOR_bcdadd_gt + || icode == CODE_FOR_bcdsub + || icode == CODE_FOR_bcdsub_lt + || icode == CODE_FOR_bcdsub_eq + || icode == CODE_FOR_bcdsub_gt) { /* Only allow 1-bit unsigned literals. */ STRIP_NOPS (arg2); @@ -12407,6 +12416,44 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target) return const0_rtx; } } + else if (icode == CODE_FOR_dfp_ddedpd_dd + || icode == CODE_FOR_dfp_ddedpd_td) + { + /* Only allow 2-bit unsigned literals where the value is 0 or 2. */ + STRIP_NOPS (arg0); + if (TREE_CODE (arg0) != INTEGER_CST + || TREE_INT_CST_LOW (arg2) & ~0x3) + { + error ("argument 1 must be 0 or 2"); + return const0_rtx; + } + } + else if (icode == CODE_FOR_dfp_denbcd_dd + || icode == CODE_FOR_dfp_denbcd_td) + { + /* Only allow 1-bit unsigned literals. */ + STRIP_NOPS (arg0); + if (TREE_CODE (arg0) != INTEGER_CST + || TREE_INT_CST_LOW (arg0) & ~0x1) + { + error ("argument 1 must be a 1-bit unsigned literal"); + return const0_rtx; + } + } + else if (icode == CODE_FOR_dfp_dscli_dd + || icode == CODE_FOR_dfp_dscli_td + || icode == CODE_FOR_dfp_dscri_dd + || icode == CODE_FOR_dfp_dscri_td) + { + /* Only allow 6-bit unsigned literals. */ + STRIP_NOPS (arg1); + if (TREE_CODE (arg1) != INTEGER_CST + || TREE_INT_CST_LOW (arg1) & ~0x3f) + { + error ("argument 2 must be a 6-bit unsigned literal"); + return const0_rtx; + } + } else if (icode == CODE_FOR_crypto_vshasigmaw || icode == CODE_FOR_crypto_vshasigmad) { @@ -13496,6 +13543,14 @@ rs6000_invalid_builtin (enum rs6000_builtins fncode) error ("Builtin function %s requires the -mpaired option", name); else if ((fnmask & RS6000_BTM_SPE) != 0) error ("Builtin function %s requires the -mspe option", name); + else if ((fnmask & (RS6000_BTM_DFP | RS6000_BTM_P8_VECTOR)) + == (RS6000_BTM_DFP | RS6000_BTM_P8_VECTOR)) + error ("Builtin function %s requires the -mhard-dfp and" + "-mpower8-vector options", name); + else if ((fnmask & RS6000_BTM_DFP) != 0) + error ("Builtin function %s requires the -mhard-dfp option", name); + else if ((fnmask & RS6000_BTM_P8_VECTOR) != 0) + error ("Builtin function %s requires the -mpower8-vector option", name); else error ("Builtin function %s is not supported with the current options", name); @@ -13775,6 +13830,9 @@ rs6000_init_builtins (void) uintTI_type_internal_node = unsigned_intTI_type_node; float_type_internal_node = float_type_node; double_type_internal_node = double_type_node; + long_double_type_internal_node = long_double_type_node; + dfloat64_type_internal_node = dfloat64_type_node; + dfloat128_type_internal_node = dfloat128_type_node; void_type_internal_node = void_type_node; /* Initialize the modes for builtin_function_type, mapping a machine mode to @@ -13789,6 +13847,9 @@ rs6000_init_builtins (void) builtin_mode_to_type[TImode][1] = unsigned_intTI_type_node; builtin_mode_to_type[SFmode][0] = float_type_node; builtin_mode_to_type[DFmode][0] = double_type_node; + builtin_mode_to_type[TFmode][0] = long_double_type_node; + builtin_mode_to_type[DDmode][0] = dfloat64_type_node; + builtin_mode_to_type[TDmode][0] = dfloat128_type_node; builtin_mode_to_type[V1TImode][0] = V1TI_type_node; builtin_mode_to_type[V1TImode][1] = unsigned_V1TI_type_node; builtin_mode_to_type[V2SImode][0] = V2SI_type_node; @@ -14881,6 +14942,8 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0, /* unsigned 1 argument functions. */ case CRYPTO_BUILTIN_VSBOX: case P8V_BUILTIN_VGBBD: + case MISC_BUILTIN_CDTBCD: + case MISC_BUILTIN_CBCDTD: h.uns_p[0] = 1; h.uns_p[1] = 1; break; @@ -14899,6 +14962,11 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0, case CRYPTO_BUILTIN_VPMSUMW: case CRYPTO_BUILTIN_VPMSUMD: case CRYPTO_BUILTIN_VPMSUM: + case MISC_BUILTIN_ADDG6S: + case MISC_BUILTIN_DIVWEU: + case MISC_BUILTIN_DIVWEUO: + case MISC_BUILTIN_DIVDEU: + case MISC_BUILTIN_DIVDEUO: h.uns_p[0] = 1; h.uns_p[1] = 1; h.uns_p[2] = 1; @@ -14960,9 +15028,18 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0, /* signed args, unsigned return. */ case VSX_BUILTIN_XVCVDPUXDS_UNS: case ALTIVEC_BUILTIN_FIXUNS_V4SF_V4SI: + case MISC_BUILTIN_UNPACK_TD: + case MISC_BUILTIN_UNPACK_V1TI: h.uns_p[0] = 1; break; + /* unsigned arguments for 128-bit pack instructions. */ + case MISC_BUILTIN_PACK_TD: + case MISC_BUILTIN_PACK_V1TI: + h.uns_p[1] = 1; + h.uns_p[2] = 1; + break; + default: break; } @@ -31226,6 +31303,7 @@ static struct rs6000_opt_mask const rs6000_builtin_mask_names[] = { "power8-vector", RS6000_BTM_P8_VECTOR, false, false }, { "crypto", RS6000_BTM_CRYPTO, false, false }, { "htm", RS6000_BTM_HTM, false, false }, + { "hard-dfp", RS6000_BTM_DFP, false, false }, }; /* Option variables that we want to support inside attribute((target)) and diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 9d0d61c74ea..2e677d5936e 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -2516,6 +2516,7 @@ extern int frame_pointer_needed; #define RS6000_BTM_FRSQRTES MASK_POPCNTB /* FRSQRTES instruction. */ #define RS6000_BTM_POPCNTD MASK_POPCNTD /* Target supports ISA 2.06. */ #define RS6000_BTM_CELL MASK_FPRND /* Target is cell powerpc. */ +#define RS6000_BTM_DFP MASK_DFP /* Decimal floating point. */ #define RS6000_BTM_COMMON (RS6000_BTM_ALTIVEC \ | RS6000_BTM_VSX \ @@ -2527,7 +2528,8 @@ extern int frame_pointer_needed; | RS6000_BTM_FRSQRTES \ | RS6000_BTM_HTM \ | RS6000_BTM_POPCNTD \ - | RS6000_BTM_CELL) + | RS6000_BTM_CELL \ + | RS6000_BTM_DFP) /* Define builtin enum index. */ @@ -2622,6 +2624,9 @@ enum rs6000_builtin_type_index RS6000_BTI_UINTTI, /* unsigned_intTI_type_node */ RS6000_BTI_float, /* float_type_node */ RS6000_BTI_double, /* double_type_node */ + RS6000_BTI_long_double, /* long_double_type_node */ + RS6000_BTI_dfloat64, /* dfloat64_type_node */ + RS6000_BTI_dfloat128, /* dfloat128_type_node */ RS6000_BTI_void, /* void_type_node */ RS6000_BTI_MAX }; @@ -2673,6 +2678,9 @@ enum rs6000_builtin_type_index #define uintTI_type_internal_node (rs6000_builtin_types[RS6000_BTI_UINTTI]) #define float_type_internal_node (rs6000_builtin_types[RS6000_BTI_float]) #define double_type_internal_node (rs6000_builtin_types[RS6000_BTI_double]) +#define long_double_type_internal_node (rs6000_builtin_types[RS6000_BTI_long_double]) +#define dfloat64_type_internal_node (rs6000_builtin_types[RS6000_BTI_dfloat64]) +#define dfloat128_type_internal_node (rs6000_builtin_types[RS6000_BTI_dfloat128]) #define void_type_internal_node (rs6000_builtin_types[RS6000_BTI_void]) extern GTY(()) tree rs6000_builtin_types[RS6000_BTI_MAX]; diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index cdefc8f78c4..937eabf3727 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -125,6 +125,15 @@ UNSPEC_P8V_MTVSRD UNSPEC_P8V_XXPERMDI UNSPEC_P8V_RELOAD_FROM_VSX + UNSPEC_ADDG6S + UNSPEC_CDTBCD + UNSPEC_CBCDTD + UNSPEC_DIVE + UNSPEC_DIVEO + UNSPEC_DIVEU + UNSPEC_DIVEUO + UNSPEC_UNPACK_128BIT + UNSPEC_PACK_128BIT ]) ;; @@ -481,6 +490,10 @@ (V2DF "X,X,X,X,X") (V1TI "X,X,X,X,X")]) +;; Mode attribute to give the correct type for integer divides +(define_mode_attr idiv_ldiv [(SI "idiv") + (DI "ldiv")]) + ;; Start with fixed-point load and store insns. Here we put only the more ;; complex forms. Basic data transfer is done later. @@ -2755,10 +2768,7 @@ (match_operand:GPR 2 "gpc_reg_operand" "r")))] "" "div<wd>u %0,%1,%2" - [(set (attr "type") - (cond [(match_operand:SI 0 "" "") - (const_string "idiv")] - (const_string "ldiv")))]) + [(set_attr "type" "<idiv_ldiv>")]) ;; For powers of two we can do srai/aze for divide and then adjust for @@ -2782,10 +2792,7 @@ (match_operand:GPR 2 "gpc_reg_operand" "r")))] "" "div<wd> %0,%1,%2" - [(set (attr "type") - (cond [(match_operand:SI 0 "" "") - (const_string "idiv")] - (const_string "ldiv")))]) + [(set_attr "type" "<idiv_ldiv>")]) (define_expand "mod<mode>3" [(use (match_operand:GPR 0 "gpc_reg_operand" "")) @@ -15735,6 +15742,191 @@ }) +;; Miscellaneous ISA 2.06 (power7) instructions +(define_insn "addg6s" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")] + UNSPEC_ADDG6S))] + "TARGET_POPCNTD" + "addg6s %0,%1,%2" + [(set_attr "type" "integer") + (set_attr "length" "4")]) + +(define_insn "cdtbcd" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r")] + UNSPEC_CDTBCD))] + "TARGET_POPCNTD" + "cdtbcd %0,%1" + [(set_attr "type" "integer") + (set_attr "length" "4")]) + +(define_insn "cbcdtd" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r")] + UNSPEC_CBCDTD))] + "TARGET_POPCNTD" + "cbcdtd %0,%1" + [(set_attr "type" "integer") + (set_attr "length" "4")]) + +(define_int_iterator UNSPEC_DIV_EXTEND [UNSPEC_DIVE + UNSPEC_DIVEO + UNSPEC_DIVEU + UNSPEC_DIVEUO]) + +(define_int_attr div_extend [(UNSPEC_DIVE "e") + (UNSPEC_DIVEO "eo") + (UNSPEC_DIVEU "eu") + (UNSPEC_DIVEUO "euo")]) + +(define_insn "div<div_extend>_<mode>" + [(set (match_operand:GPR 0 "register_operand" "=r") + (unspec:GPR [(match_operand:GPR 1 "register_operand" "r") + (match_operand:GPR 2 "register_operand" "r")] + UNSPEC_DIV_EXTEND))] + "TARGET_POPCNTD" + "div<wd><div_extend> %0,%1,%2" + [(set_attr "type" "<idiv_ldiv>")]) + + +;; Pack/unpack 128-bit floating point types that take 2 scalar registers + +; Type of the 64-bit part when packing/unpacking 128-bit floating point types +(define_mode_attr FP128_64 [(TF "DF") (TD "DI")]) + +(define_expand "unpack<mode>" + [(set (match_operand:<FP128_64> 0 "nonimmediate_operand" "") + (unspec:<FP128_64> + [(match_operand:FMOVE128 1 "register_operand" "") + (match_operand:QI 2 "const_0_to_1_operand" "")] + UNSPEC_UNPACK_128BIT))] + "" + "") + +;; The Advance Toolchain 7.0-3 added private builtins: __builtin_longdouble_dw0 +;; and __builtin_longdouble_dw1 to optimize glibc. Add support for these +;; builtins here. + +(define_expand "unpacktf_0" + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (unspec:DF [(match_operand:TF 1 "register_operand" "") + (const_int 0)] + UNSPEC_UNPACK_128BIT))] + "" + "") + +(define_expand "unpacktf_1" + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (unspec:DF [(match_operand:TF 1 "register_operand" "") + (const_int 1)] + UNSPEC_UNPACK_128BIT))] + "" + "") + +(define_insn_and_split "unpack<mode>_dm" + [(set (match_operand:<FP128_64> 0 "nonimmediate_operand" "=d,m,d,r,m") + (unspec:<FP128_64> + [(match_operand:FMOVE128 1 "register_operand" "d,d,r,d,r") + (match_operand:QI 2 "const_0_to_1_operand" "i,i,i,i,i")] + UNSPEC_UNPACK_128BIT))] + "TARGET_POWERPC64 && TARGET_DIRECT_MOVE" + "#" + "&& reload_completed" + [(set (match_dup 0) (match_dup 3))] +{ + unsigned fp_regno = REGNO (operands[1]) + UINTVAL (operands[2]); + + if (REG_P (operands[0]) && REGNO (operands[0]) == fp_regno) + { + emit_note (NOTE_INSN_DELETED); + DONE; + } + + operands[3] = gen_rtx_REG (<FP128_64>mode, fp_regno); +} + [(set_attr "type" "fp,fpstore,mffgpr,mftgpr,store") + (set_attr "length" "4")]) + +(define_insn_and_split "unpack<mode>_nodm" + [(set (match_operand:<FP128_64> 0 "nonimmediate_operand" "=d,m") + (unspec:<FP128_64> + [(match_operand:FMOVE128 1 "register_operand" "d,d") + (match_operand:QI 2 "const_0_to_1_operand" "i,i")] + UNSPEC_UNPACK_128BIT))] + "!TARGET_POWERPC64 || !TARGET_DIRECT_MOVE" + "#" + "&& reload_completed" + [(set (match_dup 0) (match_dup 3))] +{ + unsigned fp_regno = REGNO (operands[1]) + UINTVAL (operands[2]); + + if (REG_P (operands[0]) && REGNO (operands[0]) == fp_regno) + { + emit_note (NOTE_INSN_DELETED); + DONE; + } + + operands[3] = gen_rtx_REG (<FP128_64>mode, fp_regno); +} + [(set_attr "type" "fp,fpstore") + (set_attr "length" "4")]) + +(define_insn_and_split "pack<mode>" + [(set (match_operand:FMOVE128 0 "register_operand" "=d,&d") + (unspec:FMOVE128 + [(match_operand:<FP128_64> 1 "register_operand" "0,d") + (match_operand:<FP128_64> 2 "register_operand" "d,d")] + UNSPEC_PACK_128BIT))] + "" + "@ + fmr %L0,%2 + #" + "&& reload_completed && REGNO (operands[0]) != REGNO (operands[1])" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 4) (match_dup 2))] +{ + unsigned dest_hi = REGNO (operands[0]); + unsigned dest_lo = dest_hi + 1; + + gcc_assert (!IN_RANGE (REGNO (operands[1]), dest_hi, dest_lo)); + gcc_assert (!IN_RANGE (REGNO (operands[2]), dest_hi, dest_lo)); + + operands[3] = gen_rtx_REG (<FP128_64>mode, dest_hi); + operands[4] = gen_rtx_REG (<FP128_64>mode, dest_lo); +} + [(set_attr "type" "fp,fp") + (set_attr "length" "4,8")]) + +(define_insn "unpackv1ti" + [(set (match_operand:DI 0 "register_operand" "=d,d") + (unspec:DI [(match_operand:V1TI 1 "register_operand" "0,wa") + (match_operand:QI 2 "const_0_to_1_operand" "O,i")] + UNSPEC_UNPACK_128BIT))] + "TARGET_VSX" +{ + if (REGNO (operands[0]) == REGNO (operands[1]) && INTVAL (operands[2]) == 0) + return ASM_COMMENT_START " xxpermdi to same register"; + + operands[3] = GEN_INT (INTVAL (operands[2]) == 0 ? 0 : 3); + return "xxpermdi %x0,%x1,%x1,%3"; +} + [(set_attr "type" "vecperm") + (set_attr "length" "4")]) + +(define_insn "packv1ti" + [(set (match_operand:V1TI 0 "register_operand" "=wa") + (unspec:V1TI + [(match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d")] + UNSPEC_PACK_128BIT))] + "TARGET_VSX" + "xxpermdi %x0,%x1,%x2,0" + [(set_attr "type" "vecperm") + (set_attr "length" "4")]) + + (include "sync.md") (include "vector.md") diff --git a/gcc/config/sol2.h b/gcc/config/sol2.h index 2a657db59c1..a21c953b035 100644 --- a/gcc/config/sol2.h +++ b/gcc/config/sol2.h @@ -115,7 +115,6 @@ along with GCC; see the file COPYING3. If not see #define LIB_SPEC \ "%{!symbolic:\ %{pthreads|pthread:-lpthread} \ - %{pthreads|pthread|fprofile-generate*:" LIB_TLS_SPEC "} \ %{p|pg:-ldl} -lc}" #ifndef CROSS_DIRECTORY_STRUCTURE diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 8b6c647fc00..e2a4669e05d 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -5795,19 +5795,6 @@ } [(set_attr "type" "shift")]) -(define_insn "*ashlsi3_extend" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (ashift:SI (match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "arith_operand" "rI"))))] - "TARGET_ARCH64" -{ - if (GET_CODE (operands[2]) == CONST_INT) - operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); - return "sll\t%1, %2, %0"; -} - [(set_attr "type" "shift")]) - (define_expand "ashldi3" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (match_operand:DI 1 "register_operand" "r") diff --git a/gcc/config/sparc/sparc.opt b/gcc/config/sparc/sparc.opt index c02aec59f06..64e40955a53 100644 --- a/gcc/config/sparc/sparc.opt +++ b/gcc/config/sparc/sparc.opt @@ -113,6 +113,10 @@ mrelax Target Optimize tail call instructions in assembler and linker +muser-mode +Target Report Mask(USER_MODE) +Do not generate code that can only run in supervisor mode + mcpu= Target RejectNegative Joined Var(sparc_cpu_and_features) Enum(sparc_processor_type) Init(PROCESSOR_V7) Use features of and schedule code for given CPU diff --git a/gcc/config/sparc/sync.md b/gcc/config/sparc/sync.md index fd5691f73be..e6e237f256f 100644 --- a/gcc/config/sparc/sync.md +++ b/gcc/config/sparc/sync.md @@ -200,10 +200,27 @@ [(match_operand:I48MODE 2 "register_operand" "r") (match_operand:I48MODE 3 "register_operand" "0")] UNSPECV_CAS))] - "(TARGET_V9 || TARGET_LEON3) && (<MODE>mode != DImode || TARGET_ARCH64)" + "TARGET_V9 && (<MODE>mode != DImode || TARGET_ARCH64)" "cas<modesuffix>\t%1, %2, %0" [(set_attr "type" "multi")]) +(define_insn "*atomic_compare_and_swap_leon3_1" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "mem_noofs_operand" "+w")) + (set (match_dup 1) + (unspec_volatile:SI + [(match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "0")] + UNSPECV_CAS))] + "TARGET_LEON3" +{ + if (TARGET_USER_MODE) + return "casa\t%1 0xa, %2, %0"; /* ASI for user data space. */ + else + return "casa\t%1 0xb, %2, %0"; /* ASI for supervisor data space. */ +} + [(set_attr "type" "multi")]) + (define_insn "*atomic_compare_and_swapdi_v8plus" [(set (match_operand:DI 0 "register_operand" "=h") (match_operand:DI 1 "mem_noofs_operand" "+w")) diff --git a/gcc/configure b/gcc/configure index 813ccce2257..d912261c1cf 100755 --- a/gcc/configure +++ b/gcc/configure @@ -882,6 +882,7 @@ enable_werror_always enable_checking enable_coverage enable_gather_detailed_mem_stats +enable_valgrind_annotations with_stabs enable_multilib enable_multiarch @@ -1591,6 +1592,8 @@ Optional Features: Values are opt, noopt, default is noopt --enable-gather-detailed-mem-stats enable detailed memory allocation stats gathering + --enable-valgrind-annotations + enable valgrind runtime interaction --enable-multilib enable library support for multiple ABIs --enable-multiarch enable support for multiarch paths --enable-__cxa_atexit enable __cxa_atexit for C++ @@ -6772,12 +6775,11 @@ fi -if test x$ac_valgrind_checking != x ; then - # It is certainly possible that there's valgrind but no valgrind.h. - # GCC relies on making annotations so we must have both. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for VALGRIND_DISCARD in <valgrind/memcheck.h>" >&5 +# It is certainly possible that there's valgrind but no valgrind.h. +# GCC relies on making annotations so we must have both. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for VALGRIND_DISCARD in <valgrind/memcheck.h>" >&5 $as_echo_n "checking for VALGRIND_DISCARD in <valgrind/memcheck.h>... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <valgrind/memcheck.h> #ifndef VALGRIND_DISCARD @@ -6790,11 +6792,11 @@ else gcc_cv_header_valgrind_memcheck_h=no fi rm -f conftest.err conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_header_valgrind_memcheck_h" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_header_valgrind_memcheck_h" >&5 $as_echo "$gcc_cv_header_valgrind_memcheck_h" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for VALGRIND_DISCARD in <memcheck.h>" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for VALGRIND_DISCARD in <memcheck.h>" >&5 $as_echo_n "checking for VALGRIND_DISCARD in <memcheck.h>... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <memcheck.h> #ifndef VALGRIND_DISCARD @@ -6807,8 +6809,20 @@ else gcc_cv_header_memcheck_h=no fi rm -f conftest.err conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_header_memcheck_h" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_header_memcheck_h" >&5 $as_echo "$gcc_cv_header_memcheck_h" >&6; } +if test $gcc_cv_header_valgrind_memcheck_h = yes; then + +$as_echo "#define HAVE_VALGRIND_MEMCHECK_H 1" >>confdefs.h + +fi +if test $gcc_cv_header_memcheck_h = yes; then + +$as_echo "#define HAVE_MEMCHECK_H 1" >>confdefs.h + +fi + +if test x$ac_valgrind_checking != x ; then # Prepare PATH_SEPARATOR. # The user is always right. @@ -6887,16 +6901,6 @@ fi $as_echo "#define ENABLE_VALGRIND_CHECKING 1" >>confdefs.h - if test $gcc_cv_header_valgrind_memcheck_h = yes; then - -$as_echo "#define HAVE_VALGRIND_MEMCHECK_H 1" >>confdefs.h - - fi - if test $gcc_cv_header_memcheck_h = yes; then - -$as_echo "#define HAVE_MEMCHECK_H 1" >>confdefs.h - - fi fi @@ -6939,6 +6943,25 @@ cat >>confdefs.h <<_ACEOF _ACEOF +# Check whether --enable-valgrind-annotations was given. +if test "${enable_valgrind_annotations+set}" = set; then : + enableval=$enable_valgrind_annotations; +else + enable_valgrind_annotations=no +fi + +if test x$enable_valgrind_annotations != xno \ + || test x$ac_valgrind_checking != x; then + if (test $have_valgrind_h = no \ + && test $gcc_cv_header_memcheck_h = no \ + && test $gcc_cv_header_valgrind_memcheck_h = no); then + as_fn_error "*** Can't find valgrind/memcheck.h, memcheck.h or valgrind.h" "$LINENO" 5 + fi + +$as_echo "#define ENABLE_VALGRIND_ANNOTATIONS 1" >>confdefs.h + +fi + # ------------------------------- # Miscenalleous configure options # ------------------------------- @@ -17971,7 +17994,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17974 "configure" +#line 17997 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -18077,7 +18100,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18080 "configure" +#line 18103 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -23306,13 +23329,8 @@ foo: .long 25 ;; i[34567]86-*-* | x86_64-*-*) case "$target" in - i[34567]86-*-solaris2.*) - on_solaris=yes - tga_func=___tls_get_addr - ;; - x86_64-*-solaris2.1[0-9]*) + i[34567]86-*-solaris2.* | x86_64-*-solaris2.1[0-9]*) on_solaris=yes - tga_func=__tls_get_addr ;; *) on_solaris=no @@ -23587,7 +23605,6 @@ foo: .long 25 case "$target" in sparc*-sun-solaris2.*) on_solaris=yes - tga_func=__tls_get_addr ;; *) on_solaris=no @@ -23711,101 +23728,6 @@ if test $gcc_cv_as_tls = yes; then set_have_as_tls=yes fi fi -case "$target" in - # TLS was introduced in the Solaris 9 FCS release. Support for GNU-style - # TLS on x86 was only introduced in Solaris 9 4/04, replacing the earlier - # Sun style that Sun ld and GCC don't support any longer. - *-*-solaris2.*) - ld_tls_support=yes - - save_LIBS="$LIBS" - save_LDFLAGS="$LDFLAGS" - LIBS= - LDFLAGS= - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking library containing $tga_func" >&5 -$as_echo_n "checking library containing $tga_func... " >&6; } - # Before Solaris 10, __tls_get_addr (SPARC/x64) resp. ___tls_get_addr - # (32-bit x86) only lived in libthread, so check for that. Keep - # set_have_as_tls if found, disable if not. - as_ac_Search=`$as_echo "ac_cv_search_$tga_func" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing $tga_func" >&5 -$as_echo_n "checking for library containing $tga_func... " >&6; } -if { as_var=$as_ac_Search; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $tga_func (); -int -main () -{ -return $tga_func (); - ; - return 0; -} -_ACEOF -for ac_lib in '' thread; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - eval "$as_ac_Search=\$ac_res" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if { as_var=$as_ac_Search; eval "test \"\${$as_var+set}\" = set"; }; then : - break -fi -done -if { as_var=$as_ac_Search; eval "test \"\${$as_var+set}\" = set"; }; then : - -else - eval "$as_ac_Search=no" -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -eval ac_res=\$$as_ac_Search - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -eval ac_res=\$$as_ac_Search -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -else - set_have_as_tls=no -fi - - ld_tls_libs="$LIBS" - # Clear LIBS if we cannot support TLS. - if test $set_have_as_tls = no; then - LIBS= - fi - # Always define LIB_TLS_SPEC, even without TLS support. - -cat >>confdefs.h <<_ACEOF -#define LIB_TLS_SPEC "$LIBS" -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBS" >&5 -$as_echo "$LIBS" >&6; } - - LIBS="$save_LIBS" - LDFLAGS="$save_LDFLAGS" - ;; -esac if test $set_have_as_tls = yes ; then $as_echo "#define HAVE_AS_TLS 1" >>confdefs.h @@ -24496,7 +24418,7 @@ else .align 4 smac %g2, %g3, %g1 umac %g2, %g3, %g1 - cas [%g2], %g3, %g1' > conftest.s + casa [%g2] 0xb, %g3, %g1' > conftest.s if { ac_try='$gcc_cv_as $gcc_cv_as_flags -Aleon -o conftest.o conftest.s >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 (eval $ac_try) 2>&5 diff --git a/gcc/configure.ac b/gcc/configure.ac index 1235501bd49..5565524c89a 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -514,27 +514,36 @@ dnl # an if statement. This was the source of very frustrating bugs dnl # in converting to autoconf 2.5x! AC_CHECK_HEADER(valgrind.h, have_valgrind_h=yes, have_valgrind_h=no) -if test x$ac_valgrind_checking != x ; then - # It is certainly possible that there's valgrind but no valgrind.h. - # GCC relies on making annotations so we must have both. - AC_MSG_CHECKING(for VALGRIND_DISCARD in <valgrind/memcheck.h>) - AC_PREPROC_IFELSE([AC_LANG_SOURCE( - [[#include <valgrind/memcheck.h> +# It is certainly possible that there's valgrind but no valgrind.h. +# GCC relies on making annotations so we must have both. +AC_MSG_CHECKING(for VALGRIND_DISCARD in <valgrind/memcheck.h>) +AC_PREPROC_IFELSE([AC_LANG_SOURCE( + [[#include <valgrind/memcheck.h> #ifndef VALGRIND_DISCARD #error VALGRIND_DISCARD not defined #endif]])], [gcc_cv_header_valgrind_memcheck_h=yes], [gcc_cv_header_valgrind_memcheck_h=no]) - AC_MSG_RESULT($gcc_cv_header_valgrind_memcheck_h) - AC_MSG_CHECKING(for VALGRIND_DISCARD in <memcheck.h>) - AC_PREPROC_IFELSE([AC_LANG_SOURCE( - [[#include <memcheck.h> +AC_MSG_RESULT($gcc_cv_header_valgrind_memcheck_h) +AC_MSG_CHECKING(for VALGRIND_DISCARD in <memcheck.h>) +AC_PREPROC_IFELSE([AC_LANG_SOURCE( + [[#include <memcheck.h> #ifndef VALGRIND_DISCARD #error VALGRIND_DISCARD not defined #endif]])], [gcc_cv_header_memcheck_h=yes], [gcc_cv_header_memcheck_h=no]) - AC_MSG_RESULT($gcc_cv_header_memcheck_h) +AC_MSG_RESULT($gcc_cv_header_memcheck_h) +if test $gcc_cv_header_valgrind_memcheck_h = yes; then + AC_DEFINE(HAVE_VALGRIND_MEMCHECK_H, 1, + [Define if valgrind's valgrind/memcheck.h header is installed.]) +fi +if test $gcc_cv_header_memcheck_h = yes; then + AC_DEFINE(HAVE_MEMCHECK_H, 1, + [Define if valgrind's memcheck.h header is installed.]) +fi + +if test x$ac_valgrind_checking != x ; then AM_PATH_PROG_WITH_TEST(valgrind_path, valgrind, [$ac_dir/$ac_word --version | grep valgrind- >/dev/null 2>&1]) if test "x$valgrind_path" = "x" \ @@ -548,14 +557,6 @@ if test x$ac_valgrind_checking != x ; then AC_DEFINE(ENABLE_VALGRIND_CHECKING, 1, [Define if you want to run subprograms and generated programs through valgrind (a memory checker). This is extremely expensive.]) - if test $gcc_cv_header_valgrind_memcheck_h = yes; then - AC_DEFINE(HAVE_VALGRIND_MEMCHECK_H, 1, - [Define if valgrind's valgrind/memcheck.h header is installed.]) - fi - if test $gcc_cv_header_memcheck_h = yes; then - AC_DEFINE(HAVE_MEMCHECK_H, 1, - [Define if valgrind's memcheck.h header is installed.]) - fi fi AC_SUBST(valgrind_path_defines) AC_SUBST(valgrind_command) @@ -594,6 +595,21 @@ gather_stats=`if test $enable_gather_detailed_mem_stats != no; then echo 1; else AC_DEFINE_UNQUOTED(GATHER_STATISTICS, $gather_stats, [Define to enable detailed memory allocation stats gathering.]) +AC_ARG_ENABLE(valgrind-annotations, +[AS_HELP_STRING([--enable-valgrind-annotations], + [enable valgrind runtime interaction])], [], +[enable_valgrind_annotations=no]) +if test x$enable_valgrind_annotations != xno \ + || test x$ac_valgrind_checking != x; then + if (test $have_valgrind_h = no \ + && test $gcc_cv_header_memcheck_h = no \ + && test $gcc_cv_header_valgrind_memcheck_h = no); then + AC_MSG_ERROR([*** Can't find valgrind/memcheck.h, memcheck.h or valgrind.h]) + fi + AC_DEFINE(ENABLE_VALGRIND_ANNOTATIONS, 1, +[Define to get calls to the valgrind runtime enabled.]) +fi + # ------------------------------- # Miscenalleous configure options # ------------------------------- @@ -2935,13 +2951,8 @@ foo: .long 25 ;; i[34567]86-*-* | x86_64-*-*) case "$target" in - i[34567]86-*-solaris2.*) - on_solaris=yes - tga_func=___tls_get_addr - ;; - x86_64-*-solaris2.1[0-9]*) + i[34567]86-*-solaris2.* | x86_64-*-solaris2.1[0-9]*) on_solaris=yes - tga_func=__tls_get_addr ;; *) on_solaris=no @@ -3217,7 +3228,6 @@ foo: .long 25 case "$target" in sparc*-sun-solaris2.*) on_solaris=yes - tga_func=__tls_get_addr ;; *) on_solaris=no @@ -3313,37 +3323,6 @@ else [$tls_first_major,$tls_first_minor,0], [$tls_as_opt], [$conftest_s],, [set_have_as_tls=yes]) fi -case "$target" in - # TLS was introduced in the Solaris 9 FCS release. Support for GNU-style - # TLS on x86 was only introduced in Solaris 9 4/04, replacing the earlier - # Sun style that Sun ld and GCC don't support any longer. - *-*-solaris2.*) - ld_tls_support=yes - - save_LIBS="$LIBS" - save_LDFLAGS="$LDFLAGS" - LIBS= - LDFLAGS= - - AC_MSG_CHECKING(library containing $tga_func) - # Before Solaris 10, __tls_get_addr (SPARC/x64) resp. ___tls_get_addr - # (32-bit x86) only lived in libthread, so check for that. Keep - # set_have_as_tls if found, disable if not. - AC_SEARCH_LIBS([$tga_func], [thread],, [set_have_as_tls=no]) - ld_tls_libs="$LIBS" - # Clear LIBS if we cannot support TLS. - if test $set_have_as_tls = no; then - LIBS= - fi - # Always define LIB_TLS_SPEC, even without TLS support. - AC_DEFINE_UNQUOTED(LIB_TLS_SPEC, "$LIBS", - [Define to the library containing __tls_get_addr/___tls_get_addr.]) - AC_MSG_RESULT($LIBS) - - LIBS="$save_LIBS" - LDFLAGS="$save_LDFLAGS" - ;; -esac if test $set_have_as_tls = yes ; then AC_DEFINE(HAVE_AS_TLS, 1, [Define if your assembler and linker support thread-local storage.]) @@ -3684,7 +3663,7 @@ foo: .align 4 smac %g2, %g3, %g1 umac %g2, %g3, %g1 - cas [[%g2]], %g3, %g1],, + casa [[%g2]] 0xb, %g3, %g1],, [AC_DEFINE(HAVE_AS_LEON, 1, [Define if your assembler supports LEON instructions.])]) ;; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ae213426553..a5f3829d705 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2014-04-28 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/59120 + * parser.c (cp_parser_alias_declaration): Check return value of + cp_parser_require. + +2014-04-24 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_omp_atomic): Allow seq_cst before + atomic-clause, allow comma in between atomic-clause and + seq_cst. + 2014-04-24 Marc Glisse <marc.glisse@inria.fr> PR libstdc++/43622 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4e6a2b88f32..962cacedf80 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16142,15 +16142,8 @@ cp_parser_alias_declaration (cp_parser* parser) if (parser->num_template_parameter_lists) parser->type_definition_forbidden_message = saved_message; - if (type == error_mark_node) - { - cp_parser_skip_to_end_of_block_or_statement (parser); - return error_mark_node; - } - - cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); - - if (cp_parser_error_occurred (parser)) + if (type == error_mark_node + || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) { cp_parser_skip_to_end_of_block_or_statement (parser); return error_mark_node; @@ -28534,6 +28527,20 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME) + cp_lexer_consume_token (parser->lexer); + } + } + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + if (!strcmp (p, "read")) code = OMP_ATOMIC_READ; else if (!strcmp (p, "write")) @@ -28547,16 +28554,22 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok) if (p) cp_lexer_consume_token (parser->lexer); } - - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + if (!seq_cst) { - tree id = cp_lexer_peek_token (parser->lexer)->u.value; - const char *p = IDENTIFIER_POINTER (id); + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME) + cp_lexer_consume_token (parser->lexer); - if (!strcmp (p, "seq_cst")) + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { - seq_cst = true; - cp_lexer_consume_token (parser->lexer); + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (!strcmp (p, "seq_cst")) + { + seq_cst = true; + cp_lexer_consume_token (parser->lexer); + } } } cp_parser_require_pragma_eol (parser, pragma_tok); diff --git a/gcc/cselib.c b/gcc/cselib.c index c55b02772ed..00a04baab6e 100644 --- a/gcc/cselib.c +++ b/gcc/cselib.c @@ -49,9 +49,6 @@ struct elt_list { cselib_val *elt; }; -/* See the documentation of cselib_find_slot below. */ -static enum machine_mode find_slot_memmode; - static bool cselib_record_memory; static bool cselib_preserve_constants; static bool cselib_any_perm_equivs; @@ -94,7 +91,14 @@ static rtx cselib_expand_value_rtx_1 (rtx, struct expand_value_data *, int); struct cselib_hasher : typed_noop_remove <cselib_val> { typedef cselib_val value_type; - typedef rtx_def compare_type; + struct compare_type { + /* The rtx value and its mode (needed separately for constant + integers). */ + enum machine_mode mode; + rtx x; + /* The mode of the contaning MEM, if any, otherwise VOIDmode. */ + enum machine_mode memmode; + }; static inline hashval_t hash (const value_type *); static inline bool equal (const value_type *, const compare_type *); }; @@ -118,27 +122,20 @@ inline bool cselib_hasher::equal (const value_type *v, const compare_type *x_arg) { struct elt_loc_list *l; - rtx x = CONST_CAST_RTX (x_arg); - enum machine_mode mode = GET_MODE (x); - - gcc_assert (!CONST_SCALAR_INT_P (x) && GET_CODE (x) != CONST_FIXED); + rtx x = x_arg->x; + enum machine_mode mode = x_arg->mode; + enum machine_mode memmode = x_arg->memmode; if (mode != GET_MODE (v->val_rtx)) return false; - /* Unwrap X if necessary. */ - if (GET_CODE (x) == CONST - && (CONST_SCALAR_INT_P (XEXP (x, 0)) - || GET_CODE (XEXP (x, 0)) == CONST_FIXED)) - x = XEXP (x, 0); - if (GET_CODE (x) == VALUE) return x == v->val_rtx; /* We don't guarantee that distinct rtx's have different hash values, so we need to do a comparison. */ for (l = v->locs; l; l = l->next) - if (rtx_equal_for_cselib_1 (l->loc, x, find_slot_memmode)) + if (rtx_equal_for_cselib_1 (l->loc, x, memmode)) { promote_debug_loc (l); return true; @@ -498,8 +495,11 @@ preserve_constants_and_equivs (cselib_val **x, void *info ATTRIBUTE_UNUSED) if (invariant_or_equiv_p (v)) { + cselib_hasher::compare_type lookup = { + GET_MODE (v->val_rtx), v->val_rtx, VOIDmode + }; cselib_val **slot - = cselib_preserved_hash_table.find_slot_with_hash (v->val_rtx, + = cselib_preserved_hash_table.find_slot_with_hash (&lookup, v->hash, INSERT); gcc_assert (!*slot); *slot = v; @@ -572,22 +572,19 @@ cselib_get_next_uid (void) /* Search for X, whose hashcode is HASH, in CSELIB_HASH_TABLE, INSERTing if requested. When X is part of the address of a MEM, - MEMMODE should specify the mode of the MEM. While searching the - table, MEMMODE is held in FIND_SLOT_MEMMODE, so that autoinc RTXs - in X can be resolved. */ + MEMMODE should specify the mode of the MEM. */ static cselib_val ** -cselib_find_slot (rtx x, hashval_t hash, enum insert_option insert, - enum machine_mode memmode) +cselib_find_slot (enum machine_mode mode, rtx x, hashval_t hash, + enum insert_option insert, enum machine_mode memmode) { cselib_val **slot = NULL; - find_slot_memmode = memmode; + cselib_hasher::compare_type lookup = { mode, x, memmode }; if (cselib_preserve_constants) - slot = cselib_preserved_hash_table.find_slot_with_hash (x, hash, + slot = cselib_preserved_hash_table.find_slot_with_hash (&lookup, hash, NO_INSERT); if (!slot) - slot = cselib_hash_table.find_slot_with_hash (x, hash, insert); - find_slot_memmode = VOIDmode; + slot = cselib_hash_table.find_slot_with_hash (&lookup, hash, insert); return slot; } @@ -1041,18 +1038,6 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode) return 1; } -/* We need to pass down the mode of constants through the hash table - functions. For that purpose, wrap them in a CONST of the appropriate - mode. */ -static rtx -wrap_constant (enum machine_mode mode, rtx x) -{ - if (!CONST_SCALAR_INT_P (x) && GET_CODE (x) != CONST_FIXED) - return x; - gcc_assert (mode != VOIDmode); - return gen_rtx_CONST (mode, x); -} - /* Hash an rtx. Return 0 if we couldn't hash the rtx. For registers and memory locations, we look up their cselib_val structure and return its VALUE element. @@ -1411,8 +1396,7 @@ cselib_lookup_mem (rtx x, int create) mem_elt = new_cselib_val (next_uid, mode, x); add_mem_for_addr (addr, mem_elt, x); - slot = cselib_find_slot (wrap_constant (mode, x), mem_elt->hash, - INSERT, mode); + slot = cselib_find_slot (mode, x, mem_elt->hash, INSERT, VOIDmode); *slot = mem_elt; return mem_elt; } @@ -2068,7 +2052,7 @@ cselib_lookup_1 (rtx x, enum machine_mode mode, } } REG_VALUES (i)->next = new_elt_list (REG_VALUES (i)->next, e); - slot = cselib_find_slot (x, e->hash, INSERT, memmode); + slot = cselib_find_slot (mode, x, e->hash, INSERT, memmode); *slot = e; return e; } @@ -2081,7 +2065,7 @@ cselib_lookup_1 (rtx x, enum machine_mode mode, if (! hashval) return 0; - slot = cselib_find_slot (wrap_constant (mode, x), hashval, + slot = cselib_find_slot (mode, x, hashval, create ? INSERT : NO_INSERT, memmode); if (slot == 0) return 0; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 347a94a3aee..9780d923804 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -12787,9 +12787,12 @@ float __builtin_recipdivf (float, float); float __builtin_rsqrtf (float); double __builtin_recipdiv (double, double); double __builtin_rsqrt (double); -long __builtin_bpermd (long, long); uint64_t __builtin_ppc_get_timebase (); unsigned long __builtin_ppc_mftb (); +double __builtin_unpack_longdouble (long double, int); +double __builtin_longdouble_dw0 (long double); +double __builtin_longdouble_dw1 (long double); +long double __builtin_pack_longdouble (double, double); @end smallexample The @code{vec_rsqrt}, @code{__builtin_rsqrt}, and @@ -12809,6 +12812,57 @@ The @code{__builtin_ppc_mftb} function always generates one instruction and returns the Time Base Register value as an unsigned long, throwing away the most significant word on 32-bit environments. +The following built-in functions are available for the PowerPC family +of processors, starting with ISA 2.06 or later (@option{-mcpu=power7} +or @option{-mpopcntd}): +@smallexample +long __builtin_bpermd (long, long); +int __builtin_divwe (int, int); +int __builtin_divweo (int, int); +unsigned int __builtin_divweu (unsigned int, unsigned int); +unsigned int __builtin_divweuo (unsigned int, unsigned int); +long __builtin_divde (long, long); +long __builtin_divdeo (long, long); +unsigned long __builtin_divdeu (unsigned long, unsigned long); +unsigned long __builtin_divdeuo (unsigned long, unsigned long); +unsigned int cdtbcd (unsigned int); +unsigned int cbcdtd (unsigned int); +unsigned int addg6s (unsigned int, unsigned int); +@end smallexample + +The @code{__builtin_divde}, @code{__builtin_divdeo}, +@code{__builitin_divdeu}, @code{__builtin_divdeou} functions require a +64-bit environment support ISA 2.06 or later. + +The following built-in functions are available for the PowerPC family +of processors when hardware decimal floating point +(@option{-mhard-dfp}) is available: +@smallexample +_Decimal64 __builtin_dxex (_Decimal64); +_Decimal128 __builtin_dxexq (_Decimal128); +_Decimal64 __builtin_ddedpd (int, _Decimal64); +_Decimal128 __builtin_ddedpdq (int, _Decimal128); +_Decimal64 __builtin_denbcd (int, _Decimal64); +_Decimal128 __builtin_denbcdq (int, _Decimal128); +_Decimal64 __builtin_diex (_Decimal64, _Decimal64); +_Decimal128 _builtin_diexq (_Decimal128, _Decimal128); +_Decimal64 __builtin_dscli (_Decimal64, int); +_Decimal128 __builitn_dscliq (_Decimal128, int); +_Decimal64 __builtin_dscri (_Decimal64, int); +_Decimal128 __builitn_dscriq (_Decimal128, int); +unsigned long long __builtin_unpack_dec128 (_Decimal128, int); +_Decimal128 __builtin_pack_dec128 (unsigned long long, unsigned long long); +@end smallexample + +The following built-in functions are available for the PowerPC family +of processors when the Vector Scalar (vsx) instruction set is +available: +@smallexample +unsigned long long __builtin_unpack_vector_int128 (vector __int128_t, int); +vector __int128_t __builtin_pack_vector_int128 (unsigned long long, + unsigned long long); +@end smallexample + @node PowerPC AltiVec/VSX Built-in Functions @subsection PowerPC AltiVec Built-in Functions @@ -15220,6 +15274,17 @@ vector __uint128_t vec_vsubcuq (vector __uint128_t, vector __uint128_t); __int128_t vec_vsubuqm (__int128_t, __int128_t); __uint128_t vec_vsubuqm (__uint128_t, __uint128_t); + +vector __int128_t __builtin_bcdadd (vector __int128_t, vector__int128_t); +int __builtin_bcdadd_lt (vector __int128_t, vector__int128_t); +int __builtin_bcdadd_eq (vector __int128_t, vector__int128_t); +int __builtin_bcdadd_gt (vector __int128_t, vector__int128_t); +int __builtin_bcdadd_ov (vector __int128_t, vector__int128_t); +vector __int128_t bcdsub (vector __int128_t, vector__int128_t); +int __builtin_bcdsub_lt (vector __int128_t, vector__int128_t); +int __builtin_bcdsub_eq (vector __int128_t, vector__int128_t); +int __builtin_bcdsub_gt (vector __int128_t, vector__int128_t); +int __builtin_bcdsub_ov (vector __int128_t, vector__int128_t); @end smallexample If the cryptographic instructions are enabled (@option{-mcrypto} or diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 0b2b3657577..7851b0061b3 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -2544,8 +2544,7 @@ Finally a @code{stagefeedback} compiler is built using the information collected Unlike standard bootstrap, several additional restrictions apply. The compiler used to build @code{stage1} needs to support a 64-bit integral type. -It is recommended to only use GCC for this. Also parallel make is currently -not supported since collisions in profile collecting may occur. +It is recommended to only use GCC for this. @html <hr /> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ff43f262323..da7a00ed00c 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -993,6 +993,7 @@ See RS/6000 and PowerPC Options. -mhard-quad-float -msoft-quad-float @gol -mstack-bias -mno-stack-bias @gol -munaligned-doubles -mno-unaligned-doubles @gol +-muser-mode -mno-user-mode @gol -mv8plus -mno-v8plus -mvis -mno-vis @gol -mvis2 -mno-vis2 -mvis3 -mno-vis3 @gol -mcbcond -mno-cbcond @gol @@ -20961,6 +20962,14 @@ Specifying this option avoids some rare compatibility problems with code generated by other compilers. It is not the default because it results in a performance loss, especially for floating-point code. +@item -muser-mode +@itemx -mno-user-mode +@opindex muser-mode +@opindex mno-user-mode +Do not generate code that can only run in supervisor mode. This is relevant +only for the @code{casa} instruction emitted for the LEON3 processor. The +default is @option{-mno-user-mode}. + @item -mno-faster-structs @itemx -mfaster-structs @opindex mno-faster-structs diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 2b2ab5dd831..da0b3f589c9 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -6917,14 +6917,13 @@ should_move_die_to_comdat (dw_die_ref die) case DW_TAG_structure_type: case DW_TAG_enumeration_type: case DW_TAG_union_type: - /* Don't move declarations, inlined instances, or types nested in a - subprogram. */ + /* Don't move declarations, inlined instances, types nested in a + subprogram, or types that contain subprogram definitions. */ if (is_declaration_die (die) || get_AT (die, DW_AT_abstract_origin) - || is_nested_in_subprogram (die)) + || is_nested_in_subprogram (die) + || contains_subprogram_definition (die)) return 0; - /* A type definition should never contain a subprogram definition. */ - gcc_assert (!contains_subprogram_definition (die)); return 1; case DW_TAG_array_type: case DW_TAG_interface_type: @@ -7013,6 +7012,7 @@ clone_as_declaration (dw_die_ref die) switch (a->dw_attr) { + case DW_AT_abstract_origin: case DW_AT_artificial: case DW_AT_containing_type: case DW_AT_external: @@ -7245,6 +7245,12 @@ generate_skeleton_bottom_up (skeleton_chain_node *parent) dw_die_ref clone = clone_die (c); move_all_children (c, clone); + /* If the original has a DW_AT_object_pointer attribute, + it would now point to a child DIE just moved to the + cloned tree, so we need to remove that attribute from + the original. */ + remove_AT (c, DW_AT_object_pointer); + replace_child (c, clone, prev); generate_skeleton_ancestor_tree (parent); add_child_die (parent->new_die, c); @@ -7386,28 +7392,38 @@ break_out_comdat_types (dw_die_ref die) } while (next != NULL); } -/* Like clone_tree, but additionally enter all the children into - the hash table decl_table. */ +/* Like clone_tree, but copy DW_TAG_subprogram DIEs as declarations. + Enter all the cloned children into the hash table decl_table. */ static dw_die_ref -clone_tree_hash (dw_die_ref die, decl_hash_type decl_table) +clone_tree_partial (dw_die_ref die, decl_hash_type decl_table) { dw_die_ref c; - dw_die_ref clone = clone_die (die); + dw_die_ref clone; struct decl_table_entry *entry; - decl_table_entry **slot = decl_table.find_slot_with_hash (die, - htab_hash_pointer (die), INSERT); + decl_table_entry **slot; + + if (die->die_tag == DW_TAG_subprogram) + clone = clone_as_declaration (die); + else + clone = clone_die (die); + + slot = decl_table.find_slot_with_hash (die, + htab_hash_pointer (die), INSERT); + /* Assert that DIE isn't in the hash table yet. If it would be there before, the ancestors would be necessarily there as well, therefore - clone_tree_hash wouldn't be called. */ + clone_tree_partial wouldn't be called. */ gcc_assert (*slot == HTAB_EMPTY_ENTRY); + entry = XCNEW (struct decl_table_entry); entry->orig = die; entry->copy = clone; *slot = entry; - FOR_EACH_CHILD (die, c, - add_child_die (clone, clone_tree_hash (c, decl_table))); + if (die->die_tag != DW_TAG_subprogram) + FOR_EACH_CHILD (die, c, + add_child_die (clone, clone_tree_partial (c, decl_table))); return clone; } @@ -7458,9 +7474,15 @@ copy_decls_walk (dw_die_ref unit, dw_die_ref die, decl_hash_type decl_table) entry->copy = copy; *slot = entry; - FOR_EACH_CHILD (targ, c, - add_child_die (copy, - clone_tree_hash (c, decl_table))); + /* If TARG is not a declaration DIE, we need to copy its + children. */ + if (!is_declaration_die (targ)) + { + FOR_EACH_CHILD ( + targ, c, + add_child_die (copy, + clone_tree_partial (c, decl_table))); + } /* Make sure the cloned tree is marked as part of the type unit. */ diff --git a/gcc/expr.c b/gcc/expr.c index fe95ebcbfa0..989a8780dc9 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -2365,6 +2365,18 @@ use_reg_mode (rtx *call_fusage, rtx reg, enum machine_mode mode) = gen_rtx_EXPR_LIST (mode, gen_rtx_USE (VOIDmode, reg), *call_fusage); } +/* Add a CLOBBER expression for REG to the (possibly empty) list pointed + to by CALL_FUSAGE. REG must denote a hard register. */ + +void +clobber_reg_mode (rtx *call_fusage, rtx reg, enum machine_mode mode) +{ + gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER); + + *call_fusage + = gen_rtx_EXPR_LIST (mode, gen_rtx_CLOBBER (VOIDmode, reg), *call_fusage); +} + /* Add USE expressions to *CALL_FUSAGE for each of NREGS consecutive regs, starting at REGNO. All of these registers must be hard registers. */ diff --git a/gcc/expr.h b/gcc/expr.h index 524da6731a9..1823febac26 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -346,6 +346,7 @@ extern void copy_blkmode_from_reg (rtx, rtx, tree); /* Mark REG as holding a parameter for the next CALL_INSN. Mode is TYPE_MODE of the non-promoted parameter, or VOIDmode. */ extern void use_reg_mode (rtx *, rtx, enum machine_mode); +extern void clobber_reg_mode (rtx *, rtx, enum machine_mode); extern rtx copy_blkmode_to_reg (enum machine_mode, tree); @@ -356,6 +357,13 @@ use_reg (rtx *fusage, rtx reg) use_reg_mode (fusage, reg, VOIDmode); } +/* Mark REG as clobbered by the call with FUSAGE as CALL_INSN_FUNCTION_USAGE. */ +static inline void +clobber_reg (rtx *fusage, rtx reg) +{ + clobber_reg_mode (fusage, reg, VOIDmode); +} + /* Mark NREGS consecutive regs, starting at REGNO, as holding parameters for the next CALL_INSN. */ extern void use_regs (rtx *, int, int); diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 427c9b15ad8..5cf25134e30 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,23 @@ +2014-03-27 Thomas Koenig <tkoenig@gcc.gnu.org> + + PR fortran/59604 + PR fortran/58003 + * gfortran.h (gfc_convert_mpz_to_signed): Add prototype. + * arith.c (gfc_int2int): Convert number to signed if + arithmetic overflow is not checked. + * simplify.c (convert_mpz_to_unsigned): Only trigger assert for + size if range checking is in force. + (convert_mpz_to_signed): Make non-static, rename to + (gfc_convert_mpz_to_signed). + (simplify_dshift): Use gfc_convert_mpz_to_signed. + (gfc_simplify_ibclr): Likewise. + (gfc_simplify_ibits): Likewise. + (gfc_simplify_ibset): Likewise. + (simplify_shift): Likewise. + (gfc_simplify_ishiftc): Likewise. + (gfc_simplify_maskr): Likewise. + (gfc_simplify_maskl): Likewise. + 2014-04-22 Tobias Burnus <burnus@net-b.de> PR fortran/60881 diff --git a/gcc/fortran/arith.c b/gcc/fortran/arith.c index 053cf765e59..a05fa4907a4 100644 --- a/gcc/fortran/arith.c +++ b/gcc/fortran/arith.c @@ -1976,6 +1976,17 @@ gfc_int2int (gfc_expr *src, int kind) } } + /* If we do not trap numeric overflow, we need to convert the number to + signed, throwing away high-order bits if necessary. */ + if (gfc_option.flag_range_check == 0) + { + int k; + + k = gfc_validate_kind (BT_INTEGER, kind, false); + gfc_convert_mpz_to_signed (result->value.integer, + gfc_integer_kinds[k].bit_size); + } + return result; } diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 14c202dd413..f0eed809ab8 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -3022,4 +3022,8 @@ typedef int (*walk_expr_fn_t) (gfc_expr **, int *, void *); int gfc_expr_walker (gfc_expr **, walk_expr_fn_t, void *); int gfc_code_walker (gfc_code **, walk_code_fn_t, walk_expr_fn_t, void *); +/* simplify.c */ + +void gfc_convert_mpz_to_signed (mpz_t, int); + #endif /* GCC_GFORTRAN_H */ diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c index 96d0f21f36c..1b6cd5bc4c1 100644 --- a/gcc/fortran/simplify.c +++ b/gcc/fortran/simplify.c @@ -151,8 +151,10 @@ convert_mpz_to_unsigned (mpz_t x, int bitsize) if (mpz_sgn (x) < 0) { - /* Confirm that no bits above the signed range are unset. */ - gcc_assert (mpz_scan0 (x, bitsize-1) == ULONG_MAX); + /* Confirm that no bits above the signed range are unset if we + are doing range checking. */ + if (gfc_option.flag_range_check != 0) + gcc_assert (mpz_scan0 (x, bitsize-1) == ULONG_MAX); mpz_init_set_ui (mask, 1); mpz_mul_2exp (mask, mask, bitsize); @@ -175,13 +177,15 @@ convert_mpz_to_unsigned (mpz_t x, int bitsize) If the bitsize-1 bit is set, this is taken as a sign bit and the number is converted to the corresponding negative number. */ -static void -convert_mpz_to_signed (mpz_t x, int bitsize) +void +gfc_convert_mpz_to_signed (mpz_t x, int bitsize) { mpz_t mask; - /* Confirm that no bits above the unsigned range are set. */ - gcc_assert (mpz_scan1 (x, bitsize) == ULONG_MAX); + /* Confirm that no bits above the unsigned range are set if we are + doing range checking. */ + if (gfc_option.flag_range_check != 0) + gcc_assert (mpz_scan1 (x, bitsize) == ULONG_MAX); if (mpz_tstbit (x, bitsize - 1) == 1) { @@ -1943,7 +1947,7 @@ simplify_dshift (gfc_expr *arg1, gfc_expr *arg2, gfc_expr *shiftarg, mpz_setbit (result->value.integer, shift + i); /* Convert to a signed value. */ - convert_mpz_to_signed (result->value.integer, size); + gfc_convert_mpz_to_signed (result->value.integer, size); return result; } @@ -2561,7 +2565,7 @@ gfc_simplify_ibclr (gfc_expr *x, gfc_expr *y) mpz_clrbit (result->value.integer, pos); - convert_mpz_to_signed (result->value.integer, + gfc_convert_mpz_to_signed (result->value.integer, gfc_integer_kinds[k].bit_size); return result; @@ -2619,7 +2623,7 @@ gfc_simplify_ibits (gfc_expr *x, gfc_expr *y, gfc_expr *z) free (bits); - convert_mpz_to_signed (result->value.integer, + gfc_convert_mpz_to_signed (result->value.integer, gfc_integer_kinds[k].bit_size); return result; @@ -2646,7 +2650,7 @@ gfc_simplify_ibset (gfc_expr *x, gfc_expr *y) mpz_setbit (result->value.integer, pos); - convert_mpz_to_signed (result->value.integer, + gfc_convert_mpz_to_signed (result->value.integer, gfc_integer_kinds[k].bit_size); return result; @@ -3093,7 +3097,7 @@ simplify_shift (gfc_expr *e, gfc_expr *s, const char *name, } } - convert_mpz_to_signed (result->value.integer, bitsize); + gfc_convert_mpz_to_signed (result->value.integer, bitsize); free (bits); return result; @@ -3234,7 +3238,7 @@ gfc_simplify_ishftc (gfc_expr *e, gfc_expr *s, gfc_expr *sz) } } - convert_mpz_to_signed (result->value.integer, isize); + gfc_convert_mpz_to_signed (result->value.integer, isize); free (bits); return result; @@ -3954,7 +3958,7 @@ gfc_simplify_maskr (gfc_expr *i, gfc_expr *kind_arg) mpz_mul_2exp (result->value.integer, result->value.integer, arg); mpz_sub_ui (result->value.integer, result->value.integer, 1); - convert_mpz_to_signed (result->value.integer, gfc_integer_kinds[k].bit_size); + gfc_convert_mpz_to_signed (result->value.integer, gfc_integer_kinds[k].bit_size); return result; } @@ -3990,7 +3994,7 @@ gfc_simplify_maskl (gfc_expr *i, gfc_expr *kind_arg) mpz_sub (result->value.integer, z, result->value.integer); mpz_clear (z); - convert_mpz_to_signed (result->value.integer, gfc_integer_kinds[k].bit_size); + gfc_convert_mpz_to_signed (result->value.integer, gfc_integer_kinds[k].bit_size); return result; } diff --git a/gcc/gimple-ssa-strength-reduction.c b/gcc/gimple-ssa-strength-reduction.c index cf252d4269d..af9f26d2e9c 100644 --- a/gcc/gimple-ssa-strength-reduction.c +++ b/gcc/gimple-ssa-strength-reduction.c @@ -1111,14 +1111,17 @@ create_mul_imm_cand (gimple gs, tree base_in, tree stride_in, bool speed) X = Y * c ============================ X = (B + i') * (S * c) */ - base = base_cand->base_expr; - index = base_cand->index; temp = wi::to_widest (base_cand->stride) * wi::to_widest (stride_in); - stride = wide_int_to_tree (TREE_TYPE (stride_in), temp); - ctype = base_cand->cand_type; - if (has_single_use (base_in)) - savings = (base_cand->dead_savings - + stmt_cost (base_cand->cand_stmt, speed)); + if (wi::fits_to_tree_p (temp, TREE_TYPE (stride_in))) + { + base = base_cand->base_expr; + index = base_cand->index; + stride = wide_int_to_tree (TREE_TYPE (stride_in), temp); + ctype = base_cand->cand_type; + if (has_single_use (base_in)) + savings = (base_cand->dead_savings + + stmt_cost (base_cand->cand_stmt, speed)); + } } else if (base_cand->kind == CAND_ADD && integer_onep (base_cand->stride)) { diff --git a/gcc/gimplify.c b/gcc/gimplify.c index d7470fbb0a6..008a2528644 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5796,7 +5796,7 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) to the contrary in the innermost scope, generate an error. */ static bool -omp_is_private (struct gimplify_omp_ctx *ctx, tree decl, bool simd) +omp_is_private (struct gimplify_omp_ctx *ctx, tree decl, int simd) { splay_tree_node n; @@ -5830,13 +5830,13 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl, bool simd) else if ((n->value & GOVD_REDUCTION) != 0) error ("iteration variable %qE should not be reduction", DECL_NAME (decl)); - else if (simd && (n->value & GOVD_LASTPRIVATE) != 0) + else if (simd == 1 && (n->value & GOVD_LASTPRIVATE) != 0) error ("iteration variable %qE should not be lastprivate", DECL_NAME (decl)); else if (simd && (n->value & GOVD_PRIVATE) != 0) error ("iteration variable %qE should not be private", DECL_NAME (decl)); - else if (simd && (n->value & GOVD_LINEAR) != 0) + else if (simd == 2 && (n->value & GOVD_LINEAR) != 0) error ("iteration variable %qE is predetermined linear", DECL_NAME (decl)); } @@ -6602,8 +6602,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) orig_for_stmt = for_stmt = *expr_p; - simd = TREE_CODE (for_stmt) == OMP_SIMD - || TREE_CODE (for_stmt) == CILK_SIMD; + simd = (TREE_CODE (for_stmt) == OMP_SIMD + || TREE_CODE (for_stmt) == CILK_SIMD); gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, simd ? ORT_SIMD : ORT_WORKSHARE); @@ -6659,13 +6659,16 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) /* Make sure the iteration variable is private. */ tree c = NULL_TREE; + tree c2 = NULL_TREE; if (orig_for_stmt != for_stmt) /* Do this only on innermost construct for combined ones. */; else if (simd) { splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables, (splay_tree_key)decl); - omp_is_private (gimplify_omp_ctxp, decl, simd); + omp_is_private (gimplify_omp_ctxp, decl, + 1 + (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) + != 1)); if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) omp_notice_variable (gimplify_omp_ctxp, decl, true); else if (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) @@ -6691,13 +6694,14 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) : OMP_CLAUSE_PRIVATE); OMP_CLAUSE_DECL (c) = decl; OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); + OMP_FOR_CLAUSES (for_stmt) = c; omp_add_variable (gimplify_omp_ctxp, decl, (lastprivate ? GOVD_LASTPRIVATE : GOVD_PRIVATE) - | GOVD_SEEN); + | GOVD_EXPLICIT | GOVD_SEEN); c = NULL_TREE; } } - else if (omp_is_private (gimplify_omp_ctxp, decl, simd)) + else if (omp_is_private (gimplify_omp_ctxp, decl, 0)) omp_notice_variable (gimplify_omp_ctxp, decl, true); else omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN); @@ -6714,7 +6718,25 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gimplify_seq_add_stmt (&for_body, gimple_build_assign (decl, var)); - omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN); + if (simd && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) + { + c2 = build_omp_clause (input_location, OMP_CLAUSE_LINEAR); + OMP_CLAUSE_LINEAR_NO_COPYIN (c2) = 1; + OMP_CLAUSE_LINEAR_NO_COPYOUT (c2) = 1; + OMP_CLAUSE_DECL (c2) = var; + OMP_CLAUSE_CHAIN (c2) = OMP_FOR_CLAUSES (for_stmt); + OMP_FOR_CLAUSES (for_stmt) = c2; + omp_add_variable (gimplify_omp_ctxp, var, + GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN); + if (c == NULL_TREE) + { + c = c2; + c2 = NULL_TREE; + } + } + else + omp_add_variable (gimplify_omp_ctxp, var, + GOVD_PRIVATE | GOVD_SEEN); } else var = decl; @@ -6817,13 +6839,22 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gcc_unreachable (); } + if (c2) + { + gcc_assert (c); + OMP_CLAUSE_LINEAR_STEP (c2) = OMP_CLAUSE_LINEAR_STEP (c); + } + if ((var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1) && orig_for_stmt == for_stmt) { for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE - && OMP_CLAUSE_DECL (c) == decl - && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) == NULL) + if (((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) == NULL) + || (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c) + && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c) == NULL)) + && OMP_CLAUSE_DECL (c) == decl) { t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i); gcc_assert (TREE_CODE (t) == MODIFY_EXPR); @@ -6835,8 +6866,12 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gcc_assert (TREE_OPERAND (t, 0) == var); t = build2 (TREE_CODE (t), TREE_TYPE (decl), decl, TREE_OPERAND (t, 1)); - gimplify_assign (decl, t, - &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)); + gimple_seq *seq; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE) + seq = &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c); + else + seq = &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c); + gimplify_assign (decl, t, seq); } } } diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 966fd425d78..1a863b04dbc 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,16 @@ +2014-04-25 Chris Manghane <cmang@google.com> + + * go-gcc.cc: Include "cgraph.h" and "gimplify.h". + (Gcc_backend::return_statement): Push and pop function. + (Gcc_backend::label): Likewise. + (Gcc_backend::function_defer_statement): Likewise. + (Gcc_backend::switch_statement): Add function parameter. + (Gcc_backend::block): Don't permit function to be NULL. + (Gcc_backend::temporary_variable): Change go_assert to + gcc_assert. + (Gcc_backend::gc_root_variable): New function. + (Gcc_backend::write_global_definitions): New function. + 2014-04-22 Chris Manghane <cmang@google.com> * go-gcc.cc (Gcc_backend::temporary_variable): Push cfun around diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 50403e159ef..a0283fe12e0 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -29,9 +29,11 @@ #include "stor-layout.h" #include "varasm.h" #include "tree-iterator.h" +#include "cgraph.h" #include "convert.h" #include "basic-block.h" #include "gimple-expr.h" +#include "gimplify.h" #include "toplev.h" #include "output.h" #include "real.h" @@ -317,7 +319,7 @@ class Gcc_backend : public Backend Location); Bstatement* - switch_statement(Bexpression* value, + switch_statement(Bfunction* function, Bexpression* value, const std::vector<std::vector<Bexpression*> >& cases, const std::vector<Bstatement*>& statements, Location); @@ -376,6 +378,9 @@ class Gcc_backend : public Backend Location, Bstatement**); Bvariable* + gc_root_variable(Btype*, Bexpression*); + + Bvariable* immutable_struct(const std::string&, bool, bool, Btype*, Location); void @@ -420,6 +425,12 @@ class Gcc_backend : public Backend bool function_set_body(Bfunction* function, Bstatement* code_stmt); + void + write_global_definitions(const std::vector<Btype*>&, + const std::vector<Bexpression*>&, + const std::vector<Bfunction*>&, + const std::vector<Bvariable*>&); + private: // Make a Bexpression from a tree. Bexpression* @@ -1708,6 +1719,7 @@ Gcc_backend::return_statement(Bfunction* bfunction, tree result = DECL_RESULT(fntree); if (result == error_mark_node) return this->error_statement(); + tree ret; if (vals.empty()) ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node, @@ -1731,7 +1743,14 @@ Gcc_backend::return_statement(Bfunction* bfunction, // statement. tree stmt_list = NULL_TREE; tree rettype = TREE_TYPE(result); + + if (DECL_STRUCT_FUNCTION(fntree) == NULL) + push_struct_function(fntree); + else + push_cfun(DECL_STRUCT_FUNCTION(fntree)); tree rettmp = create_tmp_var(rettype, "RESULT"); + pop_cfun(); + tree field = TYPE_FIELDS(rettype); for (std::vector<Bexpression*>::const_iterator p = vals.begin(); p != vals.end(); @@ -1817,6 +1836,7 @@ Gcc_backend::if_statement(Bexpression* condition, Bblock* then_block, Bstatement* Gcc_backend::switch_statement( + Bfunction* function, Bexpression* value, const std::vector<std::vector<Bexpression*> >& cases, const std::vector<Bstatement*>& statements, @@ -1824,6 +1844,12 @@ Gcc_backend::switch_statement( { gcc_assert(cases.size() == statements.size()); + tree decl = function->get_tree(); + if (DECL_STRUCT_FUNCTION(decl) == NULL) + push_struct_function(decl); + else + push_cfun(DECL_STRUCT_FUNCTION(decl)); + tree stmt_list = NULL_TREE; std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin(); for (std::vector<Bstatement*>::const_iterator ps = statements.begin(); @@ -1863,6 +1889,7 @@ Gcc_backend::switch_statement( append_to_statement_list(t, &stmt_list); } } + pop_cfun(); tree tv = value->get_tree(); if (tv == error_mark_node) @@ -1921,13 +1948,7 @@ Gcc_backend::block(Bfunction* function, Bblock* enclosing, tree block_tree = make_node(BLOCK); if (enclosing == NULL) { - // FIXME: Permitting FUNCTION to be NULL is a temporary measure - // until we have a proper representation of the init function. - tree fndecl; - if (function == NULL) - fndecl = current_function_decl; - else - fndecl = function->get_tree(); + tree fndecl = function->get_tree(); gcc_assert(fndecl != NULL_TREE); // We may have already created a block for local variables when @@ -1981,7 +2002,6 @@ Gcc_backend::block(Bfunction* function, Bblock* enclosing, void_type_node, BLOCK_VARS(block_tree), NULL_TREE, block_tree); TREE_SIDE_EFFECTS(bind_tree) = 1; - return new Bblock(bind_tree); } @@ -2213,7 +2233,7 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, return this->error_variable(); } - go_assert(function != NULL); + gcc_assert(function != NULL); tree decl = function->get_tree(); tree var; @@ -2262,6 +2282,28 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, return new Bvariable(var); } +// Make a GC root variable. + +Bvariable* +Gcc_backend::gc_root_variable(Btype* type, Bexpression* init) +{ + tree type_tree = type->get_tree(); + tree init_tree = init->get_tree(); + if (type_tree == error_mark_node || init_tree == error_mark_node) + return this->error_variable(); + + tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, + create_tmp_var_name("gc"), type_tree); + DECL_EXTERNAL(decl) = 0; + TREE_PUBLIC(decl) = 0; + TREE_STATIC(decl) = 1; + DECL_ARTIFICIAL(decl) = 1; + DECL_INITIAL(decl) = init_tree; + rest_of_decl_compilation(decl, 1, 0); + + return new Bvariable(decl); +} + // Create a named immutable initialized data structure. Bvariable* @@ -2276,9 +2318,9 @@ Gcc_backend::immutable_struct(const std::string& name, bool is_hidden, get_identifier_from_string(name), build_qualified_type(type_tree, TYPE_QUAL_CONST)); TREE_STATIC(decl) = 1; + TREE_USED(decl) = 1; TREE_READONLY(decl) = 1; TREE_CONSTANT(decl) = 1; - TREE_USED(decl) = 1; DECL_ARTIFICIAL(decl) = 1; if (!is_hidden) TREE_PUBLIC(decl) = 1; @@ -2368,7 +2410,17 @@ Gcc_backend::label(Bfunction* function, const std::string& name, { tree decl; if (name.empty()) - decl = create_artificial_label(location.gcc_location()); + { + tree func_tree = function->get_tree(); + if (DECL_STRUCT_FUNCTION(func_tree) == NULL) + push_struct_function(func_tree); + else + push_cfun(DECL_STRUCT_FUNCTION(func_tree)); + + decl = create_artificial_label(location.gcc_location()); + + pop_cfun(); + } else { tree id = get_identifier_from_string(name); @@ -2476,11 +2528,18 @@ Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer, { tree undefer_tree = undefer->get_tree(); tree defer_tree = defer->get_tree(); + tree fntree = function->get_tree(); if (undefer_tree == error_mark_node - || defer_tree == error_mark_node) + || defer_tree == error_mark_node + || fntree == error_mark_node) return this->error_statement(); + if (DECL_STRUCT_FUNCTION(fntree) == NULL) + push_struct_function(fntree); + else + push_cfun(DECL_STRUCT_FUNCTION(fntree)); + tree stmt_list = NULL; Blabel* blabel = this->label(function, "", location); Bstatement* label_def = this->label_definition_statement(blabel); @@ -2493,6 +2552,7 @@ Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer, tree try_catch = build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body); append_to_statement_list(try_catch, &stmt_list); + pop_cfun(); return this->make_statement(stmt_list); } @@ -2537,6 +2597,88 @@ Gcc_backend::function_set_body(Bfunction* function, Bstatement* code_stmt) return true; } +// Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, +// FUNCTION_DECLS, and VARIABLE_DECLS declared globally. + +void +Gcc_backend::write_global_definitions( + const std::vector<Btype*>& type_decls, + const std::vector<Bexpression*>& constant_decls, + const std::vector<Bfunction*>& function_decls, + const std::vector<Bvariable*>& variable_decls) +{ + size_t count_definitions = type_decls.size() + constant_decls.size() + + function_decls.size() + variable_decls.size(); + + tree* defs = new tree[count_definitions]; + + // Convert all non-erroneous declarations into Gimple form. + size_t i = 0; + for (std::vector<Bvariable*>::const_iterator p = variable_decls.begin(); + p != variable_decls.end(); + ++p) + { + if ((*p)->get_tree() != error_mark_node) + { + defs[i] = (*p)->get_tree(); + go_preserve_from_gc(defs[i]); + ++i; + } + } + + for (std::vector<Btype*>::const_iterator p = type_decls.begin(); + p != type_decls.end(); + ++p) + { + tree type_tree = (*p)->get_tree(); + if (type_tree != error_mark_node + && IS_TYPE_OR_DECL_P(type_tree)) + { + defs[i] = TYPE_NAME(type_tree); + gcc_assert(defs[i] != NULL); + go_preserve_from_gc(defs[i]); + ++i; + } + } + for (std::vector<Bexpression*>::const_iterator p = constant_decls.begin(); + p != constant_decls.end(); + ++p) + { + if ((*p)->get_tree() != error_mark_node) + { + defs[i] = (*p)->get_tree(); + go_preserve_from_gc(defs[i]); + ++i; + } + } + for (std::vector<Bfunction*>::const_iterator p = function_decls.begin(); + p != function_decls.end(); + ++p) + { + tree decl = (*p)->get_tree(); + if (decl != error_mark_node) + { + go_preserve_from_gc(decl); + gimplify_function_tree(decl); + cgraph_finalize_function(decl, true); + + defs[i] = decl; + ++i; + } + } + + // Pass everything back to the middle-end. + + wrapup_global_declarations(defs, i); + + finalize_compilation_unit(); + + check_global_declarations(defs, i); + emit_debug_global_declarations(defs, i); + + delete[] defs; +} + // The single backend. static Gcc_backend gcc_backend; diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index dd76204e70c..aca3dc6f90e 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -406,9 +406,9 @@ class Backend // integers, then STATEMENTS[i] is executed. STATEMENTS[i] will // either end with a goto statement or will fall through into // STATEMENTS[i + 1]. CASES[i] is empty for the default clause, - // which need not be last. + // which need not be last. FUNCTION is the current function. virtual Bstatement* - switch_statement(Bexpression* value, + switch_statement(Bfunction* function, Bexpression* value, const std::vector<std::vector<Bexpression*> >& cases, const std::vector<Bstatement*>& statements, Location) = 0; @@ -534,6 +534,12 @@ class Backend bool address_is_taken, Location location, Bstatement** pstatement) = 0; + // Create a GC root variable. TYPE is the __go_gc_root_list struct described + // in Gogo::register_gc_vars. INIT is the composite literal consisting of a + // pointer to the next GC root and the global variables registered. + virtual Bvariable* + gc_root_variable(Btype* type, Bexpression* init) = 0; + // Create a named immutable initialized data structure. This is // used for type descriptors, map descriptors, and function // descriptors. This returns a Bvariable because it corresponds to @@ -653,6 +659,16 @@ class Backend // true on success, false on failure. virtual bool function_set_body(Bfunction* function, Bstatement* code_stmt) = 0; + + // Utility. + + // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, + // FUNCTION_DECLS, and VARIABLE_DECLS declared globally. + virtual void + write_global_definitions(const std::vector<Btype*>& type_decls, + const std::vector<Bexpression*>& constant_decls, + const std::vector<Bfunction*>& function_decls, + const std::vector<Bvariable*>& variable_decls) = 0; }; // The backend interface has to define this function. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 74ae9ddcd7d..27562639176 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3578,127 +3578,7 @@ Expression::make_unsafe_cast(Type* type, Expression* expr, return new Unsafe_type_conversion_expression(type, expr, location); } -// Unary expressions. - -class Unary_expression : public Expression -{ - public: - Unary_expression(Operator op, Expression* expr, Location location) - : Expression(EXPRESSION_UNARY, location), - op_(op), escapes_(true), create_temp_(false), expr_(expr), - issue_nil_check_(false) - { } - - // Return the operator. - Operator - op() const - { return this->op_; } - - // Return the operand. - Expression* - operand() const - { return this->expr_; } - - // Record that an address expression does not escape. - void - set_does_not_escape() - { - go_assert(this->op_ == OPERATOR_AND); - this->escapes_ = false; - } - - // Record that this is an address expression which should create a - // temporary variable if necessary. This is used for method calls. - void - set_create_temp() - { - go_assert(this->op_ == OPERATOR_AND); - this->create_temp_ = true; - } - - // Apply unary opcode OP to UNC, setting NC. Return true if this - // could be done, false if not. Issue errors for overflow. - static bool - eval_constant(Operator op, const Numeric_constant* unc, - Location, Numeric_constant* nc); - - static Expression* - do_import(Import*); - - protected: - int - do_traverse(Traverse* traverse) - { return Expression::traverse(&this->expr_, traverse); } - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - Expression* - do_flatten(Gogo*, Named_object*, Statement_inserter*); - - bool - do_is_constant() const; - - bool - do_is_immutable() const - { return this->expr_->is_immutable() - || (this->op_ == OPERATOR_AND && this->expr_->is_variable()); } - - bool - do_numeric_constant_value(Numeric_constant*) const; - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_unary(this->op_, this->expr_->copy(), - this->location()); - } - - bool - do_must_eval_subexpressions_in_order(int*) const - { return this->op_ == OPERATOR_MULT; } - - bool - do_is_addressable() const - { return this->op_ == OPERATOR_MULT; } - - tree - do_get_tree(Translate_context*); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - void - do_issue_nil_check() - { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); } - - private: - // The unary operator to apply. - Operator op_; - // Normally true. False if this is an address expression which does - // not escape the current function. - bool escapes_; - // True if this is an address expression which should create a - // temporary variable if necessary. - bool create_temp_; - // The operand. - Expression* expr_; - // Whether or not to issue a nil check for this expression if its address - // is being taken. - bool issue_nil_check_; -}; +// Class Unary_expression. // If we are taking the address of a composite literal, and the // contents are not constant, then we want to make a heap expression @@ -4214,11 +4094,18 @@ Unary_expression::do_get_tree(Translate_context* context) } } - // Build a decl for a constant constructor. - if ((this->expr_->is_composite_literal() + if (this->is_gc_root_) + { + // Build a decl for a GC root variable. GC roots are mutable, so they + // cannot be represented as an immutable_struct in the backend. + Bvariable* gc_root = gogo->backend()->gc_root_variable(btype, bexpr); + bexpr = gogo->backend()->var_expression(gc_root, loc); + } + else if ((this->expr_->is_composite_literal() || this->expr_->string_expression() != NULL) && this->expr_->is_immutable()) { + // Build a decl for a constant constructor. static unsigned int counter; char buf[100]; snprintf(buf, sizeof buf, "C%u", counter); @@ -12508,6 +12395,14 @@ Fixed_array_construction_expression::do_get_tree(Translate_context* context) return expr_to_tree(this->get_constructor(context, btype)); } +Expression* +Expression::make_array_composite_literal(Type* type, Expression_list* vals, + Location location) +{ + go_assert(type->array_type() != NULL && !type->is_slice_type()); + return new Fixed_array_construction_expression(type, NULL, vals, location); +} + // Construct a slice. class Slice_construction_expression : public Array_construction_expression diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index dc9ad71c820..0936e00bae0 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -30,6 +30,7 @@ class Var_expression; class Temporary_reference_expression; class Set_and_use_temporary_expression; class String_expression; +class Unary_expression; class Binary_expression; class Call_expression; class Func_expression; @@ -327,6 +328,10 @@ class Expression static Expression* make_struct_composite_literal(Type*, Expression_list*, Location); + // Make an array composite literal. + static Expression* + make_array_composite_literal(Type*, Expression_list*, Location); + // Make a slice composite literal. static Expression* make_slice_composite_literal(Type*, Expression_list*, Location); @@ -533,6 +538,12 @@ class Expression Expression* deref(); + // If this is a unary expression, return the Unary_expression + // structure. Otherwise return NULL. + Unary_expression* + unary_expression() + { return this->convert<Unary_expression, EXPRESSION_UNARY>(); } + // If this is a binary expression, return the Binary_expression // structure. Otherwise return NULL. Binary_expression* @@ -1286,6 +1297,143 @@ class String_expression : public Expression Type* type_; }; +// A Unary expression. + +class Unary_expression : public Expression +{ + public: + Unary_expression(Operator op, Expression* expr, Location location) + : Expression(EXPRESSION_UNARY, location), + op_(op), escapes_(true), create_temp_(false), is_gc_root_(false), + expr_(expr), issue_nil_check_(false) + { } + + // Return the operator. + Operator + op() const + { return this->op_; } + + // Return the operand. + Expression* + operand() const + { return this->expr_; } + + // Record that an address expression does not escape. + void + set_does_not_escape() + { + go_assert(this->op_ == OPERATOR_AND); + this->escapes_ = false; + } + + // Record that this is an address expression which should create a + // temporary variable if necessary. This is used for method calls. + void + set_create_temp() + { + go_assert(this->op_ == OPERATOR_AND); + this->create_temp_ = true; + } + + // Record that this is an address expression of a GC root, which is a + // mutable composite literal. This used for registering GC variables. + void + set_is_gc_root() + { + go_assert(this->op_ == OPERATOR_AND); + this->is_gc_root_ = true; + } + + // Apply unary opcode OP to UNC, setting NC. Return true if this + // could be done, false if not. Issue errors for overflow. + static bool + eval_constant(Operator op, const Numeric_constant* unc, + Location, Numeric_constant* nc); + + static Expression* + do_import(Import*); + + protected: + int + do_traverse(Traverse* traverse) + { return Expression::traverse(&this->expr_, traverse); } + + Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int); + + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + + bool + do_is_constant() const; + + bool + do_is_immutable() const + { + return (this->expr_->is_immutable() + || (this->op_ == OPERATOR_AND && this->expr_->is_variable())); + } + + bool + do_numeric_constant_value(Numeric_constant*) const; + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return Expression::make_unary(this->op_, this->expr_->copy(), + this->location()); + } + + bool + do_must_eval_subexpressions_in_order(int*) const + { return this->op_ == OPERATOR_MULT; } + + bool + do_is_addressable() const + { return this->op_ == OPERATOR_MULT; } + + tree + do_get_tree(Translate_context*); + + void + do_export(Export*) const; + + void + do_dump_expression(Ast_dump_context*) const; + + void + do_issue_nil_check() + { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); } + + private: + // The unary operator to apply. + Operator op_; + // Normally true. False if this is an address expression which does + // not escape the current function. + bool escapes_; + // True if this is an address expression which should create a + // temporary variable if necessary. + bool create_temp_; + // True if this is an address expression for a GC root. A GC root is a + // special struct composite literal that is mutable when addressed, meaning + // it cannot be represented as an immutable_struct in the backend. + bool is_gc_root_; + // The operand. + Expression* expr_; + // Whether or not to issue a nil check for this expression if its address + // is being taken. + bool issue_nil_check_; +}; + // A binary expression. class Binary_expression : public Expression diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index c00e7d16011..6b19a1d82e1 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -236,830 +236,6 @@ Gogo::define_builtin_function_trees() false); } -// Add statements to INIT_STMT_LIST which run the initialization -// functions for imported packages. This is only used for the "main" -// package. - -void -Gogo::init_imports(tree* init_stmt_list) -{ - go_assert(this->is_main_package()); - - if (this->imported_init_fns_.empty()) - return; - - tree fntype = build_function_type(void_type_node, void_list_node); - - // We must call them in increasing priority order. - std::vector<Import_init> v; - for (std::set<Import_init>::const_iterator p = - this->imported_init_fns_.begin(); - p != this->imported_init_fns_.end(); - ++p) - v.push_back(*p); - std::sort(v.begin(), v.end()); - - for (std::vector<Import_init>::const_iterator p = v.begin(); - p != v.end(); - ++p) - { - std::string user_name = p->package_name() + ".init"; - tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL, - get_identifier_from_string(user_name), - fntype); - const std::string& init_name(p->init_name()); - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(init_name)); - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; - append_to_statement_list(build_call_expr(decl, 0), init_stmt_list); - } -} - -// Register global variables with the garbage collector. We need to -// register all variables which can hold a pointer value. They become -// roots during the mark phase. We build a struct that is easy to -// hook into a list of roots. - -// struct __go_gc_root_list -// { -// struct __go_gc_root_list* __next; -// struct __go_gc_root -// { -// void* __decl; -// size_t __size; -// } __roots[]; -// }; - -// The last entry in the roots array has a NULL decl field. - -void -Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc, - tree* init_stmt_list) -{ - if (var_gc.empty()) - return; - - size_t count = var_gc.size(); - - tree root_type = Gogo::builtin_struct(NULL, "__go_gc_root", NULL_TREE, 2, - "__next", - ptr_type_node, - "__size", - sizetype); - - tree index_type = build_index_type(size_int(count)); - tree array_type = build_array_type(root_type, index_type); - - tree root_list_type = make_node(RECORD_TYPE); - root_list_type = Gogo::builtin_struct(NULL, "__go_gc_root_list", - root_list_type, 2, - "__next", - build_pointer_type(root_list_type), - "__roots", - array_type); - - // Build an initialier for the __roots array. - - vec<constructor_elt, va_gc> *roots_init; - vec_alloc(roots_init, count + 1); - - size_t i = 0; - for (std::vector<Named_object*>::const_iterator p = var_gc.begin(); - p != var_gc.end(); - ++p, ++i) - { - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(root_type); - elt->index = field; - Bvariable* bvar = (*p)->get_backend_variable(this, NULL); - tree decl = var_to_tree(bvar); - go_assert(TREE_CODE(decl) == VAR_DECL); - elt->value = build_fold_addr_expr(decl); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = DECL_SIZE_UNIT(decl); - - elt = roots_init->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(root_type, init); - } - - // The list ends with a NULL entry. - - vec<constructor_elt, va_gc> *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(root_type); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = size_zero_node; - - elt = roots_init->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(root_type, init); - - // Build a constructor for the struct. - - vec<constructor_elt, va_gc> *root_list_init; - vec_alloc(root_list_init, 2); - - elt = root_list_init->quick_push(empty); - field = TYPE_FIELDS(root_list_type); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = root_list_init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = build_constructor(array_type, roots_init); - - // Build a decl to register. - - tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, - create_tmp_var_name("gc"), root_list_type); - DECL_EXTERNAL(decl) = 0; - TREE_PUBLIC(decl) = 0; - TREE_STATIC(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - DECL_INITIAL(decl) = build_constructor(root_list_type, root_list_init); - rest_of_decl_compilation(decl, 1, 0); - - static tree register_gc_fndecl; - tree call = Gogo::call_builtin(®ister_gc_fndecl, - Linemap::predeclared_location(), - "__go_register_gc_roots", - 1, - void_type_node, - build_pointer_type(root_list_type), - build_fold_addr_expr(decl)); - if (call != error_mark_node) - append_to_statement_list(call, init_stmt_list); -} - -// Create the magic initialization function. INIT_STMT_LIST is the -// code that it needs to run. - -void -Gogo::write_initialization_function(Named_object* initfn, tree init_stmt_list) -{ - // Make sure that we thought we needed an initialization function, - // as otherwise we will not have reported it in the export data. - go_assert(this->is_main_package() || this->need_init_fn_); - - if (initfn == NULL) - initfn = this->initialization_function_decl(); - - Bfunction* fndecl = initfn->func_value()->get_or_make_decl(this, initfn); - Location loc = this->package_->location(); - std::vector<Bvariable*> vars; - this->backend()->block(fndecl, NULL, vars, loc, loc); - - if (!this->backend()->function_set_body(fndecl, tree_to_stat(init_stmt_list))) - { - go_assert(saw_errors()); - return; - } - gimplify_function_tree(function_to_tree(fndecl)); - cgraph_add_new_function(function_to_tree(fndecl), false); -} - -// Search for references to VAR in any statements or called functions. - -class Find_var : public Traverse -{ - public: - // A hash table we use to avoid looping. The index is the name of a - // named object. We only look through objects defined in this - // package. - typedef Unordered_set(const void*) Seen_objects; - - Find_var(Named_object* var, Seen_objects* seen_objects) - : Traverse(traverse_expressions), - var_(var), seen_objects_(seen_objects), found_(false) - { } - - // Whether the variable was found. - bool - found() const - { return this->found_; } - - int - expression(Expression**); - - private: - // The variable we are looking for. - Named_object* var_; - // Names of objects we have already seen. - Seen_objects* seen_objects_; - // True if the variable was found. - bool found_; -}; - -// See if EXPR refers to VAR, looking through function calls and -// variable initializations. - -int -Find_var::expression(Expression** pexpr) -{ - Expression* e = *pexpr; - - Var_expression* ve = e->var_expression(); - if (ve != NULL) - { - Named_object* v = ve->named_object(); - if (v == this->var_) - { - this->found_ = true; - return TRAVERSE_EXIT; - } - - if (v->is_variable() && v->package() == NULL) - { - Expression* init = v->var_value()->init(); - if (init != NULL) - { - std::pair<Seen_objects::iterator, bool> ins = - this->seen_objects_->insert(v); - if (ins.second) - { - // This is the first time we have seen this name. - if (Expression::traverse(&init, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - } - - // We traverse the code of any function we see. Note that this - // means that we will traverse the code of a function whose address - // is taken even if it is not called. - Func_expression* fe = e->func_expression(); - if (fe != NULL) - { - const Named_object* f = fe->named_object(); - if (f->is_function() && f->package() == NULL) - { - std::pair<Seen_objects::iterator, bool> ins = - this->seen_objects_->insert(f); - if (ins.second) - { - // This is the first time we have seen this name. - if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - - Temporary_reference_expression* tre = e->temporary_reference_expression(); - if (tre != NULL) - { - Temporary_statement* ts = tre->statement(); - Expression* init = ts->init(); - if (init != NULL) - { - std::pair<Seen_objects::iterator, bool> ins = - this->seen_objects_->insert(ts); - if (ins.second) - { - // This is the first time we have seen this temporary - // statement. - if (Expression::traverse(&init, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - - return TRAVERSE_CONTINUE; -} - -// Return true if EXPR, PREINIT, or DEP refers to VAR. - -static bool -expression_requires(Expression* expr, Block* preinit, Named_object* dep, - Named_object* var) -{ - Find_var::Seen_objects seen_objects; - Find_var find_var(var, &seen_objects); - if (expr != NULL) - Expression::traverse(&expr, &find_var); - if (preinit != NULL) - preinit->traverse(&find_var); - if (dep != NULL) - { - Expression* init = dep->var_value()->init(); - if (init != NULL) - Expression::traverse(&init, &find_var); - if (dep->var_value()->has_pre_init()) - dep->var_value()->preinit()->traverse(&find_var); - } - - return find_var.found(); -} - -// Sort variable initializations. If the initialization expression -// for variable A refers directly or indirectly to the initialization -// expression for variable B, then we must initialize B before A. - -class Var_init -{ - public: - Var_init() - : var_(NULL), init_(NULL) - { } - - Var_init(Named_object* var, Bstatement* init) - : var_(var), init_(init) - { } - - // Return the variable. - Named_object* - var() const - { return this->var_; } - - // Return the initialization expression. - Bstatement* - init() const - { return this->init_; } - - private: - // The variable being initialized. - Named_object* var_; - // The initialization statement. - Bstatement* init_; -}; - -typedef std::list<Var_init> Var_inits; - -// Sort the variable initializations. The rule we follow is that we -// emit them in the order they appear in the array, except that if the -// initialization expression for a variable V1 depends upon another -// variable V2 then we initialize V1 after V2. - -static void -sort_var_inits(Gogo* gogo, Var_inits* var_inits) -{ - typedef std::pair<Named_object*, Named_object*> No_no; - typedef std::map<No_no, bool> Cache; - Cache cache; - - Var_inits ready; - while (!var_inits->empty()) - { - Var_inits::iterator p1 = var_inits->begin(); - Named_object* var = p1->var(); - Expression* init = var->var_value()->init(); - Block* preinit = var->var_value()->preinit(); - Named_object* dep = gogo->var_depends_on(var->var_value()); - - // Start walking through the list to see which variables VAR - // needs to wait for. - Var_inits::iterator p2 = p1; - ++p2; - - for (; p2 != var_inits->end(); ++p2) - { - Named_object* p2var = p2->var(); - No_no key(var, p2var); - std::pair<Cache::iterator, bool> ins = - cache.insert(std::make_pair(key, false)); - if (ins.second) - ins.first->second = expression_requires(init, preinit, dep, p2var); - if (ins.first->second) - { - // Check for cycles. - key = std::make_pair(p2var, var); - ins = cache.insert(std::make_pair(key, false)); - if (ins.second) - ins.first->second = - expression_requires(p2var->var_value()->init(), - p2var->var_value()->preinit(), - gogo->var_depends_on(p2var->var_value()), - var); - if (ins.first->second) - { - error_at(var->location(), - ("initialization expressions for %qs and " - "%qs depend upon each other"), - var->message_name().c_str(), - p2var->message_name().c_str()); - inform(p2->var()->location(), "%qs defined here", - p2var->message_name().c_str()); - p2 = var_inits->end(); - } - else - { - // We can't emit P1 until P2 is emitted. Move P1. - Var_inits::iterator p3 = p2; - ++p3; - var_inits->splice(p3, *var_inits, p1); - } - break; - } - } - - if (p2 == var_inits->end()) - { - // VAR does not depends upon any other initialization expressions. - - // Check for a loop of VAR on itself. We only do this if - // INIT is not NULL and there is no dependency; when INIT is - // NULL, it means that PREINIT sets VAR, which we will - // interpret as a loop. - if (init != NULL && dep == NULL - && expression_requires(init, preinit, NULL, var)) - error_at(var->location(), - "initialization expression for %qs depends upon itself", - var->message_name().c_str()); - ready.splice(ready.end(), *var_inits, p1); - } - } - - // Now READY is the list in the desired initialization order. - var_inits->swap(ready); -} - -// Write out the global definitions. - -void -Gogo::write_globals() -{ - this->build_interface_method_tables(); - - Bindings* bindings = this->current_bindings(); - - for (Bindings::const_declarations_iterator p = bindings->begin_declarations(); - p != bindings->end_declarations(); - ++p) - { - // If any function declarations needed a descriptor, make sure - // we build it. - Named_object* no = p->second; - if (no->is_function_declaration()) - no->func_declaration_value()->build_backend_descriptor(this); - } - - size_t count_definitions = bindings->size_definitions(); - size_t count = count_definitions; - - tree* vec = new tree[count]; - - Named_object* init_fndecl = NULL; - tree init_stmt_list = NULL_TREE; - - if (this->is_main_package()) - this->init_imports(&init_stmt_list); - - // A list of variable initializations. - Var_inits var_inits; - - // A list of variables which need to be registered with the garbage - // collector. - std::vector<Named_object*> var_gc; - var_gc.reserve(count); - - tree var_init_stmt_list = NULL_TREE; - size_t i = 0; - for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); - p != bindings->end_definitions(); - ++p, ++i) - { - Named_object* no = *p; - - go_assert(i < count); - - go_assert(!no->is_type_declaration() && !no->is_function_declaration()); - // There is nothing to do for a package. - if (no->is_package()) - { - --i; - --count; - continue; - } - - // There is nothing to do for an object which was imported from - // a different package into the global scope. - if (no->package() != NULL) - { - --i; - --count; - continue; - } - - // Skip blank named functions and constants. - if ((no->is_function() && no->func_value()->is_sink()) - || (no->is_const() && no->const_value()->is_sink())) - { - --i; - --count; - continue; - } - - // There is nothing useful we can output for constants which - // have ideal or non-integral type. - if (no->is_const()) - { - Type* type = no->const_value()->type(); - if (type == NULL) - type = no->const_value()->expr()->type(); - if (type->is_abstract() || type->integer_type() == NULL) - { - --i; - --count; - continue; - } - } - - if (!no->is_variable()) - { - vec[i] = no->get_tree(this, NULL); - if (vec[i] == error_mark_node) - { - go_assert(saw_errors()); - --i; - --count; - continue; - } - } - else - { - Bvariable* var = no->get_backend_variable(this, NULL); - vec[i] = var_to_tree(var); - if (vec[i] == error_mark_node) - { - go_assert(saw_errors()); - --i; - --count; - continue; - } - - // Check for a sink variable, which may be used to run an - // initializer purely for its side effects. - bool is_sink = no->name()[0] == '_' && no->name()[1] == '.'; - - Bstatement* var_init_stmt = NULL; - if (!no->var_value()->has_pre_init()) - { - Bexpression* var_binit = no->var_value()->get_init(this, NULL); - if (var_binit == NULL) - ; - else if (TREE_CONSTANT(expr_to_tree(var_binit))) - { - if (expression_requires(no->var_value()->init(), NULL, - this->var_depends_on(no->var_value()), - no)) - error_at(no->location(), - "initialization expression for %qs depends " - "upon itself", - no->message_name().c_str()); - this->backend()->global_variable_set_init(var, var_binit); - } - else if (is_sink) - var_init_stmt = - this->backend()->expression_statement(var_binit); - else - { - Location loc = no->var_value()->location(); - Bexpression* var_expr = - this->backend()->var_expression(var, loc); - var_init_stmt = - this->backend()->assignment_statement(var_expr, var_binit, - loc); - } - } - else - { - // We are going to create temporary variables which - // means that we need an fndecl. - if (init_fndecl == NULL) - init_fndecl = this->initialization_function_decl(); - - Bvariable* var_decl = is_sink ? NULL : var; - var_init_stmt = - no->var_value()->get_init_block(this, init_fndecl, var_decl); - } - - if (var_init_stmt != NULL) - { - if (no->var_value()->init() == NULL - && !no->var_value()->has_pre_init()) - append_to_statement_list(stat_to_tree(var_init_stmt), - &var_init_stmt_list); - else - var_inits.push_back(Var_init(no, var_init_stmt)); - } - else if (this->var_depends_on(no->var_value()) != NULL) - { - // This variable is initialized from something that is - // not in its init or preinit. This variable needs to - // participate in dependency analysis sorting, in case - // some other variable depends on this one. - Btype* int_btype = - Type::lookup_integer_type("int")->get_backend(this); - Bexpression* zero = this->backend()->zero_expression(int_btype); - Bstatement* zero_stmt = - this->backend()->expression_statement(zero); - var_inits.push_back(Var_init(no, zero_stmt)); - } - - if (!is_sink && no->var_value()->type()->has_pointer()) - var_gc.push_back(no); - } - } - - // Register global variables with the garbage collector. - this->register_gc_vars(var_gc, &init_stmt_list); - - // Simple variable initializations, after all variables are - // registered. - append_to_statement_list(var_init_stmt_list, &init_stmt_list); - - // Complex variable initializations, first sorting them into a - // workable order. - if (!var_inits.empty()) - { - sort_var_inits(this, &var_inits); - for (Var_inits::const_iterator p = var_inits.begin(); - p != var_inits.end(); - ++p) - append_to_statement_list(stat_to_tree(p->init()), &init_stmt_list); - } - - // After all the variables are initialized, call the "init" - // functions if there are any. - for (std::vector<Named_object*>::const_iterator p = - this->init_functions_.begin(); - p != this->init_functions_.end(); - ++p) - { - tree decl = (*p)->get_tree(this, NULL); - tree call = build_call_expr(decl, 0); - append_to_statement_list(call, &init_stmt_list); - } - - // Set up a magic function to do all the initialization actions. - // This will be called if this package is imported. - if (init_stmt_list != NULL - || this->need_init_fn_ - || this->is_main_package()) - this->write_initialization_function(init_fndecl, init_stmt_list); - - // We should not have seen any new bindings created during the - // conversion. - go_assert(count_definitions == this->current_bindings()->size_definitions()); - - // Pass everything back to the middle-end. - - wrapup_global_declarations(vec, count); - - finalize_compilation_unit(); - - check_global_declarations(vec, count); - emit_debug_global_declarations(vec, count); - - delete[] vec; -} - -// Get a tree for a named object. - -tree -Named_object::get_tree(Gogo* gogo, Named_object* function) -{ - if (this->tree_ != NULL_TREE) - return this->tree_; - - if (Gogo::is_erroneous_name(this->name_)) - { - this->tree_ = error_mark_node; - return error_mark_node; - } - - tree decl; - switch (this->classification_) - { - case NAMED_OBJECT_CONST: - { - Translate_context subcontext(gogo, function, NULL, NULL); - Type* type = this->u_.const_value->type(); - Location loc = this->location(); - - Expression* const_ref = Expression::make_const_reference(this, loc); - Bexpression* const_decl = - tree_to_expr(const_ref->get_tree(&subcontext)); - if (type != NULL && type->is_numeric_type()) - { - Btype* btype = type->get_backend(gogo); - std::string name = this->get_id(gogo); - const_decl = - gogo->backend()->named_constant_expression(btype, name, - const_decl, loc); - } - decl = expr_to_tree(const_decl); - } - break; - - case NAMED_OBJECT_TYPE: - { - Named_type* named_type = this->u_.type_value; - tree type_tree = type_to_tree(named_type->get_backend(gogo)); - if (type_tree == error_mark_node) - decl = error_mark_node; - else - { - decl = TYPE_NAME(type_tree); - go_assert(decl != NULL_TREE); - - // We need to produce a type descriptor for every named - // type, and for a pointer to every named type, since - // other files or packages might refer to them. We need - // to do this even for hidden types, because they might - // still be returned by some function. Simply calling the - // type_descriptor method is enough to create the type - // descriptor, even though we don't do anything with it. - if (this->package_ == NULL) - { - named_type-> - type_descriptor_pointer(gogo, - Linemap::predeclared_location()); - Type* pn = Type::make_pointer_type(named_type); - pn->type_descriptor_pointer(gogo, - Linemap::predeclared_location()); - } - } - } - break; - - case NAMED_OBJECT_TYPE_DECLARATION: - error("reference to undefined type %qs", - this->message_name().c_str()); - return error_mark_node; - - case NAMED_OBJECT_VAR: - case NAMED_OBJECT_RESULT_VAR: - case NAMED_OBJECT_SINK: - go_unreachable(); - - case NAMED_OBJECT_FUNC: - { - Function* func = this->u_.func_value; - decl = function_to_tree(func->get_or_make_decl(gogo, this)); - if (decl != error_mark_node) - { - if (func->block() != NULL) - { - if (DECL_STRUCT_FUNCTION(decl) == NULL) - push_struct_function(decl); - else - push_cfun(DECL_STRUCT_FUNCTION(decl)); - - cfun->function_start_locus = func->location().gcc_location(); - cfun->function_end_locus = - func->block()->end_location().gcc_location(); - - func->build(gogo, this); - - gimplify_function_tree(decl); - - cgraph_finalize_function(decl, true); - - pop_cfun(); - } - } - } - break; - - case NAMED_OBJECT_ERRONEOUS: - decl = error_mark_node; - break; - - default: - go_unreachable(); - } - - if (TREE_TYPE(decl) == error_mark_node) - decl = error_mark_node; - - tree ret = decl; - - this->tree_ = ret; - - if (ret != error_mark_node) - go_preserve_from_gc(ret); - - return ret; -} - // Get the backend representation. Bfunction* @@ -1106,15 +282,6 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) return this->fndecl_; } -// Return the function's decl after it has been built. - -tree -Function::get_decl() const -{ - go_assert(this->fndecl_ != NULL); - return function_to_tree(this->fndecl_); -} - // Build the descriptor for a function declaration. This won't // necessarily happen if the package has just a declaration for the // function and no other reference to it, but we may still need the @@ -1214,55 +381,6 @@ go_type_for_mode(enum machine_mode mode, int unsignedp) return NULL_TREE; } -// Build a builtin struct with a list of fields. The name is -// STRUCT_NAME. STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE -// node; this exists so that the struct can have fields which point to -// itself. If PTYPE is not NULL, store the result in *PTYPE. There -// are NFIELDS fields. Each field is a name (a const char*) followed -// by a type (a tree). - -tree -Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type, - int nfields, ...) -{ - if (ptype != NULL && *ptype != NULL_TREE) - return *ptype; - - va_list ap; - va_start(ap, nfields); - - tree fields = NULL_TREE; - for (int i = 0; i < nfields; ++i) - { - const char* field_name = va_arg(ap, const char*); - tree type = va_arg(ap, tree); - if (type == error_mark_node) - { - if (ptype != NULL) - *ptype = error_mark_node; - return error_mark_node; - } - tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL, - get_identifier(field_name), type); - DECL_CHAIN(field) = fields; - fields = field; - } - - va_end(ap); - - if (struct_type == NULL_TREE) - struct_type = make_node(RECORD_TYPE); - finish_builtin_struct(struct_type, struct_name, fields, NULL_TREE); - - if (ptype != NULL) - { - go_preserve_from_gc(struct_type); - *ptype = struct_type; - } - - return struct_type; -} - // Build a constructor for a slice. SLICE_TYPE_TREE is the type of // the slice. VALUES is the value pointer and COUNT is the number of // entries. If CAPACITY is not NULL, it is the capacity; otherwise diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index ac9510ed9a6..c6ff9886090 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -575,6 +575,164 @@ Gogo::current_bindings() const return this->globals_; } +// Add statements to INIT_STMTS which run the initialization +// functions for imported packages. This is only used for the "main" +// package. + +void +Gogo::init_imports(std::vector<Bstatement*>& init_stmts) +{ + go_assert(this->is_main_package()); + + if (this->imported_init_fns_.empty()) + return; + + Location unknown_loc = Linemap::unknown_location(); + Function_type* func_type = + Type::make_function_type(NULL, NULL, NULL, unknown_loc); + Btype* fntype = func_type->get_backend_fntype(this); + + // We must call them in increasing priority order. + std::vector<Import_init> v; + for (std::set<Import_init>::const_iterator p = + this->imported_init_fns_.begin(); + p != this->imported_init_fns_.end(); + ++p) + v.push_back(*p); + std::sort(v.begin(), v.end()); + + // We build calls to the init functions, which take no arguments. + std::vector<Bexpression*> empty_args; + for (std::vector<Import_init>::const_iterator p = v.begin(); + p != v.end(); + ++p) + { + std::string user_name = p->package_name() + ".init"; + const std::string& init_name(p->init_name()); + + Bfunction* pfunc = this->backend()->function(fntype, user_name, init_name, + true, true, true, false, + false, unknown_loc); + Bexpression* pfunc_code = + this->backend()->function_code_expression(pfunc, unknown_loc); + Bexpression* pfunc_call = + this->backend()->call_expression(pfunc_code, empty_args, unknown_loc); + init_stmts.push_back(this->backend()->expression_statement(pfunc_call)); + } +} + +// Register global variables with the garbage collector. We need to +// register all variables which can hold a pointer value. They become +// roots during the mark phase. We build a struct that is easy to +// hook into a list of roots. + +// struct __go_gc_root_list +// { +// struct __go_gc_root_list* __next; +// struct __go_gc_root +// { +// void* __decl; +// size_t __size; +// } __roots[]; +// }; + +// The last entry in the roots array has a NULL decl field. + +void +Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc, + std::vector<Bstatement*>& init_stmts) +{ + if (var_gc.empty()) + return; + + Type* pvt = Type::make_pointer_type(Type::make_void_type()); + Type* uint_type = Type::lookup_integer_type("uint"); + Struct_type* root_type = Type::make_builtin_struct_type(2, + "__decl", pvt, + "__size", uint_type); + + Location builtin_loc = Linemap::predeclared_location(); + size_t count = var_gc.size(); + mpz_t lenval; + mpz_init_set_ui(lenval, count); + Expression* length = Expression::make_integer(&lenval, NULL, builtin_loc); + mpz_clear(lenval); + + Array_type* root_array_type = Type::make_array_type(root_type, length); + Type* ptdt = Type::make_type_descriptor_ptr_type(); + Struct_type* root_list_type = + Type::make_builtin_struct_type(2, + "__next", ptdt, + "__roots", root_array_type); + + // Build an initializer for the __roots array. + + Expression_list* roots_init = new Expression_list(); + + size_t i = 0; + for (std::vector<Named_object*>::const_iterator p = var_gc.begin(); + p != var_gc.end(); + ++p, ++i) + { + Expression_list* init = new Expression_list(); + + Location no_loc = (*p)->location(); + Expression* decl = Expression::make_var_reference(*p, no_loc); + Expression* decl_addr = + Expression::make_unary(OPERATOR_AND, decl, no_loc); + init->push_back(decl_addr); + + Expression* decl_size = + Expression::make_type_info(decl->type(), Expression::TYPE_INFO_SIZE); + init->push_back(decl_size); + + Expression* root_ctor = + Expression::make_struct_composite_literal(root_type, init, no_loc); + roots_init->push_back(root_ctor); + } + + // The list ends with a NULL entry. + + Expression_list* null_init = new Expression_list(); + Expression* nil = Expression::make_nil(builtin_loc); + null_init->push_back(nil); + + mpz_t zval; + mpz_init_set_ui(zval, 0UL); + Expression* zero = Expression::make_integer(&zval, NULL, builtin_loc); + mpz_clear(zval); + null_init->push_back(zero); + + Expression* null_root_ctor = + Expression::make_struct_composite_literal(root_type, null_init, + builtin_loc); + roots_init->push_back(null_root_ctor); + + // Build a constructor for the struct. + + Expression_list* root_list_init = new Expression_list(); + root_list_init->push_back(nil); + + Expression* roots_ctor = + Expression::make_array_composite_literal(root_array_type, roots_init, + builtin_loc); + root_list_init->push_back(roots_ctor); + + Expression* root_list_ctor = + Expression::make_struct_composite_literal(root_list_type, root_list_init, + builtin_loc); + + Expression* root_addr = Expression::make_unary(OPERATOR_AND, root_list_ctor, + builtin_loc); + root_addr->unary_expression()->set_is_gc_root(); + Expression* register_roots = Runtime::make_call(Runtime::REGISTER_GC_ROOTS, + builtin_loc, 1, root_addr); + + Translate_context context(this, NULL, NULL, NULL); + Bexpression* bcall = tree_to_expr(register_roots->get_tree(&context)); + init_stmts.push_back(this->backend()->expression_statement(bcall)); +} + // Get the name to use for the import control function. If there is a // global function or variable, then we know that that name must be // unique in the link, and we use it as the basis for our name. @@ -614,6 +772,521 @@ Gogo::initialization_function_decl() return Named_object::make_function(name, NULL, initfn); } +// Create the magic initialization function. CODE_STMT is the +// code that it needs to run. + +Named_object* +Gogo::create_initialization_function(Named_object* initfn, + Bstatement* code_stmt) +{ + // Make sure that we thought we needed an initialization function, + // as otherwise we will not have reported it in the export data. + go_assert(this->is_main_package() || this->need_init_fn_); + + if (initfn == NULL) + initfn = this->initialization_function_decl(); + + // Bind the initialization function code to a block. + Bfunction* fndecl = initfn->func_value()->get_or_make_decl(this, initfn); + Location pkg_loc = this->package_->location(); + std::vector<Bvariable*> vars; + this->backend()->block(fndecl, NULL, vars, pkg_loc, pkg_loc); + + if (!this->backend()->function_set_body(fndecl, code_stmt)) + { + go_assert(saw_errors()); + return NULL; + } + return initfn; +} + +// Search for references to VAR in any statements or called functions. + +class Find_var : public Traverse +{ + public: + // A hash table we use to avoid looping. The index is the name of a + // named object. We only look through objects defined in this + // package. + typedef Unordered_set(const void*) Seen_objects; + + Find_var(Named_object* var, Seen_objects* seen_objects) + : Traverse(traverse_expressions), + var_(var), seen_objects_(seen_objects), found_(false) + { } + + // Whether the variable was found. + bool + found() const + { return this->found_; } + + int + expression(Expression**); + + private: + // The variable we are looking for. + Named_object* var_; + // Names of objects we have already seen. + Seen_objects* seen_objects_; + // True if the variable was found. + bool found_; +}; + +// See if EXPR refers to VAR, looking through function calls and +// variable initializations. + +int +Find_var::expression(Expression** pexpr) +{ + Expression* e = *pexpr; + + Var_expression* ve = e->var_expression(); + if (ve != NULL) + { + Named_object* v = ve->named_object(); + if (v == this->var_) + { + this->found_ = true; + return TRAVERSE_EXIT; + } + + if (v->is_variable() && v->package() == NULL) + { + Expression* init = v->var_value()->init(); + if (init != NULL) + { + std::pair<Seen_objects::iterator, bool> ins = + this->seen_objects_->insert(v); + if (ins.second) + { + // This is the first time we have seen this name. + if (Expression::traverse(&init, this) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } + } + } + } + + // We traverse the code of any function we see. Note that this + // means that we will traverse the code of a function whose address + // is taken even if it is not called. + Func_expression* fe = e->func_expression(); + if (fe != NULL) + { + const Named_object* f = fe->named_object(); + if (f->is_function() && f->package() == NULL) + { + std::pair<Seen_objects::iterator, bool> ins = + this->seen_objects_->insert(f); + if (ins.second) + { + // This is the first time we have seen this name. + if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } + } + } + + Temporary_reference_expression* tre = e->temporary_reference_expression(); + if (tre != NULL) + { + Temporary_statement* ts = tre->statement(); + Expression* init = ts->init(); + if (init != NULL) + { + std::pair<Seen_objects::iterator, bool> ins = + this->seen_objects_->insert(ts); + if (ins.second) + { + // This is the first time we have seen this temporary + // statement. + if (Expression::traverse(&init, this) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } + } + } + + return TRAVERSE_CONTINUE; +} + +// Return true if EXPR, PREINIT, or DEP refers to VAR. + +static bool +expression_requires(Expression* expr, Block* preinit, Named_object* dep, + Named_object* var) +{ + Find_var::Seen_objects seen_objects; + Find_var find_var(var, &seen_objects); + if (expr != NULL) + Expression::traverse(&expr, &find_var); + if (preinit != NULL) + preinit->traverse(&find_var); + if (dep != NULL) + { + Expression* init = dep->var_value()->init(); + if (init != NULL) + Expression::traverse(&init, &find_var); + if (dep->var_value()->has_pre_init()) + dep->var_value()->preinit()->traverse(&find_var); + } + + return find_var.found(); +} + +// Sort variable initializations. If the initialization expression +// for variable A refers directly or indirectly to the initialization +// expression for variable B, then we must initialize B before A. + +class Var_init +{ + public: + Var_init() + : var_(NULL), init_(NULL) + { } + + Var_init(Named_object* var, Bstatement* init) + : var_(var), init_(init) + { } + + // Return the variable. + Named_object* + var() const + { return this->var_; } + + // Return the initialization expression. + Bstatement* + init() const + { return this->init_; } + + private: + // The variable being initialized. + Named_object* var_; + // The initialization statement. + Bstatement* init_; +}; + +typedef std::list<Var_init> Var_inits; + +// Sort the variable initializations. The rule we follow is that we +// emit them in the order they appear in the array, except that if the +// initialization expression for a variable V1 depends upon another +// variable V2 then we initialize V1 after V2. + +static void +sort_var_inits(Gogo* gogo, Var_inits* var_inits) +{ + typedef std::pair<Named_object*, Named_object*> No_no; + typedef std::map<No_no, bool> Cache; + Cache cache; + + Var_inits ready; + while (!var_inits->empty()) + { + Var_inits::iterator p1 = var_inits->begin(); + Named_object* var = p1->var(); + Expression* init = var->var_value()->init(); + Block* preinit = var->var_value()->preinit(); + Named_object* dep = gogo->var_depends_on(var->var_value()); + + // Start walking through the list to see which variables VAR + // needs to wait for. + Var_inits::iterator p2 = p1; + ++p2; + + for (; p2 != var_inits->end(); ++p2) + { + Named_object* p2var = p2->var(); + No_no key(var, p2var); + std::pair<Cache::iterator, bool> ins = + cache.insert(std::make_pair(key, false)); + if (ins.second) + ins.first->second = expression_requires(init, preinit, dep, p2var); + if (ins.first->second) + { + // Check for cycles. + key = std::make_pair(p2var, var); + ins = cache.insert(std::make_pair(key, false)); + if (ins.second) + ins.first->second = + expression_requires(p2var->var_value()->init(), + p2var->var_value()->preinit(), + gogo->var_depends_on(p2var->var_value()), + var); + if (ins.first->second) + { + error_at(var->location(), + ("initialization expressions for %qs and " + "%qs depend upon each other"), + var->message_name().c_str(), + p2var->message_name().c_str()); + inform(p2->var()->location(), "%qs defined here", + p2var->message_name().c_str()); + p2 = var_inits->end(); + } + else + { + // We can't emit P1 until P2 is emitted. Move P1. + Var_inits::iterator p3 = p2; + ++p3; + var_inits->splice(p3, *var_inits, p1); + } + break; + } + } + + if (p2 == var_inits->end()) + { + // VAR does not depends upon any other initialization expressions. + + // Check for a loop of VAR on itself. We only do this if + // INIT is not NULL and there is no dependency; when INIT is + // NULL, it means that PREINIT sets VAR, which we will + // interpret as a loop. + if (init != NULL && dep == NULL + && expression_requires(init, preinit, NULL, var)) + error_at(var->location(), + "initialization expression for %qs depends upon itself", + var->message_name().c_str()); + ready.splice(ready.end(), *var_inits, p1); + } + } + + // Now READY is the list in the desired initialization order. + var_inits->swap(ready); +} + +// Write out the global definitions. + +void +Gogo::write_globals() +{ + this->build_interface_method_tables(); + + Bindings* bindings = this->current_bindings(); + + for (Bindings::const_declarations_iterator p = bindings->begin_declarations(); + p != bindings->end_declarations(); + ++p) + { + // If any function declarations needed a descriptor, make sure + // we build it. + Named_object* no = p->second; + if (no->is_function_declaration()) + no->func_declaration_value()->build_backend_descriptor(this); + } + + // Lists of globally declared types, variables, constants, and functions + // that must be defined. + std::vector<Btype*> type_decls; + std::vector<Bvariable*> var_decls; + std::vector<Bexpression*> const_decls; + std::vector<Bfunction*> func_decls; + + // The init function declaration, if necessary. + Named_object* init_fndecl = NULL; + + std::vector<Bstatement*> init_stmts; + std::vector<Bstatement*> var_init_stmts; + + if (this->is_main_package()) + this->init_imports(init_stmts); + + // A list of variable initializations. + Var_inits var_inits; + + // A list of variables which need to be registered with the garbage + // collector. + size_t count_definitions = bindings->size_definitions(); + std::vector<Named_object*> var_gc; + var_gc.reserve(count_definitions); + + for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); + p != bindings->end_definitions(); + ++p) + { + Named_object* no = *p; + go_assert(!no->is_type_declaration() && !no->is_function_declaration()); + + // There is nothing to do for a package. + if (no->is_package()) + continue; + + // There is nothing to do for an object which was imported from + // a different package into the global scope. + if (no->package() != NULL) + continue; + + // Skip blank named functions and constants. + if ((no->is_function() && no->func_value()->is_sink()) + || (no->is_const() && no->const_value()->is_sink())) + continue; + + // There is nothing useful we can output for constants which + // have ideal or non-integral type. + if (no->is_const()) + { + Type* type = no->const_value()->type(); + if (type == NULL) + type = no->const_value()->expr()->type(); + if (type->is_abstract() || !type->is_numeric_type()) + continue; + } + + if (!no->is_variable()) + no->get_backend(this, const_decls, type_decls, func_decls); + else + { + Variable* var = no->var_value(); + Bvariable* bvar = no->get_backend_variable(this, NULL); + var_decls.push_back(bvar); + + // Check for a sink variable, which may be used to run an + // initializer purely for its side effects. + bool is_sink = no->name()[0] == '_' && no->name()[1] == '.'; + + Bstatement* var_init_stmt = NULL; + if (!var->has_pre_init()) + { + Bexpression* var_binit = var->get_init(this, NULL); + + // If the backend representation of the variable initializer is + // constant, we can just set the initial value using + // global_var_set_init instead of during the init() function. + // The initializer is constant if it is the zero-value of the + // variable's type or if the initial value is an immutable value + // that is not copied to the heap. + bool is_constant_initializer = false; + if (var->init() == NULL) + is_constant_initializer = true; + else + { + Type* var_type = var->type(); + Expression* init = var->init(); + Expression* init_cast = + Expression::make_cast(var_type, init, var->location()); + is_constant_initializer = + init_cast->is_immutable() && !var_type->has_pointer(); + } + + if (var_binit == NULL) + ; + else if (is_constant_initializer) + { + if (expression_requires(var->init(), NULL, + this->var_depends_on(var), no)) + error_at(no->location(), + "initialization expression for %qs depends " + "upon itself", + no->message_name().c_str()); + this->backend()->global_variable_set_init(bvar, var_binit); + } + else if (is_sink) + var_init_stmt = + this->backend()->expression_statement(var_binit); + else + { + Location loc = var->location(); + Bexpression* var_expr = + this->backend()->var_expression(bvar, loc); + var_init_stmt = + this->backend()->assignment_statement(var_expr, var_binit, + loc); + } + } + else + { + // We are going to create temporary variables which + // means that we need an fndecl. + if (init_fndecl == NULL) + init_fndecl = this->initialization_function_decl(); + + Bvariable* var_decl = is_sink ? NULL : bvar; + var_init_stmt = var->get_init_block(this, init_fndecl, var_decl); + } + + if (var_init_stmt != NULL) + { + if (var->init() == NULL && !var->has_pre_init()) + var_init_stmts.push_back(var_init_stmt); + else + var_inits.push_back(Var_init(no, var_init_stmt)); + } + else if (this->var_depends_on(var) != NULL) + { + // This variable is initialized from something that is + // not in its init or preinit. This variable needs to + // participate in dependency analysis sorting, in case + // some other variable depends on this one. + Btype* btype = no->var_value()->type()->get_backend(this); + Bexpression* zero = this->backend()->zero_expression(btype); + Bstatement* zero_stmt = + this->backend()->expression_statement(zero); + var_inits.push_back(Var_init(no, zero_stmt)); + } + + if (!is_sink && var->type()->has_pointer()) + var_gc.push_back(no); + } + } + + // Register global variables with the garbage collector. + this->register_gc_vars(var_gc, init_stmts); + + // Simple variable initializations, after all variables are + // registered. + init_stmts.push_back(this->backend()->statement_list(var_init_stmts)); + + // Complete variable initializations, first sorting them into a + // workable order. + if (!var_inits.empty()) + { + sort_var_inits(this, &var_inits); + for (Var_inits::const_iterator p = var_inits.begin(); + p != var_inits.end(); + ++p) + init_stmts.push_back(p->init()); + } + + // After all the variables are initialized, call the init + // functions if there are any. Init functions take no arguments, so + // we pass in EMPTY_ARGS to call them. + std::vector<Bexpression*> empty_args; + for (std::vector<Named_object*>::const_iterator p = + this->init_functions_.begin(); + p != this->init_functions_.end(); + ++p) + { + Location func_loc = (*p)->location(); + Function* func = (*p)->func_value(); + Bfunction* initfn = func->get_or_make_decl(this, *p); + Bexpression* func_code = + this->backend()->function_code_expression(initfn, func_loc); + Bexpression* call = this->backend()->call_expression(func_code, + empty_args, + func_loc); + init_stmts.push_back(this->backend()->expression_statement(call)); + } + + // Set up a magic function to do all the initialization actions. + // This will be called if this package is imported. + Bstatement* init_fncode = this->backend()->statement_list(init_stmts); + if (this->need_init_fn_ || this->is_main_package()) + { + init_fndecl = + this->create_initialization_function(init_fndecl, init_fncode); + if (init_fndecl != NULL) + func_decls.push_back(init_fndecl->func_value()->get_decl()); + } + + // We should not have seen any new bindings created during the conversion. + go_assert(count_definitions == this->current_bindings()->size_definitions()); + + // Define all globally declared values. + if (!saw_errors()) + this->backend()->write_global_definitions(type_decls, const_decls, + func_decls, var_decls); +} + // Return the current block. Block* @@ -4182,6 +4855,15 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) return this->fndecl_; } +// Return the function's decl after it has been built. + +Bfunction* +Function::get_decl() const +{ + go_assert(this->fndecl_ != NULL); + return this->fndecl_; +} + // Build the backend representation for the function code. void @@ -5266,8 +5948,7 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, { Location loc = this->location(); Expression* val_expr = - Expression::convert_for_assignment(gogo, this->type(), - this->init_, this->location()); + Expression::make_cast(this->type(), this->init_, loc); Bexpression* val = tree_to_expr(val_expr->get_tree(&context)); Bexpression* var_ref = gogo->backend()->var_expression(var_decl, loc); decl_init = gogo->backend()->assignment_statement(var_ref, val, loc); @@ -5353,8 +6034,7 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, } else { - tree fndecl = function->func_value()->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); + Bfunction* bfunction = function->func_value()->get_decl(); bool is_address_taken = (this->is_non_escaping_address_taken_ && !this->is_in_heap()); if (is_parameter) @@ -5391,8 +6071,7 @@ Result_variable::get_backend_variable(Gogo* gogo, Named_object* function, if (this->is_in_heap()) type = Type::make_pointer_type(type); Btype* btype = type->get_backend(gogo); - tree fndecl = function->func_value()->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); + Bfunction* bfunction = function->func_value()->get_decl(); std::string n = Gogo::unpack_hidden_name(name); bool is_address_taken = (this->is_non_escaping_address_taken_ && !this->is_in_heap()); @@ -5482,6 +6161,33 @@ Named_constant::import_const(Import* imp, std::string* pname, Type** ptype, imp->require_c_string(";\n"); } +// Get the backend representation. + +Bexpression* +Named_constant::get_backend(Gogo* gogo, Named_object* const_no) +{ + if (this->bconst_ == NULL) + { + Translate_context subcontext(gogo, NULL, NULL, NULL); + Type* type = this->type(); + Location loc = this->location(); + + Expression* const_ref = Expression::make_const_reference(const_no, loc); + Bexpression* const_decl = + tree_to_expr(const_ref->get_tree(&subcontext)); + if (type != NULL && type->is_numeric_type()) + { + Btype* btype = type->get_backend(gogo); + std::string name = const_no->get_id(gogo); + const_decl = + gogo->backend()->named_constant_expression(btype, name, + const_decl, loc); + } + this->bconst_ = const_decl; + } + return this->bconst_; +} + // Add a method. Named_object* @@ -5552,8 +6258,7 @@ Unknown_name::set_real_named_object(Named_object* no) Named_object::Named_object(const std::string& name, const Package* package, Classification classification) - : name_(name), package_(package), classification_(classification), - tree_(NULL) + : name_(name), package_(package), classification_(classification) { if (Gogo::is_sink_name(name)) go_assert(classification == NAMED_OBJECT_SINK); @@ -5928,6 +6633,72 @@ Named_object::get_id(Gogo* gogo) return decl_name; } +// Get the backend representation for this named object. + +void +Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls, + std::vector<Btype*>& type_decls, + std::vector<Bfunction*>& func_decls) +{ + switch (this->classification_) + { + case NAMED_OBJECT_CONST: + if (!Gogo::is_erroneous_name(this->name_)) + const_decls.push_back(this->u_.const_value->get_backend(gogo, this)); + break; + + case NAMED_OBJECT_TYPE: + { + Named_type* named_type = this->u_.type_value; + if (!Gogo::is_erroneous_name(this->name_)) + type_decls.push_back(named_type->get_backend(gogo)); + + // We need to produce a type descriptor for every named + // type, and for a pointer to every named type, since + // other files or packages might refer to them. We need + // to do this even for hidden types, because they might + // still be returned by some function. Simply calling the + // type_descriptor method is enough to create the type + // descriptor, even though we don't do anything with it. + if (this->package_ == NULL) + { + named_type-> + type_descriptor_pointer(gogo, Linemap::predeclared_location()); + Type* pn = Type::make_pointer_type(named_type); + pn->type_descriptor_pointer(gogo, Linemap::predeclared_location()); + } + } + break; + + case NAMED_OBJECT_TYPE_DECLARATION: + error("reference to undefined type %qs", + this->message_name().c_str()); + return; + + case NAMED_OBJECT_VAR: + case NAMED_OBJECT_RESULT_VAR: + case NAMED_OBJECT_SINK: + go_unreachable(); + + case NAMED_OBJECT_FUNC: + { + Function* func = this->u_.func_value; + if (!Gogo::is_erroneous_name(this->name_)) + func_decls.push_back(func->get_or_make_decl(gogo, this)); + + if (func->block() != NULL) + func->build(gogo, this); + } + break; + + case NAMED_OBJECT_ERRONEOUS: + break; + + default: + go_unreachable(); + } +} + // Class Bindings. Bindings::Bindings(Bindings* enclosing) @@ -6400,8 +7171,7 @@ Label::get_backend_label(Translate_context* context) if (this->blabel_ == NULL) { Function* function = context->function()->func_value(); - tree fndecl = function->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); + Bfunction* bfunction = function->get_decl(); this->blabel_ = context->backend()->label(bfunction, this->name_, this->location_); } @@ -6427,8 +7197,7 @@ Unnamed_label::get_blabel(Translate_context* context) if (this->blabel_ == NULL) { Function* function = context->function()->func_value(); - tree fndecl = function->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); + Bfunction* bfunction = function->get_decl(); this->blabel_ = context->backend()->label(bfunction, "", this->location_); } diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index dd43d269f40..0be81b2aafe 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -44,6 +44,7 @@ class Backend; class Export; class Import; class Bexpression; +class Btype; class Bstatement; class Bblock; class Bvariable; @@ -591,11 +592,6 @@ class Gogo Expression* runtime_error(int code, Location); - // Build a builtin struct with a list of fields. - static tree - builtin_struct(tree* ptype, const char* struct_name, tree struct_type, - int nfields, ...); - // Mark a function declaration as a builtin library function. static void mark_fndecl_as_builtin_library(tree fndecl); @@ -650,17 +646,18 @@ class Gogo Named_object* initialization_function_decl(); - // Write the magic initialization function. - void - write_initialization_function(Named_object* fndecl, tree init_stmt_list); + // Create the magic initialization function. + Named_object* + create_initialization_function(Named_object* fndecl, Bstatement* code_stmt); // Initialize imported packages. void - init_imports(tree*); + init_imports(std::vector<Bstatement*>&); // Register variables with the garbage collector. void - register_gc_vars(const std::vector<Named_object*>&, tree*); + register_gc_vars(const std::vector<Named_object*>&, + std::vector<Bstatement*>&); // Type used to map import names to packages. typedef std::map<std::string, Package*> Imports; @@ -1086,7 +1083,7 @@ class Function get_or_make_decl(Gogo*, Named_object*); // Return the function's decl after it has been built. - tree + Bfunction* get_decl() const; // Set the function decl to hold a backend representation of the function @@ -1675,7 +1672,7 @@ class Named_constant Named_constant(Type* type, Expression* expr, int iota_value, Location location) : type_(type), expr_(expr), iota_value_(iota_value), location_(location), - lowering_(false), is_sink_(false) + lowering_(false), is_sink_(false), bconst_(NULL) { } Type* @@ -1737,6 +1734,10 @@ class Named_constant static void import_const(Import*, std::string*, Type**, Expression**); + // Get the backend representation of the constant value. + Bexpression* + get_backend(Gogo*, Named_object*); + private: // The type of the constant. Type* type_; @@ -1754,6 +1755,8 @@ class Named_constant bool lowering_; // Whether this constant is blank named and needs only type checking. bool is_sink_; + // The backend representation of the constant value. + Bexpression* bconst_; }; // A type declaration. @@ -2176,9 +2179,10 @@ class Named_object std::string get_id(Gogo*); - // Return a tree representing this object. - tree - get_tree(Gogo*, Named_object* function); + // Get the backend representation of this object. + void + get_backend(Gogo*, std::vector<Bexpression*>&, std::vector<Btype*>&, + std::vector<Bfunction*>&); // Define a type declaration. void @@ -2219,8 +2223,6 @@ class Named_object Function_declaration* func_declaration_value; Package* package_value; } u_; - // The DECL tree for this object if we have already converted it. - tree tree_; }; // A binding contour. This binds names to objects. diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 49a864faa44..dabf1a83af6 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -434,15 +434,9 @@ Temporary_statement::do_get_backend(Translate_context* context) { go_assert(this->bvariable_ == NULL); - // FIXME: Permitting FUNCTION to be NULL here is a temporary measure - // until we have a better representation of the init function. Named_object* function = context->function(); - Bfunction* bfunction; - if (function == NULL) - bfunction = NULL; - else - bfunction = tree_to_function(function->func_value()->get_decl()); - + go_assert(function != NULL); + Bfunction* bfunction = function->func_value()->get_decl(); Btype* btype = this->type()->get_backend(context->gogo()); Bexpression* binit; @@ -2781,8 +2775,6 @@ Return_statement::do_get_backend(Translate_context* context) Location loc = this->location(); Function* function = context->function()->func_value(); - tree fndecl = function->get_decl(); - Function::Results* results = function->result_variables(); std::vector<Bexpression*> retvals; if (results != NULL && !results->empty()) @@ -2797,7 +2789,7 @@ Return_statement::do_get_backend(Translate_context* context) } } - return context->backend()->return_statement(tree_to_function(fndecl), + return context->backend()->return_statement(function->get_decl(), retvals, loc); } @@ -3803,8 +3795,10 @@ Constant_switch_statement::do_get_backend(Translate_context* context) this->clauses_->get_backend(context, break_label, &all_cases, &all_statements); + Bfunction* bfunction = context->function()->func_value()->get_decl(); Bstatement* switch_statement; - switch_statement = context->backend()->switch_statement(switch_val_expr, + switch_statement = context->backend()->switch_statement(bfunction, + switch_val_expr, all_cases, all_statements, this->location()); @@ -4980,7 +4974,9 @@ Select_clauses::get_backend(Translate_context* context, std::vector<Bstatement*> statements; statements.reserve(2); - Bstatement* switch_stmt = context->backend()->switch_statement(bcall, + Bfunction* bfunction = context->function()->func_value()->get_decl(); + Bstatement* switch_stmt = context->backend()->switch_statement(bfunction, + bcall, cases, clauses, location); diff --git a/gcc/graphite-scop-detection.c b/gcc/graphite-scop-detection.c index 821f0846ef2..635e21a8519 100644 --- a/gcc/graphite-scop-detection.c +++ b/gcc/graphite-scop-detection.c @@ -474,8 +474,10 @@ scopdet_basic_block_info (basic_block bb, loop_p outermost_loop, result.exits = false; /* Mark bbs terminating a SESE region difficult, if they start - a condition. */ - if (!single_succ_p (bb)) + a condition or if the block it exits to cannot be split + with make_forwarder_block. */ + if (!single_succ_p (bb) + || bb_has_abnormal_pred (single_succ (bb))) result.difficult = true; else result.exit = single_succ (bb); diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index 2d66e5cab6a..5d16b4d0f94 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -1299,7 +1299,7 @@ recompute_todo_spec (rtx next, bool for_backtrack) { HARD_REG_SET t; - find_all_hard_reg_sets (prev, &t); + find_all_hard_reg_sets (prev, &t, true); if (TEST_HARD_REG_BIT (t, regno)) return HARD_DEP; if (prev == pro) @@ -3082,7 +3082,7 @@ check_clobbered_conditions (rtx insn) if ((current_sched_info->flags & DO_PREDICATION) == 0) return; - find_all_hard_reg_sets (insn, &t); + find_all_hard_reg_sets (insn, &t, true); restart: for (i = 0; i < ready.n_ready; i++) diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 5411e00a3c4..a0f024a76ef 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1730,6 +1730,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) scan_array_reductions = true; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)) + scan_array_reductions = true; break; case OMP_CLAUSE_SHARED: @@ -1816,6 +1819,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)) scan_omp (&OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx); + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)) + scan_omp (&OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c), ctx); } /* Create a new name for omp child function. Returns an identifier. */ @@ -3801,6 +3807,14 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)); OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) = NULL; } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)) + { + lower_omp (&OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c), ctx); + gimple_seq_add_seq (stmt_list, + OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)); + OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c) = NULL; + } x = build_outer_var_ref (var, ctx); if (is_reference (var)) diff --git a/gcc/passes.c b/gcc/passes.c index 2be7856f29b..c0a76d62d21 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -132,7 +132,7 @@ opt_pass::opt_pass (const pass_data &data, context *ctxt) void pass_manager::execute_early_local_passes () { - execute_pass_list (pass_early_local_passes_1->sub); + execute_pass_list (cfun, pass_early_local_passes_1->sub); } unsigned int @@ -1498,27 +1498,17 @@ pass_manager::pass_manager (context *ctxt) call CALLBACK on the current function. */ static void -do_per_function (void (*callback) (void *data), void *data) +do_per_function (void (*callback) (function *, void *data), void *data) { if (current_function_decl) - callback (data); + callback (cfun, data); else { struct cgraph_node *node; FOR_EACH_DEFINED_FUNCTION (node) if (node->analyzed && gimple_has_body_p (node->decl) && (!node->clone_of || node->decl != node->clone_of->decl)) - { - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - callback (data); - if (!flag_wpa) - { - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - } - pop_cfun (); - ggc_collect (); - } + callback (DECL_STRUCT_FUNCTION (node->decl), data); } } @@ -1533,12 +1523,12 @@ static GTY ((length ("nnodes"))) cgraph_node_ptr *order; call CALLBACK on the current function. This function is global so that plugins can use it. */ void -do_per_function_toporder (void (*callback) (void *data), void *data) +do_per_function_toporder (void (*callback) (function *, void *data), void *data) { int i; if (current_function_decl) - callback (data); + callback (cfun, data); else { gcc_assert (!order); @@ -1554,15 +1544,7 @@ do_per_function_toporder (void (*callback) (void *data), void *data) order[i] = NULL; node->process = 0; if (cgraph_function_with_gimple_body_p (node)) - { - cgraph_get_body (node); - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - callback (data); - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - pop_cfun (); - ggc_collect (); - } + callback (DECL_STRUCT_FUNCTION (node->decl), data); } } ggc_free (order); @@ -1573,14 +1555,16 @@ do_per_function_toporder (void (*callback) (void *data), void *data) /* Helper function to perform function body dump. */ static void -execute_function_dump (void *data) +execute_function_dump (function *fn, void *data) { opt_pass *pass = (opt_pass *)data; - if (dump_file && current_function_decl) + if (dump_file) { - if (cfun->curr_properties & PROP_trees) - dump_function_to_file (current_function_decl, dump_file, dump_flags); + push_cfun (fn); + + if (fn->curr_properties & PROP_trees) + dump_function_to_file (fn->decl, dump_file, dump_flags); else print_rtl_with_bb (dump_file, get_insns (), dump_flags); @@ -1588,7 +1572,7 @@ execute_function_dump (void *data) close the file before aborting. */ fflush (dump_file); - if ((cfun->curr_properties & PROP_cfg) + if ((fn->curr_properties & PROP_cfg) && (dump_flags & TDF_GRAPH)) { if (!pass->graph_dump_initialized) @@ -1596,8 +1580,10 @@ execute_function_dump (void *data) clean_graph_dump_file (dump_file_name); pass->graph_dump_initialized = true; } - print_graph_cfg (dump_file_name, cfun); + print_graph_cfg (dump_file_name, fn); } + + pop_cfun (); } } @@ -1728,13 +1714,15 @@ pass_manager::dump_profile_report () const /* Perform all TODO actions that ought to be done on each function. */ static void -execute_function_todo (void *data) +execute_function_todo (function *fn, void *data) { unsigned int flags = (size_t)data; - flags &= ~cfun->last_verified; + flags &= ~fn->last_verified; if (!flags) return; + push_cfun (fn); + /* Always cleanup the CFG before trying to update SSA. */ if (flags & TODO_cleanup_cfg) { @@ -1774,7 +1762,10 @@ execute_function_todo (void *data) /* If we've seen errors do not bother running any verifiers. */ if (seen_error ()) - return; + { + pop_cfun (); + return; + } #if defined ENABLE_CHECKING if (flags & TODO_verify_ssa @@ -1793,7 +1784,9 @@ execute_function_todo (void *data) verify_rtl_sharing (); #endif - cfun->last_verified = flags & TODO_verify_all; + fn->last_verified = flags & TODO_verify_all; + + pop_cfun (); } /* Perform all TODO actions. */ @@ -1855,9 +1848,9 @@ verify_interpass_invariants (void) /* Clear the last verified flag. */ static void -clear_last_verified (void *data ATTRIBUTE_UNUSED) +clear_last_verified (function *fn, void *data ATTRIBUTE_UNUSED) { - cfun->last_verified = 0; + fn->last_verified = 0; } /* Helper function. Verify that the properties has been turn into the @@ -1865,10 +1858,10 @@ clear_last_verified (void *data ATTRIBUTE_UNUSED) #ifdef ENABLE_CHECKING static void -verify_curr_properties (void *data) +verify_curr_properties (function *fn, void *data) { unsigned int props = (size_t)data; - gcc_assert ((cfun->curr_properties & props) == props); + gcc_assert ((fn->curr_properties & props) == props); } #endif @@ -1927,11 +1920,11 @@ pass_fini_dump_file (opt_pass *pass) properties. */ static void -update_properties_after_pass (void *data) +update_properties_after_pass (function *fn, void *data) { opt_pass *pass = (opt_pass *) data; - cfun->curr_properties = (cfun->curr_properties | pass->properties_provided) - & ~pass->properties_destroyed; + fn->curr_properties = (fn->curr_properties | pass->properties_provided) + & ~pass->properties_destroyed; } /* Execute summary generation for all of the passes in IPA_PASS. */ @@ -2039,20 +2032,6 @@ execute_all_ipa_transforms (void) } } -/* Callback for do_per_function to apply all IPA transforms. */ - -static void -apply_ipa_transforms (void *data) -{ - struct cgraph_node *node = cgraph_get_node (current_function_decl); - if (!node->global.inlined_to && node->ipa_transforms_to_apply.exists ()) - { - *(bool *)data = true; - execute_all_ipa_transforms (); - rebuild_cgraph_edges (); - } -} - /* Check if PASS is explicitly disabled or enabled and return the gate status. FUNC is the function to be processed, and GATE_STATUS is the gate status determined by pass manager by @@ -2124,8 +2103,26 @@ execute_one_pass (opt_pass *pass) Apply all trnasforms first. */ if (pass->type == SIMPLE_IPA_PASS) { + struct cgraph_node *node; bool applied = false; - do_per_function (apply_ipa_transforms, (void *)&applied); + FOR_EACH_DEFINED_FUNCTION (node) + if (node->analyzed + && cgraph_function_with_gimple_body_p (node) + && (!node->clone_of || node->decl != node->clone_of->decl)) + { + if (!node->global.inlined_to + && node->ipa_transforms_to_apply.exists ()) + { + cgraph_get_body (node); + push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + execute_all_ipa_transforms (); + rebuild_cgraph_edges (); + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + pop_cfun (); + applied = true; + } + } if (applied) symtab_remove_unreachable_nodes (true, dump_file); /* Restore current_pass. */ @@ -2202,20 +2199,33 @@ execute_one_pass (opt_pass *pass) return true; } -void -execute_pass_list (opt_pass *pass) +static void +execute_pass_list_1 (opt_pass *pass) { do { gcc_assert (pass->type == GIMPLE_PASS || pass->type == RTL_PASS); if (execute_one_pass (pass) && pass->sub) - execute_pass_list (pass->sub); + execute_pass_list_1 (pass->sub); pass = pass->next; } while (pass); } +void +execute_pass_list (function *fn, opt_pass *pass) +{ + push_cfun (fn); + execute_pass_list_1 (pass); + if (fn->cfg) + { + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + } + pop_cfun (); +} + /* Write out all LTO data. */ static void write_lto (void) @@ -2539,7 +2549,8 @@ execute_ipa_pass_list (opt_pass *pass) if (pass->sub->type == GIMPLE_PASS) { invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL); - do_per_function_toporder ((void (*)(void *))execute_pass_list, + do_per_function_toporder ((void (*)(function *, void *)) + execute_pass_list, pass->sub); invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL); } diff --git a/gcc/rtl.h b/gcc/rtl.h index cccb884ae88..f62c334351d 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2231,7 +2231,7 @@ extern const_rtx set_of (const_rtx, const_rtx); extern void record_hard_reg_sets (rtx, const_rtx, void *); extern void record_hard_reg_uses (rtx *, void *); #ifdef HARD_CONST -extern void find_all_hard_reg_sets (const_rtx, HARD_REG_SET *); +extern void find_all_hard_reg_sets (const_rtx, HARD_REG_SET *, bool); #endif extern void note_stores (const_rtx, void (*) (rtx, const_rtx, void *), void *); extern void note_uses (rtx *, void (*) (rtx *, void *), void *); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 98c652894fb..82cfc1bf70b 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -1046,14 +1046,20 @@ record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data) /* Examine INSN, and compute the set of hard registers written by it. Store it in *PSET. Should only be called after reload. */ void -find_all_hard_reg_sets (const_rtx insn, HARD_REG_SET *pset) +find_all_hard_reg_sets (const_rtx insn, HARD_REG_SET *pset, bool implicit) { rtx link; CLEAR_HARD_REG_SET (*pset); note_stores (PATTERN (insn), record_hard_reg_sets, pset); if (CALL_P (insn)) - IOR_HARD_REG_SET (*pset, call_used_reg_set); + { + if (implicit) + IOR_HARD_REG_SET (*pset, call_used_reg_set); + + for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1)) + record_hard_reg_sets (XEXP (link, 0), NULL, pset); + } for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_INC) record_hard_reg_sets (XEXP (link, 0), NULL, pset); diff --git a/gcc/system.h b/gcc/system.h index 8b5089a28d7..b20b5cfde1d 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -1035,7 +1035,7 @@ helper_const_non_const_cast (const char *p) #endif #endif -#ifdef ENABLE_VALGRIND_CHECKING +#ifdef ENABLE_VALGRIND_ANNOTATIONS # ifdef HAVE_VALGRIND_MEMCHECK_H # include <valgrind/memcheck.h> # elif defined HAVE_MEMCHECK_H diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 70a0f89d592..261bb98a3a4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,10 +1,156 @@ -i2014-04-24 Alan Lawrence <alan.lawrence@arm.com> +2014-04-28 Richard Biener <rguenther@suse.de> + + * gcc.dg/tree-ssa/vrp91.c: New testcase. + * gcc.dg/Wstrict-overflow-14.c: XFAIL. + * gcc.dg/Wstrict-overflow-15.c: Likewise. + * gcc.dg/Wstrict-overflow-18.c: Remove XFAIL. + +2014-04-28 Richard Biener <rguenther@suse.de> + + PR tree-optimization/60979 + * gcc.dg/graphite/pr60979.c: New testcase. + +2014-04-28 Kyrylo Tkachov <kyrylo.tkachov@arm.com> + + PR c/60983 + * gcc.dg/pr60114.c: Use signed chars. + +2014-04-28 Paolo Carlini <paolo.carlini@oracle.com> + + PR c++/59120 + * g++.dg/cpp0x/alias-decl-43.C: New. + +2014-03-27 Thomas Koenig <tkoenig@gcc.gnu.org> + + PR fortran/59604 + PR fortran/58003 + * gfortran.dg/no_range_check_3.f90: New test. + +2014-04-26 Jerry DeLisle <jvdelisle@gcc.gnu> + + PR libfortran/52539 + * gfortran.dg/namelist_utf8.f90: New test. + +2014-04-26 Uros Bizjak <ubizjak@gmail.com> + + * gcc.dg/tree-ssa/alias-30.c (dg-options): Dump only fre1 details. + * gcc.dg/vect/pr60505.c: Cleanup vect tree dump. + * g++.dg/ipa/devirt-27.C (dg-options): Remove -fdump-ipa-devirt. + +2014-04-25 Cary Coutant <ccoutant@google.com> + + PR debug/60929 + * g++.dg/debug/dwarf2/dwarf4-nested.C: New test case. + * g++.dg/debug/dwarf2/dwarf4-typedef.C: Add + -fdebug-types-section flag. + +2014-04-25 Jiong Wang <jiong.wang@arm.com> + + * gcc.target/arm/tail-long-call.c: New test. + +2014-04-25 Bill Schmidt <wschmidt@linux.vnet.ibm.com> + + PR tree-optimization/60930 + * gcc.dg/torture/pr60930.c: New test. + +2014-04-25 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/60960 + * gcc.c-torture/execute/pr60960.c: New test. + +2014-04-25 Marek Polacek <polacek@redhat.com> + + * gcc.dg/pr18079-2.c: Fix quoting in dg-warning. + +2014-04-25 Marek Polacek <polacek@redhat.com> + + PR c/18079 + * gcc.dg/pr18079.c: New test. + * gcc.dg/pr18079-2.c: New test. + +2014-04-25 Uros Bizjak <ubizjak@gmail.com> + + * c-c++-common/gomp/pr60823-2.c: Require effective target + vect_simd_clones. + +2014-04-25 Marek Polacek <polacek@redhat.com> + + PR c/60114 + * gcc.dg/pr60114.c: New test. + +2014-04-25 Eric Botcazou <ebotcazou@adacore.com> + + * gcc.c-torture/execute/20140425-1.c: New test. + +2014-04-25 Marek Polacek <polacek@redhat.com> + + PR c/60156 + * c-c++-common/pr60156.c: New test. + +2014-04-25 Richard Biener <rguenther@suse.de> + + PR ipa/60912 + * g++.dg/opt/pr60912.C: New testcase. + +2014-04-25 Richard Biener <rguenther@suse.de> + + PR ipa/60911 + * gcc.dg/lto/pr60911_0.c: New testcase. + +2014-04-24 Cong Hou <congh@google.com> + + PR tree-optimization/60896 + * g++.dg/vect/pr60896.cc: New test. + +2014-04-24 Michael Meissner <meissner@linux.vnet.ibm.com> + + * gcc.target/powerpc/pack01.c: New test to test the new pack and + unpack builtin functionss for 128-bit types. + * gcc.target/powerpc/pack02.c: Likewise. + * gcc.target/powerpc/pack03.c: Likewise. + * gcc.target/powerpc/extend-divide-1.c: New test to test extended + divide builtin functionss. + * gcc.target/powerpc/extend-divide-2.c: Likewise. + * gcc.target/powerpc/bcd-1.c: New test for the new BCD builtin + functions. + * gcc.target/powerpc/bcd-2.c: Likewise. + * gcc.target/powerpc/bcd-3.c: Likewise. + * gcc.target/powerpc/dfp-builtin-1.c: New test for the new DFP + builtin functionss. + * gcc.target/powerpc/dfp-builtin-2.c: Likewise. + +2014-04-24 Vishnu K S <Vishnu.k_s@atmel.com> + + * gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c: Skip test if + keeps_null_pointer_checks. + * gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c: Ditto. + * gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c: Ditto. + * gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c: Ditto. + * gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c: Ditto. + +2014-04-24 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/atomic-16.c: Remove all dg-error directives. + Replace load with read and store with write. + +2014-04-24 Jeff Law <law@redhat.com> + + PR target/60822 + * gcc.c-torture/pr60822.c: New test. + * gcc.c-torture/pr60822.x: New test. + +2014-04-24 Dinar Temirbulatov <dtemirbulatov@gmail.com> + + PR c++/57958 + * testsuite/g++.dg/cpp0x/pr57958.C: New test. + +2014-04-24 Alan Lawrence <alan.lawrence@arm.com> * lib/target-supports.exp (check_effective_target_vect_perm): Return true for aarch64_be. 2014-04-24 Radovan Obradovic <robradovic@mips.com> - Tom de Vries <tom@codesourcery.com> + Tom de Vries <tom@codesourcery.com> * gcc.dg/fuse-caller-save.c: New test. @@ -36,7 +182,7 @@ i2014-04-24 Alan Lawrence <alan.lawrence@arm.com> 2014-04-23 Kyrylo Tkachov <kyrylo.tkachov@arm.com> - * gcc.target/aarch64/rev16_1.c: New test. + * gcc.target/aarch64/rev16_1.c: New test. 2014-04-23 Richard Biener <rguenther@suse.de> @@ -241,7 +387,7 @@ i2014-04-24 Alan Lawrence <alan.lawrence@arm.com> PR tree-optimization/60836 * g++.dg/vect/pr60836.cc: New testcase. -2014-04-17 Richard Biener <rguenther@suse.de> +2014-04-17 Richard Biener <rguenther@suse.de> PR tree-optimization/60841 * gcc.dg/vect/pr60841.c: New testcase. @@ -1924,8 +2070,7 @@ i2014-04-24 Alan Lawrence <alan.lawrence@arm.com> 2014-02-19 Paul Pluzhnikov <ppluzhnikov@google.com> - * gcc.dg/vect/no-vfa-vect-depend-2.c (main1): Fix buffer - overflow. + * gcc.dg/vect/no-vfa-vect-depend-2.c (main1): Fix buffer overflow. 2014-02-19 Jakub Jelinek <jakub@redhat.com> @@ -2234,8 +2379,7 @@ i2014-04-24 Alan Lawrence <alan.lawrence@arm.com> 2014-02-10 Jakub Jelinek <jakub@redhat.com> - * gcc.dg/vect/pr59984.c: Require effective target - vect_simd_clones. + * gcc.dg/vect/pr59984.c: Require effective target vect_simd_clones. 2014-02-09 Paul Thomas <pault@gcc.gnu.org> diff --git a/gcc/testsuite/c-c++-common/gomp/atomic-16.c b/gcc/testsuite/c-c++-common/gomp/atomic-16.c index 87fbaa23317..9332396eaa5 100644 --- a/gcc/testsuite/c-c++-common/gomp/atomic-16.c +++ b/gcc/testsuite/c-c++-common/gomp/atomic-16.c @@ -7,28 +7,28 @@ void foo () { int v; - #pragma omp atomic seq_cst load /* { dg-error "expected end of line" } */ - v = x; /* { dg-error "invalid form" } */ - #pragma omp atomic seq_cst, load /* { dg-error "expected end of line" } */ - v = x; /* { dg-error "invalid form" } */ - #pragma omp atomic seq_cst store /* { dg-error "expected end of line" } */ - x = v; /* { dg-error "invalid form" } */ - #pragma omp atomic seq_cst ,store /* { dg-error "expected end of line" } */ - x = v; /* { dg-error "invalid form" } */ - #pragma omp atomic seq_cst update /* { dg-error "expected end of line" } */ + #pragma omp atomic seq_cst read + v = x; + #pragma omp atomic seq_cst, read + v = x; + #pragma omp atomic seq_cst write + x = v; + #pragma omp atomic seq_cst ,write + x = v; + #pragma omp atomic seq_cst update x += v; - #pragma omp atomic seq_cst , update /* { dg-error "expected end of line" } */ + #pragma omp atomic seq_cst , update x += v; - #pragma omp atomic seq_cst capture /* { dg-error "expected end of line" } */ - v = x += 2; /* { dg-error "invalid form" } */ - #pragma omp atomic seq_cst, capture /* { dg-error "expected end of line" } */ - v = x += 2; /* { dg-error "invalid form" } */ - #pragma omp atomic load , seq_cst /* { dg-error "expected end of line" } */ - v = x; /* { dg-error "invalid form" } */ - #pragma omp atomic store ,seq_cst /* { dg-error "expected end of line" } */ - x = v; /* { dg-error "invalid form" } */ - #pragma omp atomic update, seq_cst /* { dg-error "expected end of line" } */ + #pragma omp atomic seq_cst capture + v = x += 2; + #pragma omp atomic seq_cst, capture + v = x += 2; + #pragma omp atomic read , seq_cst + v = x; + #pragma omp atomic write ,seq_cst + x = v; + #pragma omp atomic update, seq_cst x += v; - #pragma omp atomic capture, seq_cst /* { dg-error "expected end of line" } */ + #pragma omp atomic capture, seq_cst v = x += 2; } diff --git a/gcc/testsuite/c-c++-common/gomp/pr60823-2.c b/gcc/testsuite/c-c++-common/gomp/pr60823-2.c index e0bf570ddca..4c87620076a 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr60823-2.c +++ b/gcc/testsuite/c-c++-common/gomp/pr60823-2.c @@ -1,5 +1,6 @@ /* PR tree-optimization/60823 */ /* { dg-do run } */ +/* { dg-require-effective-target vect_simd_clones } */ /* { dg-options "-O2 -fopenmp-simd" } */ #pragma omp declare simd simdlen(4) notinbranch diff --git a/gcc/testsuite/c-c++-common/pr60156.c b/gcc/testsuite/c-c++-common/pr60156.c new file mode 100644 index 00000000000..1e8204c99c7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr60156.c @@ -0,0 +1,9 @@ +/* PR c/60156 */ +/* { dg-do compile } */ +/* { dg-options "-Wpedantic" } */ + +int +main (int argc, char *argv[], ...) /* { dg-warning "declared as variadic function" } */ +{ + return 0; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-43.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-43.C new file mode 100644 index 00000000000..02eb33643ac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-43.C @@ -0,0 +1,4 @@ +// PR c++/59120 +// { dg-do compile { target c++11 } } + +template<typename T> using X = int T::T*; // { dg-error "expected" } diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-nested.C b/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-nested.C new file mode 100644 index 00000000000..160694c3c9f --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-nested.C @@ -0,0 +1,55 @@ +// { dg-do compile } +// { dg-options "--std=c++11 -dA -gdwarf-4 -fdebug-types-section -fno-merge-debug-strings" } + +// Check that -fdebug-types-sections does not copy a full referenced type +// into a type unit. + +// Checks that at least one type unit is generated. +// +// { dg-final { scan-assembler "DIE \\(\[^\n\]*\\) DW_TAG_type_unit" } } +// +// Check that func is declared exactly once in the debug info (in the +// compile unit). +// +// { dg-final { scan-assembler-times "\\.ascii \"func\\\\0\"\[^\n\]*DW_AT_name" 1 } } +// +// Check to make sure that no type unit contains a DIE with DW_AT_low_pc +// or DW_AT_ranges. These patterns assume that the compile unit is always +// emitted after all type units. +// +// { dg-final { scan-assembler-not "\\.quad\[^\n\]*DW_AT_low_pc.*DIE \\(\[^\n\]*\\) DW_TAG_compile_unit" } } +// { dg-final { scan-assembler-not "\\.quad\[^\n\]*DW_AT_ranges.*DIE \\(\[^\n\]*\\) DW_TAG_compile_unit" } } + +struct A { + A(); + virtual ~A(); + virtual void foo(); + private: + int data; +}; + +struct B { + B(); + virtual ~B(); +}; + +extern B* table[]; + +struct D { + template <typename T> + T* get(int i) + { + B*& cell = table[i]; + if (cell == 0) + cell = new T(); + return static_cast<T*>(cell); + } +}; + +void func(D* d) +{ + struct C : B { + A a; + }; + d->get<C>(0)->a.foo(); +} diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-typedef.C b/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-typedef.C index c5520fa72b0..89a6bb44e10 100644 --- a/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-typedef.C +++ b/gcc/testsuite/g++.dg/debug/dwarf2/dwarf4-typedef.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-gdwarf-4" } */ +/* { dg-options "-gdwarf-4 -fdebug-types-section" } */ /* Regression test for an ICE in output_die when using -gdwarf-4. */ diff --git a/gcc/testsuite/g++.dg/ipa/devirt-27.C b/gcc/testsuite/g++.dg/ipa/devirt-27.C index 1dcf76cc3c1..749f40af151 100644 --- a/gcc/testsuite/g++.dg/ipa/devirt-27.C +++ b/gcc/testsuite/g++.dg/ipa/devirt-27.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fdump-ipa-devirt -fdump-tree-optimized" } */ +/* { dg-options "-O3 -fdump-tree-optimized" } */ struct A { int a; diff --git a/gcc/testsuite/g++.dg/opt/pr60912.C b/gcc/testsuite/g++.dg/opt/pr60912.C new file mode 100644 index 00000000000..ad51ba72570 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr60912.C @@ -0,0 +1,18 @@ +// { dg-do run } +// { dg-options "-O -fno-inline -fipa-pta" } + +struct IFoo +{ + virtual void Foo () = 0; +}; + +struct Bar:IFoo +{ + void Foo () {} +}; + +int main () +{ + (new Bar ())->Foo (); + return 0; +} diff --git a/gcc/testsuite/g++.dg/vect/pr60896.cc b/gcc/testsuite/g++.dg/vect/pr60896.cc new file mode 100644 index 00000000000..c6ce68b82a2 --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/pr60896.cc @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-options "-O3" } */ + +struct A +{ + int m_fn1 (); + short *m_fn2 (); +}; + +struct B +{ + void *fC; +}; + +int a, b; +unsigned char i; +void fn1 (unsigned char *p1, A &p2) +{ + int c = p2.m_fn1 (); + for (int d = 0; c; d++) + { + short *e = p2.m_fn2 (); + unsigned char *f = &p1[0]; + for (int g = 0; g < a; g++) + { + int h = e[0]; + b += h * f[g]; + } + } +} + +void fn2 (A &p1, A &p2, B &p3) +{ + int j = p2.m_fn1 (); + for (int k = 0; j; k++) + if (0) + ; + else + fn1 (&i, p1); + if (p3.fC) + ; + else + ; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20140425-1.c b/gcc/testsuite/gcc.c-torture/execute/20140425-1.c new file mode 100644 index 00000000000..c447ef95b6c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20140425-1.c @@ -0,0 +1,23 @@ +/* PR target/60941 */ +/* Reported by Martin Husemann <martin@netbsd.org> */ + +extern void abort (void); + +static void __attribute__((noinline)) +set (unsigned long *l) +{ + *l = 31; +} + +int main (void) +{ + unsigned long l; + int i; + + set (&l); + i = (int) l; + l = (unsigned long)(2U << i); + if (l != 0) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr60822.c b/gcc/testsuite/gcc.c-torture/execute/pr60822.c new file mode 100644 index 00000000000..d2253310e69 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr60822.c @@ -0,0 +1,24 @@ +struct X { + char fill0[800000]; + int a; + char fill1[900000]; + int b; +}; + +int __attribute__((noinline,noclone)) +Avg(struct X *p, int s) +{ + return (s * (long long)(p->a + p->b)) >> 17; +} + +struct X x; + +int main() +{ + x.a = 1 << 17; + x.b = 2 << 17; + if (Avg(&x, 1) != 3) + __builtin_abort(); + return 0; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/pr60822.x b/gcc/testsuite/gcc.c-torture/execute/pr60822.x new file mode 100644 index 00000000000..4efed4c325f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr60822.x @@ -0,0 +1,7 @@ +load_lib target-supports.exp + +if { [check_effective_target_int32plus] } { + return 0 +} + +return 1; diff --git a/gcc/testsuite/gcc.c-torture/execute/pr60960.c b/gcc/testsuite/gcc.c-torture/execute/pr60960.c new file mode 100644 index 00000000000..b4f08d4c543 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr60960.c @@ -0,0 +1,38 @@ +/* PR tree-optimization/60960 */ + +typedef unsigned char v4qi __attribute__ ((vector_size (4))); + +__attribute__((noinline, noclone)) v4qi +f1 (v4qi v) +{ + return v / 2; +} + +__attribute__((noinline, noclone)) v4qi +f2 (v4qi v) +{ + return v / (v4qi) { 2, 2, 2, 2 }; +} + +__attribute__((noinline, noclone)) v4qi +f3 (v4qi x, v4qi y) +{ + return x / y; +} + +int +main () +{ + v4qi x = { 5, 5, 5, 5 }; + v4qi y = { 2, 2, 2, 2 }; + v4qi z = f1 (x); + if (__builtin_memcmp (&y, &z, sizeof (y)) != 0) + __builtin_abort (); + z = f2 (x); + if (__builtin_memcmp (&y, &z, sizeof (y)) != 0) + __builtin_abort (); + z = f3 (x, y); + if (__builtin_memcmp (&y, &z, sizeof (y)) != 0) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-14.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-14.c index 6f3c5a24fd1..dda07ea733b 100644 --- a/gcc/testsuite/gcc.dg/Wstrict-overflow-14.c +++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-14.c @@ -10,6 +10,6 @@ foo (int j) int sum = 0; for (i = 1; i < j; i += i) - sum += i / 16; /* { dg-warning "assuming signed overflow does not occur" "" } */ + sum += i / 16; /* { dg-warning "assuming signed overflow does not occur" "" { xfail *-*-* } } */ return sum; } diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-15.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-15.c index d1627d2f47b..c9e275c0bd6 100644 --- a/gcc/testsuite/gcc.dg/Wstrict-overflow-15.c +++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-15.c @@ -10,6 +10,6 @@ foo (int j) int sum = 0; for (i = 1; i < j; i += i) - sum += __builtin_abs (i); /* { dg-warning "assuming signed overflow does not occur" "" } */ + sum += __builtin_abs (i); /* { dg-warning "assuming signed overflow does not occur" "" { xfail *-*-* } } */ return sum; } diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-18.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-18.c index 2767c44fbf2..7bf111a50ea 100644 --- a/gcc/testsuite/gcc.dg/Wstrict-overflow-18.c +++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-18.c @@ -17,7 +17,7 @@ foo (struct c *p) for (i = 0; i < p->a - p->b; ++i) { - if (i > 0) /* { dg-bogus "warning" "" { xfail *-*-* } } */ + if (i > 0) /* { dg-bogus "warning" "" } */ sum += 2; bar (p); } diff --git a/gcc/testsuite/gcc.dg/graphite/pr60979.c b/gcc/testsuite/gcc.dg/graphite/pr60979.c new file mode 100644 index 00000000000..0004a51248d --- /dev/null +++ b/gcc/testsuite/gcc.dg/graphite/pr60979.c @@ -0,0 +1,37 @@ +/* { dg-options "-O -fgraphite-identity" } */ + +#include <setjmp.h> + +struct x; + +typedef struct x **(*a)(struct x *); + +struct x { + union { + struct { + union { + a *i; + } l; + int s; + } y; + } e; +}; + +jmp_buf c; + +void +b(struct x *r) +{ + int f; + static int w = 0; + volatile jmp_buf m; + f = (*(((struct x *)r)->e.y.l.i[2]((struct x *)r)))->e.y.s; + if (w++ != 0) + __builtin_memcpy((char *)m, (const char *)c, sizeof(jmp_buf)); + if (setjmp (c) == 0) { + int z; + for (z = 0; z < 0; ++z) + ; + } + d((const char *)m); +} diff --git a/gcc/testsuite/gcc.dg/lto/pr60911_0.c b/gcc/testsuite/gcc.dg/lto/pr60911_0.c new file mode 100644 index 00000000000..e4820a20497 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr60911_0.c @@ -0,0 +1,21 @@ +// { dg-lto-do run } +// { dg-lto-options { { -O2 -flto -fipa-pta } } } + +int __attribute__ ((__noinline__)) f (unsigned *p, int *x) +{ + int y = *p++ & 0xfff; + *x++ = y; + *x = *p; + return y; +} + +int +main () +{ + unsigned u[2] = { 0x3aad, 0x5ad1 }; + int x[2] = { 17689, 23456 }; + + if (f (u, x) != 0xaad || x[0] != 0xaad || x[1] != 0x5ad1) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr18079-2.c b/gcc/testsuite/gcc.dg/pr18079-2.c new file mode 100644 index 00000000000..2c83b701e10 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr18079-2.c @@ -0,0 +1,16 @@ +/* PR c/18079 */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +__attribute__ ((always_inline)) void fndecl1 (void); +__attribute__ ((noinline)) void fndecl1 (void); /* { dg-warning "attribute 'noinline' follows declaration with attribute 'always_inline'" } */ + +__attribute__ ((noinline)) void fndecl2 (void); +__attribute__ ((always_inline)) void fndecl2 (void); /* { dg-warning "attribute 'always_inline' follows declaration with attribute 'noinline'" } */ + + +__attribute__ ((hot)) void fndecl3 (void); +__attribute__ ((cold)) void fndecl3 (void); /* { dg-warning "attribute 'cold' follows declaration with attribute 'hot'" } */ + +__attribute__ ((cold)) void fndecl4 (void); +__attribute__ ((hot)) void fndecl4 (void); /* { dg-warning "attribute 'hot' follows declaration with attribute 'cold'" } */ diff --git a/gcc/testsuite/gcc.dg/pr18079.c b/gcc/testsuite/gcc.dg/pr18079.c new file mode 100644 index 00000000000..b84cdebde3f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr18079.c @@ -0,0 +1,33 @@ +/* PR c/18079 */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +__attribute__ ((noinline)) +__attribute__ ((always_inline)) +int +fn1 (int r) +{ /* { dg-warning "attribute ignored due to conflict" } */ + return r & 4; +} + +__attribute__ ((noinline, always_inline)) +int +fn2 (int r) +{ /* { dg-warning "attribute ignored due to conflict" } */ + return r & 4; +} + +__attribute__ ((always_inline)) +__attribute__ ((noinline)) +inline int +fn3 (int r) +{ /* { dg-warning "attribute ignored due to conflict" } */ + return r & 8; +} + +__attribute__ ((always_inline, noinline)) +inline int +fn4 (int r) +{ /* { dg-warning "attribute ignored due to conflict" } */ + return r & 8; +} diff --git a/gcc/testsuite/gcc.dg/pr60114.c b/gcc/testsuite/gcc.dg/pr60114.c new file mode 100644 index 00000000000..c656a9586aa --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr60114.c @@ -0,0 +1,31 @@ +/* PR c/60114 */ +/* { dg-do compile } */ +/* { dg-options "-Wconversion" } */ + +struct S { int n, u[2]; }; +const signed char z[] = { + [0] = 0x100, /* { dg-warning "9:overflow in implicit constant conversion" } */ + [2] = 0x101, /* { dg-warning "9:overflow in implicit constant conversion" } */ +}; +int A[] = { + 0, 0x80000000, /* { dg-warning "16:conversion of unsigned constant value to negative integer" } */ + 0xA, 0x80000000, /* { dg-warning "18:conversion of unsigned constant value to negative integer" } */ + 0xA, 0xA, 0x80000000 /* { dg-warning "23:conversion of unsigned constant value to negative integer" } */ + }; +int *p = (int []) { 0x80000000 }; /* { dg-warning "21:conversion of unsigned constant value to negative integer" } */ +union { int k; } u = { .k = 0x80000000 }; /* { dg-warning "29:conversion of unsigned constant value to negative integer" } */ +typedef int H[]; +void +foo (void) +{ + signed char a[][3] = { { 0x100, /* { dg-warning "28:overflow in implicit constant conversion" } */ + 1, 0x100 }, /* { dg-warning "24:overflow in implicit constant conversion" } */ + { '\0', 0x100, '\0' } /* { dg-warning "27:overflow in implicit constant conversion" } */ + }; + (const signed char []) { 0x100 }; /* { dg-warning "28:overflow in implicit constant conversion" } */ + (const float []) { 1e0, 1e1, 1e100 }; /* { dg-warning "32:conversion" } */ + struct S s1 = { 0x80000000 }; /* { dg-warning "19:conversion of unsigned constant value to negative integer" } */ + struct S s2 = { .n = 0x80000000 }; /* { dg-warning "24:conversion of unsigned constant value to negative integer" } */ + struct S s3 = { .u[1] = 0x80000000 }; /* { dg-warning "27:conversion of unsigned constant value to negative integer" } */ + H h = { 1, 2, 0x80000000 }; /* { dg-warning "17:conversion of unsigned constant value to negative integer" } */ +} diff --git a/gcc/testsuite/gcc.dg/torture/pr60930.c b/gcc/testsuite/gcc.dg/torture/pr60930.c new file mode 100644 index 00000000000..5e35f19882d --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr60930.c @@ -0,0 +1,22 @@ +/* { dg-do run } */ + +int x = 1; + +__attribute__((noinline, noclone)) void +foo (unsigned long long t) +{ + asm volatile ("" : : "r" (&t)); + if (t == 1) + __builtin_abort (); +} + +int +main () +{ +#if __SIZEOF_LONG_LONG__ >= 8 + unsigned long long t = 0xffffffffffffffffULL * (0xffffffffUL * x); + if (t != 0xffffffff00000001ULL) + foo (t);; +#endif + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-30.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-30.c index addf1284057..7ef830d1937 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/alias-30.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-30.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fdump-tree-fre-details" } */ +/* { dg-options "-O -fdump-tree-fre1-details" } */ extern int posix_memalign(void **memptr, __SIZE_TYPE__ alignment, __SIZE_TYPE__ size); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c index f1f3101d3d2..3ed98aeb857 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/isolate-1.c @@ -1,6 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-isolate-paths" } */ +/* { dg-skip-if "" keeps_null_pointer_checks } */ struct demangle_component diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c index bfcaa2b01da..912d98e2246 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/isolate-2.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fisolate-erroneous-paths-attribute -fdump-tree-isolate-paths -fdump-tree-phicprop1" } */ +/* { dg-skip-if "" keeps_null_pointer_checks } */ int z; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c index 7dddd8062c0..9c2c5d55c27 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/isolate-3.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-isolate-paths" } */ +/* { dg-skip-if "" keeps_null_pointer_checks } */ typedef long unsigned int size_t; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c index c9c074df62b..d50a2b27f47 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/isolate-4.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fisolate-erroneous-paths-attribute -fdump-tree-isolate-paths -fdump-tree-phicprop1" } */ +/* { dg-skip-if "" keeps_null_pointer_checks } */ extern void foo(void *) __attribute__ ((__nonnull__ (1))); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c b/gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c index 4d01d5c6399..e6ae37a7f74 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/isolate-5.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-isolate-paths -fdump-tree-optimized" } */ +/* { dg-skip-if "" keeps_null_pointer_checks } */ struct demangle_component { diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp91.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp91.c new file mode 100644 index 00000000000..68d8fd33a0b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp91.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-S -O2 -fdump-tree-vrp2" } */ + +unsigned short data; +void foo () +{ + unsigned char x16; + unsigned int i; + for (i = 0; i < 8; i++) + { + x16 = data & 1; + data >>= 1; + if (x16 == 1) + { + data ^= 0x4; + } + data >>= 1; + } +} + +/* { dg-final { scan-tree-dump "\\\[0, 7\\\]" "vrp2" } } */ +/* { dg-final { cleanup-tree-dump "vrp2" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr60505.c b/gcc/testsuite/gcc.dg/vect/pr60505.c index 694051320ce..70e2ec06fe5 100644 --- a/gcc/testsuite/gcc.dg/vect/pr60505.c +++ b/gcc/testsuite/gcc.dg/vect/pr60505.c @@ -10,3 +10,5 @@ void foo(char *in, char *out, int num) out[i] = (ovec[i] = in[i]); out[num] = ovec[num/2]; } + +/* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gcc.target/arm/tail-long-call.c b/gcc/testsuite/gcc.target/arm/tail-long-call.c new file mode 100644 index 00000000000..9b274686849 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/tail-long-call.c @@ -0,0 +1,12 @@ +/* { dg-skip-if "need at least armv5te" { *-*-* } { "-march=armv[234]*" "-mthumb" } { "" } } */ +/* { dg-options "-O2 -march=armv5te -marm" } */ +/* { dg-final { scan-assembler "bx" } } */ +/* { dg-final { scan-assembler-not "blx" } } */ + +int lcal (int) __attribute__ ((long_call)); + +int +dec (int a) +{ + return lcal (a); +} diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-1.c b/gcc/testsuite/gcc.target/powerpc/bcd-1.c new file mode 100644 index 00000000000..c7496c23579 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/bcd-1.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target { powerpc*-*-linux* } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-options "-mcpu=power7 -O2" } */ +/* { dg-final { scan-assembler-times "cdtbcd " 1 } } */ +/* { dg-final { scan-assembler-times "cbcdtd " 1 } } */ +/* { dg-final { scan-assembler-times "addg6s " 1 } } */ +/* { dg-final { scan-assembler-not "bl __builtin" } } */ + +unsigned int +to_bcd (unsigned int a) +{ + return __builtin_cdtbcd (a); +} + +unsigned int +from_bcd (unsigned int a) +{ + return __builtin_cbcdtd (a); +} + +unsigned int +bcd_arith (unsigned int a, unsigned int b) +{ + return __builtin_addg6s (a, b); +} diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-2.c b/gcc/testsuite/gcc.target/powerpc/bcd-2.c new file mode 100644 index 00000000000..d330b742376 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/bcd-2.c @@ -0,0 +1,44 @@ +/* { dg-do compile { target { powerpc*-*-linux* && lp64 } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target powerpc_p8vector_ok } */ +/* { dg-options "-mcpu=power8 -O2" } */ +/* { dg-final { scan-assembler-times "bcdadd\[.\] " 2 } } */ +/* { dg-final { scan-assembler-times "bcdsub\[.\] " 2 } } */ +/* { dg-final { scan-assembler-not "bl __builtin" } } */ +/* { dg-final { scan-assembler-not "mtvsr" } } */ +/* { dg-final { scan-assembler-not "mfvsr" } } */ +/* { dg-final { scan-assembler-not "lvx" } } */ +/* { dg-final { scan-assembler-not "lxvw4x" } } */ +/* { dg-final { scan-assembler-not "lxvd2x" } } */ +/* { dg-final { scan-assembler-not "stvx" } } */ +/* { dg-final { scan-assembler-not "stxvw4x" } } */ +/* { dg-final { scan-assembler-not "stxvd2x" } } */ + +typedef __int128_t __attribute__((__vector_size__(16))) vector_128_t; +typedef __int128_t scalar_128_t; +typedef unsigned long long scalar_64_t; + +vector_128_t +do_add_0 (vector_128_t a, vector_128_t b) +{ + return __builtin_bcdadd (a, b, 0); +} + +vector_128_t +do_add_1 (vector_128_t a, vector_128_t b) +{ + return __builtin_bcdadd (a, b, 1); +} + +vector_128_t +do_sub_0 (vector_128_t a, vector_128_t b) +{ + return __builtin_bcdsub (a, b, 0); +} + +vector_128_t +do_sub_1 (vector_128_t a, vector_128_t b) +{ + return __builtin_bcdsub (a, b, 1); +} diff --git a/gcc/testsuite/gcc.target/powerpc/bcd-3.c b/gcc/testsuite/gcc.target/powerpc/bcd-3.c new file mode 100644 index 00000000000..436cecf6fff --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/bcd-3.c @@ -0,0 +1,103 @@ +/* { dg-do compile { target { powerpc*-*-linux* && lp64 } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target powerpc_p8vector_ok } */ +/* { dg-options "-mcpu=power8 -O2" } */ +/* { dg-final { scan-assembler-times "bcdadd\[.\] " 4 } } */ +/* { dg-final { scan-assembler-times "bcdsub\[.\] " 4 } } */ +/* { dg-final { scan-assembler-not "bl __builtin" } } */ +/* { dg-final { scan-assembler-not "mtvsr" } } */ +/* { dg-final { scan-assembler-not "mfvsr" } } */ +/* { dg-final { scan-assembler-not "lvx" } } */ +/* { dg-final { scan-assembler-not "lxvw4x" } } */ +/* { dg-final { scan-assembler-not "lxvd2x" } } */ +/* { dg-final { scan-assembler-not "stvx" } } */ +/* { dg-final { scan-assembler-not "stxvw4x" } } */ +/* { dg-final { scan-assembler-not "stxvd2x" } } */ + +typedef __int128_t __attribute__((__vector_size__(16))) vector_128_t; +typedef __int128_t scalar_128_t; +typedef unsigned long long scalar_64_t; + +/* Test whether the peephole works to allow folding a bcdadd, with a + bcdadd_<test> into a single instruction. */ + +vector_128_t +do_add_lt (vector_128_t a, vector_128_t b, int *p) +{ + vector_128_t ret = __builtin_bcdadd (a, b, 0); + if (__builtin_bcdadd_lt (a, b, 0)) + *p = 1; + + return ret; +} + +vector_128_t +do_add_eq (vector_128_t a, vector_128_t b, int *p) +{ + vector_128_t ret = __builtin_bcdadd (a, b, 0); + if (__builtin_bcdadd_eq (a, b, 0)) + *p = 1; + + return ret; +} + +vector_128_t +do_add_gt (vector_128_t a, vector_128_t b, int *p) +{ + vector_128_t ret = __builtin_bcdadd (a, b, 0); + if (__builtin_bcdadd_gt (a, b, 0)) + *p = 1; + + return ret; +} + +vector_128_t +do_add_ov (vector_128_t a, vector_128_t b, int *p) +{ + vector_128_t ret = __builtin_bcdadd (a, b, 0); + if (__builtin_bcdadd_ov (a, b, 0)) + *p = 1; + + return ret; +} + +vector_128_t +do_sub_lt (vector_128_t a, vector_128_t b, int *p) +{ + vector_128_t ret = __builtin_bcdsub (a, b, 0); + if (__builtin_bcdsub_lt (a, b, 0)) + *p = 1; + + return ret; +} + +vector_128_t +do_sub_eq (vector_128_t a, vector_128_t b, int *p) +{ + vector_128_t ret = __builtin_bcdsub (a, b, 0); + if (__builtin_bcdsub_eq (a, b, 0)) + *p = 1; + + return ret; +} + +vector_128_t +do_sub_gt (vector_128_t a, vector_128_t b, int *p) +{ + vector_128_t ret = __builtin_bcdsub (a, b, 0); + if (__builtin_bcdsub_gt (a, b, 0)) + *p = 1; + + return ret; +} + +vector_128_t +do_sub_ov (vector_128_t a, vector_128_t b, int *p) +{ + vector_128_t ret = __builtin_bcdsub (a, b, 0); + if (__builtin_bcdsub_ov (a, b, 0)) + *p = 1; + + return ret; +} diff --git a/gcc/testsuite/gcc.target/powerpc/dfp-builtin-1.c b/gcc/testsuite/gcc.target/powerpc/dfp-builtin-1.c new file mode 100644 index 00000000000..614f272642c --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/dfp-builtin-1.c @@ -0,0 +1,88 @@ +/* { dg-do compile { target { powerpc*-*-linux* } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-options "-mcpu=power7 -O2" } */ +/* { dg-final { scan-assembler-times "ddedpd " 4 } } */ +/* { dg-final { scan-assembler-times "denbcd " 2 } } */ +/* { dg-final { scan-assembler-times "dxex " 1 } } */ +/* { dg-final { scan-assembler-times "diex " 1 } } */ +/* { dg-final { scan-assembler-times "dscli " 2 } } */ +/* { dg-final { scan-assembler-times "dscri " 2 } } */ +/* { dg-final { scan-assembler-not "bl __builtin" } } */ +/* { dg-final { scan-assembler-not "dctqpq" } } */ +/* { dg-final { scan-assembler-not "drdpq" } } */ +/* { dg-final { scan-assembler-not "stfd" } } */ +/* { dg-final { scan-assembler-not "lfd" } } */ + +_Decimal64 +do_dedpd_0 (_Decimal64 a) +{ + return __builtin_ddedpd (0, a); +} + +_Decimal64 +do_dedpd_1 (_Decimal64 a) +{ + return __builtin_ddedpd (1, a); +} + +_Decimal64 +do_dedpd_2 (_Decimal64 a) +{ + return __builtin_ddedpd (2, a); +} + +_Decimal64 +do_dedpd_3 (_Decimal64 a) +{ + return __builtin_ddedpd (3, a); +} + +_Decimal64 +do_enbcd_0 (_Decimal64 a) +{ + return __builtin_denbcd (0, a); +} + +_Decimal64 +do_enbcd_1 (_Decimal64 a) +{ + return __builtin_denbcd (1, a); +} + +_Decimal64 +do_xex (_Decimal64 a) +{ + return __builtin_dxex (a); +} + +_Decimal64 +do_iex (_Decimal64 a, _Decimal64 b) +{ + return __builtin_diex (a, b); +} + +_Decimal64 +do_scli_1 (_Decimal64 a) +{ + return __builtin_dscli (a, 1); +} + +_Decimal64 +do_scli_10 (_Decimal64 a) +{ + return __builtin_dscli (a, 10); +} + +_Decimal64 +do_scri_1 (_Decimal64 a) +{ + return __builtin_dscri (a, 1); +} + +_Decimal64 +do_scri_10 (_Decimal64 a) +{ + return __builtin_dscri (a, 10); +} diff --git a/gcc/testsuite/gcc.target/powerpc/dfp-builtin-2.c b/gcc/testsuite/gcc.target/powerpc/dfp-builtin-2.c new file mode 100644 index 00000000000..189bc9ad6ae --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/dfp-builtin-2.c @@ -0,0 +1,88 @@ +/* { dg-do compile { target { powerpc*-*-linux* } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-options "-mcpu=power7 -O2" } */ +/* { dg-final { scan-assembler-times "ddedpdq " 4 } } */ +/* { dg-final { scan-assembler-times "denbcdq " 2 } } */ +/* { dg-final { scan-assembler-times "dxexq " 1 } } */ +/* { dg-final { scan-assembler-times "diexq " 1 } } */ +/* { dg-final { scan-assembler-times "dscliq " 2 } } */ +/* { dg-final { scan-assembler-times "dscriq " 2 } } */ +/* { dg-final { scan-assembler-not "bl __builtin" } } */ +/* { dg-final { scan-assembler-not "dctqpq" } } */ +/* { dg-final { scan-assembler-not "drdpq" } } */ +/* { dg-final { scan-assembler-not "stfd" } } */ +/* { dg-final { scan-assembler-not "lfd" } } */ + +_Decimal128 +do_dedpdq_0 (_Decimal128 a) +{ + return __builtin_ddedpdq (0, a); +} + +_Decimal128 +do_dedpdq_1 (_Decimal128 a) +{ + return __builtin_ddedpdq (1, a); +} + +_Decimal128 +do_dedpdq_2 (_Decimal128 a) +{ + return __builtin_ddedpdq (2, a); +} + +_Decimal128 +do_dedpdq_3 (_Decimal128 a) +{ + return __builtin_ddedpdq (3, a); +} + +_Decimal128 +do_enbcdq_0 (_Decimal128 a) +{ + return __builtin_denbcdq (0, a); +} + +_Decimal128 +do_enbcdq_1 (_Decimal128 a) +{ + return __builtin_denbcdq (1, a); +} + +_Decimal128 +do_xexq (_Decimal128 a) +{ + return __builtin_dxexq (a); +} + +_Decimal128 +do_iexq (_Decimal128 a, _Decimal128 b) +{ + return __builtin_diexq (a, b); +} + +_Decimal128 +do_scliq_1 (_Decimal128 a) +{ + return __builtin_dscliq (a, 1); +} + +_Decimal128 +do_scliq_10 (_Decimal128 a) +{ + return __builtin_dscliq (a, 10); +} + +_Decimal128 +do_scriq_1 (_Decimal128 a) +{ + return __builtin_dscriq (a, 1); +} + +_Decimal128 +do_scriq_10 (_Decimal128 a) +{ + return __builtin_dscriq (a, 10); +} diff --git a/gcc/testsuite/gcc.target/powerpc/extend-divide-1.c b/gcc/testsuite/gcc.target/powerpc/extend-divide-1.c new file mode 100644 index 00000000000..5f948b7212f --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/extend-divide-1.c @@ -0,0 +1,34 @@ +/* { dg-do compile { target { powerpc*-*-linux* } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-options "-mcpu=power7 -O2" } */ +/* { dg-final { scan-assembler-times "divwe " 1 } } */ +/* { dg-final { scan-assembler-times "divweo " 1 } } */ +/* { dg-final { scan-assembler-times "divweu " 1 } } */ +/* { dg-final { scan-assembler-times "divweuo " 1 } } */ +/* { dg-final { scan-assembler-not "bl __builtin" } } */ + +int +div_we (int a, int b) +{ + return __builtin_divwe (a, b); +} + +int +div_weo (int a, int b) +{ + return __builtin_divweo (a, b); +} + +unsigned int +div_weu (unsigned int a, unsigned int b) +{ + return __builtin_divweu (a, b); +} + +unsigned int +div_weuo (unsigned int a, unsigned int b) +{ + return __builtin_divweuo (a, b); +} diff --git a/gcc/testsuite/gcc.target/powerpc/extend-divide-2.c b/gcc/testsuite/gcc.target/powerpc/extend-divide-2.c new file mode 100644 index 00000000000..8ee6c8cf768 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/extend-divide-2.c @@ -0,0 +1,34 @@ +/* { dg-do compile { target { powerpc*-*-linux* && lp64 } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-options "-mcpu=power7 -O2" } */ +/* { dg-final { scan-assembler-times "divde " 1 } } */ +/* { dg-final { scan-assembler-times "divdeo " 1 } } */ +/* { dg-final { scan-assembler-times "divdeu " 1 } } */ +/* { dg-final { scan-assembler-times "divdeuo " 1 } } */ +/* { dg-final { scan-assembler-not "bl __builtin" } } */ + +long +div_de (long a, long b) +{ + return __builtin_divde (a, b); +} + +long +div_deo (long a, long b) +{ + return __builtin_divdeo (a, b); +} + +unsigned long +div_deu (unsigned long a, unsigned long b) +{ + return __builtin_divdeu (a, b); +} + +unsigned long +div_deuo (unsigned long a, unsigned long b) +{ + return __builtin_divdeuo (a, b); +} diff --git a/gcc/testsuite/gcc.target/powerpc/pack01.c b/gcc/testsuite/gcc.target/powerpc/pack01.c new file mode 100644 index 00000000000..efac4087c78 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pack01.c @@ -0,0 +1,91 @@ +/* { dg-do run { target { powerpc*-*-linux* && lp64 } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target p8vector_hw } */ +/* { dg-options "-mcpu=power8 -O2" } */ + +#include <stddef.h> +#include <stdlib.h> +#include <altivec.h> + +#ifdef DEBUG +#include <stdio.h> +#endif + +typedef __int128_t __attribute__((__vector_size__(16))) vector_128_t; +typedef __int128_t scalar_128_t; +typedef unsigned long long scalar_64_t; + +volatile scalar_64_t one = 1; +volatile scalar_64_t two = 2; + +int +main (void) +{ + scalar_128_t a = (((scalar_128_t)one) << 64) | ((scalar_128_t)two); + vector_128_t v1 = (vector_128_t) { a }; + vector_128_t v2 = __builtin_pack_vector_int128 (one, two); + scalar_64_t x0 = __builtin_unpack_vector_int128 (v1, 0); + scalar_64_t x1 = __builtin_unpack_vector_int128 (v1, 1); + vector_128_t v3 = __builtin_pack_vector_int128 (x0, x1); + + size_t i; + union { + scalar_128_t i128; + vector_128_t v128; + scalar_64_t u64; + unsigned char uc[sizeof (scalar_128_t)]; + char c[sizeof (scalar_128_t)]; + } u, u2; + +#ifdef DEBUG + { + printf ("a = 0x"); + u.i128 = a; + for (i = 0; i < sizeof (scalar_128_t); i++) + printf ("%.2x", u.uc[i]); + + printf ("\nv1 = 0x"); + u.v128 = v1; + for (i = 0; i < sizeof (scalar_128_t); i++) + printf ("%.2x", u.uc[i]); + + printf ("\nv2 = 0x"); + u.v128 = v2; + for (i = 0; i < sizeof (scalar_128_t); i++) + printf ("%.2x", u.uc[i]); + + printf ("\nv3 = 0x"); + u.v128 = v3; + for (i = 0; i < sizeof (scalar_128_t); i++) + printf ("%.2x", u.uc[i]); + + printf ("\nx0 = 0x"); + u.u64 = x0; + for (i = 0; i < sizeof (scalar_64_t); i++) + printf ("%.2x", u.uc[i]); + + printf ("\nx1 = 0x"); + u.u64 = x1; + for (i = 0; i < sizeof (scalar_64_t); i++) + printf ("%.2x", u.uc[i]); + + printf ("\n"); + } +#endif + + u2.i128 = a; + u.v128 = v1; + if (memcmp (u.c, u2.c, sizeof (scalar_128_t)) != 0) + abort (); + + u.v128 = v2; + if (memcmp (u.c, u2.c, sizeof (scalar_128_t)) != 0) + abort (); + + u.v128 = v3; + if (memcmp (u.c, u2.c, sizeof (scalar_128_t)) != 0) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/powerpc/pack02.c b/gcc/testsuite/gcc.target/powerpc/pack02.c new file mode 100644 index 00000000000..74b6cd04dcc --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pack02.c @@ -0,0 +1,95 @@ +/* { dg-do run { target { powerpc*-*-linux* } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target vsx_hw } */ +/* { dg-options "-O2" } */ + +#include <stddef.h> +#include <stdlib.h> +#include <math.h> + +#ifdef DEBUG +#include <stdio.h> +#endif + +int +main (void) +{ + double high = pow (2.0, 60); + double low = 2.0; + long double a = ((long double)high) + ((long double)low); + double x0 = __builtin_unpack_longdouble (a, 0); + double x1 = __builtin_unpack_longdouble (a, 1); + long double b = __builtin_pack_longdouble (x0, x1); + +#ifdef DEBUG + { + size_t i; + union { + long double ld; + double d; + unsigned char uc[sizeof (long double)]; + char c[sizeof (long double)]; + } u; + + printf ("a = 0x"); + u.ld = a; + for (i = 0; i < sizeof (long double); i++) + printf ("%.2x", u.uc[i]); + + printf (", %Lg\n", a); + + printf ("b = 0x"); + u.ld = b; + for (i = 0; i < sizeof (long double); i++) + printf ("%.2x", u.uc[i]); + + printf (", %Lg\n", b); + + printf ("hi = 0x"); + u.d = high; + for (i = 0; i < sizeof (double); i++) + printf ("%.2x", u.uc[i]); + + printf (",%*s %g\n", (int)(2 * (sizeof (long double) - sizeof (double))), "", high); + + printf ("lo = 0x"); + u.d = low; + for (i = 0; i < sizeof (double); i++) + printf ("%.2x", u.uc[i]); + + printf (",%*s %g\n", (int)(2 * (sizeof (long double) - sizeof (double))), "", low); + + printf ("x0 = 0x"); + u.d = x0; + for (i = 0; i < sizeof (double); i++) + printf ("%.2x", u.uc[i]); + + printf (",%*s %g\n", (int)(2 * (sizeof (long double) - sizeof (double))), "", x0); + + printf ("x1 = 0x"); + u.d = x1; + for (i = 0; i < sizeof (double); i++) + printf ("%.2x", u.uc[i]); + + printf (",%*s %g\n", (int)(2 * (sizeof (long double) - sizeof (double))), "", x1); + } +#endif + + if (high != x0) + abort (); + + if (low != x1) + abort (); + + if (a != b) + abort (); + + if (x0 != high) + abort (); + + if (x1 != low) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/powerpc/pack03.c b/gcc/testsuite/gcc.target/powerpc/pack03.c new file mode 100644 index 00000000000..59f0e74ba9c --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pack03.c @@ -0,0 +1,88 @@ +/* { dg-do run { target { powerpc*-*-linux* } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } { "*" } { "" } } */ +/* { dg-require-effective-target vsx_hw } */ +/* { dg-options "-O2" } */ + +#include <stddef.h> +#include <stdlib.h> +#include <math.h> + +#ifdef DEBUG +#include <stdio.h> +#endif + +int +main (void) +{ + _Decimal128 one = (_Decimal128)1.0; + _Decimal128 two = (_Decimal128)2.0; + _Decimal128 ten = (_Decimal128)10.0; + _Decimal128 a = one; + _Decimal128 b; + _Decimal128 c; + unsigned long long x0; + unsigned long long x1; + size_t i; + + for (i = 0; i < 25; i++) + a *= ten; + + a += two; + + x0 = __builtin_unpack_dec128 (a, 0); + x1 = __builtin_unpack_dec128 (a, 1); + b = __builtin_pack_dec128 (x0, x1); + c = __builtin_dscliq (one, 25) + two; + +#ifdef DEBUG + { + union { + _Decimal128 d; + unsigned long long ull; + unsigned char uc[sizeof (_Decimal128)]; + } u; + + printf ("a = 0x"); + u.d = a; + for (i = 0; i < sizeof (_Decimal128); i++) + printf ("%.2x", u.uc[i]); + + printf (", %Lg\n", (long double)a); + + printf ("b = 0x"); + u.d = b; + for (i = 0; i < sizeof (_Decimal128); i++) + printf ("%.2x", u.uc[i]); + + printf (", %Lg\n", (long double)b); + + printf ("c = 0x"); + u.d = c; + for (i = 0; i < sizeof (_Decimal128); i++) + printf ("%.2x", u.uc[i]); + + printf (", %Lg\n", (long double)c); + + printf ("x0 = 0x"); + u.ull = x0; + for (i = 0; i < sizeof (unsigned long long); i++) + printf ("%.2x", u.uc[i]); + + printf ("\nx1 = 0x"); + u.ull = x1; + for (i = 0; i < sizeof (unsigned long long); i++) + printf ("%.2x", u.uc[i]); + + printf ("\n"); + } +#endif + + if (a != b) + abort (); + + if (a != c) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gfortran.dg/namelist_utf8.f90 b/gcc/testsuite/gfortran.dg/namelist_utf8.f90 new file mode 100644 index 00000000000..c494b8c3b77 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/namelist_utf8.f90 @@ -0,0 +1,30 @@ +! { dg-do run } +! PR52539 UTF-8 support for namelist read and write + +character(len=10, kind=4) :: str, str2 +character(len=25, kind=4) :: str3 + +namelist /nml/ str + +str = 4_'a'//char (int (z'4F60'),4) & + //char (int (z'597D'), 4)//4_'b' + +open(99, encoding='utf-8',form='formatted') +write(99, '(3a)') '&nml str = "', str, '" /' +write(99, '(a)') str +rewind(99) + +str = 4_'XXXX' +str2 = 4_'YYYY' +read(99,nml=nml) +read(99, *) str2 +if (str2 /= str) call abort +rewind(99) + +read(99,'(A)') str3 +if (str3 /= 4_'&nml str = "' // str // 4_'" /') call abort +read(99,'(A)') str3 +if (str3 /= str) call abort + +close(99, status='delete') +end diff --git a/gcc/testsuite/gfortran.dg/no_range_check_3.f90 b/gcc/testsuite/gfortran.dg/no_range_check_3.f90 new file mode 100644 index 00000000000..24223af5b38 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/no_range_check_3.f90 @@ -0,0 +1,12 @@ +! { dg-do run } +! { dg-options "-fno-range-check" } +program test + integer :: i + i = int(z'FFFFFFFF',kind(i)) + if (i /= -1) call abort + if (int(z'FFFFFFFF',kind(i)) /= -1) call abort + + if (popcnt(int(z'0F00F00080000001',8)) /= 10) call abort + if (popcnt(int(z'800F0001',4)) /= 6) call abort + +end program test diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index df6923f76ef..9c175de4e9d 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1082,6 +1082,11 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) need_stmts = true; goto do_decl_clause; + case OMP_CLAUSE_LINEAR: + if (OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause)) + need_stmts = true; + goto do_decl_clause; + case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYPRIVATE: @@ -1157,6 +1162,12 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause)); break; + case OMP_CLAUSE_LINEAR: + walk_body (convert_nonlocal_reference_stmt, + convert_nonlocal_reference_op, info, + &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause)); + break; + default: break; } @@ -1605,6 +1616,11 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) need_stmts = true; goto do_decl_clause; + case OMP_CLAUSE_LINEAR: + if (OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause)) + need_stmts = true; + goto do_decl_clause; + case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYPRIVATE: @@ -1685,6 +1701,12 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause)); break; + case OMP_CLAUSE_LINEAR: + walk_body (convert_local_reference_stmt, + convert_local_reference_op, info, + &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause)); + break; + default: break; } diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 46dc00c38a3..0d941019f0e 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -586,7 +586,7 @@ extern gimple_opt_pass *make_pass_convert_switch (gcc::context *ctxt); extern opt_pass *current_pass; extern bool execute_one_pass (opt_pass *); -extern void execute_pass_list (opt_pass *); +extern void execute_pass_list (function *, opt_pass *); extern void execute_ipa_pass_list (opt_pass *); extern void execute_ipa_summary_passes (ipa_opt_pass_d *); extern void execute_all_ipa_transforms (void); @@ -614,7 +614,7 @@ extern bool function_called_by_processed_nodes_p (void); extern bool first_pass_instance; /* Declare for plugins. */ -extern void do_per_function_toporder (void (*) (void *), void *); +extern void do_per_function_toporder (void (*) (function *, void *), void *); extern void disable_pass (const char *); extern void enable_pass (const char *); diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index e040c4fc58d..5074142f6f2 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -7243,10 +7243,7 @@ ipa_pta_execute (void) tree ptr; struct function *fn; unsigned i; - varinfo_t fi; basic_block bb; - struct pt_solution uses, clobbers; - struct cgraph_edge *e; /* Nodes without a body are not interesting. */ if (!cgraph_function_with_gimple_body_p (node) || node->clone_of) @@ -7262,21 +7259,6 @@ ipa_pta_execute (void) find_what_p_points_to (ptr); } - /* Compute the call-use and call-clobber sets for all direct calls. */ - fi = lookup_vi_for_tree (node->decl); - gcc_assert (fi->is_fn_info); - clobbers - = find_what_var_points_to (first_vi_for_offset (fi, fi_clobbers)); - uses = find_what_var_points_to (first_vi_for_offset (fi, fi_uses)); - for (e = node->callers; e; e = e->next_caller) - { - if (!e->call_stmt) - continue; - - *gimple_call_clobber_set (e->call_stmt) = clobbers; - *gimple_call_use_set (e->call_stmt) = uses; - } - /* Compute the call-use and call-clobber sets for indirect calls and calls to external functions. */ FOR_EACH_BB_FN (bb, fn) @@ -7287,17 +7269,27 @@ ipa_pta_execute (void) { gimple stmt = gsi_stmt (gsi); struct pt_solution *pt; - varinfo_t vi; + varinfo_t vi, fi; tree decl; if (!is_gimple_call (stmt)) continue; - /* Handle direct calls to external functions. */ + /* Handle direct calls to functions with body. */ decl = gimple_call_fndecl (stmt); if (decl - && (!(fi = lookup_vi_for_tree (decl)) - || !fi->is_fn_info)) + && (fi = lookup_vi_for_tree (decl)) + && fi->is_fn_info) + { + *gimple_call_clobber_set (stmt) + = find_what_var_points_to + (first_vi_for_offset (fi, fi_clobbers)); + *gimple_call_use_set (stmt) + = find_what_var_points_to + (first_vi_for_offset (fi, fi_uses)); + } + /* Handle direct calls to external functions. */ + else if (decl) { pt = gimple_call_use_set (stmt); if (gimple_call_flags (stmt) & ECF_CONST) @@ -7341,10 +7333,9 @@ ipa_pta_execute (void) pt->nonlocal = 1; } } - /* Handle indirect calls. */ - if (!decl - && (fi = get_fi_for_callee (stmt))) + else if (!decl + && (fi = get_fi_for_callee (stmt))) { /* We need to accumulate all clobbers/uses of all possible callees. */ diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 8a0103b1637..7621348944f 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -398,7 +398,7 @@ record_temporary_equivalences_from_stmts_at_dest (edge e, ssa_op_iter iter; if (backedge_seen) - FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_ALL_DEFS) + FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF) { /* This call only invalidates equivalences created by PHI nodes. This is by design to keep the cost of diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c index 9ac111772f4..e22ce2cc71d 100644 --- a/gcc/tree-vect-generic.c +++ b/gcc/tree-vect-generic.c @@ -969,7 +969,8 @@ expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree compute_type if (!optimize || !VECTOR_INTEGER_TYPE_P (type) - || TREE_CODE (rhs2) != VECTOR_CST) + || TREE_CODE (rhs2) != VECTOR_CST + || !VECTOR_MODE_P (TYPE_MODE (type))) break; ret = expand_vector_divmod (gsi, type, rhs1, rhs2, code); diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 75116177fed..094cf047e05 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -392,6 +392,8 @@ vect_recog_dot_prod_pattern (vec<gimple> *stmts, tree *type_in, gcc_assert (STMT_VINFO_DEF_TYPE (stmt_vinfo) == vect_internal_def); oprnd00 = gimple_assign_rhs1 (stmt); oprnd01 = gimple_assign_rhs2 (stmt); + STMT_VINFO_PATTERN_DEF_SEQ (vinfo_for_stmt (last_stmt)) + = STMT_VINFO_PATTERN_DEF_SEQ (stmt_vinfo); } else { @@ -3065,8 +3067,7 @@ vect_mark_pattern_stmts (gimple orig_stmt, gimple pattern_stmt, } gimple_set_bb (def_stmt, gimple_bb (orig_stmt)); STMT_VINFO_RELATED_STMT (def_stmt_info) = orig_stmt; - STMT_VINFO_DEF_TYPE (def_stmt_info) - = STMT_VINFO_DEF_TYPE (orig_stmt_info); + STMT_VINFO_DEF_TYPE (def_stmt_info) = vect_internal_def; if (STMT_VINFO_VECTYPE (def_stmt_info) == NULL_TREE) STMT_VINFO_VECTYPE (def_stmt_info) = pattern_vectype; } diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 2e2a27f874f..7951805e473 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -3949,52 +3949,6 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, } } -/* Return true if VAR may overflow at STMT. This checks any available - loop information to see if we can determine that VAR does not - overflow. */ - -static bool -vrp_var_may_overflow (tree var, gimple stmt) -{ - struct loop *l; - tree chrec, init, step; - - if (current_loops == NULL) - return true; - - l = loop_containing_stmt (stmt); - if (l == NULL - || !loop_outer (l)) - return true; - - chrec = instantiate_parameters (l, analyze_scalar_evolution (l, var)); - if (TREE_CODE (chrec) != POLYNOMIAL_CHREC) - return true; - - init = initial_condition_in_loop_num (chrec, l->num); - step = evolution_part_in_loop_num (chrec, l->num); - - if (step == NULL_TREE - || !is_gimple_min_invariant (step) - || !valid_value_p (init)) - return true; - - /* If we get here, we know something useful about VAR based on the - loop information. If it wraps, it may overflow. */ - - if (scev_probably_wraps_p (init, step, stmt, get_chrec_loop (chrec), - true)) - return true; - - if (dump_file && (dump_flags & TDF_DETAILS) != 0) - { - print_generic_expr (dump_file, var, 0); - fprintf (dump_file, ": loop information indicates does not overflow\n"); - } - - return false; -} - /* Given two numeric value ranges VR0, VR1 and a comparison code COMP: @@ -8382,32 +8336,32 @@ vrp_visit_phi_node (gimple phi) && (cmp_min != 0 || cmp_max != 0)) goto varying; - /* If the new minimum is smaller or larger than the previous - one, go all the way to -INF. In the first case, to avoid - iterating millions of times to reach -INF, and in the - other case to avoid infinite bouncing between different - minimums. */ - if (cmp_min > 0 || cmp_min < 0) - { - if (!needs_overflow_infinity (TREE_TYPE (vr_result.min)) - || !vrp_var_may_overflow (lhs, phi)) - vr_result.min = TYPE_MIN_VALUE (TREE_TYPE (vr_result.min)); - else if (supports_overflow_infinity (TREE_TYPE (vr_result.min))) - vr_result.min = - negative_overflow_infinity (TREE_TYPE (vr_result.min)); - } - - /* Similarly, if the new maximum is smaller or larger than - the previous one, go all the way to +INF. */ - if (cmp_max < 0 || cmp_max > 0) - { - if (!needs_overflow_infinity (TREE_TYPE (vr_result.max)) - || !vrp_var_may_overflow (lhs, phi)) - vr_result.max = TYPE_MAX_VALUE (TREE_TYPE (vr_result.max)); - else if (supports_overflow_infinity (TREE_TYPE (vr_result.max))) - vr_result.max = - positive_overflow_infinity (TREE_TYPE (vr_result.max)); - } + /* If the new minimum is larger than than the previous one + retain the old value. If the new minimum value is smaller + than the previous one and not -INF go all the way to -INF + 1. + In the first case, to avoid infinite bouncing between different + minimums, and in the other case to avoid iterating millions of + times to reach -INF. Going to -INF + 1 also lets the following + iteration compute whether there will be any overflow, at the + expense of one additional iteration. */ + if (cmp_min < 0) + vr_result.min = lhs_vr->min; + else if (cmp_min > 0 + && !vrp_val_is_min (vr_result.min)) + vr_result.min + = int_const_binop (PLUS_EXPR, + vrp_val_min (TREE_TYPE (vr_result.min)), + build_int_cst (TREE_TYPE (vr_result.min), 1)); + + /* Similarly for the maximum value. */ + if (cmp_max > 0) + vr_result.max = lhs_vr->max; + else if (cmp_max < 0 + && !vrp_val_is_max (vr_result.max)) + vr_result.max + = int_const_binop (MINUS_EXPR, + vrp_val_max (TREE_TYPE (vr_result.min)), + build_int_cst (TREE_TYPE (vr_result.min), 1)); /* If we dropped either bound to +-INF then if this is a loop PHI node SCEV may known more about its value-range. */ diff --git a/gcc/tree.h b/gcc/tree.h index 57c952802a8..3e8e625ab9f 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1333,6 +1333,9 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_LINEAR_STEP(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR), 1) +#define OMP_CLAUSE_LINEAR_GIMPLE_SEQ(NODE) \ + (OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_init + #define OMP_CLAUSE_ALIGNED_ALIGNMENT(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALIGNED), 1) |