aarch64.c (aarch64_simd_call_p): New function.
authorSteve Ellcey <sellcey@marvell.com>
Fri, 11 Jan 2019 16:50:17 +0000 (16:50 +0000)
committerSteve Ellcey <sje@gcc.gnu.org>
Fri, 11 Jan 2019 16:50:17 +0000 (16:50 +0000)
2019-01-11  Steve Ellcey  <sellcey@marvell.com>

* config/aarch64/aarch64.c (aarch64_simd_call_p): New function.
(aarch64_hard_regno_call_part_clobbered): Add insn argument.
(aarch64_return_call_with_max_clobbers): New function.
(TARGET_RETURN_CALL_WITH_MAX_CLOBBERS): New macro.
* config/avr/avr.c (avr_hard_regno_call_part_clobbered): Add insn
argument.
* config/i386/i386.c (ix86_hard_regno_call_part_clobbered): Ditto.
* config/mips/mips.c (mips_hard_regno_call_part_clobbered): Ditto.
* config/rs6000/rs6000.c (rs6000_hard_regno_call_part_clobbered): Ditto.
* config/s390/s390.c (s390_hard_regno_call_part_clobbered): Ditto.
* cselib.c (cselib_process_insn): Add argument to
targetm.hard_regno_call_part_clobbered call.
* ira-conflicts.c (ira_build_conflicts): Ditto.
* ira-costs.c (ira_tune_allocno_costs): Ditto.
* lra-constraints.c (inherit_reload_reg): Ditto.
* lra-int.h (struct lra_reg): Add call_insn field, remove call_p field.
* lra-lives.c (check_pseudos_live_through_calls): Add call_insn
argument.  Call targetm.return_call_with_max_clobbers.
Add argument to targetm.hard_regno_call_part_clobbered call.
(calls_have_same_clobbers_p): New function.
(process_bb_lives): Add call_insn and last_call_insn variables.
Pass call_insn to check_pseudos_live_through_calls.
Modify if stmt to check targetm.return_call_with_max_clobbers.
Update setting of flush variable.
(lra_create_live_ranges_1): Set call_insn to NULL instead of call_p
to false.
* lra.c (initialize_lra_reg_info_element): Set call_insn to NULL.
* regcprop.c (copyprop_hardreg_forward_1): Add argument to
        targetm.hard_regno_call_part_clobbered call.
* reginfo.c (choose_hard_reg_mode): Ditto.
* regrename.c (check_new_reg_p): Ditto.
* reload.c (find_equiv_reg): Ditto.
* reload1.c (emit_reload_insns): Ditto.
* sched-deps.c (deps_analyze_insn): Ditto.
* sel-sched.c (init_regs_for_mode): Ditto.
(mark_unavailable_hard_regs): Ditto.
* targhooks.c (default_dwarf_frame_reg_mode): Ditto.
* target.def (hard_regno_call_part_clobbered): Add insn argument.
(return_call_with_max_clobbers): New target function.
* doc/tm.texi: Regenerate.
* doc/tm.texi.in (TARGET_RETURN_CALL_WITH_MAX_CLOBBERS): New hook.
* hooks.c (hook_bool_uint_mode_false): Change to
hook_bool_insn_uint_mode_false.
* hooks.h (hook_bool_uint_mode_false): Ditto.

From-SVN: r267848

28 files changed:
gcc/ChangeLog
gcc/config/aarch64/aarch64.c
gcc/config/avr/avr.c
gcc/config/i386/i386.c
gcc/config/mips/mips.c
gcc/config/rs6000/rs6000.c
gcc/config/s390/s390.c
gcc/cselib.c
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/hooks.c
gcc/hooks.h
gcc/ira-conflicts.c
gcc/ira-costs.c
gcc/lra-assigns.c
gcc/lra-constraints.c
gcc/lra-int.h
gcc/lra-lives.c
gcc/lra.c
gcc/regcprop.c
gcc/reginfo.c
gcc/regrename.c
gcc/reload.c
gcc/reload1.c
gcc/sched-deps.c
gcc/sel-sched.c
gcc/target.def
gcc/targhooks.c

