From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id 554F83947421 for ; Thu, 8 Dec 2022 14:48:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 554F83947421 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=foss.arm.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=foss.arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id AF85C23A; Thu, 8 Dec 2022 06:48:49 -0800 (PST) Received: from [10.57.6.230] (unknown [10.57.6.230]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 102C53F73B; Thu, 8 Dec 2022 06:48:41 -0800 (PST) Message-ID: Date: Thu, 8 Dec 2022 14:48:40 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.2 Subject: Re: [GCC][PATCH 13/15, v4] arm: Add support for dwarf debug directives and pseudo hard-register for PAC feature. Content-Language: en-GB To: Srinath Parvathaneni , gcc-patches@gcc.gnu.org Cc: richard.earnshaw@arm.com, kyrylo.tkachov@arm.com References: <78382b9a-a434-4222-9c2b-bf3f7d35ef17@AZ-NEU-EX04.Arm.com> From: Richard Earnshaw In-Reply-To: <78382b9a-a434-4222-9c2b-bf3f7d35ef17@AZ-NEU-EX04.Arm.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-3495.8 required=5.0 tests=BAYES_00,GIT_PATCH_0,KAM_DMARC_STATUS,KAM_LAZY_DOMAIN_SECURITY,KAM_LOTSOFHASH,KAM_SHORT,NICE_REPLY_A,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On 09/11/2022 14:32, Srinath Parvathaneni via Gcc-patches wrote: > Hello, > > This patch teaches the DWARF support in gcc about RA_AUTH_CODE pseudo hard-register and also > updates the ".save", ".cfi_register", ".cfi_offset", ".cfi_restore" directives accordingly. > This patch also adds support to emit ".pacspval" directive when "pac ip, lr, sp" instruction > in generated in the assembly. > > RA_AUTH_CODE register number is 107 and it's dwarf register number is 143. > > Applying this patch on top of PACBTI series posted here > https://gcc.gnu.org/pipermail/gcc-patches/2022-August/599658.html and when compiling the following > test.c with "-march=armv8.1-m.main+mve+pacbti -mbranch-protection=pac-ret -mthumb -mfloat-abi=hard > fasynchronous-unwind-tables -g -O0 -S" command line options, the assembly output after this patch > looks like below: > > $cat test.c > > void fun1(int a); > void fun(int a,...) > { > fun1(a); > } > > int main() > { > fun (10); > return 0; > } > > $ arm-none-eabi-gcc -march=armv8.1-m.main+mve+pacbti -mbranch-protection=pac-ret -mthumb -mfloat-abi=hard > -fasynchronous-unwind-tables -g -O0 -S test.s > > Assembly output: > ... > fun: > ... > .pacspval > pac ip, lr, sp > .cfi_register 143, 12 > push {r3, r7, ip, lr} > .save {r3, r7, ra_auth_code, lr} > ... > .cfi_offset 143, -24 > ... > .cfi_restore 143 > ... > aut ip, lr, sp > bx lr > ... > main: > ... > .pacspval > pac ip, lr, sp > .cfi_register 143, 12 > push {r3, r7, ip, lr} > .save {r3, r7, ra_auth_code, lr} > ... > .cfi_offset 143, -8 > ... > .cfi_restore 143 > ... > aut ip, lr, sp > bx lr > ... > > Regression tested on arm-none-eabi target and found no regressions. > > Ok for master? > > Regards, > Srinath. > > gcc/testsuite/ChangeLog: > > 2022-11-04 Srinath Parvathaneni > > * g++.target/arm/pac-1.C: New test. > * gcc.target/arm/pac-9.c: New test. > > > 2022-11-04 Srinath Parvathaneni > > * config/arm/aout.h (ra_auth_code): Add entry in enum. > * config/arm/arm.cc (pac_emit): Declare new global boolean variable. > (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): Update frame related infomration and reg notes > for pac/pacbit 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_unwind_emit_set): Add entry for IP_REGNUM in switch case. > (arm_unwind_emit): Update REG_CFA_REGISTER case._ > (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-11-04 Srinath Parvathaneni > > * 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 a2dc3fc145c52d8381c54634687376089a47e704..91c400f12568156ed29bf5d5e59460bf887fbefb 100644 > --- a/gcc/config/arm/arm.h > +++ b/gcc/config/arm/arm.h > @@ -820,7 +820,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] > @@ -861,7 +862,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. > @@ -891,7 +892,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 > @@ -1067,10 +1068,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) > > @@ -1257,12 +1258,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) Pseudo is probably a poor name for this, given the compiler's use of pseudo in a subtly different context. It's probably better to drop PSEUDO and just use IS_PAC_REGNUM. > + > /* Use different register alloc ordering for Thumb. */ > #define ADJUST_REG_ALLOC_ORDER arm_order_regs_for_local_alloc () > > @@ -1301,6 +1305,7 @@ enum reg_class > SFP_REG, > AFP_REG, > VPR_REG, > + PAC_REG, > GENERAL_AND_VPR_REGS, > ALL_REGS, > LIM_REG_CLASSES > @@ -1331,6 +1336,7 @@ enum reg_class > "SFP_REG", \ > "AFP_REG", \ > "VPR_REG", \ > + "PAC_REG", \ > "GENERAL_AND_VPR_REGS", \ > "ALL_REGS" \ > } > @@ -1360,6 +1366,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 3c4722337fdd72586e0655e2009370ad7595fafc..414561624d2eacccc10395db757bfa3c638bb387 100644 > --- a/gcc/config/arm/arm.cc > +++ b/gcc/config/arm/arm.cc > @@ -2452,6 +2452,9 @@ enum tls_reloc { > TLS_DESCSEQ /* GNU scheme */ > }; > > +/* True if PACBTI/PAC instruction is emitted. */ > +static bool pac_emit = false; The logic behind this global looks incorrect. It's initialized here to false, but the only other time it is changed is in arm_expand_prologue where it is unconditionally (and permanently) set to true if current_function_pac_enabled_p () returns true. But once set, it is never reset for the rest of the compilation. I think you should remove this entirely and just use current_function_pac_enabled_p() where you've used this. > + > /* The maximum number of insns to be used when loading a constant. */ > inline static int > arm_constant_limit (bool size_p) > @@ -22154,7 +22157,10 @@ 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 > + && pac_emit) > + reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE); The dwarf code emitter should be able to handle register-register copies like this if the original set operation is marked correctly. Unfortunately, I think this is still needed to get the Arm-specific .save directive to emit the right output. This needs to be mentioned in a comment somewhere. See also the comment above about pac_emit. reg and reg1 is also somewhat confusing. I think it would be better to use 'dwarf_reg' in place of 'reg1'. > > XVECEXP (par, 0, 0) > = gen_rtx_SET (gen_frame_mem > @@ -22172,7 +22178,7 @@ emit_multi_reg_push (unsigned long mask, unsigned long dwarf_regs_mask) > if (dwarf_regs_mask & (1 << i)) > { > 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; > } > @@ -22185,7 +22191,10 @@ 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 > + && pac_emit) > + reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE); > > XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg); > > @@ -22196,7 +22205,7 @@ emit_multi_reg_push (unsigned long mask, unsigned long dwarf_regs_mask) > (SImode, > plus_constant (Pmode, stack_pointer_rtx, > 4 * j)), > - reg); > + reg1); > RTX_FRAME_RELATED_P (tmp) = 1; > XVECEXP (dwarf, 0, dwarf_par_index++) = tmp; > } > @@ -22281,7 +22290,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 && pac_emit) > + reg1 = gen_rtx_REG (SImode, RA_AUTH_CODE); > if ((num_regs == 1) && emit_update && !return_in_pc) > { > /* Emit single load with writeback. */ > @@ -22289,7 +22300,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; > } > > @@ -22303,7 +22314,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++; > } > @@ -23541,9 +23552,14 @@ arm_expand_prologue (void) > instruction will be added before the push of the clobbered IP > (if necessary) by the bti pass. */ > if (aarch_bti_enabled () && !clobber_ip) > - emit_insn (gen_pacbti_nop ()); > + insn = emit_insn (gen_pacbti_nop ()); > else > - emit_insn (gen_pac_nop ()); > + insn = emit_insn (gen_pac_nop ()); > + > + rtx dwarf = gen_rtx_SET (ip_rtx, gen_rtx_REG (SImode, RA_AUTH_CODE)); > + RTX_FRAME_RELATED_P (insn) = 1; > + add_reg_note (insn, REG_CFA_REGISTER, dwarf); > + pac_emit = true; > } > > if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM) > @@ -25602,6 +25618,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) > @@ -29573,6 +29592,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; This value should be #defined somewhere and then the macro definition used here. DWARF_PAC_REGNUM ? > + > return DWARF_FRAME_REGISTERS; > } > > @@ -29666,7 +29688,7 @@ arm_unwind_emit_sequence (FILE * out_file, rtx p) > gcc_assert (nregs); > > reg = REGNO (SET_SRC (XVECEXP (p, 0, 1))); > - if (reg < 16) > + if (reg < 16 || IS_PAC_PSEUDO_REGNUM (reg)) > { > /* For -Os dummy registers can be pushed at the beginning to > avoid separate stack pointer adjustment. */ > @@ -29723,6 +29745,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); > > @@ -29817,7 +29841,7 @@ arm_unwind_emit_set (FILE * out_file, rtx p) > /* Move from sp to reg. */ > asm_fprintf (out_file, "\t.movsp %r\n", REGNO (e0)); > } > - else if (GET_CODE (e1) == PLUS > + else if (GET_CODE (e1) == PLUS > && REG_P (XEXP (e1, 0)) > && REGNO (XEXP (e1, 0)) == SP_REGNUM > && CONST_INT_P (XEXP (e1, 1))) > @@ -29826,6 +29850,13 @@ arm_unwind_emit_set (FILE * out_file, rtx p) > asm_fprintf (out_file, "\t.movsp %r, #%d\n", > REGNO (e0), (int)INTVAL(XEXP (e1, 1))); > } > + else if (REGNO (e0) == IP_REGNUM && GET_CODE (e1) == UNSPEC) > + { > + if (XINT (e1, 1) == UNSPEC_PAC_NOP) > + asm_fprintf (out_file, "\t.pacspval\n"); > + else if (XINT (e1, 1) != UNSPEC_PACBTI_NOP) > + abort (); Just use else gcc_assert (XINT (e1, 1) == USPEC_PACBTI_NOP); > + } > else > abort (); > break; > @@ -29880,8 +29911,15 @@ arm_unwind_emit (FILE * out_file, rtx_insn *insn) > src = SET_SRC (pat); > dest = SET_DEST (pat); > > - gcc_assert (src == stack_pointer_rtx); > + gcc_assert (src == stack_pointer_rtx > + || IS_PAC_PSEUDO_REGNUM (REGNO (src))); > reg = REGNO (dest); > + > + if (IS_PAC_PSEUDO_REGNUM (REGNO (src))) > + { > + pat = PATTERN (insn); > + goto found; > + } This is rather convoluted. I think it would be better to structure this as if (IS_PAC_REGNUM (REGNO (src))) // code just for pac else // existing code for stack_pointer_rtx > asm_fprintf (out_file, "\t.unwind_raw 0, 0x%x @ vsp = r%d\n", > reg + 0x90, reg); > } > @@ -30590,6 +30628,9 @@ arm_conditional_register_usage (void) > global_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1; > } > > + if (TARGET_HAVE_PACBTI) > + fixed_regs[RA_AUTH_CODE] = 0; Really? RA_AUTH_CODE should always be fixed. It's not generally available to the register allocator. > + > /* The Q and GE bits are only accessed via special ACLE patterns. */ > CLEAR_HARD_REG_BIT (operand_reg_set, APSRQ_REGNUM); > CLEAR_HARD_REG_BIT (operand_reg_set, APSRGE_REGNUM); > diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md > index 6e86811ee05f54f0e4bec3a5e632e3bb541fc423..3aea721f9b82445f6b318fd09dcd3d260683baa7 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..96a3ba51362e02a5fe90b517ee28c41e87024475 > --- /dev/null > +++ b/gcc/testsuite/g++.target/arm/pac-1.C > @@ -0,0 +1,36 @@ > +/* 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+mve+pacbti -mbranch-protection=pac-ret -mthumb -mfloat-abi=hard -g -O0" } */ > + > +__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-times "\.pacspval" 2 } } */ > +/* { dg-final { scan-assembler-times "pac ip, lr, sp" 2 } } */ > +/* { dg-final { scan-assembler-times "\.cfi_register 143, 12" 2 } } */ > +/* { dg-final { scan-assembler-times "\.save {r7, ra_auth_code, lr}" 1 } } */ > +/* { dg-final { scan-assembler-times "\.cfi_offset 143, -8" 2 } } */ > +/* { dg-final { scan-assembler-times "\.save {r4, r7, ra_auth_code, lr}" 1 } } */ > 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..283b6786e7fe50f8e3cddea5161743a7553fe6eb > --- /dev/null > +++ b/gcc/testsuite/gcc.target/arm/pac-9.c > @@ -0,0 +1,32 @@ > +/* Check that GCC does .save and .cfi_offset directives with RA_AUTH_CODE pseudo hard-register. */ > +/* { dg-do compile } */ > +/* { dg-require-effective-target mbranch_protection_ok } */ > +/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-marm" "-mcpu=*" } } */ > +/* { dg-options "-march=armv8.1-m.main+mve+pacbti -mbranch-protection=pac-ret -mthumb -mfloat-abi=hard -fasynchronous-unwind-tables -g -O0" } */ > + > +#include "stdio.h" > + > +__attribute__((noinline)) int > +fn1 (int a) > +{ > + const char *fmt = "branch-protection"; > + int fun1(int x,const char *fmt,int c,int d) > + { > + printf("string = %s\n",fmt); > + return x+c+d; > + } > + return fun1(a,fmt,10,10); > +} > + > +int main (void) > +{ > + return fn1 (40); > +} > + > +/* { dg-final { scan-assembler-times "\.pacspval" 3 } } */ > +/* { dg-final { scan-assembler-times "pac ip, lr, sp" 3 } } */ > +/* { dg-final { scan-assembler-times "\.cfi_register 143, 12" 3 } } */ > +/* { dg-final { scan-assembler-times "\.save {r7, ra_auth_code, lr}" 2 } } */ > +/* { dg-final { scan-assembler-times "\.cfi_offset 143, -8" 2 } } */ > +/* { dg-final { scan-assembler-times "\.save {r3, r7, ra_auth_code, lr}" 1 } } */ > +/* { dg-final { scan-assembler-times "\.cfi_offset 143, -12" 1 } } */ > > > R.