As discussed in https://gcc.gnu.org/pipermail/gcc-patches/2025-June/685733.html the operand of the call should be a mem rather than an unspec.
This patch moves the unspec to an additional argument of the parallel and adjusts cmse_nonsecure_call_inline_register_clear accordingly. The scan-rtl-dump in cmse-18.c needs a fix since we no longer emit the 'unspec' part. In addition, I noticed that since arm_v8_1m_mve_ok is always true in the context of the test (we know we support CMSE as per cmse.exp, and arm_v8_1m_mve_ok finds the adequate options), we actually only use the more permissive regex. To improve that, the patch duplicates the test, such that cmse-18.c forces -march=armv8-m.main+fp (so FPCXP is disabled), and cmse-19.c forces -march=armv8.1-m.main+mve (so FPCXP is enabled). Each test uses the appropriate scan-rtl-dump, and also checks we are using UNSPEC_NONSECURE_MEM (we need to remove -slim for that). The tests enable an FPU via -march so that the test passes whether the testing harness forces -mfloat-abi or not. 2025-07-08 Christophe Lyon <christophe.l...@linaro.org> PR target/120977 gcc/ * config/arm/arm.md (call): Move unspec parameter to parallel. (nonsecure_call_internal): Likewise. (call_value): Likewise. (nonsecure_call_value_internal): Likewise. * config/arm/thumb1.md (nonsecure_call_reg_thumb1_v5): Likewise. (nonsecure_call_value_reg_thumb1_v5): Likewise. * config/arm/thumb2.md (nonsecure_call_reg_thumb2_fpcxt): Likewise. (nonsecure_call_reg_thumb2): Likewise. (nonsecure_call_value_reg_thumb2_fpcxt): Likewise. (nonsecure_call_value_reg_thumb2): Likewise. * config/arm/arm.cc (cmse_nonsecure_call_inline_register_clear): Likewise. gcc/testsuite * gcc.target/arm/cmse/cmse-18.c: Check only the case when FPCXT is not enabled. * gcc.target/arm/cmse/cmse-19.c: New test. CI-tag:always-notify --- gcc/config/arm/arm.cc | 5 +++-- gcc/config/arm/arm.md | 13 +++++++------ gcc/config/arm/thumb1.md | 9 ++++----- gcc/config/arm/thumb2.md | 21 ++++++++++----------- gcc/testsuite/gcc.target/arm/cmse/cmse-18.c | 7 ++++--- gcc/testsuite/gcc.target/arm/cmse/cmse-19.c | 14 ++++++++++++++ 6 files changed, 42 insertions(+), 27 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/cmse/cmse-19.c diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index bde06f3fa86..5d6574761bc 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -18982,7 +18982,8 @@ cmse_nonsecure_call_inline_register_clear (void) call = SET_SRC (call); /* Check if it is a cmse_nonsecure_call. */ - unspec = XEXP (call, 0); + unspec = XVECEXP (pat, 0, 2); + if (GET_CODE (unspec) != UNSPEC || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM) continue; @@ -19009,7 +19010,7 @@ cmse_nonsecure_call_inline_register_clear (void) /* Make sure the register used to hold the function address is not cleared. */ - address = RTVEC_ELT (XVEC (unspec, 0), 0); + address = XEXP (call, 0); gcc_assert (MEM_P (address)); gcc_assert (REG_P (XEXP (address, 0))); address_regnum = REGNO (XEXP (address, 0)); diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 5e5e1120e77..537a3e26a45 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -8623,7 +8623,7 @@ (define_expand "call" if (detect_cmse_nonsecure_call (addr)) { pat = gen_nonsecure_call_internal (operands[0], operands[1], - operands[2]); + operands[2], const0_rtx); emit_call_insn (pat); } else @@ -8665,10 +8665,10 @@ (define_expand "call_internal" (clobber (reg:SI LR_REGNUM))])]) (define_expand "nonsecure_call_internal" - [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand")] - UNSPEC_NONSECURE_MEM) + [(parallel [(call (match_operand 0 "memory_operand") (match_operand 1 "general_operand")) (use (match_operand 2 "" "")) + (unspec:SI [(match_operand 3)] UNSPEC_NONSECURE_MEM) (clobber (reg:SI LR_REGNUM))])] "use_cmse" { @@ -8745,7 +8745,8 @@ (define_expand "call_value" if (detect_cmse_nonsecure_call (addr)) { pat = gen_nonsecure_call_value_internal (operands[0], operands[1], - operands[2], operands[3]); + operands[2], operands[3], + const0_rtx); emit_call_insn (pat); } else @@ -8779,10 +8780,10 @@ (define_expand "call_value_internal" (define_expand "nonsecure_call_value_internal" [(parallel [(set (match_operand 0 "" "") - (call (unspec:SI [(match_operand 1 "memory_operand")] - UNSPEC_NONSECURE_MEM) + (call (match_operand 1 "memory_operand") (match_operand 2 "general_operand"))) (use (match_operand 3 "" "")) + (unspec:SI [(match_operand 4)] UNSPEC_NONSECURE_MEM) (clobber (reg:SI LR_REGNUM))])] "use_cmse" " diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md index f9e89e991d9..4da0086b252 100644 --- a/gcc/config/arm/thumb1.md +++ b/gcc/config/arm/thumb1.md @@ -1874,10 +1874,10 @@ (define_insn "*call_reg_thumb1_v5" ) (define_insn "*nonsecure_call_reg_thumb1_v5" - [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))] - UNSPEC_NONSECURE_MEM) + [(call (mem:SI (reg:SI R4_REGNUM)) (match_operand 0 "" "")) (use (match_operand 1 "" "")) + (unspec:SI [(match_operand 2)]UNSPEC_NONSECURE_MEM) (clobber (reg:SI LR_REGNUM))] "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)" "bl\\t__gnu_cmse_nonsecure_call" @@ -1919,11 +1919,10 @@ (define_insn "*call_value_reg_thumb1_v5" (define_insn "*nonsecure_call_value_reg_thumb1_v5" [(set (match_operand 0 "" "") - (call (unspec:SI - [(mem:SI (reg:SI R4_REGNUM))] - UNSPEC_NONSECURE_MEM) + (call (mem:SI (reg:SI R4_REGNUM)) (match_operand 1 "" ""))) (use (match_operand 2 "" "")) + (unspec:SI [(match_operand 3)] UNSPEC_NONSECURE_MEM) (clobber (reg:SI LR_REGNUM))] "TARGET_THUMB1 && use_cmse" "bl\\t__gnu_cmse_nonsecure_call" diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md index 019f9d438c0..2c2026b1e74 100644 --- a/gcc/config/arm/thumb2.md +++ b/gcc/config/arm/thumb2.md @@ -537,10 +537,10 @@ (define_insn "*call_reg_thumb2" ) (define_insn "*nonsecure_call_reg_thumb2_fpcxt" - [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "l*r"))] - UNSPEC_NONSECURE_MEM) + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) (match_operand 1 "" "")) (use (match_operand 2 "" "")) + (unspec:SI [(match_operand 3)] UNSPEC_NONSECURE_MEM) (clobber (reg:SI LR_REGNUM))] "TARGET_THUMB2 && use_cmse && TARGET_HAVE_FPCXT_CMSE" "blxns\\t%0" @@ -549,10 +549,10 @@ (define_insn "*nonsecure_call_reg_thumb2_fpcxt" ) (define_insn "*nonsecure_call_reg_thumb2" - [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))] - UNSPEC_NONSECURE_MEM) + [(call (mem:SI (reg:SI R4_REGNUM)) (match_operand 0 "" "")) (use (match_operand 1 "" "")) + (unspec:SI [(match_operand 2)] UNSPEC_NONSECURE_MEM) (clobber (reg:SI LR_REGNUM))] "TARGET_THUMB2 && use_cmse && !TARGET_HAVE_FPCXT_CMSE" "bl\\t__gnu_cmse_nonsecure_call" @@ -573,11 +573,10 @@ (define_insn "*call_value_reg_thumb2" (define_insn "*nonsecure_call_value_reg_thumb2_fpcxt" [(set (match_operand 0 "" "") - (call - (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))] - UNSPEC_NONSECURE_MEM) - (match_operand 2 "" ""))) + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" ""))) (use (match_operand 3 "" "")) + (unspec:SI [(match_operand 4)] UNSPEC_NONSECURE_MEM) (clobber (reg:SI LR_REGNUM))] "TARGET_THUMB2 && use_cmse && TARGET_HAVE_FPCXT_CMSE" "blxns\\t%1" @@ -587,10 +586,10 @@ (define_insn "*nonsecure_call_value_reg_thumb2_fpcxt" (define_insn "*nonsecure_call_value_reg_thumb2" [(set (match_operand 0 "" "") - (call - (unspec:SI [(mem:SI (reg:SI R4_REGNUM))] UNSPEC_NONSECURE_MEM) - (match_operand 1 "" ""))) + (call (mem:SI (reg:SI R4_REGNUM)) + (match_operand 1 "" ""))) (use (match_operand 2 "" "")) + (unspec:SI [(match_operand 3)] UNSPEC_NONSECURE_MEM) (clobber (reg:SI LR_REGNUM))] "TARGET_THUMB2 && use_cmse && !TARGET_HAVE_FPCXT_CMSE" "bl\\t__gnu_cmse_nonsecure_call" diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-18.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-18.c index db7d975a90e..eb8a358481d 100644 --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-18.c +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-18.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ -/* { dg-options "-mcmse -fdump-rtl-final-slim" } */ +/* Make sure FPCXT is not enabled. */ +/* { dg-options "-mcmse -fdump-rtl-final -march=armv8-m.main+fp" } */ typedef void (*f)(int) __attribute__((cmse_nonsecure_call)); @@ -8,5 +9,5 @@ void bar(f func, int a) func(a); } -/* { dg-final { scan-rtl-dump "call unspec\\\[\\\[r4:SI\\\]\\\]" "final" { target { ! arm_v8_1m_mve_ok } } } } */ -/* { dg-final { scan-rtl-dump "call unspec\\\[\\\[r\[0-7\]:SI\\\]\\\]" "final" { target { arm_v8_1m_mve_ok } } } } */ +/* { dg-final { scan-rtl-dump "call \\\(mem:SI \\\(reg:SI 4 r4" "final" } } */ +/* { dg-final { scan-rtl-dump "UNSPEC_NONSECURE_MEM" "final" } } */ diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-19.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-19.c new file mode 100644 index 00000000000..ae075c371f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-19.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* This is a duplicate of cmse-18.c, targetting arm_v8_1m_mve, to make sure + FPCXT is enabled. */ +/* { dg-options "-mcmse -fdump-rtl-final -march=armv8.1-m.main+mve" } */ + +typedef void (*f)(int) __attribute__((cmse_nonsecure_call)); + +void bar(f func, int a) +{ + func(a); +} + +/* { dg-final { scan-rtl-dump "call \\\(mem:SI \\\(reg/f:SI \[0-7] r\[0-7\]" "final" } } */ +/* { dg-final { scan-rtl-dump "UNSPEC_NONSECURE_MEM" "final" } } */ -- 2.34.1