index 4b5a67a857a1caf37ed86f61ec93e695bd1d952b..42af06bbc4827724003e3eb9cda3261d9e82850e 100644 (file)
@@ -1,3 +1,50 @@
+2019-01-11  Steve Ellcey  <sellcey@marvell.com>
+
+       * config/aarch64/aarch64.c (aarch64_simd_call_p): New function.
+       (aarch64_hard_regno_call_part_clobbered): Add insn argument.
+       (aarch64_return_call_with_max_clobbers): New function.
+       (TARGET_RETURN_CALL_WITH_MAX_CLOBBERS): New macro.
+       * config/avr/avr.c (avr_hard_regno_call_part_clobbered): Add insn
+       argument.
+       * config/i386/i386.c (ix86_hard_regno_call_part_clobbered): Ditto.
+       * config/mips/mips.c (mips_hard_regno_call_part_clobbered): Ditto.
+       * config/rs6000/rs6000.c (rs6000_hard_regno_call_part_clobbered): Ditto.
+       * config/s390/s390.c (s390_hard_regno_call_part_clobbered): Ditto.
+       * cselib.c (cselib_process_insn): Add argument to
+       targetm.hard_regno_call_part_clobbered call.
+       * ira-conflicts.c (ira_build_conflicts): Ditto.
+       * ira-costs.c (ira_tune_allocno_costs): Ditto.
+       * lra-constraints.c (inherit_reload_reg): Ditto.
+       * lra-int.h (struct lra_reg): Add call_insn field, remove call_p field.
+       * lra-lives.c (check_pseudos_live_through_calls): Add call_insn
+       argument.  Call targetm.return_call_with_max_clobbers.
+       Add argument to targetm.hard_regno_call_part_clobbered call.
+       (calls_have_same_clobbers_p): New function.
+       (process_bb_lives): Add call_insn and last_call_insn variables.
+       Pass call_insn to check_pseudos_live_through_calls.
+       Modify if stmt to check targetm.return_call_with_max_clobbers.
+       Update setting of flush variable.
+       (lra_create_live_ranges_1): Set call_insn to NULL instead of call_p
+       to false.
+       * lra.c (initialize_lra_reg_info_element): Set call_insn to NULL.
+       * regcprop.c (copyprop_hardreg_forward_1): Add argument to
+        targetm.hard_regno_call_part_clobbered call.
+       * reginfo.c (choose_hard_reg_mode): Ditto.
+       * regrename.c (check_new_reg_p): Ditto.
+       * reload.c (find_equiv_reg): Ditto.
+       * reload1.c (emit_reload_insns): Ditto.
+       * sched-deps.c (deps_analyze_insn): Ditto.
+       * sel-sched.c (init_regs_for_mode): Ditto.
+       (mark_unavailable_hard_regs): Ditto.
+       * targhooks.c (default_dwarf_frame_reg_mode): Ditto.
+       * target.def (hard_regno_call_part_clobbered): Add insn argument.
+       (return_call_with_max_clobbers): New target function.
+       * doc/tm.texi: Regenerate.
+       * doc/tm.texi.in (TARGET_RETURN_CALL_WITH_MAX_CLOBBERS): New hook.
+       * hooks.c (hook_bool_uint_mode_false): Change to
+       hook_bool_insn_uint_mode_false.
+       * hooks.h (hook_bool_uint_mode_false): Ditto.
+
 2019-01-11  Steve Ellcey  <sellcey@marvell.com>
 
        * config/aarch64/aarch64.c (aarch64_simd_call_p): New function.
index 588fc80bbd7ccf8c3570656e151abc9ec130c03a..fd60bddb1e1cbcb3dd46c319ccd182c7b9d1cd41 100644 (file)
@@ -1699,9 +1699,25 @@ aarch64_remove_extra_call_preserved_regs (rtx_insn *insn,
    clobbers the top 64 bits when restoring the bottom 64 bits.  */
 
 static bool
-aarch64_hard_regno_call_part_clobbered (unsigned int regno, machine_mode mode)
+aarch64_hard_regno_call_part_clobbered (rtx_insn *insn, unsigned int regno,
+                                       machine_mode mode)
 {
-  return FP_REGNUM_P (regno) && maybe_gt (GET_MODE_SIZE (mode), 8);
+  bool simd_p = insn && CALL_P (insn) && aarch64_simd_call_p (insn);
+  return FP_REGNUM_P (regno)
+        && maybe_gt (GET_MODE_SIZE (mode), simd_p ? 16 : 8);
+}
+
+/* Implement TARGET_RETURN_CALL_WITH_MAX_CLOBBERS.  */
+
+rtx_insn *
+aarch64_return_call_with_max_clobbers (rtx_insn *call_1, rtx_insn *call_2)
+{
+  gcc_assert (CALL_P (call_1) && CALL_P (call_2));
+
+  if (!aarch64_simd_call_p (call_1) || aarch64_simd_call_p (call_2))
+    return call_1;
+  else
+    return call_2;
 }
 
 /* Implement REGMODE_NATURAL_SIZE.  */
@@ -18868,6 +18884,10 @@ aarch64_libgcc_floating_mode_supported_p
 #define TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS \
   aarch64_remove_extra_call_preserved_regs
 
+#undef TARGET_RETURN_CALL_WITH_MAX_CLOBBERS
+#define TARGET_RETURN_CALL_WITH_MAX_CLOBBERS \
+  aarch64_return_call_with_max_clobbers
+
 #undef TARGET_CONSTANT_ALIGNMENT
 #define TARGET_CONSTANT_ALIGNMENT aarch64_constant_alignment
 
index 023308b6cf6b90a573f09088d08403123baf2d39..a53b9092e2f6d76a8e02ff6db764f7406c8214a8 100644 (file)
@@ -12181,7 +12181,8 @@ avr_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
 /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED.  */
 
 static bool
-avr_hard_regno_call_part_clobbered (unsigned regno, machine_mode mode)
+avr_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED,
+                                   unsigned regno, machine_mode mode)
 {
   /* FIXME: This hook gets called with MODE:REGNO combinations that don't
         represent valid hard registers like, e.g. HI:29.  Returning TRUE
index 0e23eaaa79c80caa11a4ed266dd9249e57f829fc..1bb535a8d8184bd65f9c3bf9bfc4c58dfe75da13 100644 (file)
@@ -40216,7 +40216,8 @@ ix86_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
    the low 16 bytes are saved.  */
 
 static bool
-ix86_hard_regno_call_part_clobbered (unsigned int regno, machine_mode mode)
+ix86_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED,
+                                    unsigned int regno, machine_mode mode)
 {
   return SSE_REGNO_P (regno) && GET_MODE_SIZE (mode) > 16;
 }
