Hello,

This patch teaches the DWARF support in gcc about RA_AUTH_CODE pseudo 
hard-register and also 
.save {ra_auth_code} and .cfi_offset ra_auth_code <offset> dwarf directives for 
the PAC feature
in Armv8.1-M architecture.

RA_AUTH_CODE register number is 107 and it's dwarf register number is 143.

When compiled with " -march=armv8.1-m.main -mbranch-protection=pac-ret+leaf+bti 
-mthumb
-mfloat-abi=soft -fasynchronous-unwind-tables -g -O2 -S" command line options, 
the assembly
output after this patch looks like below:

        ...
        .cfi_startproc
        pacbti  ip, lr, sp
        movs    r1, #40
        push    {ip, lr}
        .save {ra_auth_code, lr}
        .cfi_def_cfa_offset 8
        .cfi_offset 143, -8
        .cfi_offset 14, -4
        ...
        pop     {ip, lr}
        .cfi_restore 14
        .cfi_restore 143
        .cfi_def_cfa_offset 0
        movs    r0, #0
        aut     ip, lr, sp
        bx      lr
        .cfi_endproc
        ...

This patch can be committed after the patch at 
https://gcc.gnu.org/pipermail/gcc-patches/2021-November/583407.html
is committed.

Regression tested on arm-none-eabi target and found no regressions.

Ok for master?

Regards,
Srinath.

gcc/ChangeLog:

2022-04-06  Srinath Parvathaneni  <srinath.parvathan...@arm.com>

        * config/arm/aout.h (ra_auth_code): Add to enum.
        * config/arm/arm.cc (emit_multi_reg_push): Add RA_AUTH_CODE register to
        dwarf frame expression.
        (arm_emit_multi_reg_pop): Restore RA_AUTH_CODE register.
        (arm_expand_prologue): Mark as frame related insn.
        (arm_regno_class): Check for pac pseudo reigster.
        (arm_dbx_register_number): Assign ra_auth_code register number in dwarf.
        (arm_unwind_emit_sequence): Print .save directive with ra_auth_code
        register.
        (arm_conditional_register_usage): Mark ra_auth_code in fixed reigsters.
        * config/arm/arm.h (FIRST_PSEUDO_REGISTER): Modify.
        (IS_PAC_Pseudo_REGNUM): Define.
        (enum reg_class): Add PAC_REG entry.
        * config/arm/arm.md (RA_AUTH_CODE): Define.

gcc/testsuite/ChangeLog:

2022-04-06  Srinath Parvathaneni  <srinath.parvathan...@arm.com>

        * g++.target/arm/pac-1.C: New test.
        * gcc.target/arm/pac-9.c: Likewise.


###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/config/arm/aout.h b/gcc/config/arm/aout.h
index 
b918ad3782fbee82320febb8b6e72ad615780261..ffeed45a678f17c63d5b42c21f020ca416cbf23f
 100644
--- a/gcc/config/arm/aout.h
+++ b/gcc/config/arm/aout.h
@@ -74,7 +74,8 @@
   "wr8",   "wr9",   "wr10",  "wr11",                           \
   "wr12",  "wr13",  "wr14",  "wr15",                           \
   "wcgr0", "wcgr1", "wcgr2", "wcgr3",                          \
-  "cc", "vfpcc", "sfp", "afp", "apsrq", "apsrge", "p0"         \
+  "cc", "vfpcc", "sfp", "afp", "apsrq", "apsrge", "p0",                \
+  "ra_auth_code"                                               \
 }
 #endif
 
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 
3495ab857eac38ecdf37e55f1d201b1c35cbde0b..c77777067819f6785e44d30d8e5365505ab98682
 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -816,7 +816,8 @@ extern const int arm_arch_cde_coproc_bits[];
        s16-s31       S VFP variable (aka d8-d15).
        vfpcc           Not a real register.  Represents the VFP condition
                        code flags.
