ia64 uses default_zero_call_used_regs(), which uses emit_move_insn()
to zero out registers. ia64 predicate registers use BImode, which is not
supported by emit_move_insn().

Implement ia64_zero_call_used_regs() to zero PRs by manually emitting
a CCImode move. default_zero_call_used_regs() is then called to handle
the remaining registers.

        PR target/121535

gcc/ChangeLog:

        * config/ia64/ia64.cc (TARGET_ZERO_CALL_USED_REGS): Override
        function with target-specific one.
        (struct gcc_target): Move to end of file.
        (ia64_zero_call_used_regs): Add target-specific function.

gcc/testsuite/ChangeLog:

        * gcc.target/ia64/pr121535.c: New test.

Signed-off-by: Tomas Glozar <[email protected]>
---
I verified that the patch correctly zeroes out the registers
in the testsuite example:

f:
        .prologue 2, 2
        .vframe r2
        mov r2 = r12
        .body
...
        cmp4.ne p6, p7 = 1, r14
...
        (p0) cmp.eq.unc p6, p0 = r0, r0
        (p0) cmp.eq.unc p7, p0 = r0, r0
        br.ret.sptk.many b0
        ;;
        .endp f#

 gcc/config/ia64/ia64.cc                  | 55 +++++++++++++++++++++++-
 gcc/testsuite/gcc.target/ia64/pr121535.c |  7 +++
 2 files changed, 60 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/ia64/pr121535.c

diff --git a/gcc/config/ia64/ia64.cc b/gcc/config/ia64/ia64.cc
index 8dab9279fe7..886d5a1055a 100644
--- a/gcc/config/ia64/ia64.cc
+++ b/gcc/config/ia64/ia64.cc
@@ -578,6 +578,9 @@ static const scoped_attribute_specs *const 
ia64_attribute_table[] =
 #undef TARGET_FUNCTION_VALUE_REGNO_P
 #define TARGET_FUNCTION_VALUE_REGNO_P ia64_function_value_regno_p
 
+#undef TARGET_ZERO_CALL_USED_REGS
+#define TARGET_ZERO_CALL_USED_REGS ia64_zero_call_used_regs
+
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX ia64_struct_value_rtx
 #undef TARGET_RETURN_IN_MEMORY
@@ -688,8 +691,6 @@ static const scoped_attribute_specs *const 
ia64_attribute_table[] =
 
 #undef TARGET_DOCUMENTATION_NAME
 #define TARGET_DOCUMENTATION_NAME "IA-64"
-
-struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Returns TRUE iff the target attribute indicated by ATTR_ID takes a plain
    identifier as an argument, so the front end shouldn't look it up.  */
@@ -5330,6 +5331,54 @@ ia64_function_value_regno_p (const unsigned int regno)
           || (regno >= FR_RET_FIRST && regno <= FR_RET_LAST));
 }
 
+/* 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
+ia64_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs)
+{
+  HARD_REG_SET nonpredicate, failed;
+
+  CLEAR_HARD_REG_SET (nonpredicate);
+  CLEAR_HARD_REG_SET (failed);
+
+  /* Mark all non-predicate registers.  */
+  for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+    if (TEST_HARD_REG_BIT (need_zeroed_hardregs, regno)
+       && !PR_REGNO_P (regno))
+      SET_HARD_REG_BIT (nonpredicate, regno);
+
+  /* Let the generic helper emit zeroing for the remaining hard regs.
+     It returns the subset it actually managed to zero.  */
+  if (!hard_reg_set_empty_p (nonpredicate))
+    failed = default_zero_call_used_regs (nonpredicate);
+
+  /* Finally, emit zeroing of predicate registers.  */
+  for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (TEST_HARD_REG_BIT (need_zeroed_hardregs, regno)
+       && PR_REGNO_P (regno))
+      {
+       rtx_insn *last_insn = get_last_insn ();
+       /* Prepare PR0 register, which is hardwired to 1 */
+       rtx zero = gen_rtx_REG (CCImode, PR_REG (0));
+       rtx regno_rtx = gen_rtx_REG (CCImode, regno);
+       enum insn_code code = optab_handler (mov_optab, CCImode);
+
+       gcc_assert (code != CODE_FOR_nothing);
+
+       rtx_insn *insn = emit_insn (GEN_FCN (code) (regno_rtx, zero));
+
+       if (!valid_insn_p (insn))
+         {
+           SET_HARD_REG_BIT (failed, regno);
+           delete_insns_since (last_insn);
+         }
+      }
+
+  return failed;
+}
+
 /* This is called from dwarf2out.cc via TARGET_ASM_OUTPUT_DWARF_DTPREL.
    We need to emit DTP-relative relocations.  */
 
@@ -11960,4 +12009,6 @@ ia64_can_change_mode_class (machine_mode from, 
machine_mode to,
   return true;
 }
 
+struct gcc_target targetm = TARGET_INITIALIZER;
+
 #include "gt-ia64.h"
diff --git a/gcc/testsuite/gcc.target/ia64/pr121535.c 
b/gcc/testsuite/gcc.target/ia64/pr121535.c
new file mode 100644
index 00000000000..134120c019a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia64/pr121535.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+__attribute__ ((zero_call_used_regs("used"))) int f(int x)
+{
+  if (x == 1)
+    return 0;
+  return 1;
+}
-- 
2.51.1

Reply via email to