index 95dc9468e68c57a033af89bf11c7f487eab2d2b2..a8022b88ae88b097fd52e3806730fe9e027bdbbd 100644 (file)
@@ -12906,7 +12906,8 @@ mips_hard_regno_scratch_ok (unsigned int regno)
    registers with MODE > 64 bits are part clobbered too.  */
 
 static bool
-mips_hard_regno_call_part_clobbered (unsigned int regno, machine_mode mode)
+mips_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED,
+                                    unsigned int regno, machine_mode mode)
 {
   if (TARGET_FLOATXX
       && hard_regno_nregs (regno, mode) == 1
index 0357dc88e596edae6f1c97e1a4457b53ec11c564..3330b680d61b874f5d737145851ed2376f2c3815 100644 (file)
@@ -2197,7 +2197,8 @@ rs6000_modes_tieable_p (machine_mode mode1, machine_mode mode2)
 /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED.  */
 
 static bool
-rs6000_hard_regno_call_part_clobbered (unsigned int regno, machine_mode mode)
+rs6000_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED,
+                                      unsigned int regno, machine_mode mode)
 {
   if (TARGET_32BIT
       && TARGET_POWERPC64
index ea2be105af3aa609d03f59419d3a0fb95c82ae24..6a571a3e05438bb6e9db2797cdb367acd6f71177 100644 (file)
@@ -10098,7 +10098,8 @@ s390_hard_regno_scratch_ok (unsigned int regno)
    bytes are saved across calls, however.  */
 
 static bool
-s390_hard_regno_call_part_clobbered (unsigned int regno, machine_mode mode)
+s390_hard_regno_call_part_clobbered (rtx_insn *insn ATTRIBUTE_UNUSED,
+                                    unsigned int regno, machine_mode mode)
 {
   if (!TARGET_64BIT
       && TARGET_ZARCH
index cef4bc0de73ceb1b53226ab488743345a10b3d86..84c17c23f6d54de3e62be8d9478473bc13909cad 100644 (file)
@@ -2770,7 +2770,7 @@ cselib_process_insn (rtx_insn *insn)
        if (call_used_regs[i]
            || (REG_VALUES (i) && REG_VALUES (i)->elt
                && (targetm.hard_regno_call_part_clobbered
-                   (i, GET_MODE (REG_VALUES (i)->elt->val_rtx)))))
+                   (insn, i, GET_MODE (REG_VALUES (i)->elt->val_rtx)))))
          cselib_invalidate_regno (i, reg_raw_mode[i]);
 
       /* Since it is not clear how cselib is going to be used, be
index daf29f046c35db5e29258f1077b30c7aadcba7ce..07a4442f09a5693a9f3ee997636a6be6d32ca4a9 100644 (file)
@@ -1894,12 +1894,14 @@ of @code{CALL_USED_REGISTERS}.
 @cindex call-used register
 @cindex call-clobbered register
 @cindex call-saved register
-@deftypefn {Target Hook} bool TARGET_HARD_REGNO_CALL_PART_CLOBBERED (unsigned int @var{regno}, machine_mode @var{mode})
+@deftypefn {Target Hook} bool TARGET_HARD_REGNO_CALL_PART_CLOBBERED (rtx_insn *@var{insn}, unsigned int @var{regno}, machine_mode @var{mode})
 This hook should return true if @var{regno} is partly call-saved and
 partly call-clobbered, and if a value of mode @var{mode} would be partly
-clobbered by a call.  For example, if the low 32 bits of @var{regno} are
-preserved across a call but higher bits are clobbered, this hook should
-return true for a 64-bit mode but false for a 32-bit mode.
+clobbered by call instruction @var{insn}.  If @var{insn} is NULL then it
+should return true if any call could partly clobber the register.
+For example, if the low 32 bits of @var{regno} are preserved across a call
+but higher bits are clobbered, this hook should return true for a 64-bit
+mode but false for a 32-bit mode.
 
 The default implementation returns false, which is correct
 for targets that don't have partly call-clobbered registers.
@@ -1917,6 +1919,18 @@ This hook removes registers from the set of call-clobbered registers
  Defining the hook is purely an optimization.
 @end deftypefn
 
+@deftypefn {Target Hook} {rtx_insn *} TARGET_RETURN_CALL_WITH_MAX_CLOBBERS (rtx_insn *@var{call_1}, rtx_insn *@var{call_2})
+This hook returns a pointer to the call that partially clobbers the
+most registers.  If a platform supports multiple ABIs where the registers
+that are partially clobbered may vary, this function compares two
+calls and returns a pointer to the one that clobbers the most registers.
+If both calls clobber the same registers, @var{call_1} must be returned.
+
+The registers clobbered in different ABIs must be a proper subset or
+superset of all other ABIs.  @var{call_1} must always be a call insn,
+call_2 may be NULL or a call insn.
+@end deftypefn
+
 @findex fixed_regs
 @findex call_used_regs
 @findex global_regs
index d9f40a1a5f37492e895d053aee2b1437471b4694..41a6cb11cb0fe696b3033a0926c3ae715d65f2a2 100644 (file)
@@ -1709,6 +1709,8 @@ of @code{CALL_USED_REGISTERS}.
 
 @hook TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS
 
+@hook TARGET_RETURN_CALL_WITH_MAX_CLOBBERS
+
 @findex fixed_regs
 @findex call_used_regs
 @findex global_regs
index bbc35fc6ee51ffbb801abb49da9721c68c8ea85b..f95659b3807949c615f15ba36b7a1d55e49daa5e 100644 (file)
@@ -142,7 +142,7 @@ hook_bool_puint64_puint64_true (poly_uint64, poly_uint64)
 
 /* Generic hook that takes (unsigned int, machine_mode) and returns false.  */
 bool
-hook_bool_uint_mode_false (unsigned int, machine_mode)
+hook_bool_insn_uint_mode_false (rtx_insn *, unsigned int, machine_mode)
 {
   return false;
 }
index 9e4bc292c8b9d1940e777957a9d20622361e077d..0bc8117c2c821c5e960c002dac04a2bedec4e673 100644 (file)
@@ -40,7 +40,8 @@ extern bool hook_bool_const_rtx_insn_const_rtx_insn_true (const rtx_insn *,
 extern bool hook_bool_mode_uhwi_false (machine_mode,
                                       unsigned HOST_WIDE_INT);
 extern bool hook_bool_puint64_puint64_true (poly_uint64, poly_uint64);
-extern bool hook_bool_uint_mode_false (unsigned int, machine_mode);
+extern bool hook_bool_insn_uint_mode_false (rtx_insn *, unsigned int,
+                                           machine_mode);
 extern bool hook_bool_uint_mode_true (unsigned int, machine_mode);
 extern bool hook_bool_tree_false (tree);
 extern bool hook_bool_const_tree_false (const_tree);
index 7ec709db830c53fa4bb77aff5e5c612096f7bc6c..5bd6c0c3d7a864bc6b5e20f33e333ab2b45e4e89 100644 (file)
@@ -808,7 +808,7 @@ ira_build_conflicts (void)
                 regs must conflict with them.  */
              for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
                if (!TEST_HARD_REG_BIT (call_used_reg_set, regno)
-                   && targetm.hard_regno_call_part_clobbered (regno,
+                   && targetm.hard_regno_call_part_clobbered (NULL, regno,
                                                               obj_mode))
                  {
                    SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno);
index 0ca70a0053a7ab2eebc1f6f7ff96f5060fb60b8d..a17dae3302cd61a441705a895542c04ffccc0eee 100644 (file)
@@ -2379,7 +2379,7 @@ ira_tune_allocno_costs (void)
                                                   *crossed_calls_clobber_regs)
                  && (ira_hard_reg_set_intersection_p (regno, mode,
                                                       call_used_reg_set)
-                     || targetm.hard_regno_call_part_clobbered (regno,
+                     || targetm.hard_regno_call_part_clobbered (NULL, regno,
                                                                 mode)))
                cost += (ALLOCNO_CALL_FREQ (a)
                         * (ira_memory_move_cost[mode][rclass][0]
index 5a4e1eb93dc8f3c54b760ff462c13aa766d20b18..bcd81450c06eb224c18af96e848b6ef0b41b965b 100644 (file)
@@ -1640,7 +1640,7 @@ lra_assign (bool &fails_p)
        asm is removed and it can result in incorrect allocation.  */
     for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
       if (lra_reg_info[i].nrefs != 0 && reg_renumber[i] >= 0
-         && lra_reg_info[i].call_p
+         && lra_reg_info[i].call_insn
          && overlaps_hard_reg_set_p (call_used_reg_set,
                                      PSEUDO_REGNO_MODE (i), reg_renumber[i]))
        gcc_unreachable ();
index c08ad9a8964e880ae11ae196ab933b1d9ef4f20c..0ef13439b5055dd2c5d5049d7f62f6b3b1ddfe2a 100644 (file)
@@ -5379,7 +5379,8 @@ need_for_call_save_p (int regno)
               : call_used_reg_set,
               PSEUDO_REGNO_MODE (regno), reg_renumber[regno])
              || (targetm.hard_regno_call_part_clobbered
-                 (reg_renumber[regno], PSEUDO_REGNO_MODE (regno)))));
+                 (lra_reg_info[regno].call_insn,
+                  reg_renumber[regno], PSEUDO_REGNO_MODE (regno)))));
 }
 
 /* Global registers occurring in the current EBB.  */