-       vpr             Used to represent MVE VPR predication.  */
+       vpr             Used to represent MVE VPR predication.
+       ra_auth_code    Pseudo register to save PAC.  */
 
 /* The stack backtrace structure is as follows:
   fp points to here:  |  save code pointer  |      [fp]
@@ -857,7 +858,7 @@ extern const int arm_arch_cde_coproc_bits[];
   1,1,1,1,1,1,1,1,             \
   1,1,1,1,                     \
   /* Specials.  */             \
-  1,1,1,1,1,1,1                        \
+  1,1,1,1,1,1,1,1              \
 }
 
 /* 1 for registers not available across function calls.
@@ -887,7 +888,7 @@ extern const int arm_arch_cde_coproc_bits[];
   1,1,1,1,1,1,1,1,             \
   1,1,1,1,                     \
   /* Specials.  */             \
-  1,1,1,1,1,1,1                        \
+  1,1,1,1,1,1,1,1              \
 }
 
 #ifndef SUBTARGET_CONDITIONAL_REGISTER_USAGE
@@ -1063,10 +1064,10 @@ extern const int arm_arch_cde_coproc_bits[];
    && (LAST_VFP_REGNUM - (REGNUM) >= 2 * (N) - 1))
 
 /* The number of hard registers is 16 ARM + 1 CC + 1 SFP + 1 AFP
-   + 1 APSRQ + 1 APSRGE + 1 VPR.  */
+   + 1 APSRQ + 1 APSRGE + 1 VPR + 1 Pseudo register to save PAC.  */
 /* Intel Wireless MMX Technology registers add 16 + 4 more.  */
 /* VFP (VFP3) adds 32 (64) + 1 VFPCC.  */
-#define FIRST_PSEUDO_REGISTER   107
+#define FIRST_PSEUDO_REGISTER   108
 
 #define DBX_REGISTER_NUMBER(REGNO) arm_dbx_register_number (REGNO)
 
@@ -1253,12 +1254,15 @@ extern int arm_regs_in_sequence[];
   CC_REGNUM, VFPCC_REGNUM,                     \
   FRAME_POINTER_REGNUM, ARG_POINTER_REGNUM,    \
   SP_REGNUM, PC_REGNUM, APSRQ_REGNUM,          \
-  APSRGE_REGNUM, VPR_REGNUM                    \
+  APSRGE_REGNUM, VPR_REGNUM, RA_AUTH_CODE      \
 }
 
 #define IS_VPR_REGNUM(REGNUM) \
   ((REGNUM) == VPR_REGNUM)
 
+#define IS_PAC_Pseudo_REGNUM(REGNUM) \
+  ((REGNUM) == RA_AUTH_CODE)
+
 /* Use different register alloc ordering for Thumb.  */
 #define ADJUST_REG_ALLOC_ORDER arm_order_regs_for_local_alloc ()
 
@@ -1297,6 +1301,7 @@ enum reg_class
   SFP_REG,
   AFP_REG,
   VPR_REG,
+  PAC_REG,
   GENERAL_AND_VPR_REGS,
   ALL_REGS,
   LIM_REG_CLASSES
@@ -1327,6 +1332,7 @@ enum reg_class
   "SFP_REG",           \
   "AFP_REG",           \
   "VPR_REG",           \
+  "PAC_REG",           \
   "GENERAL_AND_VPR_REGS", \
   "ALL_REGS"           \
 }
@@ -1356,6 +1362,7 @@ enum reg_class
   { 0x00000000, 0x00000000, 0x00000000, 0x00000040 }, /* SFP_REG */    \
   { 0x00000000, 0x00000000, 0x00000000, 0x00000080 }, /* AFP_REG */    \
   { 0x00000000, 0x00000000, 0x00000000, 0x00000400 }, /* VPR_REG.  */  \
