Avoid ICE on m68k -fzero-call-used-regs -fpic [PR110934]

Message ID 20240117172527.27233-1-mikpelinux@gmail.com
State New
Headers
Series Avoid ICE on m68k -fzero-call-used-regs -fpic [PR110934] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Testing passed

Commit Message

Mikael Pettersson Jan. 17, 2024, 5:03 p.m. UTC
  PR110934 is a problem on m68k where -fzero-call-used-regs -fpic ICEs
when clearing an FP register.

The generic code generates an XFmode move of zero to that register,
which becomes an XFmode load from initialized data, which due to -fpic
uses a non-constant address, which the backend rejects.  The
zero-call-used-regs pass runs very late, after register allocation and
frame layout, and at that point we can't allow new uses of the PIC
register or new pseudos.

To clear an FP register on m68k it's enough to do the move in SFmode,
but the generic code can't be told to do that, so this patch updates
m68k to use its own TARGET_ZERO_CALL_USED_REGS.

Bootstrapped and regression tested on m68k-linux-gnu.

Ok for master? (I don't have commit rights.)

gcc/

	PR target/110934
	* config/m68k/m68k.cc (m68k_zero_call_used_regs): New function.
	(TARGET_ZERO_CALL_USED_REGS): Define.

gcc/testsuite/

	PR target/110934
	* gcc.target/m68k/pr110934.c: New test.
---
 gcc/config/m68k/m68k.cc                  | 46 ++++++++++++++++++++++++
 gcc/testsuite/gcc.target/m68k/pr110934.c |  9 +++++
 2 files changed, 55 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/m68k/pr110934.c
  

Comments

Jeff Law Jan. 19, 2024, 11:21 p.m. UTC | #1
On 1/17/24 10:03, Mikael Pettersson wrote:
> PR110934 is a problem on m68k where -fzero-call-used-regs -fpic ICEs
> when clearing an FP register.
> 
> The generic code generates an XFmode move of zero to that register,
> which becomes an XFmode load from initialized data, which due to -fpic
> uses a non-constant address, which the backend rejects.  The
> zero-call-used-regs pass runs very late, after register allocation and
> frame layout, and at that point we can't allow new uses of the PIC
> register or new pseudos.
> 
> To clear an FP register on m68k it's enough to do the move in SFmode,
> but the generic code can't be told to do that, so this patch updates
> m68k to use its own TARGET_ZERO_CALL_USED_REGS.
> 
> Bootstrapped and regression tested on m68k-linux-gnu.
> 
> Ok for master? (I don't have commit rights.)
We can certainly have new uses of the PIC register after reload.  What 
we can't do is allocate a new scratch register after reload to hold the 
address of the object from the GOT.  It's a subtle difference.

Because we're zeroing call used registers and we only do this at return 
points, we could (in theory) use one of the call-used address registers 
as a scratch.  Doing that requires (AFAICT) defining the same target 
hook you're using, so it's not any cleaner from that point of view.

> 

> +/* Implement TARGET_ZERO_CALL_USED_REGS.  */
> +
> +static HARD_REG_SET
> +m68k_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs)
> +{
> +  rtx zero_fpreg = NULL_RTX;
> +
> +  for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
> +    if (TEST_HARD_REG_BIT (need_zeroed_hardregs, regno))
> +      {
> +	rtx reg, zero;
> +
> +	if (INT_REGNO_P (regno))
> +	  {
> +	    reg = regno_reg_rtx[regno];
> +	    zero = CONST0_RTX (SImode);
> +	  }
> +	else if (FP_REGNO_P (regno))
> +	  {
> +	    reg = gen_raw_REG (SFmode, regno);
> +	    if (zero_fpreg == NULL_RTX)
> +	      {
> +		/* On the 040/060 clearing an FP reg loads a large
> +		   immediate.  To reduce code size use the first
> +		   cleared FP reg to clear remaing ones.  Don't do
Minor typo.  s/remaing/remaining/

I'll fix that and push the patch to the trunk.  It's as clean as other 
approaches I pondered would likely be.

Jeff
  

Patch

diff --git a/gcc/config/m68k/m68k.cc b/gcc/config/m68k/m68k.cc
index e9325686b92..72a29d772ea 100644
--- a/gcc/config/m68k/m68k.cc
+++ b/gcc/config/m68k/m68k.cc
@@ -197,6 +197,7 @@  static bool m68k_modes_tieable_p (machine_mode, machine_mode);
 static machine_mode m68k_promote_function_mode (const_tree, machine_mode,
 						int *, const_tree, int);
 static void m68k_asm_final_postscan_insn (FILE *, rtx_insn *insn, rtx [], int);
+static HARD_REG_SET m68k_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs);
 
 /* Initialize the GCC target structure.  */
 
@@ -361,6 +362,9 @@  static void m68k_asm_final_postscan_insn (FILE *, rtx_insn *insn, rtx [], int);
 #undef TARGET_ASM_FINAL_POSTSCAN_INSN
 #define TARGET_ASM_FINAL_POSTSCAN_INSN m68k_asm_final_postscan_insn
 
+#undef TARGET_ZERO_CALL_USED_REGS
+#define TARGET_ZERO_CALL_USED_REGS m68k_zero_call_used_regs
+
 TARGET_GNU_ATTRIBUTES (m68k_attribute_table,
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
@@ -7166,4 +7170,46 @@  m68k_promote_function_mode (const_tree type, machine_mode mode,
   return mode;
 }
 
+/* Implement TARGET_ZERO_CALL_USED_REGS.  */
+
+static HARD_REG_SET
+m68k_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs)
+{
+  rtx zero_fpreg = NULL_RTX;
+
+  for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (TEST_HARD_REG_BIT (need_zeroed_hardregs, regno))
+      {
+	rtx reg, zero;
+
+	if (INT_REGNO_P (regno))
+	  {
+	    reg = regno_reg_rtx[regno];
+	    zero = CONST0_RTX (SImode);
+	  }
+	else if (FP_REGNO_P (regno))
+	  {
+	    reg = gen_raw_REG (SFmode, regno);
+	    if (zero_fpreg == NULL_RTX)
+	      {
+		/* On the 040/060 clearing an FP reg loads a large
+		   immediate.  To reduce code size use the first
+		   cleared FP reg to clear remaing ones.  Don't do
+		   this on cores which use fmovecr.  */
+		zero = CONST0_RTX (SFmode);
+		if (TUNE_68040_60)
+		  zero_fpreg = reg;
+	      }
+	    else
+	      zero = zero_fpreg;
+	  }
+	else
+	  gcc_unreachable ();
+
+	emit_move_insn (reg, zero);
+      }
+
+  return need_zeroed_hardregs;
+}
+
 #include "gt-m68k.h"
diff --git a/gcc/testsuite/gcc.target/m68k/pr110934.c b/gcc/testsuite/gcc.target/m68k/pr110934.c
new file mode 100644
index 00000000000..8c21d46f660
--- /dev/null
+++ b/gcc/testsuite/gcc.target/m68k/pr110934.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile } */
+/* { do-options "-fzero-call-used-regs=used -fpic -O2" } */
+
+extern double clobber_fp0 (void);
+
+void foo (void)
+{
+  clobber_fp0 ();
+}