index 9d9e81d100d0d6602da415757bbc6f1437cf9255..d0a8facc50e5ec429fa5e3b6ddb0ef80fe6b22c7 100644 (file)
@@ -91,10 +91,6 @@ struct lra_reg
   /* True if the pseudo should not be assigned to a stack register.  */
   bool no_stack_p;
 #endif
-  /* True if the pseudo crosses a call.         It is setup in lra-lives.c
-     and used to check that the pseudo crossing a call did not get a
-     call used hard register.  */
-  bool call_p;
   /* Number of references and execution frequencies of the register in
      *non-debug* insns.         */
   int nrefs, freq;
@@ -107,6 +103,8 @@ struct lra_reg
   int val;
   /* Offset from relative eliminate register to pesudo reg.  */
   poly_int64 offset;
+  /* Call instruction, if any, that may affect this psuedo reg.  */
+  rtx_insn *call_insn;
   /* These members are set up in lra-lives.c and updated in
      lra-coalesce.c.  */
   /* The biggest size mode in which each pseudo reg is referred in
index a00ec389bf9dee72570ce52e2af67a2dd80a5868..55b2adc2a5beca5953ffbc276041440e563337aa 100644 (file)
@@ -576,25 +576,39 @@ lra_setup_reload_pseudo_preferenced_hard_reg (int regno,
 
 /* Check that REGNO living through calls and setjumps, set up conflict
    regs using LAST_CALL_USED_REG_SET, and clear corresponding bits in
-   PSEUDOS_LIVE_THROUGH_CALLS and PSEUDOS_LIVE_THROUGH_SETJUMPS.  */
+   PSEUDOS_LIVE_THROUGH_CALLS and PSEUDOS_LIVE_THROUGH_SETJUMPS.
+   CALL_INSN is a call that is representative of all calls in the region
+   described by the PSEUDOS_LIVE_THROUGH_* sets, in terms of the registers
+   that it preserves and clobbers.  */
+
 static inline void
 check_pseudos_live_through_calls (int regno,
-                                 HARD_REG_SET last_call_used_reg_set)
+                                 HARD_REG_SET last_call_used_reg_set,
+                                 rtx_insn *call_insn)
 {
   int hr;
+  rtx_insn *old_call_insn;
 
   if (! sparseset_bit_p (pseudos_live_through_calls, regno))
     return;
+
+  gcc_assert (call_insn && CALL_P (call_insn));
+  old_call_insn = lra_reg_info[regno].call_insn;
+  if (!old_call_insn
+      || (targetm.return_call_with_max_clobbers
+         && targetm.return_call_with_max_clobbers (old_call_insn, call_insn)
+            == call_insn))
+    lra_reg_info[regno].call_insn = call_insn;
+
   sparseset_clear_bit (pseudos_live_through_calls, regno);
   IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs,
                    last_call_used_reg_set);
 
   for (hr = 0; HARD_REGISTER_NUM_P (hr); hr++)