+  { 0x00000000, 0x00000000, 0x00000000, 0x00000800 }, /* PAC_REG.  */  \
   { 0x00005FFF, 0x00000000, 0x00000000, 0x00000400 }, /* GENERAL_AND_VPR_REGS. 
 */ \
   { 0xFFFF7FFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000040F }  /* ALL_REGS.  */ \
 }
diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index 
a2b720a666077c528034c13e27d7c7168cb824d7..a14ea47badd8b90315376c27553e5894beeea990
 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -22151,7 +22151,9 @@ emit_multi_reg_push (unsigned long mask, unsigned long 
dwarf_regs_mask)
     {
       if (mask & (1 << i))
        {
-         reg = gen_rtx_REG (SImode, i);
+         rtx reg1 = reg = gen_rtx_REG (SImode, i);
+         if (arm_current_function_pac_enabled_p () && i == IP_REGNUM)
+           reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE);
 
          XVECEXP (par, 0, 0)
            = gen_rtx_SET (gen_frame_mem
@@ -22168,8 +22170,12 @@ emit_multi_reg_push (unsigned long mask, unsigned long 
dwarf_regs_mask)
 
          if (dwarf_regs_mask & (1 << i))
            {
+             /* Only the first register in the multi push instruction is stored
+                to frame memory here.
+               Eg: push {r7 ,r8, ip, lr}
+               Only r7 is stored to frame memory here.  */
              tmp = gen_rtx_SET (gen_frame_mem (SImode, stack_pointer_rtx),
-                                reg);
+                                reg1);
              RTX_FRAME_RELATED_P (tmp) = 1;
              XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
            }
@@ -22182,18 +22188,25 @@ emit_multi_reg_push (unsigned long mask, unsigned 
long dwarf_regs_mask)
     {
       if (mask & (1 << i))
        {
-         reg = gen_rtx_REG (SImode, i);
+         rtx reg1 = reg = gen_rtx_REG (SImode, i);
+         if (arm_current_function_pac_enabled_p () && i == IP_REGNUM)
+           reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE);
 
          XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
 
          if (dwarf_regs_mask & (1 << i))
            {
+             /* Except the first register in the multi push instruction all the
+                remaining registers are stored to frame memory here.
+                Eg: push {r7, r8, ip, lr}
+                r8, ip (ra_auth_code in case PACBTI enabled) and lr registers
+                are stored to frame memory here.  */
              tmp
                = gen_rtx_SET (gen_frame_mem
                               (SImode,
                                plus_constant (Pmode, stack_pointer_rtx,
                                               4 * j)),
-                              reg);
+                              reg1);
              RTX_FRAME_RELATED_P (tmp) = 1;
              XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
            }
@@ -22278,7 +22291,9 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask)
   for (j = 0, i = 0; j < num_regs; i++)
     if (saved_regs_mask & (1 << i))
       {
-        reg = gen_rtx_REG (SImode, i);
+       rtx reg1 = reg = gen_rtx_REG (SImode, i);
+       if (arm_current_function_pac_enabled_p () && i == IP_REGNUM)
+         reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE);
         if ((num_regs == 1) && emit_update && !return_in_pc)
           {
             /* Emit single load with writeback.  */
@@ -22286,7 +22301,7 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask)
                                  gen_rtx_POST_INC (Pmode,
                                                    stack_pointer_rtx));
             tmp = emit_insn (gen_rtx_SET (reg, tmp));
-            REG_NOTES (tmp) = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
+           REG_NOTES (tmp) = alloc_reg_note (REG_CFA_RESTORE, reg1, dwarf);
             return;
           }
 
@@ -22300,7 +22315,7 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask)
         /* We need to maintain a sequence for DWARF info too.  As dwarf info
            should not have PC, skip PC.  */
         if (i != PC_REGNUM)
-          dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
+         dwarf = alloc_reg_note (REG_CFA_RESTORE, reg1, dwarf);
 
         j++;
       }
