diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-12-19 18:31:46 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-12-19 18:31:46 +0000 |
commit | f3c16ea146feeb67202a03cdb4b9bf1593532d87 (patch) | |
tree | 4702937af89d3c818a0457703cf47e93b835ba15 | |
parent | 413748f6ac6cc83d67f14e4fd367c90e67fa7c83 (diff) | |
parent | 16f72d88dd84fd56a31eca8767a8f3c8d0fab88b (diff) | |
download | gcc-f3c16ea146feeb67202a03cdb4b9bf1593532d87.zip gcc-f3c16ea146feeb67202a03cdb4b9bf1593532d87.tar.gz gcc-f3c16ea146feeb67202a03cdb4b9bf1593532d87.tar.bz2 |
Merge from trunk revision 218953.
From-SVN: r218965
38 files changed, 855 insertions, 128 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 72e8dfd..19b33e7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,92 @@ +2014-12-19 Martin Liska <mliska@suse.cz> + + PR ipa/63569 + * ipa-icf-gimple.c (func_checker::compare_operand): Add missing + comparison for volatile flag. + +2014-12-19 Kyrylo Tkachov <kyrylo.tkachov@arm.com> + + * doc/invoke.texi (ARM options): Remove mention of Advanced RISC + Machines. + +2014-12-19 Xingxing Pan <xxingpan@marvell.com> + + * config/arm/cortex-a9-neon.md (cortex_a9_neon_vmov): Change + reservation to cortex_a9_neon_dp. + +2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org> + + * config/sh/sh.c (prepare_move_operands): Split HI/QImode load/store + to two move insns via r0. + +2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org> + + * config/sh/predicates.md (arith_or_int_operand): New predicate. + * config/sh/sh.md (addsi3): Use arith_or_int_operand for operand 2. + Return fail if operands[0] and operands[1] are overlap when + operands[2] is integer constant. + (*addsi3_compact): Make it define_insn_and_split which splits + reg0 := reg1 + constant to reg0 = constant and reg0 := reg0 + reg1. + +2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org> + + * config/sh/sh-protos.h (sh_movsf_ie_ra_split_p): Declare. + * config/sh/sh.c (sh_movsf_ie_ra_split_p): New function. + * config/sh/sh.md (movsi_ie): Use "mr" constraint for the 8-th + altarnative of operand 0. + (movesf_ie): Use "X" constraint instead of "Bsc". + (movsf_ie_ra): New insn_and_split. + (movsf): Use movsfie_ra when lra_in_progress is true. + +2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org> + + * config/sh/predicates.md (general_movsrc_operand): Allow only + valid plus address expressions. + (general_movdst_operand): Likewise. + (t_reg_operand): Allow (zero_extend (reg t)). + * config/sh/sh-protos.h (sh_hard_regno_caller_save_mode): Declare. + * config/sh/sh.c (sh_hard_regno_caller_save_mode): New function. + (sh_secondary_reload): Return NO_REGS instead of FPUL_REGS in one + case. + * config/sh/sh.h (HARD_REGNO_CALLER_SAVE_MODE): Define. + * config/sh/sh.md (untyped_call): Clobber function value + registers before call. + +2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org> + + * config/sh/sh.c (sh_lra_p): New function. + (TARGET_LRA_P): Define. + (sh_legitimize_reload_address): Return false if sh_lra_p is true. + * config/sh/sh.opt (mlra): New option. + +2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org> + + * lra-constraints.c (process_address_1): Try if target can split + displacement with targetm.legitimize_address_displacement. + * target.def (legitimize_address_displacement): New hook. + * targhooks.c (default_legitimize_address_displacement): New function. + * targhooks.h (default_legitimize_address_displacement): Declare. + * config/sh/sh.c (sh_legitimize_address_displacement): New function. + (TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT): Define. + * doc/tm.texi.in (TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT): New hook. + * doc/tm.texi: Regenerate. + +2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org> + + * lra-constraints.c (get_equiv): Don't return memory equivalence + when targetm.cannot_substitute_mem_equiv_p is true. + * target.def (cannot_substitute_mem_equiv_p): New hook. + * config/sh/sh.c (sh_cannot_substitute_mem_equiv_p): New function. + (TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P): Define. + * doc/tm.texi.in (TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P): New hook. + * doc/tm.texi: Regenerate. + +2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org> + + * lra-constraints.c (process_address_1): Swap base_term and + index_term if INDEX_REG_CLASS is assigned to base_term already + when INDEX_REG_CLASS is a single register class. + 2014-12-18 Vladimir Makarov <vmakarov@redhat.com> * lra-constraints.c (lra-constraints.c): Exchange places of sclass diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 2d0c2fe..94e6c34 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,20 @@ +2014-12-19 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/63831 + * c-cppbuiltin.c (c_cpp_builtins): Don't define __has_attribute + and __has_cpp_attribute here. + * c-ppoutput.c (init_pp_output): Set cb->has_attribute to + c_common_has_attribute. + * c-common.h (c_common_has_attribute): New prototype. + * c-lex.c (init_c_lex): Set cb->has_attribute to + c_common_has_attribute instead of cb_has_attribute. + (get_token_no_padding): New function. + (cb_has_attribute): Renamed to ... + (c_common_has_attribute): ... this. No longer static. Use + get_token_no_padding, require ()s, don't build TREE_LIST + unnecessarily, fix up formatting, adjust diagnostics, call + init_attributes. + 2014-12-15 Jason Merrill <jason@redhat.com> * c.opt (-fsized-deallocation, -Wc++14-compat): New. diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 658cef0..c7eebcf 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -959,6 +959,7 @@ extern void c_cpp_builtins_optimize_pragma (cpp_reader *, tree, tree); extern bool c_cpp_error (cpp_reader *, int, int, location_t, unsigned int, const char *, va_list *) ATTRIBUTE_GCC_DIAG(6,0); +extern int c_common_has_attribute (cpp_reader *); extern bool parse_optimize_options (tree, bool); diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index 2dfecb6..057776f 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -800,11 +800,6 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__has_include(STR)=__has_include__(STR)"); cpp_define (pfile, "__has_include_next(STR)=__has_include_next__(STR)"); - /* Set attribute test macros for all C/C++ (not for just C++11 etc.) - The builtin __has_attribute__ is defined in libcpp. */ - cpp_define (pfile, "__has_attribute(STR)=__has_attribute__(STR)"); - cpp_define (pfile, "__has_cpp_attribute(STR)=__has_attribute__(STR)"); - if (c_dialect_cxx ()) { if (flag_weak && SUPPORTS_ONE_ONLY) diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c index 357d137..f67e490 100644 --- a/gcc/c-family/c-lex.c +++ b/gcc/c-family/c-lex.c @@ -64,7 +64,6 @@ static void cb_ident (cpp_reader *, unsigned int, const cpp_string *); static void cb_def_pragma (cpp_reader *, unsigned int); static void cb_define (cpp_reader *, unsigned int, cpp_hashnode *); static void cb_undef (cpp_reader *, unsigned int, cpp_hashnode *); -static int cb_has_attribute (cpp_reader *); void init_c_lex (void) @@ -89,7 +88,7 @@ init_c_lex (void) cb->def_pragma = cb_def_pragma; cb->valid_pch = c_common_valid_pch; cb->read_pch = c_common_read_pch; - cb->has_attribute = cb_has_attribute; + cb->has_attribute = c_common_has_attribute; /* Set the debug callbacks if we can use them. */ if ((debug_info_level == DINFO_LEVEL_VERBOSE @@ -288,57 +287,80 @@ cb_undef (cpp_reader * ARG_UNUSED (pfile), source_location loc, (const char *) NODE_NAME (node)); } +/* Wrapper around cpp_get_token to skip CPP_PADDING tokens + and not consume CPP_EOF. */ +static const cpp_token * +get_token_no_padding (cpp_reader *pfile) +{ + for (;;) + { + const cpp_token *ret = cpp_peek_token (pfile, 0); + if (ret->type == CPP_EOF) + return ret; + ret = cpp_get_token (pfile); + if (ret->type != CPP_PADDING) + return ret; + } +} + /* Callback for has_attribute. */ -static int -cb_has_attribute (cpp_reader *pfile) +int +c_common_has_attribute (cpp_reader *pfile) { int result = 0; - bool paren = false; - tree attr_ns = NULL_TREE, attr_id = NULL_TREE, attr_name = NULL_TREE; + tree attr_name = NULL_TREE; const cpp_token *token; - token = cpp_get_token (pfile); - if (token->type == CPP_OPEN_PAREN) + token = get_token_no_padding (pfile); + if (token->type != CPP_OPEN_PAREN) { - paren = true; - token = cpp_get_token (pfile); + cpp_error (pfile, CPP_DL_ERROR, + "missing '(' after \"__has_attribute\""); + return 0; } - + token = get_token_no_padding (pfile); if (token->type == CPP_NAME) { - //node = token->val.node.node; - const cpp_token *nxt_token = cpp_peek_token (pfile, 0); - if (c_dialect_cxx() && nxt_token->type == CPP_SCOPE) + attr_name = get_identifier ((const char *) + cpp_token_as_text (pfile, token)); + if (c_dialect_cxx ()) { - nxt_token = cpp_get_token (pfile); // Eat scope. - nxt_token = cpp_get_token (pfile); - if (nxt_token->type == CPP_NAME) + int idx = 0; + const cpp_token *nxt_token; + do + nxt_token = cpp_peek_token (pfile, idx++); + while (nxt_token->type == CPP_PADDING); + if (nxt_token->type == CPP_SCOPE) { - attr_ns = get_identifier ( - (const char *) cpp_token_as_text (pfile, token)); - attr_id = get_identifier ( - (const char *) cpp_token_as_text (pfile, nxt_token)); - attr_name = build_tree_list (attr_ns, attr_id); + get_token_no_padding (pfile); // Eat scope. + nxt_token = get_token_no_padding (pfile); + if (nxt_token->type == CPP_NAME) + { + tree attr_ns = attr_name; + tree attr_id + = get_identifier ((const char *) + cpp_token_as_text (pfile, nxt_token)); + attr_name = build_tree_list (attr_ns, attr_id); + } + else + { + cpp_error (pfile, CPP_DL_ERROR, + "attribute identifier required after scope"); + attr_name = NULL_TREE; + } } - else - cpp_error (pfile, CPP_DL_ERROR, - "attribute identifier required after scope"); - } - else - { - attr_ns = get_identifier ("gnu"); - attr_id = get_identifier ( - (const char *) cpp_token_as_text (pfile, token)); - attr_name = build_tree_list (attr_ns, attr_id); } if (attr_name) { + init_attributes (); const struct attribute_spec *attr = lookup_attribute_spec (attr_name); if (attr) { - if (is_attribute_p ("noreturn", TREE_VALUE (attr_name))) + if (TREE_CODE (attr_name) == TREE_LIST) + attr_name = TREE_VALUE (attr_name); + if (is_attribute_p ("noreturn", attr_name)) result = 200809; - else if (is_attribute_p ("deprecated", TREE_VALUE (attr_name))) + else if (is_attribute_p ("deprecated", attr_name)) result = 201309; else result = 1; @@ -346,16 +368,18 @@ cb_has_attribute (cpp_reader *pfile) } } else - cpp_error (pfile, CPP_DL_ERROR, - "operator \"__has_attribute__\" requires an identifier"); + { + cpp_error (pfile, CPP_DL_ERROR, + "macro \"__has_attribute\" requires an identifier"); + return 0; + } - if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN) + if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN) cpp_error (pfile, CPP_DL_ERROR, - "missing ')' after \"__has_attribute__\""); + "missing ')' after \"__has_attribute\""); return result; } - /* Read a token and return its type. Fill *VALUE with its value, if applicable. Fill *CPP_FLAGS with the token's flags, if it is diff --git a/gcc/c-family/c-ppoutput.c b/gcc/c-family/c-ppoutput.c index 0292d16..66fbd7e 100644 --- a/gcc/c-family/c-ppoutput.c +++ b/gcc/c-family/c-ppoutput.c @@ -151,6 +151,8 @@ init_pp_output (FILE *out_stream) cb->used_undef = cb_used_undef; } + cb->has_attribute = c_common_has_attribute; + /* Initialize the print structure. */ print.src_line = 1; print.printed = 0; diff --git a/gcc/config/arm/cortex-a9-neon.md b/gcc/config/arm/cortex-a9-neon.md index 3ff93f9..5c02b32 100644 --- a/gcc/config/arm/cortex-a9-neon.md +++ b/gcc/config/arm/cortex-a9-neon.md @@ -376,7 +376,7 @@ (define_insn_reservation "cortex_a9_neon_vmov" 3 (and (eq_attr "tune" "cortexa9") (eq_attr "cortex_a9_neon_type" "neon_vmov")) - "cortex_a8_neon_dp") + "cortex_a9_neon_dp") ;; Instructions using this reservation read their (D|Q)n operands at N2, ;; their (D|Q)m operands at N1, their (D|Q)d operands at N3, and diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md index 52267f7..8772332 100644 --- a/gcc/config/sh/predicates.md +++ b/gcc/config/sh/predicates.md @@ -182,6 +182,19 @@ return 0; }) +;; Likewise arith_operand but always permits const_int. +(define_predicate "arith_or_int_operand" + (match_code "subreg,reg,const_int,const_vector") +{ + if (arith_operand (op, mode)) + return 1; + + if (CONST_INT_P (op)) + return 1; + + return 0; +}) + ;; Returns 1 if OP is a valid source operand for a compare insn. (define_predicate "arith_reg_or_0_operand" (match_code "subreg,reg,const_int,const_vector") @@ -510,7 +523,25 @@ && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1))) return false; - if ((mode == QImode || mode == HImode) + if (GET_CODE (x) == PLUS) + { + rtx y = XEXP (x, 0); + + if (! REG_P (y) + && ! (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y)))) + return false; + y = XEXP (x, 1); + if (! REG_P (y) + && ! (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y))) + && ! CONST_INT_P (y)) + return false; + } + + /* LRA will try to satisfy the constraints for the memory displacements + and thus we must not reject invalid displacements in the predicate, + or else LRA will bail out. + FIXME: maybe remove this check completely? */ + if (!lra_in_progress && (mode == QImode || mode == HImode) && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) @@ -595,7 +626,25 @@ && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1))) return false; - if ((mode == QImode || mode == HImode) + if (GET_CODE (x) == PLUS) + { + rtx y = XEXP (x, 0); + + if (! REG_P (y) + && ! (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y)))) + return false; + y = XEXP (x, 1); + if (! REG_P (y) + && ! (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y))) + && ! CONST_INT_P (y)) + return false; + } + + /* LRA will try to satisfy the constraints for the memory displacements + and thus we must not reject invalid displacements in the predicate, + or else LRA will bail out. + FIXME: maybe remove this check completely? */ + if (!lra_in_progress && (mode == QImode || mode == HImode) && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) @@ -1117,6 +1166,8 @@ case ZERO_EXTEND: case SIGN_EXTEND: + if (REG_P (XEXP (op, 0)) && REGNO (XEXP (op, 0)) == T_REG) + return true; return GET_CODE (XEXP (op, 0)) == SUBREG && REG_P (SUBREG_REG (XEXP (op, 0))) && REGNO (SUBREG_REG (XEXP (op, 0))) == T_REG; diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index 262c4fb..b0fc67a 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -159,6 +159,7 @@ extern rtx sh_find_equiv_gbr_addr (rtx_insn* cur_insn, rtx mem); extern int sh_eval_treg_value (rtx op); extern HOST_WIDE_INT sh_disp_addr_displacement (rtx mem_op); extern int sh_max_mov_insn_displacement (machine_mode mode, bool consider_sh2a); +extern bool sh_movsf_ie_ra_split_p (rtx, rtx, rtx); /* Result value of sh_find_set_of_reg. */ struct set_of_reg @@ -262,5 +263,7 @@ extern int sh2a_get_function_vector_number (rtx); extern bool sh2a_is_function_vector_call (rtx); extern void sh_fix_range (const char *); extern bool sh_hard_regno_mode_ok (unsigned int, machine_mode); +extern machine_mode sh_hard_regno_caller_save_mode (unsigned int, unsigned int, + machine_mode); extern bool sh_can_use_simple_return_p (void); #endif /* ! GCC_SH_PROTOS_H */ diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index b89d048..8ad8afa5 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -222,6 +222,7 @@ static int sh_mode_after (int, int, rtx_insn *); static int sh_mode_entry (int); static int sh_mode_exit (int); static int sh_mode_priority (int entity, int n); +static bool sh_lra_p (void); static rtx mark_constant_pool_use (rtx); static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, @@ -291,6 +292,8 @@ static reg_class_t sh_secondary_reload (bool, rtx, reg_class_t, static bool sh_legitimate_address_p (machine_mode, rtx, bool); static rtx sh_legitimize_address (rtx, rtx, machine_mode); static rtx sh_delegitimize_address (rtx); +static bool sh_cannot_substitute_mem_equiv_p (rtx); +static bool sh_legitimize_address_displacement (rtx *, rtx *, machine_mode); static int shmedia_target_regs_stack_space (HARD_REG_SET *); static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *); static int shmedia_target_regs_stack_adjust (HARD_REG_SET *); @@ -618,6 +621,9 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO sh_encode_section_info +#undef TARGET_LRA_P +#define TARGET_LRA_P sh_lra_p + #undef TARGET_SECONDARY_RELOAD #define TARGET_SECONDARY_RELOAD sh_secondary_reload @@ -630,6 +636,13 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P sh_legitimate_address_p +#undef TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P +#define TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P sh_cannot_substitute_mem_equiv_p + +#undef TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT +#define TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT \ + sh_legitimize_address_displacement + #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT sh_trampoline_init #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS @@ -1765,6 +1778,38 @@ prepare_move_operands (rtx operands[], machine_mode mode) && GET_CODE (XEXP (operands[0], 0)) == PLUS && REG_P (XEXP (XEXP (operands[0], 0), 1))) operands[1] = copy_to_mode_reg (mode, operands[1]); + + /* When the displacement addressing is used, RA will assign r0 to + the pseudo register operand for the QI/HImode load/store. + This tends to make a long live range for R0 and might cause + anomalous register spills in some case with LRA. See PR + target/55212. + We split possible load/store to two move insns via r0 so as to + shorten R0 live range. It will make some codes worse but will + win on avarage for LRA. */ + else if (sh_lra_p () + && TARGET_SH1 && ! TARGET_SH2A + && (mode == QImode || mode == HImode) + && ((REG_P (operands[0]) && MEM_P (operands[1])) + || (REG_P (operands[1]) && MEM_P (operands[0])))) + { + bool load_p = REG_P (operands[0]); + rtx reg = operands[load_p ? 0 : 1]; + rtx adr = XEXP (operands[load_p ? 1 : 0], 0); + + if (REGNO (reg) >= FIRST_PSEUDO_REGISTER + && GET_CODE (adr) == PLUS + && REG_P (XEXP (adr, 0)) + && (REGNO (XEXP (adr, 0)) >= FIRST_PSEUDO_REGISTER) + && CONST_INT_P (XEXP (adr, 1)) + && INTVAL (XEXP (adr, 1)) != 0 + && sh_legitimate_index_p (mode, XEXP (adr, 1), false, true)) + { + rtx r0_rtx = gen_rtx_REG (mode, R0_REG); + emit_move_insn (r0_rtx, operands[1]); + operands[1] = r0_rtx; + } + } } if (mode == Pmode || mode == ptr_mode) @@ -10475,6 +10520,9 @@ sh_legitimize_reload_address (rtx *p, machine_mode mode, int opnum, enum reload_type type = (enum reload_type) itype; const int mode_sz = GET_MODE_SIZE (mode); + if (sh_lra_p ()) + return false; + if (! ALLOW_INDEXED_ADDRESS && GET_CODE (*p) == PLUS && REG_P (XEXP (*p, 0)) && REG_P (XEXP (*p, 1))) @@ -12170,6 +12218,26 @@ sh_hard_regno_mode_ok (unsigned int regno, machine_mode mode) return true; } +/* Specify the modes required to caller save a given hard regno. + choose_hard_reg_mode chooses mode based on HARD_REGNO_MODE_OK + and returns ?Imode for float regs when sh_hard_regno_mode_ok + permits integer modes on them. That makes LRA's split process + unhappy. See PR55212. + */ +machine_mode +sh_hard_regno_caller_save_mode (unsigned int regno, unsigned int nregs, + machine_mode mode) +{ + if (FP_REGISTER_P (regno) + && (mode == SFmode + || mode == SCmode + || ((mode == DFmode || mode == DCmode) + && ((regno - FIRST_FP_REG) & 1) == 0))) + return mode; + + return choose_hard_reg_mode (regno, nregs, false); +} + /* Return the class of registers for which a mode change from FROM to TO is invalid. */ bool @@ -13167,7 +13235,7 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, { if (rclass == FPUL_REGS) return GENERAL_REGS; - return FPUL_REGS; + return NO_REGS; // LRA wants NO_REGS here, it used to be FPUL_REGS; } if ((rclass == TARGET_REGS || (TARGET_SHMEDIA && rclass == SIBCALL_REGS)) @@ -13214,6 +13282,76 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, return NO_REGS; } +/* Return true if SUBST can't safely replace its equivalent during RA. */ +static bool +sh_cannot_substitute_mem_equiv_p (rtx) +{ + if (TARGET_SHMEDIA) + return false; + + /* If SUBST is mem[base+index] or QI/HImode mem[base+disp], the insn + uses R0 and may cause spill failure when R0 is already used. + We have to return true for that case at least. + Moreover SH has strong R0 parity and also have not enough numbers of + the hard registers to make the equiv substitution win in the size + and the speed on average working sets. The pseudos produced to + hold the equiv values can't get good hard registers for bad cases + and end up memory save/restore insns which make the code worse. */ + return true; +} + +/* Return true if DISP can be legitimized. */ +static bool +sh_legitimize_address_displacement (rtx *disp, rtx *offs, + machine_mode mode) +{ + if (TARGET_SHMEDIA) + return false; + + if (((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode) + || (TARGET_SH2E && mode == SFmode)) + return false; + + struct disp_adjust adj = sh_find_mov_disp_adjust (mode, INTVAL (*disp)); + if (adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX) + { + *disp = adj.mov_disp; + *offs = adj.offset_adjust; + return true; + } + + return false; +} + +/* Return true if movsf insn should be splited with an additional + register. */ +bool +sh_movsf_ie_ra_split_p (rtx op0, rtx op1, rtx op2) +{ + /* op0 == op1 */ + if (rtx_equal_p (op0, op1)) + return true; + /* fy, FQ, reg */ + if (GET_CODE (op1) == CONST_DOUBLE + && ! satisfies_constraint_G (op1) + && ! satisfies_constraint_H (op1) + && REG_P (op0) + && REG_P (op2)) + return true; + /* f, r, y */ + if (REG_P (op0) && FP_REGISTER_P (REGNO (op0)) + && REG_P (op1) && GENERAL_REGISTER_P (REGNO (op1)) + && REG_P (op2) && (REGNO (op2) == FPUL_REG)) + return true; + /* r, f, y */ + if (REG_P (op1) && FP_REGISTER_P (REGNO (op1)) + && REG_P (op0) && GENERAL_REGISTER_P (REGNO (op0)) + && REG_P (op2) && (REGNO (op2) == FPUL_REG)) + return true; + + return false; +} + static void sh_conditional_register_usage (void) { @@ -13724,6 +13862,13 @@ sh_mode_priority (int entity ATTRIBUTE_UNUSED, int n) return ((TARGET_FPU_SINGLE != 0) ^ (n) ? FP_MODE_SINGLE : FP_MODE_DOUBLE); } +/* Return true if we use LRA instead of reload pass. */ +static bool +sh_lra_p (void) +{ + return sh_lra_flag; +} + /* Implement TARGET_USE_BY_PIECES_INFRASTRUCTURE_P. */ static bool diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 92835d7..ae1e39b 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -905,6 +905,10 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ && (GET_MODE_SIZE (MODE2) <= 4)) \ : ((MODE1) != SFmode && (MODE2) != SFmode)))) +/* Specify the modes required to caller save a given hard regno. */ +#define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \ + sh_hard_regno_caller_save_mode ((REGNO), (NREGS), (MODE)) + /* A C expression that is nonzero if hard register NEW_REG can be considered for use as a rename register for OLD_REG register */ #define HARD_REGNO_RENAME_OK(OLD_REG, NEW_REG) \ diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 5aa50a25..a74e17f 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -2020,11 +2020,16 @@ (define_expand "addsi3" [(set (match_operand:SI 0 "arith_reg_operand" "") (plus:SI (match_operand:SI 1 "arith_operand" "") - (match_operand:SI 2 "arith_operand" "")))] + (match_operand:SI 2 "arith_or_int_operand" "")))] "" { if (TARGET_SHMEDIA) operands[1] = force_reg (SImode, operands[1]); + else if (! arith_operand (operands[2], SImode)) + { + if (reg_overlap_mentioned_p (operands[0], operands[1])) + FAIL; + } }) (define_insn "addsi3_media" @@ -2051,12 +2056,22 @@ [(set_attr "type" "arith_media") (set_attr "highpart" "ignore")]) -(define_insn "*addsi3_compact" - [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (plus:SI (match_operand:SI 1 "arith_operand" "%0") - (match_operand:SI 2 "arith_operand" "rI08")))] - "TARGET_SH1" - "add %2,%0" +(define_insn_and_split "*addsi3_compact" + [(set (match_operand:SI 0 "arith_reg_dest" "=r,&r") + (plus:SI (match_operand:SI 1 "arith_operand" "%0,r") + (match_operand:SI 2 "arith_or_int_operand" "rI08,rn")))] + "TARGET_SH1 + && (rtx_equal_p (operands[0], operands[1]) + && arith_operand (operands[2], SImode)) + || ! reg_overlap_mentioned_p (operands[0], operands[1])" + "@ + add %2,%0 + #" + "reload_completed + && ! reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))] + "" [(set_attr "type" "arith")]) ;; ------------------------------------------------------------------------- @@ -6665,7 +6680,7 @@ label: ;; TARGET_FMOVD is in effect, and mode switching is done before reload. (define_insn "movsi_ie" [(set (match_operand:SI 0 "general_movdst_operand" - "=r,r,r,r,r,r,r,r,m,<,<,x,l,x,l,y,<,r,y,r,*f,y,*f,y") + "=r,r,r,r,r,r,r,r,mr,<,<,x,l,x,l,y,<,r,y,r,*f,y,*f,y") (match_operand:SI 1 "general_movsrc_operand" "Q,r,I08,I20,I28,mr,x,l,r,x,l,r,r,>,>,>,y,i,r,y,y,*f,*f,y"))] "(TARGET_SH2E || TARGET_SH2A) @@ -8329,7 +8344,7 @@ label: (match_operand:SF 1 "general_movsrc_operand" "f,r,G,H,FQ,mf,f,FQ,mr,r,y,f,>,fr,y,r,y,>,y")) (use (reg:SI FPSCR_MODES_REG)) - (clobber (match_scratch:SI 2 "=X,X,Bsc,Bsc,&z,X,X,X,X,X,X,X,X,y,X,X,X,X,X"))] + (clobber (match_scratch:SI 2 "=X,X,X,X,&z,X,X,X,X,X,X,X,X,y,X,X,X,X,X"))] "TARGET_SH2E && (arith_reg_operand (operands[0], SFmode) || fpul_operand (operands[0], SFmode) || arith_reg_operand (operands[1], SFmode) || fpul_operand (operands[1], SFmode) @@ -8409,6 +8424,104 @@ label: (const_string "none") (const_string "none")])]) +(define_insn_and_split "movsf_ie_ra" + [(set (match_operand:SF 0 "general_movdst_operand" + "=f,r,f,f,fy,f,m,r,r,m,f,y,y,rf,r,y,<,y,y") + (match_operand:SF 1 "general_movsrc_operand" + "f,r,G,H,FQ,m,f,FQ,m,r,y,f,>,fr,y,r,y,>,y")) + (use (reg:SI FPSCR_MODES_REG)) + (clobber (match_scratch:SF 2 "=r,r,X,X,&z,r,r,X,r,r,r,r,r,y,r,r,r,r,r")) + (const_int 0)] + "TARGET_SH2E + && (arith_reg_operand (operands[0], SFmode) + || fpul_operand (operands[0], SFmode) + || arith_reg_operand (operands[1], SFmode) + || fpul_operand (operands[1], SFmode))" + "@ + fmov %1,%0 + mov %1,%0 + fldi0 %0 + fldi1 %0 + # + fmov.s %1,%0 + fmov.s %1,%0 + mov.l %1,%0 + mov.l %1,%0 + mov.l %1,%0 + fsts fpul,%0 + flds %1,fpul + lds.l %1,%0 + # + sts %1,%0 + lds %1,%0 + sts.l %1,%0 + lds.l %1,%0 + ! move optimized away" + "reload_completed + && sh_movsf_ie_ra_split_p (operands[0], operands[1], operands[2])" + [(const_int 0)] +{ + if (! rtx_equal_p (operands[0], operands[1])) + { + emit_insn (gen_movsf_ie (operands[2], operands[1])); + emit_insn (gen_movsf_ie (operands[0], operands[2])); + } +} + [(set_attr "type" "fmove,move,fmove,fmove,pcfload,fload,fstore,pcload,load, + store,fmove,fmove,load,*,fpul_gp,gp_fpul,fstore,load,nil") + (set_attr "late_fp_use" "*,*,*,*,*,*,yes,*,*,*,*,*,*,*,yes,*,yes,*,*") + (set_attr_alternative "length" + [(const_int 2) + (const_int 2) + (const_int 2) + (const_int 2) + (const_int 4) + (if_then_else + (match_test "TARGET_SH2A") + (const_int 4) (const_int 2)) + (if_then_else + (match_test "TARGET_SH2A") + (const_int 4) (const_int 2)) + (const_int 2) + (if_then_else + (match_test "TARGET_SH2A") + (const_int 4) (const_int 2)) + (if_then_else + (match_test "TARGET_SH2A") + (const_int 4) (const_int 2)) + (const_int 2) + (const_int 2) + (const_int 2) + (const_int 4) + (const_int 2) + (const_int 2) + (const_int 2) + (const_int 2) + (const_int 0)]) + (set_attr_alternative "fp_mode" + [(if_then_else (eq_attr "fmovd" "yes") + (const_string "single") (const_string "none")) + (const_string "none") + (const_string "single") + (const_string "single") + (const_string "none") + (if_then_else (eq_attr "fmovd" "yes") + (const_string "single") (const_string "none")) + (if_then_else (eq_attr "fmovd" "yes") + (const_string "single") (const_string "none")) + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none") + (const_string "none")])]) + (define_split [(set (match_operand:SF 0 "register_operand" "") (match_operand:SF 1 "register_operand" "")) @@ -8439,6 +8552,14 @@ label: } if (TARGET_SH2E) { + if (lra_in_progress) + { + if (GET_CODE (operands[0]) == SCRATCH) + DONE; + emit_insn (gen_movsf_ie_ra (operands[0], operands[1])); + DONE; + } + emit_insn (gen_movsf_ie (operands[0], operands[1])); DONE; } @@ -10055,6 +10176,18 @@ label: (match_operand 2 "" "")])] "(TARGET_SH2E || TARGET_SH2A) || TARGET_SHMEDIA" { + if (! TARGET_SHMEDIA) + { + /* RA does not know that the call sets the function value registers. + We avoid problems by claiming that those registers are clobbered + at this point. */ + for (int i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_clobber (SET_SRC (set)); + } + } + emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx)); for (int i = 0; i < XVECLEN (operands[2], 0); i++) diff --git a/gcc/config/sh/sh.opt b/gcc/config/sh/sh.opt index bb6d395..375bb88 100644 --- a/gcc/config/sh/sh.opt +++ b/gcc/config/sh/sh.opt @@ -360,3 +360,6 @@ mfsrra Target Var(TARGET_FSRRA) Enable the use of the fsrra instruction +mlra +Target Report Var(sh_lra_flag) Init(0) Save +Use LRA instead of reload (transitional) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 33a7ed2..45d4e25 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -12712,8 +12712,7 @@ Replaced by @samp{-mmultcost}. @subsection ARM Options @cindex ARM options -These @samp{-m} options are defined for Advanced RISC Machines (ARM) -architectures: +These @samp{-m} options are defined for the ARM port: @table @gcctabopt @item -mabi=@var{name} diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index ee741a9..a3fda45 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -2847,6 +2847,25 @@ A target hook which returns true if we need register usage leveling. That means A target hook which returns true if an address with the same structure can have different maximal legitimate displacement. For example, the displacement can depend on memory mode or on operand combinations in the insn. The default version of this target hook returns always false. @end deftypefn +@deftypefn {Target Hook} bool TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P (rtx @var{subst}) +A target hook which returns @code{true} if @var{subst} can't +substitute safely pseudos with equivalent memory values during +register allocation. +The default version of this target hook returns @code{false}. +On most machines, this default should be used. For generally +machines with non orthogonal register usage for addressing, such +as SH, this hook can be used to avoid excessive spilling. +@end deftypefn + +@deftypefn {Target Hook} bool TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT (rtx *@var{disp}, rtx *@var{offset}, machine_mode @var{mode}) +A target hook which returns @code{true} if *@var{disp} is +legitimezed to valid address displacement with subtracting *@var{offset} +at memory mode @var{mode}. +The default version of this target hook returns @code{false}. +This hook will benefit machines with limited base plus displacement +addressing. +@end deftypefn + @deftypefn {Target Hook} reg_class_t TARGET_SPILL_CLASS (reg_class_t, @var{machine_mode}) This hook defines a class of registers which could be used for spilling pseudos of the given mode and class, or @code{NO_REGS} if only memory should be used. Not defining this hook is equivalent to returning @code{NO_REGS} for all inputs. @end deftypefn diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 8f86538..20c0129 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -2481,6 +2481,10 @@ as below: @hook TARGET_DIFFERENT_ADDR_DISPLACEMENT_P +@hook TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P + +@hook TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT + @hook TARGET_SPILL_CLASS @hook TARGET_CSTORE_MODE diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 6f5acc1..5b95b21 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -5142,6 +5142,9 @@ Expression* Binary_expression::do_flatten(Gogo* gogo, Named_object*, Statement_inserter* inserter) { + if (this->classification() == EXPRESSION_ERROR) + return this; + Location loc = this->location(); Temporary_statement* temp; if (this->left_->type()->is_string_type() @@ -6877,30 +6880,53 @@ Expression* Builtin_call_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter) { - if (this->code_ == BUILTIN_APPEND - || this->code_ == BUILTIN_COPY) + Location loc = this->location(); + + switch (this->code_) { - Location loc = this->location(); - Type* at = this->args()->front()->type(); + default: + break; + + case BUILTIN_APPEND: + case BUILTIN_COPY: + { + Type* at = this->args()->front()->type(); + for (Expression_list::iterator pa = this->args()->begin(); + pa != this->args()->end(); + ++pa) + { + if ((*pa)->is_nil_expression()) + { + Expression* nil = Expression::make_nil(loc); + Expression* zero = Expression::make_integer_ul(0, NULL, loc); + *pa = Expression::make_slice_value(at, nil, zero, zero, loc); + } + if (!(*pa)->is_variable()) + { + Temporary_statement* temp = + Statement::make_temporary(NULL, *pa, loc); + inserter->insert(temp); + *pa = Expression::make_temporary_reference(temp, loc); + } + } + } + break; + + case BUILTIN_PANIC: for (Expression_list::iterator pa = this->args()->begin(); - pa != this->args()->end(); - ++pa) - { - if ((*pa)->is_nil_expression()) + pa != this->args()->end(); + ++pa) + { + if (!(*pa)->is_variable() && (*pa)->type()->interface_type() != NULL) { - Expression* nil = Expression::make_nil(loc); - Expression* zero = Expression::make_integer_ul(0, NULL, loc); - *pa = Expression::make_slice_value(at, nil, zero, zero, loc); + Temporary_statement* temp = + Statement::make_temporary(NULL, *pa, loc); + inserter->insert(temp); + *pa = Expression::make_temporary_reference(temp, loc); } - if (!(*pa)->is_variable()) - { - Temporary_statement* temp = - Statement::make_temporary(NULL, *pa, loc); - inserter->insert(temp); - *pa = Expression::make_temporary_reference(temp, loc); - } - } + } } + return this; } diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index c84df3b..5da0471 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -421,6 +421,28 @@ Temporary_statement::do_check_types(Gogo*) } } +// Flatten a temporary statement: add another temporary when it might +// be needed for interface conversion. + +Statement* +Temporary_statement::do_flatten(Gogo*, Named_object*, Block*, + Statement_inserter* inserter) +{ + if (this->type_ != NULL + && this->init_ != NULL + && !Type::are_identical(this->type_, this->init_->type(), false, NULL) + && this->init_->type()->interface_type() != NULL + && !this->init_->is_variable()) + { + Temporary_statement *temp = + Statement::make_temporary(NULL, this->init_, this->location()); + inserter->insert(temp); + this->init_ = Expression::make_temporary_reference(temp, + this->location()); + } + return this; +} + // Convert to backend representation. Bstatement* @@ -440,9 +462,10 @@ Temporary_statement::do_get_backend(Translate_context* context) binit = this->init_->get_backend(context); else { - Expression* init = Expression::make_cast(this->type_, this->init_, - this->location()); - context->gogo()->lower_expression(context->function(), NULL, &init); + Expression* init = Expression::convert_for_assignment(context->gogo(), + this->type_, + this->init_, + this->location()); binit = init->get_backend(context); } diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index aaad66e..5634b61 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -550,6 +550,9 @@ class Temporary_statement : public Statement void do_check_types(Gogo*); + Statement* + do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*); + Bstatement* do_get_backend(Translate_context*); diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c index ec0290a..fa2c353 100644 --- a/gcc/ipa-icf-gimple.c +++ b/gcc/ipa-icf-gimple.c @@ -230,6 +230,9 @@ func_checker::compare_operand (tree t1, tree t2) tree tt1 = TREE_TYPE (t1); tree tt2 = TREE_TYPE (t2); + if (TREE_THIS_VOLATILE (t1) != TREE_THIS_VOLATILE (t2)) + return return_false_with_msg ("different operand volatility"); + if (!func_checker::compatible_types_p (tt1, tt2)) return false; diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index 23fd44d..382281c 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -488,7 +488,11 @@ get_equiv (rtx x) || lra_get_regno_hard_regno (regno) >= 0) return x; if ((res = ira_reg_equiv[regno].memory) != NULL_RTX) - return res; + { + if (targetm.cannot_substitute_mem_equiv_p (res)) + return x; + return res; + } if ((res = ira_reg_equiv[regno].constant) != NULL_RTX) return res; if ((res = ira_reg_equiv[regno].invariant) != NULL_RTX) @@ -2834,6 +2838,20 @@ process_address_1 (int nop, bool check_only_p, decompose_mem_address (&ad, SUBREG_REG (op)); else return false; + /* If INDEX_REG_CLASS is assigned to base_term already and isn't to + index_term, swap them so to avoid assigning INDEX_REG_CLASS to both + when INDEX_REG_CLASS is a single register class. */ + if (ad.base_term != NULL + && ad.index_term != NULL + && ira_class_hard_regs_num[INDEX_REG_CLASS] == 1 + && REG_P (*ad.base_term) + && REG_P (*ad.index_term) + && in_class_p (*ad.base_term, INDEX_REG_CLASS, NULL) + && ! in_class_p (*ad.index_term, INDEX_REG_CLASS, NULL)) + { + std::swap (ad.base, ad.index); + std::swap (ad.base_term, ad.index_term); + } if (! check_only_p) change_p = equiv_address_substitution (&ad); if (ad.base_term != NULL @@ -2997,6 +3015,32 @@ process_address_1 (int nop, bool check_only_p, delete_insns_since (PREV_INSN (last_insn)); } } + /* Try if target can split displacement into legitimite new disp + and offset. If it's the case, we replace the last insn with + insns for base + offset => new_reg and set new_reg + new disp + to *ad.inner. */ + last_insn = get_last_insn (); + if ((set = single_set (last_insn)) != NULL_RTX + && GET_CODE (SET_SRC (set)) == PLUS + && REG_P (XEXP (SET_SRC (set), 0)) + && REGNO (XEXP (SET_SRC (set), 0)) < FIRST_PSEUDO_REGISTER + && CONST_INT_P (XEXP (SET_SRC (set), 1))) + { + rtx addend, disp = XEXP (SET_SRC (set), 1); + if (targetm.legitimize_address_displacement (&disp, &addend, + ad.mode)) + { + rtx_insn *new_insns; + start_sequence (); + lra_emit_add (new_reg, XEXP (SET_SRC (set), 0), addend); + new_insns = get_insns (); + end_sequence (); + new_reg = gen_rtx_PLUS (Pmode, new_reg, disp); + delete_insns_since (PREV_INSN (last_insn)); + add_insn (new_insns); + insns = get_insns (); + } + } end_sequence (); emit_insn (insns); *ad.inner = new_reg; diff --git a/gcc/target.def b/gcc/target.def index e7cec46..6258b3a 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -5037,6 +5037,33 @@ DEFHOOK reg_class_t, (reg_class_t rclass), default_preferred_rename_class) +/* This target hook allows the backend to avoid unsafe substitution + during register allocation. */ +DEFHOOK +(cannot_substitute_mem_equiv_p, + "A target hook which returns @code{true} if @var{subst} can't\n\ +substitute safely pseudos with equivalent memory values during\n\ +register allocation.\n\ +The default version of this target hook returns @code{false}.\n\ +On most machines, this default should be used. For generally\n\ +machines with non orthogonal register usage for addressing, such\n\ +as SH, this hook can be used to avoid excessive spilling.", + bool, (rtx subst), + hook_bool_rtx_false) + +/* This target hook allows the backend to legitimize base plus + displacement addressing. */ +DEFHOOK +(legitimize_address_displacement, + "A target hook which returns @code{true} if *@var{disp} is\n\ +legitimezed to valid address displacement with subtracting *@var{offset}\n\ +at memory mode @var{mode}.\n\ +The default version of this target hook returns @code{false}.\n\ +This hook will benefit machines with limited base plus displacement\n\ +addressing.", + bool, (rtx *disp, rtx *offset, machine_mode mode), + default_legitimize_address_displacement) + /* This target hook allows the backend to perform additional processing while initializing for variable expansion. */ DEFHOOK diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 42fd82e..5e723b4 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -167,6 +167,14 @@ default_legitimize_address (rtx x, rtx orig_x ATTRIBUTE_UNUSED, return x; } +bool +default_legitimize_address_displacement (rtx *disp ATTRIBUTE_UNUSED, + rtx *offset ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED) +{ + return false; +} + rtx default_expand_builtin_saveregs (void) { diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 9734220..26e4f5f 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -24,6 +24,8 @@ extern bool default_legitimate_address_p (machine_mode, rtx, bool); extern void default_external_libcall (rtx); extern rtx default_legitimize_address (rtx, rtx, machine_mode); +extern bool default_legitimize_address_displacement (rtx *, rtx *, + machine_mode); extern int default_unspec_may_trap_p (const_rtx, unsigned); extern machine_mode default_promote_function_mode (const_tree, machine_mode, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 87453b5..5ba1eff 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2014-12-19 Martin Liska <mliska@suse.cz> + + PR ipa/63569 + * gcc.dg/ipa/pr63569.c: New test. + +2014-12-19 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/63831 + * c-c++-common/cpp/pr63831-1.c: New test. + * c-c++-common/cpp/pr63831-2.c: New test. + 2014-12-18 Paolo Carlini <paolo.carlini@oracle.com> PR c++/63723 diff --git a/gcc/testsuite/c-c++-common/cpp/pr63831-1.c b/gcc/testsuite/c-c++-common/cpp/pr63831-1.c new file mode 100644 index 0000000..c9e7756 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/pr63831-1.c @@ -0,0 +1,64 @@ +/* PR preprocessor/63831 */ +/* { dg-do compile } */ + +#ifdef __has_attribute +typedef char T1[__has_attribute (__noreturn__) == 200809 ? 1 : -1]; +typedef char T2[__has_attribute (alloc_size) == 1 ? 1 : -1]; +typedef char T3[__has_attribute (non_existent_attribuuuute) == 0 ? 1 : -1]; +#endif +#if __has_attribute (noreturn) == 200809 +typedef char T4; +#endif +#define d deprecated +typedef char T5[__has_attribute (d) == 201309 ? 1 : -1]; +T1 t1; +T2 t2; +T3 t3; +T4 t4; +T5 t5; +#ifdef __cplusplus +typedef char T6[__has_attribute (gnu::__noreturn__) == 200809 ? 1 : -1]; +typedef char T7[__has_attribute (gnu::alloc_size) == 1 ? 1 : -1]; +typedef char T8[__has_attribute (gnu::non_existent_attribuuuute) == 0 ? 1 : -1]; +#if __has_attribute (gnu::noreturn) == 200809 +typedef char T9; +#endif +#define d2 gnu::deprecated +typedef char T10[__has_attribute (d) == 201309 ? 1 : -1]; +T6 t6; +T7 t7; +T8 t8; +T9 t9; +T10 t10; +#endif +#ifdef __has_cpp_attribute +typedef char T11[__has_cpp_attribute (__noreturn__) == 200809 ? 1 : -1]; +typedef char T12[__has_cpp_attribute (alloc_size) == 1 ? 1 : -1]; +typedef char T13[__has_cpp_attribute (non_existent_attribuuuute) == 0 ? 1 : -1]; +#endif +#if __has_cpp_attribute (noreturn) == 200809 +typedef char T14; +#endif +#define d deprecated +typedef char T15[__has_cpp_attribute (d) == 201309 ? 1 : -1]; +T11 t11; +T12 t12; +T13 t13; +T14 t14; +T15 t15; +#ifdef __cplusplus +typedef char T16[__has_cpp_attribute (gnu::__noreturn__) == 200809 ? 1 : -1]; +typedef char T17[__has_cpp_attribute (gnu::alloc_size) == 1 ? 1 : -1]; +typedef char T18[__has_cpp_attribute (gnu::non_existent_attribuuuute) == 0 ? 1 : -1]; +#if __has_cpp_attribute (gnu::noreturn) == 200809 +typedef char T19; +#endif +#define d2 gnu::deprecated +typedef char T20[__has_cpp_attribute (d) == 201309 ? 1 : -1]; +T16 t16; +T17 t17; +T18 t18; +T19 t19; +T20 t20; +#endif +int t21 = __has_attribute (noreturn) + __has_cpp_attribute (__malloc__); diff --git a/gcc/testsuite/c-c++-common/cpp/pr63831-2.c b/gcc/testsuite/c-c++-common/cpp/pr63831-2.c new file mode 100644 index 0000000..cc87d1d --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/pr63831-2.c @@ -0,0 +1,7 @@ +/* PR preprocessor/63831 */ +/* { dg-do compile } */ +/* { dg-options "-save-temps" } */ + +#include "pr63831-1.c" + +/* { dg-final { cleanup-saved-temps } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/pr63569.c b/gcc/testsuite/gcc.dg/ipa/pr63569.c new file mode 100644 index 0000000..8bd5c1f --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr63569.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-ipa-icf-details" } */ + +static int f(int t, int *a) __attribute__((noinline)); + +static int g(int t, volatile int *a) __attribute__((noinline)); +static int g(int t, volatile int *a) +{ + int i; + int tt = 0; + for(i=0;i<t;i++) + tt += *a; + return tt; +} +static int f(int t, int *a) +{ + int i; + int tt = 0; + for(i=0;i<t;i++) + tt += *a; + return tt; +} + + +int h(int t, int *a) +{ + return f(t, a) + g(t, a); +} + +/* { dg-final { scan-ipa-dump "different operand volatility" "icf" } } */ +/* { dg-final { scan-ipa-dump "Equal symbols: 0" "icf" } } */ +/* { dg-final { cleanup-ipa-dump "icf" } } */ diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index df71ac2..71a2d0d 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,23 @@ +2014-12-19 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/63831 + * directives.c (lex_macro_node): Remove __has_attribute__ handling. + * internal.h (struct spec_node): Remove n__has_attribute__ field. + (struct lexer_state): Remove in__has_attribute__ field. + * macro.c (_cpp_builtin_macro_text): Handle BT_HAS_ATTRIBUTE. + * identifiers.c (_cpp_init_hashtable): Remove __has_attribute__ + handling. + * init.c (builtin_array): Add __has_attribute and __has_cpp_attribute. + (cpp_init_special_builtins): Don't initialize __has_attribute + or __has_cpp_attribute if CLK_ASM or pfile->cb.has_attribute is NULL. + * traditional.c (enum ls): Remove ls_has_attribute, + ls_has_attribute_close. + (_cpp_scan_out_logical_line): Remove __has_attribute__ handling. + * include/cpplib.h (enum cpp_builtin_type): Add BT_HAS_ATTRIBUTE. + * pch.c (cpp_read_state): Remove __has_attribute__ handling. + * expr.c (eval_token): Likewise. + (parse_has_attribute): Removed. + 2014-12-11 Uros Bizjak <ubizjak@gmail.com> * directives.c (cpp_define_formatted): Use xvasprintf. diff --git a/libcpp/directives.c b/libcpp/directives.c index c9be412..d0ff56a 100644 --- a/libcpp/directives.c +++ b/libcpp/directives.c @@ -571,10 +571,6 @@ lex_macro_node (cpp_reader *pfile, bool is_def_or_undef) || node == pfile->spec_nodes.n__has_include_next__)) cpp_error (pfile, CPP_DL_ERROR, "\"__has_include__\" cannot be used as a macro name"); - else if (is_def_or_undef - && node == pfile->spec_nodes.n__has_attribute__) - cpp_error (pfile, CPP_DL_ERROR, - "\"__has_attribute__\" cannot be used as a macro name"); else if (! (node->flags & NODE_POISONED)) return node; } diff --git a/libcpp/expr.c b/libcpp/expr.c index 529709c..c24b640 100644 --- a/libcpp/expr.c +++ b/libcpp/expr.c @@ -65,7 +65,6 @@ static unsigned int interpret_int_suffix (cpp_reader *, const uchar *, size_t); static void check_promotion (cpp_reader *, const struct op *); static cpp_num parse_has_include (cpp_reader *, enum include_type); -static cpp_num parse_has_attribute (cpp_reader *); /* Token type abuse to create unary plus and minus operators. */ #define CPP_UPLUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1)) @@ -1055,8 +1054,6 @@ eval_token (cpp_reader *pfile, const cpp_token *token, return parse_has_include (pfile, IT_INCLUDE); else if (token->val.node.node == pfile->spec_nodes.n__has_include_next__) return parse_has_include (pfile, IT_INCLUDE_NEXT); - else if (token->val.node.node == pfile->spec_nodes.n__has_attribute__) - return parse_has_attribute (pfile); else if (CPP_OPTION (pfile, cplusplus) && (token->val.node.node == pfile->spec_nodes.n_true || token->val.node.node == pfile->spec_nodes.n_false)) @@ -2150,21 +2147,3 @@ parse_has_include (cpp_reader *pfile, enum include_type type) return result; } - -/* Handle meeting "__has_attribute__" in a preprocessor expression. */ -static cpp_num -parse_has_attribute (cpp_reader *pfile) -{ - pfile->state.in__has_attribute__++; - - cpp_num result; - result.unsignedp = false; - result.high = 0; - result.overflow = false; - - result.low = pfile->cb.has_attribute (pfile); - - pfile->state.in__has_attribute__--; - - return result; -} diff --git a/libcpp/identifiers.c b/libcpp/identifiers.c index 108939a..35d1906 100644 --- a/libcpp/identifiers.c +++ b/libcpp/identifiers.c @@ -72,7 +72,6 @@ _cpp_init_hashtable (cpp_reader *pfile, cpp_hash_table *table) s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC; s->n__has_include__ = cpp_lookup (pfile, DSC("__has_include__")); s->n__has_include_next__ = cpp_lookup (pfile, DSC("__has_include_next__")); - s->n__has_attribute__ = cpp_lookup (pfile, DSC("__has_attribute__")); } /* Tear down the identifier hash table. */ diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 406200a..b36918e 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -676,6 +676,7 @@ enum cpp_builtin_type BT_PRAGMA, /* `_Pragma' operator */ BT_TIMESTAMP, /* `__TIMESTAMP__' */ BT_COUNTER, /* `__COUNTER__' */ + BT_HAS_ATTRIBUTE, /* `__has_attribute__(x)' */ BT_FIRST_USER, /* User defined builtin macros. */ BT_LAST_USER = BT_FIRST_USER + 31 }; diff --git a/libcpp/init.c b/libcpp/init.c index 2add6ea..cf0145b 100644 --- a/libcpp/init.c +++ b/libcpp/init.c @@ -380,6 +380,8 @@ static const struct builtin_macro builtin_array[] = B("__LINE__", BT_SPECLINE, true), B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL, true), B("__COUNTER__", BT_COUNTER, true), + B("__has_attribute", BT_HAS_ATTRIBUTE, true), + B("__has_cpp_attribute", BT_HAS_ATTRIBUTE, true), /* Keep builtins not used for -traditional-cpp at the end, and update init_builtins() if any more are added. */ B("_Pragma", BT_PRAGMA, true), @@ -460,6 +462,10 @@ cpp_init_special_builtins (cpp_reader *pfile) for (b = builtin_array; b < builtin_array + n; b++) { + if (b->value == BT_HAS_ATTRIBUTE + && (CPP_OPTION (pfile, lang) == CLK_ASM + || pfile->cb.has_attribute == NULL)) + continue; cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len); hp->type = NT_MACRO; hp->flags |= NODE_BUILTIN; diff --git a/libcpp/internal.h b/libcpp/internal.h index 3a111c0..427f4c6 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -261,9 +261,6 @@ struct lexer_state /* Nonzero if in a __has_include__ or __has_include_next__ statement. */ unsigned char in__has_include__; - /* Nonzero if in a __has_attribute__ statement. */ - unsigned char in__has_attribute__; - /* Nonzero if prevent_expansion is true only because output is being discarded. */ unsigned char discarding_output; @@ -287,7 +284,6 @@ struct spec_nodes cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */ cpp_hashnode *n__has_include__; /* __has_include__ operator */ cpp_hashnode *n__has_include_next__; /* __has_include_next__ operator */ - cpp_hashnode *n__has_attribute__; /* __has_attribute__ operator */ }; typedef struct _cpp_line_note _cpp_line_note; diff --git a/libcpp/macro.c b/libcpp/macro.c index 678bf2b..c510e49 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -393,6 +393,10 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node) "__COUNTER__ expanded inside directive with -fdirectives-only"); number = pfile->counter++; break; + + case BT_HAS_ATTRIBUTE: + number = pfile->cb.has_attribute (pfile); + break; } if (result == NULL) diff --git a/libcpp/pch.c b/libcpp/pch.c index d7a2dac..3ff39d7 100644 --- a/libcpp/pch.c +++ b/libcpp/pch.c @@ -835,7 +835,6 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f, s->n__VA_ARGS__ = cpp_lookup (r, DSC("__VA_ARGS__")); s->n__has_include__ = cpp_lookup (r, DSC("__has_include__")); s->n__has_include_next__ = cpp_lookup (r, DSC("__has_include_next__")); - s->n__has_attribute__ = cpp_lookup (r, DSC("__has_attribute__")); } old_state = r->state; diff --git a/libcpp/traditional.c b/libcpp/traditional.c index 664bf05..3d40c2f 100644 --- a/libcpp/traditional.c +++ b/libcpp/traditional.c @@ -76,9 +76,7 @@ enum ls {ls_none = 0, /* Normal state. */ ls_predicate, /* After the predicate, maybe paren? */ ls_answer, /* In answer to predicate. */ ls_has_include, /* After __has_include__. */ - ls_has_include_close, /* Looking for ')' of __has_include__. */ - ls_has_attribute, /* After __has_attribute__. */ - ls_has_attribute_close}; /* Looking for ')' of __has_attribute__. */ + ls_has_include_close}; /* Looking for ')' of __has_include__. */ /* Lexing TODO: Maybe handle space in escaped newlines. Stop lex.c from recognizing comments and directives during its lexing pass. */ @@ -535,12 +533,6 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) lex_state = ls_has_include; continue; } - else if (pfile->state.in_expression - && node == pfile->spec_nodes.n__has_attribute__) - { - lex_state = ls_has_attribute; - continue; - } } break; @@ -566,8 +558,6 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) lex_state = ls_defined_close; else if (lex_state == ls_has_include) lex_state = ls_has_include_close; - else if (lex_state == ls_has_attribute) - lex_state = ls_has_attribute_close; } break; @@ -606,8 +596,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) } } else if (lex_state == ls_answer || lex_state == ls_defined_close - || lex_state == ls_has_include_close - || lex_state == ls_has_attribute_close) + || lex_state == ls_has_include_close) lex_state = ls_none; } break; @@ -689,8 +678,7 @@ _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro) else if (lex_state == ls_hash || lex_state == ls_predicate || lex_state == ls_defined - || lex_state == ls_has_include - || lex_state == ls_has_attribute) + || lex_state == ls_has_include) lex_state = ls_none; /* ls_answer and ls_defined_close keep going until ')'. */ |