-    if (targetm.hard_regno_call_part_clobbered (hr,
+    if (targetm.hard_regno_call_part_clobbered (call_insn, hr,
                                                PSEUDO_REGNO_MODE (regno)))
       add_to_hard_reg_set (&lra_reg_info[regno].conflict_hard_regs,
                           PSEUDO_REGNO_MODE (regno), hr);
-  lra_reg_info[regno].call_p = true;
   if (! sparseset_bit_p (pseudos_live_through_setjumps, regno))
     return;
   sparseset_clear_bit (pseudos_live_through_setjumps, regno);
@@ -615,6 +629,19 @@ reg_early_clobber_p (const struct lra_insn_reg *reg, int n_alt)
                  && TEST_BIT (reg->early_clobber_alts, n_alt))));
 }
 
+/* Return true if call instructions CALL1 and CALL2 use ABIs that
+   preserve the same set of registers.  */
+
+static bool
+calls_have_same_clobbers_p (rtx_insn *call1, rtx_insn *call2)
+{
+  if (!targetm.return_call_with_max_clobbers)
+    return false;
+
+  return (targetm.return_call_with_max_clobbers (call1, call2) == call1
+          && targetm.return_call_with_max_clobbers (call2, call1) == call2);
+}
+
 /* Process insns of the basic block BB to update pseudo live ranges,
    pseudo hard register conflicts, and insn notes.  We do it on
    backward scan of BB insns.  CURR_POINT is the program point where
@@ -635,6 +662,8 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
   rtx link, *link_loc;
   bool need_curr_point_incr;
   HARD_REG_SET last_call_used_reg_set;
+  rtx_insn *call_insn = NULL;
+  rtx_insn *last_call_insn = NULL;
 
   reg_live_out = df_get_live_out (bb);
   sparseset_clear (pseudos_live);
@@ -847,7 +876,8 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
              update_pseudo_point (reg->regno, curr_point, USE_POINT);
              mark_regno_live (reg->regno, reg->biggest_mode);
              check_pseudos_live_through_calls (reg->regno,
-                                               last_call_used_reg_set);
+                                               last_call_used_reg_set,
+                                               call_insn);
            }
 
          if (!HARD_REGISTER_NUM_P (reg->regno))
@@ -896,7 +926,8 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
 
       if (call_p)
        {
-         if (! flag_ipa_ra)
+         call_insn = curr_insn;
+         if (! flag_ipa_ra && ! targetm.return_call_with_max_clobbers)
            COPY_HARD_REG_SET(last_call_used_reg_set, call_used_reg_set);
          else
            {
@@ -905,18 +936,24 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
                                      call_used_reg_set);
 
              bool flush = (! hard_reg_set_empty_p (last_call_used_reg_set)
-                           && ! hard_reg_set_equal_p (last_call_used_reg_set,
-                                                      this_call_used_reg_set));
+                           && ( ! hard_reg_set_equal_p (last_call_used_reg_set,
+                                                      this_call_used_reg_set)))
+                          || (last_call_insn && ! calls_have_same_clobbers_p
+                                                    (call_insn,
+                                                     last_call_insn));
 
              EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j)
                {
                  IOR_HARD_REG_SET (lra_reg_info[j].actual_call_used_reg_set,
                                    this_call_used_reg_set);
+
                  if (flush)
-                   check_pseudos_live_through_calls
-                     (j, last_call_used_reg_set);
+                   check_pseudos_live_through_calls (j,
+                                                     last_call_used_reg_set,
+                                                     last_call_insn);
                }
              COPY_HARD_REG_SET(last_call_used_reg_set, this_call_used_reg_set);
+             last_call_insn = call_insn;
            }
 
          sparseset_ior (pseudos_live_through_calls,
@@ -956,7 +993,8 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
              update_pseudo_point (reg->regno, curr_point, USE_POINT);
            mark_regno_live (reg->regno, reg->biggest_mode);
            check_pseudos_live_through_calls (reg->regno,
-                                             last_call_used_reg_set);
+                                             last_call_used_reg_set,
+                                             call_insn);
          }
 
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
@@ -1125,7 +1163,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
       if (sparseset_cardinality (pseudos_live_through_calls) == 0)
        break;
       if (sparseset_bit_p (pseudos_live_through_calls, j))
-       check_pseudos_live_through_calls (j, last_call_used_reg_set);
+       check_pseudos_live_through_calls (j, last_call_used_reg_set, call_insn);
     }
 
   for (i = 0; HARD_REGISTER_NUM_P (i); ++i)
@@ -1359,7 +1397,7 @@ lra_create_live_ranges_1 (bool all_p, bool dead_insn_p)
        lra_reg_info[i].biggest_mode = GET_MODE (regno_reg_rtx[i]);
       else
        lra_reg_info[i].biggest_mode = VOIDmode;
-      lra_reg_info[i].call_p = false;
+      lra_reg_info[i].call_insn = NULL;
       if (!HARD_REGISTER_NUM_P (i)
          && lra_reg_info[i].nrefs != 0)
        {
index 592b9908597cd9adc50fd8420eaf894b6403bf5e..e00e6e77e9f8f24528d84794a9b7fa9bb763db2d 100644 (file)
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -1344,6 +1344,7 @@ initialize_lra_reg_info_element (int i)
   lra_reg_info[i].val = get_new_reg_value ();
   lra_reg_info[i].offset = 0;
   lra_reg_info[i].copies = NULL;
+  lra_reg_info[i].call_insn = NULL;
 }
 
 /* Initialize common reg info and copies.  */