@@ -25585,6 +25600,9 @@ arm_regno_class (int regno)
   if (IS_VPR_REGNUM (regno))
     return VPR_REG;
 
+  if (IS_PAC_Pseudo_REGNUM (regno))
+    return PAC_REG;
+
   if (TARGET_THUMB1)
     {
       if (regno == STACK_POINTER_REGNUM)
@@ -29557,6 +29575,9 @@ arm_dbx_register_number (unsigned int regno)
   if (IS_IWMMXT_REGNUM (regno))
     return 112 + regno - FIRST_IWMMXT_REGNUM;
 
+  if (IS_PAC_Pseudo_REGNUM (regno))
+    return 143;
+
   return DWARF_FRAME_REGISTERS;
 }
 
@@ -29678,6 +29699,11 @@ arm_unwind_emit_sequence (FILE * out_file, rtx p)
       reg_size = 8;
       fprintf (out_file, "\t.vsave {");
     }
+  else if (IS_PAC_Pseudo_REGNUM (reg))
+    {
+      reg_size = 4;
+      fprintf (out_file, "\t.save {");
+    }
   else
     /* Unknown register type.  */
     gcc_unreachable ();
@@ -29707,6 +29733,8 @@ arm_unwind_emit_sequence (FILE * out_file, rtx p)
         double precision register names.  */
       if (IS_VFP_REGNUM (reg))
        asm_fprintf (out_file, "d%d", (reg - FIRST_VFP_REGNUM) / 2);
+      else if (IS_PAC_Pseudo_REGNUM (reg))
+       asm_fprintf (asm_out_file, "ra_auth_code");
       else
        asm_fprintf (out_file, "%r", reg);
 
@@ -30575,7 +30603,10 @@ arm_conditional_register_usage (void)
     }
 
   if (TARGET_HAVE_PACBTI)
-    call_used_regs[IP_REGNUM] = 1;
+    {
+      call_used_regs[IP_REGNUM] = 1;
+      fixed_regs[RA_AUTH_CODE] = 0;
+    }
 
   /* The Q and GE bits are only accessed via special ACLE patterns.  */
   CLEAR_HARD_REG_BIT (operand_reg_set, APSRQ_REGNUM);
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 
2221bc68f358f277eff176b7abab5adf1e952399..aaaf13574593846d02655d593d45d751a5b7512e
 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -42,6 +42,7 @@
    (APSRQ_REGNUM    104)       ; Q bit pseudo register
    (APSRGE_REGNUM   105)       ; GE bits pseudo register
    (VPR_REGNUM      106)       ; Vector Predication Register - MVE register.
+   (RA_AUTH_CODE    107)       ; Pseudo register to save PAC.
   ]
 )
 ;; 3rd operand to select_dominance_cc_mode
