# DP: Fix PR target/110934 (m68k), taken from the trunk

From f1dea0fed946ba40bd6bbe40ad1386aa9303418c Mon Sep 17 00:00:00 2001
From: Mikael Pettersson <mikpelinux@gmail.com>
Date: Fri, 19 Jan 2024 16:23:34 -0700
Subject: [PATCH] [PATCH] Avoid ICE on m68k -fzero-call-used-regs -fpic
 [PR110934]

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

--- a/src/gcc/config/m68k/m68k.cc
+++ b/src/gcc/config/m68k/m68k.cc
@@ -196,6 +196,7 @@ static bool m68k_modes_tieable_p (machin
 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);
 
 /* Initialize the GCC target structure.  */
 
@@ -360,6 +361,9 @@ static void m68k_asm_final_postscan_insn
 #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
+
 static const struct attribute_spec 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 t
   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 remaining 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"
--- /dev/null
+++ b/src/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 ();
+}