index b107ea24b20eb93c271094d554b0d180cf6ca548..e6bdeb07d8fc1960038318ee66aecca68b3120d1 100644 (file)
@@ -1054,7 +1054,7 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
          for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
            if ((TEST_HARD_REG_BIT (regs_invalidated_by_this_call, regno)
                 || (targetm.hard_regno_call_part_clobbered
-                    (regno, vd->e[regno].mode)))
+                    (insn, regno, vd->e[regno].mode)))
                && (regno < set_regno || regno >= set_regno + set_nregs))
              kill_value_regno (regno, 1, vd);
 
index 7a7fa4d8b242c5225bd7d8de2477dc73aad74f33..315c5ecabe6d7bb220f3accc8b01674876606605 100644 (file)
@@ -639,7 +639,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED,
     if (hard_regno_nregs (regno, mode) == nregs
        && targetm.hard_regno_mode_ok (regno, mode)
        && (!call_saved
-           || !targetm.hard_regno_call_part_clobbered (regno, mode))
+           || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
        && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode)))
       found_mode = mode;
 
@@ -647,7 +647,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED,
     if (hard_regno_nregs (regno, mode) == nregs
        && targetm.hard_regno_mode_ok (regno, mode)
        && (!call_saved
-           || !targetm.hard_regno_call_part_clobbered (regno, mode))
+           || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
        && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode)))
       found_mode = mode;
 