diff --git a/gcc/testsuite/g++.target/arm/pac-1.C 
b/gcc/testsuite/g++.target/arm/pac-1.C
new file mode 100644
index 
0000000000000000000000000000000000000000..b447213ab4e1b72cacd483efece077fbbca3a608
--- /dev/null
+++ b/gcc/testsuite/g++.target/arm/pac-1.C
@@ -0,0 +1,33 @@
+/* Check that GCC does .save and .cfi_offset directives with RA_AUTH_CODE 
pseudo hard-register.  */
+/* { dg-do compile } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" 
"-mcpu=*" } } */
+/* { dg-options "-march=armv8.1-m.main -mbranch-protection=pac-ret+leaf+bti 
-mthumb -mfloat-abi=soft --save-temps -g" } */
+
+__attribute__((noinline)) void
+fn1 (int a, int b, int c)
+{
+  if (a != b + c)
+    __builtin_abort ();
+  else
+    throw b+c;
+}
+
+int main ()
+{
+  int a = 120;
+  try
+    {
+      fn1 (a, 40, 80);
+    }
+  catch (int x)
+    {
+      if (x != a)
+        __builtin_abort ();
+      else
+       return 0;
+    }
+}
+
+/* { dg-final { scan-assembler "\.save \{r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.save \{r4, r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.cfi_offset 143, \-8" } } */
diff --git a/gcc/testsuite/gcc.target/arm/pac-9.c 
b/gcc/testsuite/gcc.target/arm/pac-9.c
new file mode 100644
index 
0000000000000000000000000000000000000000..2a69db6e8e8a32090a6c16ccc66871946188f8d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pac-9.c
@@ -0,0 +1,21 @@
+/* Check that GCC does .save and .cfi_offset directives with RA_AUTH_CODE 
pseudo hard-register.  */
+/* { dg-do compile } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" 
"-mcpu=*" } } */
+/* { dg-options "-march=armv8.1-m.main -mbranch-protection=pac-ret+leaf+bti 
-mthumb -mfloat-abi=soft -fasynchronous-unwind-tables --save-temps -g" } */
+
+__attribute__((noinline)) void
+fn1 (int a, int b, int c)
+{
+  if (a != b + c)
+    __builtin_abort ();
+}
+
+int main ()
+{
+  fn1 (40, 40, 80);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "\.save \{r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.save \{r3, r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.cfi_offset 143, \-8" } } */

diff --git a/gcc/config/arm/aout.h b/gcc/config/arm/aout.h
index 
b918ad3782fbee82320febb8b6e72ad615780261..ffeed45a678f17c63d5b42c21f020ca416cbf23f
 100644
--- a/gcc/config/arm/aout.h
+++ b/gcc/config/arm/aout.h
@@ -74,7 +74,8 @@
   "wr8",   "wr9",   "wr10",  "wr11",                           \
   "wr12",  "wr13",  "wr14",  "wr15",                           \
   "wcgr0", "wcgr1", "wcgr2", "wcgr3",                          \
-  "cc", "vfpcc", "sfp", "afp", "apsrq", "apsrge", "p0"         \
+  "cc", "vfpcc", "sfp", "afp", "apsrq", "apsrge", "p0",                \
+  "ra_auth_code"                                               \
 }
 #endif
 
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 
3495ab857eac38ecdf37e55f1d201b1c35cbde0b..c77777067819f6785e44d30d8e5365505ab98682
 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -816,7 +816,8 @@ extern const int arm_arch_cde_coproc_bits[];
        s16-s31       S VFP variable (aka d8-d15).
        vfpcc           Not a real register.  Represents the VFP condition
                        code flags.
-       vpr             Used to represent MVE VPR predication.  */
+       vpr             Used to represent MVE VPR predication.
+       ra_auth_code    Pseudo register to save PAC.  */
 
 /* The stack backtrace structure is as follows:
   fp points to here:  |  save code pointer  |      [fp]
@@ -857,7 +858,7 @@ extern const int arm_arch_cde_coproc_bits[];
   1,1,1,1,1,1,1,1,             \
   1,1,1,1,                     \
   /* Specials.  */             \
-  1,1,1,1,1,1,1                        \
+  1,1,1,1,1,1,1,1              \
 }
 
 /* 1 for registers not available across function calls.
@@ -887,7 +888,7 @@ extern const int arm_arch_cde_coproc_bits[];
   1,1,1,1,1,1,1,1,             \
   1,1,1,1,                     \
   /* Specials.  */             \
-  1,1,1,1,1,1,1                        \
+  1,1,1,1,1,1,1,1              \
 }
 
 #ifndef SUBTARGET_CONDITIONAL_REGISTER_USAGE
