]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
* attribs.c (decl_attributes): Avoid emitting a warning if
authorbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 May 2012 12:08:31 +0000 (12:08 +0000)
committerbernds <bernds@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 May 2012 12:08:31 +0000 (12:08 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@187459 138bc75d-0d04-0410-961f-82ee72b054a4

23 files changed:
gcc/ChangeLog
gcc/ada/gcc-interface/utils.c
gcc/attribs.c
gcc/builtin-attrs.def
gcc/builtins.def
gcc/c-family/c-common.c
gcc/caller-save.c
gcc/calls.c
gcc/cse.c
gcc/doc/rtl.texi
gcc/expr.c
gcc/ira-build.c
gcc/ira-costs.c
gcc/ira-int.h
gcc/ira-lives.c
gcc/ira.c
gcc/lto/lto-lang.c
gcc/postreload.c
gcc/reg-notes.def
gcc/regcprop.c
gcc/sched-deps.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/retarg.c [new file with mode: 0644]

index b517b048705945bfd9b80fe759f98fd924ee6066..bd8f7759033248e5250c7f61aea3f6c0506d7b1a 100644 (file)
@@ -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
index 5d264e01ac3759f03310a2a7d7ac13400166d9be..ce480208f99748ed18baa270e095bd42b74f4af1 100644 (file)
@@ -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
 }
index 0e94fd29cb55da9b7be5f42e11e0a5b0427413ef..d3af4141f4e4660f0262dd2b06d00bada26df112 100644 (file)
@@ -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
index c3132cc4138799e5f911f94b0dbde01ee005d6e2..9eb5e71c9b4eef452b37e4b734e705a3ad487125 100644 (file)
@@ -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)
index d03e41092b8744bc0ee31722652959325a4109f0..de45724998eaeb97907ebfbeb11fcd3810791398 100644 (file)
@@ -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)
index ad988286ee66b6f9a0aef43587064b45c106580c..f32a94a7c65a14d3f0253ccacb06efaf85f88eb5 100644 (file)
@@ -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)        \
index 39bccc4fc8e65b2d8531cf0e50c219f63d54ae8c..c8f3b145946e9060db28504bd42fcb415bab9063 100644 (file)
@@ -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;
        }
index a01c4233357041a07418994b3a05b162063465c3..03c92168a24e5c76015e7189ac2f888002edd623 100644 (file)
@@ -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!  */
 
index a8df74b0be024d93b3dcaea20af0b286f27a4329..0ad7b2e2a46cd141c4e6ddacedbb9e013f95a954 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -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)
index 82eb216292780e5b5920596f18e94d5643e91973..3f8c094bfa0a329b0e3750ad3efd7437a4814883 100644 (file)
@@ -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.
-
-@code{CLOBBER}ed registers in this list augment registers specified in
-@code{CALL_USED_REGISTERS} (@pxref{Register Basics}).
+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.
+
+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
index 3edb4a27d9edc3fce75c7bbb71a5e4397c1c2146..0d52725ae070c0f1a4c25aa2fcf4d8b8022499c8 100644 (file)
@@ -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
index 78d0b36acda431e8082ffda67a27939193804fa8..2edab52b1e5ca7992cf57e25e42b3d7de8b7e137 100644 (file)
@@ -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
index 1199763aeb377c36dcd34123894b1b6e6b4b4718..5d061942f8367c59e901486752530525eb9e037e 100644 (file)
@@ -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,
index 5db2ccc268c4163bf8906435dd3acc98405c4b60..02bec132614c3da9a7798bc31b7c4428b9735335 100644 (file)
@@ -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)
index f639e12449bdc1365f16bc4410707ff4310a4d32..ad451f5b3f971ee73e684d845f6e5784f8ed001d 100644 (file)
@@ -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)++;
                }
            }
 
index f0d885c88134d6c12c388a9fbd0c20526f2693ca..4d1ff0efb3a091929965833eb7de1fef08629e6c 100644 (file)
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -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]);
index 740193074c648611dbec0425ea6104f84ae7d5df..280d88359deae2a727a9973273a8a0a4cbb91197 100644 (file)
@@ -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
 }
index 751483e26fbc5a62b48fc42e94cf837618c2b0f6..7f333063e19879a477fbd3b74d6ea901c40d5781 100644 (file)
@@ -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);
index f2f097385a6ea01f3f0adffb87f81bdc1811a079..640abb217d5ff44a9f6c6fe754c134cd738328fb 100644 (file)
@@ -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)
index ceb46355359eaaa818c28e70902ab986d5aa7144..4d6ea29f7f7c2c9055e775e289ee7c704afdbfcf 100644 (file)
@@ -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)))
index be45c6afa168a0f686c385294a1553b3d65bbc32..fece83ec3937c222233498d6cfa345ba0ad892bf 100644 (file)
@@ -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
index 9a34ac44c358448afa6217a25e776fb8d27436b3..8b90aa8daffd16d891b5372d9b3a655b61b0990e 100644 (file)
@@ -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
diff --git a/gcc/testsuite/gcc.target/i386/retarg.c b/gcc/testsuite/gcc.target/i386/retarg.c
new file mode 100644 (file)
index 0000000..3af770d
--- /dev/null
@@ -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" } } */