@@ -655,7 +655,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED,
     if (hard_regno_nregs (regno, mode) == nregs
        && targetm.hard_regno_mode_ok (regno, mode)
        && (!call_saved
-           || !targetm.hard_regno_call_part_clobbered (regno, mode))
+           || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
        && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode)))
       found_mode = mode;
 
@@ -663,7 +663,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED,
     if (hard_regno_nregs (regno, mode) == nregs
        && targetm.hard_regno_mode_ok (regno, mode)
        && (!call_saved
-           || !targetm.hard_regno_call_part_clobbered (regno, mode))
+           || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
        && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (found_mode)))
       found_mode = mode;
 
@@ -677,7 +677,7 @@ choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED,
       if (hard_regno_nregs (regno, mode) == nregs
          && targetm.hard_regno_mode_ok (regno, mode)
          && (!call_saved
-             || !targetm.hard_regno_call_part_clobbered (regno, mode)))
+             || !targetm.hard_regno_call_part_clobbered (NULL, regno, mode)))
        return mode;
     }
 
index a180cedb8928a97f064d9a6282307f5bb2afe739..637b3cbe6d74bd0c09165529fc40985354563a9a 100644 (file)
@@ -339,9 +339,9 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg,
         && ! DEBUG_INSN_P (tmp->insn))
        || (this_head->need_caller_save_reg
            && ! (targetm.hard_regno_call_part_clobbered
-                 (reg, GET_MODE (*tmp->loc)))
+                 (NULL, reg, GET_MODE (*tmp->loc)))
            && (targetm.hard_regno_call_part_clobbered
-               (new_reg, GET_MODE (*tmp->loc)))))
+               (NULL, new_reg, GET_MODE (*tmp->loc)))))
       return false;
 
   return true;
index 3ad11a81ec5e576a510f6100d2eb54aa1faf8e31..72cc38a0e093b93cc9785ad9f47e0c185ce74651 100644 (file)
@@ -6912,13 +6912,14 @@ find_equiv_reg (rtx goal, rtx_insn *insn, enum reg_class rclass, int other,
          if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER)
            for (i = 0; i < nregs; ++i)
              if (call_used_regs[regno + i]
-                 || targetm.hard_regno_call_part_clobbered (regno + i, mode))
+                 || targetm.hard_regno_call_part_clobbered (NULL, regno + i,
+                                                            mode))
                return 0;
 
          if (valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER)
            for (i = 0; i < valuenregs; ++i)
              if (call_used_regs[valueno + i]
-                 || targetm.hard_regno_call_part_clobbered (valueno + i,
+                 || targetm.hard_regno_call_part_clobbered (NULL, valueno + i,
                                                             mode))
                return 0;
        }
index 42012e4a6b3989a6c36d6a559976efa45a42d920..bb112d817cf596d997ea8fc64a29d09228a0bdf6 100644 (file)
@@ -8289,7 +8289,8 @@ emit_reload_insns (struct insn_chain *chain)
                           : out_regno + k);
                      reg_reloaded_insn[regno + k] = insn;
                      SET_HARD_REG_BIT (reg_reloaded_valid, regno + k);
-                     if (targetm.hard_regno_call_part_clobbered (regno + k,
+                     if (targetm.hard_regno_call_part_clobbered (NULL,
+                                                                 regno + k,
                                                                  mode))
                        SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
                                          regno + k);
@@ -8369,7 +8370,8 @@ emit_reload_insns (struct insn_chain *chain)
                           : in_regno + k);
                      reg_reloaded_insn[regno + k] = insn;
                      SET_HARD_REG_BIT (reg_reloaded_valid, regno + k);