@@ -1063,10 +1064,10 @@ extern const int arm_arch_cde_coproc_bits[];
    && (LAST_VFP_REGNUM - (REGNUM) >= 2 * (N) - 1))
 
 /* The number of hard registers is 16 ARM + 1 CC + 1 SFP + 1 AFP
-   + 1 APSRQ + 1 APSRGE + 1 VPR.  */
+   + 1 APSRQ + 1 APSRGE + 1 VPR + 1 Pseudo register to save PAC.  */
 /* Intel Wireless MMX Technology registers add 16 + 4 more.  */
 /* VFP (VFP3) adds 32 (64) + 1 VFPCC.  */
-#define FIRST_PSEUDO_REGISTER   107
+#define FIRST_PSEUDO_REGISTER   108
 
 #define DBX_REGISTER_NUMBER(REGNO) arm_dbx_register_number (REGNO)
 
@@ -1253,12 +1254,15 @@ extern int arm_regs_in_sequence[];
   CC_REGNUM, VFPCC_REGNUM,                     \
   FRAME_POINTER_REGNUM, ARG_POINTER_REGNUM,    \
   SP_REGNUM, PC_REGNUM, APSRQ_REGNUM,          \
-  APSRGE_REGNUM, VPR_REGNUM                    \
+  APSRGE_REGNUM, VPR_REGNUM, RA_AUTH_CODE      \
 }
 
 #define IS_VPR_REGNUM(REGNUM) \
   ((REGNUM) == VPR_REGNUM)
 
+#define IS_PAC_Pseudo_REGNUM(REGNUM) \
+  ((REGNUM) == RA_AUTH_CODE)
+
 /* Use different register alloc ordering for Thumb.  */
 #define ADJUST_REG_ALLOC_ORDER arm_order_regs_for_local_alloc ()
 
@@ -1297,6 +1301,7 @@ enum reg_class
   SFP_REG,
   AFP_REG,
   VPR_REG,
+  PAC_REG,
   GENERAL_AND_VPR_REGS,
   ALL_REGS,
   LIM_REG_CLASSES
@@ -1327,6 +1332,7 @@ enum reg_class
   "SFP_REG",           \
   "AFP_REG",           \
   "VPR_REG",           \
+  "PAC_REG",           \
   "GENERAL_AND_VPR_REGS", \
   "ALL_REGS"           \
 }
@@ -1356,6 +1362,7 @@ enum reg_class
   { 0x00000000, 0x00000000, 0x00000000, 0x00000040 }, /* SFP_REG */    \
   { 0x00000000, 0x00000000, 0x00000000, 0x00000080 }, /* AFP_REG */    \
   { 0x00000000, 0x00000000, 0x00000000, 0x00000400 }, /* VPR_REG.  */  \
+  { 0x00000000, 0x00000000, 0x00000000, 0x00000800 }, /* PAC_REG.  */  \
   { 0x00005FFF, 0x00000000, 0x00000000, 0x00000400 }, /* GENERAL_AND_VPR_REGS. 
 */ \
   { 0xFFFF7FFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000040F }  /* ALL_REGS.  */ \
 }
diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index 
a2b720a666077c528034c13e27d7c7168cb824d7..a14ea47badd8b90315376c27553e5894beeea990
 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -22151,7 +22151,9 @@ emit_multi_reg_push (unsigned long mask, unsigned long 
dwarf_regs_mask)
     {
       if (mask & (1 << i))
        {
-         reg = gen_rtx_REG (SImode, i);
+         rtx reg1 = reg = gen_rtx_REG (SImode, i);
+         if (arm_current_function_pac_enabled_p () && i == IP_REGNUM)
+           reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE);
 
          XVECEXP (par, 0, 0)
            = gen_rtx_SET (gen_frame_mem
@@ -22168,8 +22170,12 @@ emit_multi_reg_push (unsigned long mask, unsigned long 
dwarf_regs_mask)
 
          if (dwarf_regs_mask & (1 << i))
            {
+             /* Only the first register in the multi push instruction is stored
+                to frame memory here.
+               Eg: push {r7 ,r8, ip, lr}
+               Only r7 is stored to frame memory here.  */
              tmp = gen_rtx_SET (gen_frame_mem (SImode, stack_pointer_rtx),
-                                reg);
+                                reg1);
              RTX_FRAME_RELATED_P (tmp) = 1;
              XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
            }
@@ -22182,18 +22188,25 @@ emit_multi_reg_push (unsigned long mask, unsigned 
long dwarf_regs_mask)
     {
       if (mask & (1 << i))
        {
-         reg = gen_rtx_REG (SImode, i);
+         rtx reg1 = reg = gen_rtx_REG (SImode, i);
+         if (arm_current_function_pac_enabled_p () && i == IP_REGNUM)
+           reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE);
 
          XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
 
          if (dwarf_regs_mask & (1 << i))
            {
+             /* Except the first register in the multi push instruction all the
+                remaining registers are stored to frame memory here.
+                Eg: push {r7, r8, ip, lr}
+                r8, ip (ra_auth_code in case PACBTI enabled) and lr registers
+                are stored to frame memory here.  */
              tmp
                = gen_rtx_SET (gen_frame_mem
                               (SImode,
                                plus_constant (Pmode, stack_pointer_rtx,
                                               4 * j)),
-                              reg);
+                              reg1);
              RTX_FRAME_RELATED_P (tmp) = 1;
              XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
            }
@@ -22278,7 +22291,9 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask)
   for (j = 0, i = 0; j < num_regs; i++)
     if (saved_regs_mask & (1 << i))
       {
-        reg = gen_rtx_REG (SImode, i);
+       rtx reg1 = reg = gen_rtx_REG (SImode, i);
+       if (arm_current_function_pac_enabled_p () && i == IP_REGNUM)
+         reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE);
         if ((num_regs == 1) && emit_update && !return_in_pc)
           {
             /* Emit single load with writeback.  */
@@ -22286,7 +22301,7 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask)
                                  gen_rtx_POST_INC (Pmode,
                                                    stack_pointer_rtx));
             tmp = emit_insn (gen_rtx_SET (reg, tmp));
-            REG_NOTES (tmp) = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
+           REG_NOTES (tmp) = alloc_reg_note (REG_CFA_RESTORE, reg1, dwarf);
             return;
           }
 
@@ -22300,7 +22315,7 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask)
         /* We need to maintain a sequence for DWARF info too.  As dwarf info
            should not have PC, skip PC.  */
         if (i != PC_REGNUM)
-          dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
+         dwarf = alloc_reg_note (REG_CFA_RESTORE, reg1, dwarf);
 
         j++;
       }
@@ -25585,6 +25600,9 @@ arm_regno_class (int regno)
   if (IS_VPR_REGNUM (regno))
     return VPR_REG;
 
+  if (IS_PAC_Pseudo_REGNUM (regno))
+    return PAC_REG;
+
   if (TARGET_THUMB1)
     {
       if (regno == STACK_POINTER_REGNUM)
@@ -29557,6 +29575,9 @@ arm_dbx_register_number (unsigned int regno)
   if (IS_IWMMXT_REGNUM (regno))
     return 112 + regno - FIRST_IWMMXT_REGNUM;
 
+  if (IS_PAC_Pseudo_REGNUM (regno))
+    return 143;
+
   return DWARF_FRAME_REGISTERS;
 }
 
@@ -29678,6 +29699,11 @@ arm_unwind_emit_sequence (FILE * out_file, rtx p)
       reg_size = 8;
       fprintf (out_file, "\t.vsave {");
     }
+  else if (IS_PAC_Pseudo_REGNUM (reg))
+    {
+      reg_size = 4;
+      fprintf (out_file, "\t.save {");
+    }
   else
     /* Unknown register type.  */
     gcc_unreachable ();
@@ -29707,6 +29733,8 @@ arm_unwind_emit_sequence (FILE * out_file, rtx p)
         double precision register names.  */
       if (IS_VFP_REGNUM (reg))
        asm_fprintf (out_file, "d%d", (reg - FIRST_VFP_REGNUM) / 2);
