This contains both a generic fixlet for targets implementing the leaf register 
optimization (SPARC and Xtensa) and the implementation of the target hook 
TARGET_ZERO_CALL_USED_REGS, which is needed to make this work on the SPARC.

Tested on SPARC/Solaris and SPARC64/Linux, applied on the mainline.


2020-12-01  Eric Botcazou  <ebotca...@adacore.com>

        * function.c (gen_call_used_regs_seq): In a function subject to the
        leaf register optimization, skip registers that are not present.
        * config/sparc/sparc.c (TARGET_ZERO_CALL_USED_REGS): Define to...
        (sparc_zero_call_used_regs): ...this.  New function.

-- 
Eric Botcazou
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 02138c5d478..ec0921b7ef5 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -708,6 +708,7 @@ static HOST_WIDE_INT sparc_constant_alignment (const_tree, HOST_WIDE_INT);
 static bool sparc_vectorize_vec_perm_const (machine_mode, rtx, rtx, rtx,
 					    const vec_perm_indices &);
 static bool sparc_can_follow_jump (const rtx_insn *, const rtx_insn *);
+static HARD_REG_SET sparc_zero_call_used_regs (HARD_REG_SET);
 
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
 /* Table of valid machine attributes.  */
@@ -959,6 +960,9 @@ char sparc_hard_reg_printed[8];
 #undef TARGET_CAN_FOLLOW_JUMP
 #define TARGET_CAN_FOLLOW_JUMP sparc_can_follow_jump
 
+#undef TARGET_ZERO_CALL_USED_REGS
+#define TARGET_ZERO_CALL_USED_REGS sparc_zero_call_used_regs
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Return the memory reference contained in X if any, zero otherwise.  */
@@ -13810,4 +13814,50 @@ sparc_constant_alignment (const_tree exp, HOST_WIDE_INT align)
   return align;
 }
 
+/* Implement TARGET_ZERO_CALL_USED_REGS.
+
+   Generate a sequence of instructions that zero registers specified by
+   NEED_ZEROED_HARDREGS.  Return the ZEROED_HARDREGS that are actually
+   zeroed.  */
+
+static HARD_REG_SET
+sparc_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs)
+{
+  for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (TEST_HARD_REG_BIT (need_zeroed_hardregs, regno))
+      {
+	/* Do not touch the CC registers or the FP registers if no VIS.  */
+	if (regno >= SPARC_FCC_REG
+	    || (regno >= SPARC_FIRST_FP_REG && !TARGET_VIS))
+	  CLEAR_HARD_REG_BIT (need_zeroed_hardregs, regno);
+
+	/* Do not access the odd upper FP registers individually.  */
+	else if (regno >= SPARC_FIRST_V9_FP_REG && (regno & 1))
+	  ;
+
+	/* Use the most natural mode for the registers, which is not given by
+	   regno_reg_rtx/reg_raw_mode for the FP registers on the SPARC.  */
+	else
+	  {
+	    machine_mode mode;
+	    rtx reg;
+
+	    if (regno < SPARC_FIRST_FP_REG)
+	      {
+		reg = regno_reg_rtx[regno];
+		mode = GET_MODE (reg);
+	      }
+	    else
+	      {
+		mode = regno < SPARC_FIRST_V9_FP_REG ? SFmode : DFmode;
+		reg = gen_raw_REG (mode, regno);
+	      }
+
+	    emit_move_insn (reg, CONST0_RTX (mode));
+	  }
+      }
+
+  return need_zeroed_hardregs;
+}
+
 #include "gt-sparc.h"
diff --git a/gcc/function.c b/gcc/function.c
index 004fa389207..59fd72b0e82 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -5880,6 +5880,10 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
 	continue;
       if (only_arg && !FUNCTION_ARG_REGNO_P (regno))
 	continue;
+#ifdef LEAF_REG_REMAP
+      if (crtl->uses_only_leaf_regs && LEAF_REG_REMAP (regno) < 0)
+	continue;
+#endif
 
       /* Now this is a register that we might want to zero.  */
       SET_HARD_REG_BIT (selected_hardregs, regno);

Reply via email to