-                     if (targetm.hard_regno_call_part_clobbered (regno + k,
+                     if (targetm.hard_regno_call_part_clobbered (NULL,
+                                                                 regno + k,
                                                                  mode))
                        SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
                                          regno + k);
@@ -8485,7 +8487,7 @@ emit_reload_insns (struct insn_chain *chain)
                      CLEAR_HARD_REG_BIT (reg_reloaded_dead, src_regno + k);
                      SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + k);
                      if (targetm.hard_regno_call_part_clobbered
-                         (src_regno + k, mode))
+                         (NULL, src_regno + k, mode))
                        SET_HARD_REG_BIT (reg_reloaded_call_part_clobbered,
                                          src_regno + k);
                      else
index a9e934d7fa054d5b00bb7a97911a51e5e93d134f..6cf4cafbff303ef6e2278344aa48102588f2717c 100644 (file)
@@ -3728,7 +3728,7 @@ deps_analyze_insn (struct deps_desc *deps, rtx_insn *insn)
              Since we only have a choice between 'might be clobbered'
              and 'definitely not clobbered', we must include all
              partly call-clobbered registers here.  */
-           else if (targetm.hard_regno_call_part_clobbered (i,
+           else if (targetm.hard_regno_call_part_clobbered (insn, i,
                                                             reg_raw_mode[i])
                      || TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
               SET_REGNO_REG_SET (reg_pending_clobbers, i);
index bf4b2ddca181322822ed596e41b4e8760b065d0c..315f2c0c0ab41b649b6404ae5ee605f00d1d6830 100644 (file)
@@ -1102,7 +1102,7 @@ init_regs_for_mode (machine_mode mode)
       if (i >= 0)
         continue;
 
-      if (targetm.hard_regno_call_part_clobbered (cur_reg, mode))
+      if (targetm.hard_regno_call_part_clobbered (NULL, cur_reg, mode))
         SET_HARD_REG_BIT (sel_hrd.regs_for_call_clobbered[mode],
                           cur_reg);
 
@@ -1251,7 +1251,7 @@ mark_unavailable_hard_regs (def_t def, struct reg_rename *reg_rename_p,
 
   /* Exclude registers that are partially call clobbered.  */
   if (def->crosses_call
-      && !targetm.hard_regno_call_part_clobbered (regno, mode))
+      && !targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
     AND_COMPL_HARD_REG_SET (reg_rename_p->available_for_renaming,
                             sel_hrd.regs_for_call_clobbered[mode]);
 
index e361c41d3def8848e030df4fdcc9334072f20e01..ebda60e52ca23c543b270fc57f349c096aa51855 100644 (file)
@@ -5766,14 +5766,30 @@ DEFHOOK
 (hard_regno_call_part_clobbered,
  "This hook should return true if @var{regno} is partly call-saved and\n\
 partly call-clobbered, and if a value of mode @var{mode} would be partly\n\
-clobbered by a call.  For example, if the low 32 bits of @var{regno} are\n\
-preserved across a call but higher bits are clobbered, this hook should\n\
-return true for a 64-bit mode but false for a 32-bit mode.\n\
+clobbered by call instruction @var{insn}.  If @var{insn} is NULL then it\n\
+should return true if any call could partly clobber the register.\n\
+For example, if the low 32 bits of @var{regno} are preserved across a call\n\
+but higher bits are clobbered, this hook should return true for a 64-bit\n\
+mode but false for a 32-bit mode.\n\
 \n\
 The default implementation returns false, which is correct\n\
 for targets that don't have partly call-clobbered registers.",
- bool, (unsigned int regno, machine_mode mode),
- hook_bool_uint_mode_false)
+ bool, (rtx_insn *insn, unsigned int regno, machine_mode mode),
+ hook_bool_insn_uint_mode_false)
+
+DEFHOOK
+(return_call_with_max_clobbers,
+ "This hook returns a pointer to the call that partially clobbers the\n\
+most registers.  If a platform supports multiple ABIs where the registers\n\
+that are partially clobbered may vary, this function compares two\n\
+calls and returns a pointer to the one that clobbers the most registers.\n\
+If both calls clobber the same registers, @var{call_1} must be returned.\n\
+\n\
+The registers clobbered in different ABIs must be a proper subset or\n\
+superset of all other ABIs.  @var{call_1} must always be a call insn,\n\
+call_2 may be NULL or a call insn.",
+ rtx_insn *, (rtx_insn *call_1, rtx_insn *call_2),
+ NULL)
 
 DEFHOOK
 (remove_extra_call_preserved_regs,
index 6bd9767b4699c2f0b6e717dcc97fb1a201e5fd4a..529590b55df064371d51e0ae0e0570615eb5276c 100644 (file)
@@ -1930,7 +1930,7 @@ default_dwarf_frame_reg_mode (int regno)
 {
   machine_mode save_mode = reg_raw_mode[regno];
 
-  if (targetm.hard_regno_call_part_clobbered (regno, save_mode))
+  if (targetm.hard_regno_call_part_clobbered (NULL, regno, save_mode))
     save_mode = choose_hard_reg_mode (regno, 1, true);
   return save_mode;
 }