+      else if (IS_PAC_Pseudo_REGNUM (reg))
+       asm_fprintf (asm_out_file, "ra_auth_code");
       else
        asm_fprintf (out_file, "%r", reg);
 
@@ -30575,7 +30603,10 @@ arm_conditional_register_usage (void)
     }
 
   if (TARGET_HAVE_PACBTI)
-    call_used_regs[IP_REGNUM] = 1;
+    {
+      call_used_regs[IP_REGNUM] = 1;
+      fixed_regs[RA_AUTH_CODE] = 0;
+    }
 
   /* The Q and GE bits are only accessed via special ACLE patterns.  */
   CLEAR_HARD_REG_BIT (operand_reg_set, APSRQ_REGNUM);
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 
2221bc68f358f277eff176b7abab5adf1e952399..aaaf13574593846d02655d593d45d751a5b7512e
 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -42,6 +42,7 @@
    (APSRQ_REGNUM    104)       ; Q bit pseudo register
    (APSRGE_REGNUM   105)       ; GE bits pseudo register
    (VPR_REGNUM      106)       ; Vector Predication Register - MVE register.
+   (RA_AUTH_CODE    107)       ; Pseudo register to save PAC.
   ]
 )
 ;; 3rd operand to select_dominance_cc_mode
diff --git a/gcc/testsuite/g++.target/arm/pac-1.C 
b/gcc/testsuite/g++.target/arm/pac-1.C
new file mode 100644
index 
0000000000000000000000000000000000000000..b447213ab4e1b72cacd483efece077fbbca3a608
--- /dev/null
+++ b/gcc/testsuite/g++.target/arm/pac-1.C
@@ -0,0 +1,33 @@
+/* Check that GCC does .save and .cfi_offset directives with RA_AUTH_CODE 
pseudo hard-register.  */
+/* { dg-do compile } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" 
"-mcpu=*" } } */
+/* { dg-options "-march=armv8.1-m.main -mbranch-protection=pac-ret+leaf+bti 
-mthumb -mfloat-abi=soft --save-temps -g" } */
+
+__attribute__((noinline)) void
+fn1 (int a, int b, int c)
+{
+  if (a != b + c)
+    __builtin_abort ();
+  else
+    throw b+c;
+}
+
+int main ()
+{
+  int a = 120;
+  try
+    {
+      fn1 (a, 40, 80);
+    }
+  catch (int x)
+    {
+      if (x != a)
+        __builtin_abort ();
+      else
+       return 0;
+    }
+}
+
+/* { dg-final { scan-assembler "\.save \{r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.save \{r4, r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.cfi_offset 143, \-8" } } */
diff --git a/gcc/testsuite/gcc.target/arm/pac-9.c 
b/gcc/testsuite/gcc.target/arm/pac-9.c
new file mode 100644
index 
0000000000000000000000000000000000000000..2a69db6e8e8a32090a6c16ccc66871946188f8d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pac-9.c
@@ -0,0 +1,21 @@
+/* Check that GCC does .save and .cfi_offset directives with RA_AUTH_CODE 
pseudo hard-register.  */
+/* { dg-do compile } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" 
"-mcpu=*" } } */
+/* { dg-options "-march=armv8.1-m.main -mbranch-protection=pac-ret+leaf+bti 
-mthumb -mfloat-abi=soft -fasynchronous-unwind-tables --save-temps -g" } */
+
+__attribute__((noinline)) void
+fn1 (int a, int b, int c)
+{
+  if (a != b + c)
+    __builtin_abort ();
+}
+
+int main ()
+{
+  fn1 (40, 40, 80);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "\.save \{r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.save \{r3, r7, ra_auth_code, lr\}" } } */
+/* { dg-final { scan-assembler "\.cfi_offset 143, \-8" } } */

Reply via email to