mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-25 12:41:01 +08:00
attribs.c (decl_attributes): Avoid emitting a warning if ATTR_FLAG_BUILT_IN.
* attribs.c (decl_attributes): Avoid emitting a warning if ATTR_FLAG_BUILT_IN. * doc/rtl.texi (CALL_INSN_FUNCTION_USAGE): Use lowercase for rtx codes. Document meaning of sets inside CALL_INSN_FUNCTION_USAGE. * c-family/c-common.c (DEF_ATTR_STRING): Define and undefine as necessary. * builtin-attrs.def (DEF_ATTR_FOR_STRING): Define. Use it to define a string "1". (ATTR_RET1_NOTHROW_NONNULL_LEAF): New attr definition. * builtins.def (BUILT_IN_MEMCPY, BUILT_IN_MEMMOVE, BUILT_IN_MEMSET, BUILT_IN_STRCPY): Use it for these functions. * postreload.c (reload_combine): Deal with SETs inside CALL_INSN_FUNCTION_USAGE. * caller-save.c (setup_save_areas, save_call_clobbered_regs): Look for REG_RETURNED notes and use a cheap restore if possible. * ira-int.h (struct ira_allocno): New member cheap_calls_crossed_num. (ALLOCNO_CHEAP_CALLS_CROSSED_NUM): New macro. * ira-build.c (ira_create_allocno, create_cap_allocno, propagate_allocno_info, propagate_some_info_from_allocno, copy_info_to_removed_store_destination, ira_flattening): Handle it. * ira-lives.c (pseudo_regno_single_word_and_live_p, find_call_crossed_cheap_reg): New static functions. (process_bb_node_lives): Look for SETs in CALL_INSN_FUNCTION_USAGE, and set ALLOCNO_CHEAP_CALLS_CROSSED_NUM if possible. Also make a REG_RETURNED note in that case. * ira.c (setup_reg_renumber): Change assert to allow cases where allocnos only cross calls for which they are cheap to restore. * ira-costs.c (ira_tune_allocno_costs): Compare ALLOCNO_CALLS_CROSSED_NUM to ALLOCNO_CHEAP_CALLS_CROSSED_NUM rather than 0. * reg-notes.def (REG_RETURNED): New note. * cse.c (cse_insn): Likewise. * sched-deps.c (sched_analyze_insn): Likewise. * expr.c (init_block_move_fn): Set a "fn spec" attribute. * calls.c (decl_return_flags): New static function. (expand_call): Generate a SET in CALL_INSN_FUNCTION_USAGE for functions that return one of their arguments. * lto/lto-lang.c (handle_fnspec_attribute): New static function. (lto_attribute_table): Add "fn spec". (DEF_ATTR_STRING): Define and undefine along with the other macros. * regcprop.c (struct kill_set_value_data): New. (kill_set_value): Interpret data as a pointer to such a struct. Do nothing if the caller wants the register to be ignored. (copyprop_hardreg_forward_1): Handle SETs in CALL_INSN_FUNCTION_USAGE. testsuite/ * gcc.target/i386/retarg.c: New test. From-SVN: r187459
This commit is contained in:
parent
92290a187e
commit
e384e6b59c
@ -1,3 +1,50 @@
|
||||
2012-05-14 Bernd Schmidt <bernds@codesourcery.com>
|
||||
|
||||
* attribs.c (decl_attributes): Avoid emitting a warning if
|
||||
ATTR_FLAG_BUILT_IN.
|
||||
* doc/rtl.texi (CALL_INSN_FUNCTION_USAGE): Use lowercase for rtx
|
||||
codes. Document meaning of sets inside CALL_INSN_FUNCTION_USAGE.
|
||||
* c-family/c-common.c (DEF_ATTR_STRING): Define and undefine as
|
||||
necessary.
|
||||
* builtin-attrs.def (DEF_ATTR_FOR_STRING): Define. Use it to
|
||||
define a string "1".
|
||||
(ATTR_RET1_NOTHROW_NONNULL_LEAF): New attr definition.
|
||||
* builtins.def (BUILT_IN_MEMCPY, BUILT_IN_MEMMOVE, BUILT_IN_MEMSET,
|
||||
BUILT_IN_STRCPY): Use it for these functions.
|
||||
* postreload.c (reload_combine): Deal with SETs inside
|
||||
CALL_INSN_FUNCTION_USAGE.
|
||||
* caller-save.c (setup_save_areas, save_call_clobbered_regs):
|
||||
Look for REG_RETURNED notes and use a cheap restore if possible.
|
||||
* ira-int.h (struct ira_allocno): New member cheap_calls_crossed_num.
|
||||
(ALLOCNO_CHEAP_CALLS_CROSSED_NUM): New macro.
|
||||
* ira-build.c (ira_create_allocno, create_cap_allocno,
|
||||
propagate_allocno_info, propagate_some_info_from_allocno,
|
||||
copy_info_to_removed_store_destination, ira_flattening): Handle it.
|
||||
* ira-lives.c (pseudo_regno_single_word_and_live_p,
|
||||
find_call_crossed_cheap_reg): New static functions.
|
||||
(process_bb_node_lives): Look for SETs in CALL_INSN_FUNCTION_USAGE,
|
||||
and set ALLOCNO_CHEAP_CALLS_CROSSED_NUM if possible. Also make
|
||||
a REG_RETURNED note in that case.
|
||||
* ira.c (setup_reg_renumber): Change assert to allow cases where
|
||||
allocnos only cross calls for which they are cheap to restore.
|
||||
* ira-costs.c (ira_tune_allocno_costs): Compare
|
||||
ALLOCNO_CALLS_CROSSED_NUM to ALLOCNO_CHEAP_CALLS_CROSSED_NUM rather
|
||||
than 0.
|
||||
* reg-notes.def (REG_RETURNED): New note.
|
||||
* cse.c (cse_insn): Likewise.
|
||||
* sched-deps.c (sched_analyze_insn): Likewise.
|
||||
* expr.c (init_block_move_fn): Set a "fn spec" attribute.
|
||||
* calls.c (decl_return_flags): New static function.
|
||||
(expand_call): Generate a SET in CALL_INSN_FUNCTION_USAGE for
|
||||
functions that return one of their arguments.
|
||||
* lto/lto-lang.c (handle_fnspec_attribute): New static function.
|
||||
(lto_attribute_table): Add "fn spec".
|
||||
(DEF_ATTR_STRING): Define and undefine along with the other macros.
|
||||
* regcprop.c (struct kill_set_value_data): New.
|
||||
(kill_set_value): Interpret data as a pointer to such a struct.
|
||||
Do nothing if the caller wants the register to be ignored.
|
||||
(copyprop_hardreg_forward_1): Handle SETs in CALL_INSN_FUNCTION_USAGE.
|
||||
|
||||
2012-05-14 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/53340
|
||||
|
@ -5902,11 +5902,13 @@ enum built_in_attribute
|
||||
{
|
||||
#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
|
||||
#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
|
||||
#define DEF_ATTR_STRING(ENUM, VALUE) ENUM,
|
||||
#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
|
||||
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
|
||||
#include "builtin-attrs.def"
|
||||
#undef DEF_ATTR_NULL_TREE
|
||||
#undef DEF_ATTR_INT
|
||||
#undef DEF_ATTR_STRING
|
||||
#undef DEF_ATTR_IDENT
|
||||
#undef DEF_ATTR_TREE_LIST
|
||||
ATTR_LAST
|
||||
@ -5922,6 +5924,8 @@ install_builtin_attributes (void)
|
||||
built_in_attributes[(int) ENUM] = NULL_TREE;
|
||||
#define DEF_ATTR_INT(ENUM, VALUE) \
|
||||
built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE);
|
||||
#define DEF_ATTR_STRING(ENUM, VALUE) \
|
||||
built_in_attributes[(int) ENUM] = build_string (strlen (VALUE), VALUE);
|
||||
#define DEF_ATTR_IDENT(ENUM, STRING) \
|
||||
built_in_attributes[(int) ENUM] = get_identifier (STRING);
|
||||
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
|
||||
@ -5932,6 +5936,7 @@ install_builtin_attributes (void)
|
||||
#include "builtin-attrs.def"
|
||||
#undef DEF_ATTR_NULL_TREE
|
||||
#undef DEF_ATTR_INT
|
||||
#undef DEF_ATTR_STRING
|
||||
#undef DEF_ATTR_IDENT
|
||||
#undef DEF_ATTR_TREE_LIST
|
||||
}
|
||||
|
@ -312,8 +312,9 @@ decl_attributes (tree *node, tree attributes, int flags)
|
||||
|
||||
if (spec == NULL)
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute directive ignored",
|
||||
name);
|
||||
if (!(flags & (int) ATTR_FLAG_BUILT_IN))
|
||||
warning (OPT_Wattributes, "%qE attribute directive ignored",
|
||||
name);
|
||||
continue;
|
||||
}
|
||||
else if (list_length (args) < spec->min_length
|
||||
|
@ -59,6 +59,14 @@ DEF_ATTR_FOR_INT (5)
|
||||
DEF_ATTR_FOR_INT (6)
|
||||
#undef DEF_ATTR_FOR_INT
|
||||
|
||||
/* Construct a tree for a given string and a list containing it. */
|
||||
#define DEF_ATTR_FOR_STRING(ENUM, VALUE) \
|
||||
DEF_ATTR_STRING (ATTR_##ENUM, VALUE) \
|
||||
DEF_ATTR_TREE_LIST (ATTR_LIST_##ENUM, ATTR_NULL, \
|
||||
ATTR_##ENUM, ATTR_NULL)
|
||||
DEF_ATTR_FOR_STRING (STR1, "1")
|
||||
#undef DEF_ATTR_FOR_STRING
|
||||
|
||||
/* Construct a tree for a list of two integers. */
|
||||
#define DEF_LIST_INT_INT(VALUE1, VALUE2) \
|
||||
DEF_ATTR_TREE_LIST (ATTR_LIST_##VALUE1##_##VALUE2, ATTR_NULL, \
|
||||
@ -84,6 +92,7 @@ DEF_ATTR_IDENT (ATTR_NONNULL, "nonnull")
|
||||
DEF_ATTR_IDENT (ATTR_NORETURN, "noreturn")
|
||||
DEF_ATTR_IDENT (ATTR_NOTHROW, "nothrow")
|
||||
DEF_ATTR_IDENT (ATTR_LEAF, "leaf")
|
||||
DEF_ATTR_IDENT (ATTR_FNSPEC, "fn spec")
|
||||
DEF_ATTR_IDENT (ATTR_PRINTF, "printf")
|
||||
DEF_ATTR_IDENT (ATTR_ASM_FPRINTF, "asm_fprintf")
|
||||
DEF_ATTR_IDENT (ATTR_GCC_DIAG, "gcc_diag")
|
||||
@ -170,6 +179,10 @@ DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_5, ATTR_NONNULL, ATTR_LIST_5, \
|
||||
/* Nothrow const functions whose pointer parameter(s) are all nonnull. */
|
||||
DEF_ATTR_TREE_LIST (ATTR_CONST_NOTHROW_NONNULL, ATTR_CONST, ATTR_NULL, \
|
||||
ATTR_NOTHROW_NONNULL)
|
||||
/* Nothrow leaf functions whose pointer parameter(s) are all nonnull,
|
||||
and which return their first argument. */
|
||||
DEF_ATTR_TREE_LIST (ATTR_RET1_NOTHROW_NONNULL_LEAF, ATTR_FNSPEC, ATTR_LIST_STR1, \
|
||||
ATTR_NOTHROW_NONNULL_LEAF)
|
||||
/* Nothrow const leaf functions whose pointer parameter(s) are all nonnull. */
|
||||
DEF_ATTR_TREE_LIST (ATTR_CONST_NOTHROW_NONNULL_LEAF, ATTR_CONST, ATTR_NULL, \
|
||||
ATTR_NOTHROW_NONNULL_LEAF)
|
||||
|
@ -532,10 +532,10 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_BZERO, "bzero", BT_FN_VOID_PTR_SIZE, ATTR_NOTHR
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_INDEX, "index", BT_FN_STRING_CONST_STRING_INT, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMCHR, "memchr", BT_FN_PTR_CONST_PTR_INT_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMCMP, "memcmp", BT_FN_INT_CONST_PTR_CONST_PTR_SIZE, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMCPY, "memcpy", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMMOVE, "memmove", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMCPY, "memcpy", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMMOVE, "memmove", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMPCPY, "mempcpy", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMSET, "memset", BT_FN_PTR_PTR_INT_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_MEMSET, "memset", BT_FN_PTR_PTR_INT_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_RINDEX, "rindex", BT_FN_STRING_CONST_STRING_INT, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STPCPY, "stpcpy", BT_FN_STRING_STRING_CONST_STRING, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STPNCPY, "stpncpy", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
@ -543,7 +543,7 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_STRCASECMP, "strcasecmp", BT_FN_INT_CONST_STRIN
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCAT, "strcat", BT_FN_STRING_STRING_CONST_STRING, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCHR, "strchr", BT_FN_STRING_CONST_STRING_INT, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCMP, "strcmp", BT_FN_INT_CONST_STRING_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCPY, "strcpy", BT_FN_STRING_STRING_CONST_STRING, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCPY, "strcpy", BT_FN_STRING_STRING_CONST_STRING, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_STRCSPN, "strcspn", BT_FN_SIZE_CONST_STRING_CONST_STRING, ATTR_PURE_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRDUP, "strdup", BT_FN_STRING_CONST_STRING, ATTR_MALLOC_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRNDUP, "strndup", BT_FN_STRING_CONST_STRING_SIZE, ATTR_MALLOC_NOTHROW_NONNULL_LEAF)
|
||||
@ -757,8 +757,8 @@ DEF_BUILTIN_STUB (BUILT_IN_ALLOCA_WITH_ALIGN, "__builtin_alloca_with_align")
|
||||
|
||||
/* Object size checking builtins. */
|
||||
DEF_GCC_BUILTIN (BUILT_IN_OBJECT_SIZE, "object_size", BT_FN_SIZE_CONST_PTR_INT, ATTR_PURE_NOTHROW_LEAF_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMCPY_CHK, "__memcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMMOVE_CHK, "__memmove_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMCPY_CHK, "__memcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMMOVE_CHK, "__memmove_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_RET1_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMPCPY_CHK, "__mempcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMSET_CHK, "__memset_chk", BT_FN_PTR_PTR_INT_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_STPCPY_CHK, "__stpcpy_chk", BT_FN_STRING_STRING_CONST_STRING_SIZE, ATTR_NOTHROW_NONNULL_LEAF)
|
||||
|
@ -4603,11 +4603,13 @@ enum built_in_attribute
|
||||
{
|
||||
#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
|
||||
#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
|
||||
#define DEF_ATTR_STRING(ENUM, VALUE) ENUM,
|
||||
#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
|
||||
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
|
||||
#include "builtin-attrs.def"
|
||||
#undef DEF_ATTR_NULL_TREE
|
||||
#undef DEF_ATTR_INT
|
||||
#undef DEF_ATTR_STRING
|
||||
#undef DEF_ATTR_IDENT
|
||||
#undef DEF_ATTR_TREE_LIST
|
||||
ATTR_LAST
|
||||
@ -5926,6 +5928,8 @@ c_init_attributes (void)
|
||||
built_in_attributes[(int) ENUM] = NULL_TREE;
|
||||
#define DEF_ATTR_INT(ENUM, VALUE) \
|
||||
built_in_attributes[(int) ENUM] = build_int_cst (integer_type_node, VALUE);
|
||||
#define DEF_ATTR_STRING(ENUM, VALUE) \
|
||||
built_in_attributes[(int) ENUM] = build_string (strlen (VALUE), VALUE);
|
||||
#define DEF_ATTR_IDENT(ENUM, STRING) \
|
||||
built_in_attributes[(int) ENUM] = get_identifier (STRING);
|
||||
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
|
||||
|
@ -433,6 +433,8 @@ setup_save_areas (void)
|
||||
/* Create hard reg saved regs. */
|
||||
for (chain = reload_insn_chain; chain != 0; chain = next)
|
||||
{
|
||||
rtx cheap;
|
||||
|
||||
insn = chain->insn;
|
||||
next = chain->next;
|
||||
if (!CALL_P (insn)
|
||||
@ -466,6 +468,9 @@ setup_save_areas (void)
|
||||
new_saved_hard_reg (regno, freq);
|
||||
SET_HARD_REG_BIT (hard_regs_used, regno);
|
||||
}
|
||||
cheap = find_reg_note (insn, REG_RETURNED, NULL);
|
||||
if (cheap)
|
||||
cheap = XEXP (cheap, 0);
|
||||
/* Look through all live pseudos, mark their hard registers. */
|
||||
EXECUTE_IF_SET_IN_REG_SET
|
||||
(&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
|
||||
@ -473,7 +478,7 @@ setup_save_areas (void)
|
||||
int r = reg_renumber[regno];
|
||||
int bound;
|
||||
|
||||
if (r < 0)
|
||||
if (r < 0 || regno_reg_rtx[regno] == cheap)
|
||||
continue;
|
||||
|
||||
bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
|
||||
@ -508,12 +513,18 @@ setup_save_areas (void)
|
||||
memset (saved_reg_conflicts, 0, saved_regs_num * saved_regs_num);
|
||||
for (chain = reload_insn_chain; chain != 0; chain = next)
|
||||
{
|
||||
rtx cheap;
|
||||
call_saved_regs_num = 0;
|
||||
insn = chain->insn;
|
||||
next = chain->next;
|
||||
if (!CALL_P (insn)
|
||||
|| find_reg_note (insn, REG_NORETURN, NULL))
|
||||
continue;
|
||||
|
||||
cheap = find_reg_note (insn, REG_RETURNED, NULL);
|
||||
if (cheap)
|
||||
cheap = XEXP (cheap, 0);
|
||||
|
||||
REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
|
||||
&chain->live_throughout);
|
||||
COPY_HARD_REG_SET (used_regs, call_used_reg_set);
|
||||
@ -546,7 +557,7 @@ setup_save_areas (void)
|
||||
int r = reg_renumber[regno];
|
||||
int bound;
|
||||
|
||||
if (r < 0)
|
||||
if (r < 0 || regno_reg_rtx[regno] == cheap)
|
||||
continue;
|
||||
|
||||
bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
|
||||
@ -796,6 +807,11 @@ save_call_clobbered_regs (void)
|
||||
unsigned regno;
|
||||
HARD_REG_SET hard_regs_to_save;
|
||||
reg_set_iterator rsi;
|
||||
rtx cheap;
|
||||
|
||||
cheap = find_reg_note (insn, REG_RETURNED, NULL);
|
||||
if (cheap)
|
||||
cheap = XEXP (cheap, 0);
|
||||
|
||||
/* Use the register life information in CHAIN to compute which
|
||||
regs are live during the call. */
|
||||
@ -817,7 +833,7 @@ save_call_clobbered_regs (void)
|
||||
int nregs;
|
||||
enum machine_mode mode;
|
||||
|
||||
if (r < 0)
|
||||
if (r < 0 || regno_reg_rtx[regno] == cheap)
|
||||
continue;
|
||||
nregs = hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
|
||||
mode = HARD_REGNO_CALLER_SAVE_MODE
|
||||
@ -851,6 +867,17 @@ save_call_clobbered_regs (void)
|
||||
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
|
||||
if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
|
||||
n_regs_saved++;
|
||||
|
||||
if (cheap
|
||||
&& HARD_REGISTER_P (cheap)
|
||||
&& TEST_HARD_REG_BIT (call_used_reg_set, REGNO (cheap)))
|
||||
{
|
||||
rtx call_set = single_set (insn);
|
||||
rtx dest = SET_DEST (call_set);
|
||||
rtx pat = gen_rtx_SET (VOIDmode, cheap,
|
||||
copy_rtx (dest));
|
||||
chain = insert_one_insn (chain, 0, -1, pat);
|
||||
}
|
||||
}
|
||||
last = chain;
|
||||
}
|
||||
|
53
gcc/calls.c
53
gcc/calls.c
@ -574,6 +574,41 @@ special_function_p (const_tree fndecl, int flags)
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Similar to special_function_p; return a set of ERF_ flags for the
|
||||
function FNDECL. */
|
||||
static int
|
||||
decl_return_flags (tree fndecl)
|
||||
{
|
||||
tree attr;
|
||||
tree type = TREE_TYPE (fndecl);
|
||||
if (!type)
|
||||
return 0;
|
||||
|
||||
attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
|
||||
if (!attr)
|
||||
return 0;
|
||||
|
||||
attr = TREE_VALUE (TREE_VALUE (attr));
|
||||
if (!attr || TREE_STRING_LENGTH (attr) < 1)
|
||||
return 0;
|
||||
|
||||
switch (TREE_STRING_POINTER (attr)[0])
|
||||
{
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
return ERF_RETURNS_ARG | (TREE_STRING_POINTER (attr)[0] - '1');
|
||||
|
||||
case 'm':
|
||||
return ERF_NOALIAS;
|
||||
|
||||
case '.':
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return nonzero when FNDECL represents a call to setjmp. */
|
||||
|
||||
int
|
||||
@ -2247,8 +2282,9 @@ expand_call (tree exp, rtx target, int ignore)
|
||||
(on machines that lack push insns), or 0 if space not preallocated. */
|
||||
rtx argblock = 0;
|
||||
|
||||
/* Mask of ECF_ flags. */
|
||||
/* Mask of ECF_ and ERF_ flags. */
|
||||
int flags = 0;
|
||||
int return_flags = 0;
|
||||
#ifdef REG_PARM_STACK_SPACE
|
||||
/* Define the boundary of the register parm stack space that needs to be
|
||||
saved, if any. */
|
||||
@ -2293,6 +2329,7 @@ expand_call (tree exp, rtx target, int ignore)
|
||||
{
|
||||
fntype = TREE_TYPE (fndecl);
|
||||
flags |= flags_from_decl_or_type (fndecl);
|
||||
return_flags |= decl_return_flags (fndecl);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3105,6 +3142,20 @@ expand_call (tree exp, rtx target, int ignore)
|
||||
VOIDmode, void_type_node,
|
||||
true);
|
||||
|
||||
if (pass == 1 && (return_flags & ERF_RETURNS_ARG))
|
||||
{
|
||||
int arg_nr = return_flags & ERF_RETURN_ARG_MASK;
|
||||
if (PUSH_ARGS_REVERSED)
|
||||
arg_nr = num_actuals - arg_nr - 1;
|
||||
if (args[arg_nr].reg
|
||||
&& valreg
|
||||
&& REG_P (valreg)
|
||||
&& GET_MODE (args[arg_nr].reg) == GET_MODE (valreg))
|
||||
call_fusage
|
||||
= gen_rtx_EXPR_LIST (TYPE_MODE (TREE_TYPE (args[arg_nr].tree_value)),
|
||||
gen_rtx_SET (VOIDmode, valreg, args[arg_nr].reg),
|
||||
call_fusage);
|
||||
}
|
||||
/* All arguments and registers used for the call must be set up by
|
||||
now! */
|
||||
|
||||
|
@ -4312,7 +4312,8 @@ canonicalize_insn (rtx insn, struct set **psets, int n_sets)
|
||||
if (CALL_P (insn))
|
||||
{
|
||||
for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
|
||||
XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
|
||||
if (GET_CODE (XEXP (tem, 0)) != SET)
|
||||
XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
|
||||
}
|
||||
|
||||
if (GET_CODE (x) == SET && GET_CODE (SET_SRC (x)) == CALL)
|
||||
|
@ -3455,20 +3455,26 @@ unpredictably.
|
||||
@code{call_insn} insns have the same extra fields as @code{insn} insns,
|
||||
accessed in the same way and in addition contain a field
|
||||
@code{CALL_INSN_FUNCTION_USAGE}, which contains a list (chain of
|
||||
@code{expr_list} expressions) containing @code{use} and @code{clobber}
|
||||
expressions that denote hard registers and @code{MEM}s used or
|
||||
clobbered by the called function.
|
||||
@code{expr_list} expressions) containing @code{use}, @code{clobber} and
|
||||
sometimes @code{set} expressions that denote hard registers and
|
||||
@code{mem}s used or clobbered by the called function.
|
||||
|
||||
A @code{MEM} generally points to a stack slots in which arguments passed
|
||||
A @code{mem} generally points to a stack slot in which arguments passed
|
||||
to the libcall by reference (@pxref{Register Arguments,
|
||||
TARGET_PASS_BY_REFERENCE}) are stored. If the argument is
|
||||
caller-copied (@pxref{Register Arguments, TARGET_CALLEE_COPIES}),
|
||||
the stack slot will be mentioned in @code{CLOBBER} and @code{USE}
|
||||
entries; if it's callee-copied, only a @code{USE} will appear, and the
|
||||
@code{MEM} may point to addresses that are not stack slots.
|
||||
the stack slot will be mentioned in @code{clobber} and @code{use}
|
||||
entries; if it's callee-copied, only a @code{use} will appear, and the
|
||||
@code{mem} may point to addresses that are not stack slots.
|
||||
|
||||
@code{CLOBBER}ed registers in this list augment registers specified in
|
||||
@code{CALL_USED_REGISTERS} (@pxref{Register Basics}).
|
||||
Registers occurring inside a @code{clobber} in this list augment
|
||||
registers specified in @code{CALL_USED_REGISTERS} (@pxref{Register
|
||||
Basics}).
|
||||
|
||||
If the list contains a @code{set} involving two registers, it indicates
|
||||
that the function returns one of its arguments. Such a @code{set} may
|
||||
look like a no-op if the same register holds the argument and the return
|
||||
value.
|
||||
|
||||
@findex code_label
|
||||
@findex CODE_LABEL_NUMBER
|
||||
|
12
gcc/expr.c
12
gcc/expr.c
@ -1386,7 +1386,7 @@ init_block_move_fn (const char *asmspec)
|
||||
{
|
||||
if (!block_move_fn)
|
||||
{
|
||||
tree args, fn;
|
||||
tree args, fn, attrs, attr_args;
|
||||
|
||||
fn = get_identifier ("memcpy");
|
||||
args = build_function_type_list (ptr_type_node, ptr_type_node,
|
||||
@ -1401,6 +1401,11 @@ init_block_move_fn (const char *asmspec)
|
||||
DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT;
|
||||
DECL_VISIBILITY_SPECIFIED (fn) = 1;
|
||||
|
||||
attr_args = build_tree_list (NULL_TREE, build_string (1, "1"));
|
||||
attrs = tree_cons (get_identifier ("fn spec"), attr_args, NULL);
|
||||
|
||||
decl_attributes (&fn, attrs, ATTR_FLAG_BUILT_IN);
|
||||
|
||||
block_move_fn = fn;
|
||||
}
|
||||
|
||||
@ -8190,10 +8195,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
|
||||
|| DECL_RTL (treeop1) == stack_pointer_rtx
|
||||
|| DECL_RTL (treeop1) == arg_pointer_rtx))
|
||||
{
|
||||
tree t = treeop1;
|
||||
|
||||
treeop1 = TREE_OPERAND (treeop0, 0);
|
||||
TREE_OPERAND (treeop0, 0) = t;
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* If the result is to be ptr_mode and we are adding an integer to
|
||||
|
@ -508,6 +508,7 @@ ira_create_allocno (int regno, bool cap_p,
|
||||
ALLOCNO_HARD_REGNO (a) = -1;
|
||||
ALLOCNO_CALL_FREQ (a) = 0;
|
||||
ALLOCNO_CALLS_CROSSED_NUM (a) = 0;
|
||||
ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a) = 0;
|
||||
#ifdef STACK_REGS
|
||||
ALLOCNO_NO_STACK_REG_P (a) = false;
|
||||
ALLOCNO_TOTAL_NO_STACK_REG_P (a) = false;
|
||||
@ -904,6 +905,7 @@ create_cap_allocno (ira_allocno_t a)
|
||||
merge_hard_reg_conflicts (a, cap, false);
|
||||
|
||||
ALLOCNO_CALLS_CROSSED_NUM (cap) = ALLOCNO_CALLS_CROSSED_NUM (a);
|
||||
ALLOCNO_CHEAP_CALLS_CROSSED_NUM (cap) = ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a);
|
||||
if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
|
||||
{
|
||||
fprintf (ira_dump_file, " Creating cap ");
|
||||
@ -1707,6 +1709,8 @@ propagate_allocno_info (void)
|
||||
merge_hard_reg_conflicts (a, parent_a, true);
|
||||
ALLOCNO_CALLS_CROSSED_NUM (parent_a)
|
||||
+= ALLOCNO_CALLS_CROSSED_NUM (a);
|
||||
ALLOCNO_CHEAP_CALLS_CROSSED_NUM (parent_a)
|
||||
+= ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a);
|
||||
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a)
|
||||
+= ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a);
|
||||
aclass = ALLOCNO_CLASS (a);
|
||||
@ -2082,6 +2086,8 @@ propagate_some_info_from_allocno (ira_allocno_t a, ira_allocno_t from_a)
|
||||
ALLOCNO_FREQ (a) += ALLOCNO_FREQ (from_a);
|
||||
ALLOCNO_CALL_FREQ (a) += ALLOCNO_CALL_FREQ (from_a);
|
||||
ALLOCNO_CALLS_CROSSED_NUM (a) += ALLOCNO_CALLS_CROSSED_NUM (from_a);
|
||||
ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a)
|
||||
+= ALLOCNO_CHEAP_CALLS_CROSSED_NUM (from_a);
|
||||
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a)
|
||||
+= ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (from_a);
|
||||
if (! ALLOCNO_BAD_SPILL_P (from_a))
|
||||
@ -2709,6 +2715,8 @@ copy_info_to_removed_store_destinations (int regno)
|
||||
ALLOCNO_CALL_FREQ (parent_a) += ALLOCNO_CALL_FREQ (a);
|
||||
ALLOCNO_CALLS_CROSSED_NUM (parent_a)
|
||||
+= ALLOCNO_CALLS_CROSSED_NUM (a);
|
||||
ALLOCNO_CHEAP_CALLS_CROSSED_NUM (parent_a)
|
||||
+= ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a);
|
||||
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a)
|
||||
+= ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a);
|
||||
merged_p = true;
|
||||
@ -2804,6 +2812,8 @@ ira_flattening (int max_regno_before_emit, int ira_max_point_before_emit)
|
||||
ALLOCNO_CALL_FREQ (parent_a) -= ALLOCNO_CALL_FREQ (a);
|
||||
ALLOCNO_CALLS_CROSSED_NUM (parent_a)
|
||||
-= ALLOCNO_CALLS_CROSSED_NUM (a);
|
||||
ALLOCNO_CHEAP_CALLS_CROSSED_NUM (parent_a)
|
||||
-= ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a);
|
||||
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (parent_a)
|
||||
-= ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a);
|
||||
ira_assert (ALLOCNO_CALLS_CROSSED_NUM (parent_a) >= 0
|
||||
|
@ -2107,7 +2107,8 @@ ira_tune_allocno_costs (void)
|
||||
mode = ALLOCNO_MODE (a);
|
||||
n = ira_class_hard_regs_num[aclass];
|
||||
min_cost = INT_MAX;
|
||||
if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
|
||||
if (ALLOCNO_CALLS_CROSSED_NUM (a)
|
||||
!= ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a))
|
||||
{
|
||||
ira_allocate_and_set_costs
|
||||
(&ALLOCNO_HARD_REG_COSTS (a), aclass,
|
||||
|
@ -376,6 +376,9 @@ struct ira_allocno
|
||||
int call_freq;
|
||||
/* Accumulated number of the intersected calls. */
|
||||
int calls_crossed_num;
|
||||
/* The number of calls across which it is live, but which should not
|
||||
affect register preferences. */
|
||||
int cheap_calls_crossed_num;
|
||||
/* Array of usage costs (accumulated and the one updated during
|
||||
coloring) for each hard register of the allocno class. The
|
||||
member value can be NULL if all costs are the same and equal to
|
||||
@ -418,6 +421,7 @@ struct ira_allocno
|
||||
#define ALLOCNO_HARD_REGNO(A) ((A)->hard_regno)
|
||||
#define ALLOCNO_CALL_FREQ(A) ((A)->call_freq)
|
||||
#define ALLOCNO_CALLS_CROSSED_NUM(A) ((A)->calls_crossed_num)
|
||||
#define ALLOCNO_CHEAP_CALLS_CROSSED_NUM(A) ((A)->cheap_calls_crossed_num)
|
||||
#define ALLOCNO_MEM_OPTIMIZED_DEST(A) ((A)->mem_optimized_dest)
|
||||
#define ALLOCNO_MEM_OPTIMIZED_DEST_P(A) ((A)->mem_optimized_dest_p)
|
||||
#define ALLOCNO_SOMEWHERE_RENAMED_P(A) ((A)->somewhere_renamed_p)
|
||||
|
@ -241,6 +241,24 @@ dec_register_pressure (enum reg_class pclass, int nregs)
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine from the objects_live bitmap whether REGNO is currently live,
|
||||
and occupies only one object. Return false if we have no information. */
|
||||
static bool
|
||||
pseudo_regno_single_word_and_live_p (int regno)
|
||||
{
|
||||
ira_allocno_t a = ira_curr_regno_allocno_map[regno];
|
||||
ira_object_t obj;
|
||||
|
||||
if (a == NULL)
|
||||
return false;
|
||||
if (ALLOCNO_NUM_OBJECTS (a) > 1)
|
||||
return false;
|
||||
|
||||
obj = ALLOCNO_OBJECT (a, 0);
|
||||
|
||||
return sparseset_bit_p (objects_live, OBJECT_CONFLICT_ID (obj));
|
||||
}
|
||||
|
||||
/* Mark the pseudo register REGNO as live. Update all information about
|
||||
live ranges and register pressure. */
|
||||
static void
|
||||
@ -1043,6 +1061,67 @@ bb_has_abnormal_call_pred (basic_block bb)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Look through the CALL_INSN_FUNCTION_USAGE of a call insn INSN, and see if
|
||||
we find a SET rtx that we can use to deduce that a register can be cheaply
|
||||
caller-saved. Return such a register, or NULL_RTX if none is found. */
|
||||
static rtx
|
||||
find_call_crossed_cheap_reg (rtx insn)
|
||||
{
|
||||
rtx cheap_reg = NULL_RTX;
|
||||
rtx exp = CALL_INSN_FUNCTION_USAGE (insn);
|
||||
|
||||
while (exp != NULL)
|
||||
{
|
||||
rtx x = XEXP (exp, 0);
|
||||
if (GET_CODE (x) == SET)
|
||||
{
|
||||
exp = x;
|
||||
break;
|
||||
}
|
||||
exp = XEXP (exp, 1);
|
||||
}
|
||||
if (exp != NULL)
|
||||
{
|
||||
basic_block bb = BLOCK_FOR_INSN (insn);
|
||||
rtx reg = SET_SRC (exp);
|
||||
rtx prev = PREV_INSN (insn);
|
||||
while (prev && !(INSN_P (prev)
|
||||
&& BLOCK_FOR_INSN (prev) != bb))
|
||||
{
|
||||
if (NONDEBUG_INSN_P (prev))
|
||||
{
|
||||
rtx set = single_set (prev);
|
||||
|
||||
if (set && rtx_equal_p (SET_DEST (set), reg))
|
||||
{
|
||||
rtx src = SET_SRC (set);
|
||||
if (!REG_P (src) || HARD_REGISTER_P (src)
|
||||
|| !pseudo_regno_single_word_and_live_p (REGNO (src)))
|
||||
break;
|
||||
if (!modified_between_p (src, prev, insn))
|
||||
cheap_reg = src;
|
||||
break;
|
||||
}
|
||||
if (set && rtx_equal_p (SET_SRC (set), reg))
|
||||
{
|
||||
rtx dest = SET_DEST (set);
|
||||
if (!REG_P (dest) || HARD_REGISTER_P (dest)
|
||||
|| !pseudo_regno_single_word_and_live_p (REGNO (dest)))
|
||||
break;
|
||||
if (!modified_between_p (dest, prev, insn))
|
||||
cheap_reg = dest;
|
||||
break;
|
||||
}
|
||||
|
||||
if (reg_overlap_mentioned_p (reg, PATTERN (prev)))
|
||||
break;
|
||||
}
|
||||
prev = PREV_INSN (prev);
|
||||
}
|
||||
}
|
||||
return cheap_reg;
|
||||
}
|
||||
|
||||
/* Process insns of the basic block given by its LOOP_TREE_NODE to
|
||||
update allocno live ranges, allocno hard register conflicts,
|
||||
intersected calls, and register pressure info for allocnos for the
|
||||
@ -1185,6 +1264,13 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
|
||||
|
||||
if (call_p)
|
||||
{
|
||||
/* Try to find a SET in the CALL_INSN_FUNCTION_USAGE, and from
|
||||
there, try to find a pseudo that is live across the call but
|
||||
can be cheaply reconstructed from the return value. */
|
||||
rtx cheap_reg = find_call_crossed_cheap_reg (insn);
|
||||
if (cheap_reg != NULL_RTX)
|
||||
add_reg_note (insn, REG_RETURNED, cheap_reg);
|
||||
|
||||
last_call_num++;
|
||||
sparseset_clear (allocnos_processed);
|
||||
/* The current set of live allocnos are live across the call. */
|
||||
@ -1226,6 +1312,9 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
|
||||
/* Mark it as saved at the next call. */
|
||||
allocno_saved_at_call[num] = last_call_num + 1;
|
||||
ALLOCNO_CALLS_CROSSED_NUM (a)++;
|
||||
if (cheap_reg != NULL_RTX
|
||||
&& ALLOCNO_REGNO (a) == (int) REGNO (cheap_reg))
|
||||
ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a)++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1962,6 +1962,8 @@ setup_reg_renumber (void)
|
||||
call_used_reg_set))
|
||||
{
|
||||
ira_assert (!optimize || flag_caller_saves
|
||||
|| (ALLOCNO_CALLS_CROSSED_NUM (a)
|
||||
== ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a))
|
||||
|| regno >= ira_reg_equiv_len
|
||||
|| ira_reg_equiv_const[regno]
|
||||
|| ira_reg_equiv_invariant_p[regno]);
|
||||
|
@ -53,6 +53,7 @@ static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree ignore_attribute (tree *, tree, tree, int, bool *);
|
||||
|
||||
static tree handle_format_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
|
||||
|
||||
/* Table of machine-independent attributes supported in GIMPLE. */
|
||||
@ -83,6 +84,8 @@ const struct attribute_spec lto_attribute_table[] =
|
||||
handle_sentinel_attribute, false },
|
||||
{ "type generic", 0, 0, false, true, true,
|
||||
handle_type_generic_attribute, false },
|
||||
{ "fn spec", 1, 1, false, true, true,
|
||||
handle_fnspec_attribute, false },
|
||||
{ "transaction_pure", 0, 0, false, true, true,
|
||||
handle_transaction_pure_attribute, false },
|
||||
/* For internal use only. The leading '*' both prevents its usage in
|
||||
@ -110,11 +113,13 @@ enum built_in_attribute
|
||||
{
|
||||
#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
|
||||
#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
|
||||
#define DEF_ATTR_STRING(ENUM, VALUE) ENUM,
|
||||
#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
|
||||
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
|
||||
#include "builtin-attrs.def"
|
||||
#undef DEF_ATTR_NULL_TREE
|
||||
#undef DEF_ATTR_INT
|
||||
#undef DEF_ATTR_STRING
|
||||
#undef DEF_ATTR_IDENT
|
||||
#undef DEF_ATTR_TREE_LIST
|
||||
ATTR_LAST
|
||||
@ -483,6 +488,20 @@ handle_format_arg_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
|
||||
}
|
||||
|
||||
|
||||
/* Handle a "fn spec" attribute; arguments as in
|
||||
struct attribute_spec.handler. */
|
||||
|
||||
static tree
|
||||
handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
|
||||
tree args, int ARG_UNUSED (flags),
|
||||
bool *no_add_attrs ATTRIBUTE_UNUSED)
|
||||
{
|
||||
gcc_assert (args
|
||||
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST
|
||||
&& !TREE_CHAIN (args));
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Cribbed from c-common.c. */
|
||||
|
||||
static void
|
||||
@ -568,6 +587,8 @@ lto_init_attributes (void)
|
||||
built_in_attributes[(int) ENUM] = NULL_TREE;
|
||||
#define DEF_ATTR_INT(ENUM, VALUE) \
|
||||
built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE);
|
||||
#define DEF_ATTR_STRING(ENUM, VALUE) \
|
||||
built_in_attributes[(int) ENUM] = build_string (strlen (VALUE), VALUE);
|
||||
#define DEF_ATTR_IDENT(ENUM, STRING) \
|
||||
built_in_attributes[(int) ENUM] = get_identifier (STRING);
|
||||
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
|
||||
@ -578,6 +599,7 @@ lto_init_attributes (void)
|
||||
#include "builtin-attrs.def"
|
||||
#undef DEF_ATTR_NULL_TREE
|
||||
#undef DEF_ATTR_INT
|
||||
#undef DEF_ATTR_STRING
|
||||
#undef DEF_ATTR_IDENT
|
||||
#undef DEF_ATTR_TREE_LIST
|
||||
}
|
||||
|
@ -1358,8 +1358,10 @@ reload_combine (void)
|
||||
for (link = CALL_INSN_FUNCTION_USAGE (insn); link;
|
||||
link = XEXP (link, 1))
|
||||
{
|
||||
rtx usage_rtx = XEXP (XEXP (link, 0), 0);
|
||||
if (REG_P (usage_rtx))
|
||||
rtx setuse = XEXP (link, 0);
|
||||
rtx usage_rtx = XEXP (setuse, 0);
|
||||
if ((GET_CODE (setuse) == USE || GET_CODE (setuse) == CLOBBER)
|
||||
&& REG_P (usage_rtx))
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int start_reg = REGNO (usage_rtx);
|
||||
|
@ -212,3 +212,8 @@ REG_NOTE (TM)
|
||||
for pushed arguments. This will only be generated when
|
||||
ACCUMULATE_OUTGOING_ARGS is false. */
|
||||
REG_NOTE (ARGS_SIZE)
|
||||
|
||||
/* Used for communication between IRA and caller-save.c, indicates
|
||||
that the return value of a call can be used to reinitialize a
|
||||
pseudo reg. */
|
||||
REG_NOTE (RETURNED)
|
||||
|
@ -254,18 +254,27 @@ kill_clobbered_value (rtx x, const_rtx set, void *data)
|
||||
kill_value (x, vd);
|
||||
}
|
||||
|
||||
/* A structure passed as data to kill_set_value through note_stores. */
|
||||
struct kill_set_value_data
|
||||
{
|
||||
struct value_data *vd;
|
||||
rtx ignore_set_reg;
|
||||
};
|
||||
|
||||
/* Called through note_stores. If X is set, not clobbered, kill its
|
||||
current value and install it as the root of its own value list. */
|
||||
|
||||
static void
|
||||
kill_set_value (rtx x, const_rtx set, void *data)
|
||||
{
|
||||
struct value_data *const vd = (struct value_data *) data;
|
||||
struct kill_set_value_data *ksvd = (struct kill_set_value_data *) data;
|
||||
if (rtx_equal_p (x, ksvd->ignore_set_reg))
|
||||
return;
|
||||
if (GET_CODE (set) != CLOBBER)
|
||||
{
|
||||
kill_value (x, vd);
|
||||
kill_value (x, ksvd->vd);
|
||||
if (REG_P (x))
|
||||
set_value_regno (REGNO (x), GET_MODE (x), vd);
|
||||
set_value_regno (REGNO (x), GET_MODE (x), ksvd->vd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -743,6 +752,7 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
|
||||
rtx set;
|
||||
bool replaced[MAX_RECOG_OPERANDS];
|
||||
bool changed = false;
|
||||
struct kill_set_value_data ksvd;
|
||||
|
||||
if (!NONDEBUG_INSN_P (insn))
|
||||
{
|
||||
@ -976,14 +986,39 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
|
||||
note_uses (&PATTERN (insn), cprop_find_used_regs, vd);
|
||||
}
|
||||
|
||||
ksvd.vd = vd;
|
||||
ksvd.ignore_set_reg = NULL_RTX;
|
||||
|
||||
/* Clobber call-clobbered registers. */
|
||||
if (CALL_P (insn))
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
|
||||
kill_value_regno (i, 1, vd);
|
||||
{
|
||||
int set_regno = INVALID_REGNUM;
|
||||
int set_nregs = 0;
|
||||
rtx exp;
|
||||
for (exp = CALL_INSN_FUNCTION_USAGE (insn); exp; exp = XEXP (exp, 1))
|
||||
{
|
||||
rtx x = XEXP (exp, 0);
|
||||
if (GET_CODE (x) == SET)
|
||||
{
|
||||
rtx dest = SET_DEST (x);
|
||||
kill_value (dest, vd);
|
||||
set_value_regno (REGNO (dest), GET_MODE (dest), vd);
|
||||
copy_value (dest, SET_SRC (x), vd);
|
||||
ksvd.ignore_set_reg = dest;
|
||||
set_regno = REGNO (dest);
|
||||
set_nregs
|
||||
= hard_regno_nregs[set_regno][GET_MODE (dest)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||
if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)
|
||||
&& (i < set_regno || i >= set_regno + set_nregs))
|
||||
kill_value_regno (i, 1, vd);
|
||||
}
|
||||
|
||||
/* Notice stores. */
|
||||
note_stores (PATTERN (insn), kill_set_value, vd);
|
||||
note_stores (PATTERN (insn), kill_set_value, &ksvd);
|
||||
|
||||
/* Notice copies. */
|
||||
if (set && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set)))
|
||||
|
@ -2870,7 +2870,7 @@ sched_analyze_insn (struct deps_desc *deps, rtx x, rtx insn)
|
||||
{
|
||||
if (GET_CODE (XEXP (link, 0)) == CLOBBER)
|
||||
sched_analyze_1 (deps, XEXP (link, 0), insn);
|
||||
else
|
||||
else if (GET_CODE (XEXP (link, 0)) != SET)
|
||||
sched_analyze_2 (deps, XEXP (link, 0), insn);
|
||||
}
|
||||
/* Don't schedule anything after a tail call, tail call needs
|
||||
|
@ -1,3 +1,7 @@
|
||||
2012-05-14 Bernd Schmidt <bernds@codesourcery.com>
|
||||
|
||||
* gcc.target/i386/retarg.c: New test.
|
||||
|
||||
2012-05-13 Alessandro Fanfarillo <fanfarillo.gcc@gmail.com>
|
||||
|
||||
PR fortran/45170
|
||||
|
13
gcc/testsuite/gcc.target/i386/retarg.c
Normal file
13
gcc/testsuite/gcc.target/i386/retarg.c
Normal file
@ -0,0 +1,13 @@
|
||||
/* { dg-require-effective-target lp64 } */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void *p (void *x, void *y, int z)
|
||||
{
|
||||
memcpy (x, y, z);
|
||||
return x;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler-not "%rdi" } } */
|
Loading…
x
Reference in New Issue
Block a user