]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
arm: Fix CMSE nonecure calls [PR 120977]
authorChristophe Lyon <christophe.lyon@linaro.org>
Tue, 8 Jul 2025 08:08:21 +0000 (08:08 +0000)
committerChristophe Lyon <christophe.lyon@linaro.org>
Fri, 8 Aug 2025 14:20:18 +0000 (14:20 +0000)
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.lyon@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.

gcc/config/arm/arm.cc
gcc/config/arm/arm.md
gcc/config/arm/thumb1.md
gcc/config/arm/thumb2.md
gcc/testsuite/gcc.target/arm/cmse/cmse-18.c
gcc/testsuite/gcc.target/arm/cmse/cmse-19.c [new file with mode: 0644]

index 29b45ae96bda15981fbfb1ca81b328580f807a89..8b951f3d4a67c326bcd06974a8be5ea68194c9a0 100644 (file)
@@ -18983,7 +18983,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;
@@ -19010,7 +19011,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));
index 5e5e1120e77a67eafe61ced0a7182cf312bf594b..537a3e26a4544b43a4979f685cd9ba28a9b44d25 100644 (file)
     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
              (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"
   {
     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
 
 (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"
   "
index f9e89e991d9bca3c4431ac88c6ba07c4362b61bb..4da0086b25271237781799f44b711e5adf2a33b9 100644 (file)
 )
 
 (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"
 
 (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"
index 019f9d438c08fd68725d1da6bc2af358d06223c7..2c2026b1e7475d11e177171598f2e2b7159be199 100644 (file)
 )
 
 (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"
 )
 
 (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"
 
 (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"
 
 (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"
index db7d975a90ea4b3333d1810aea03949ec1e8837e..eb8a358481dfbb759ca8503449e8fdd35f1410b6 100644 (file)
@@ -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 (file)
index 0000000..ae075c3
--- /dev/null
@@ -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" } } */