public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension
@ 2019-10-23 14:31 Mihail Ionescu
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions Mihail Ionescu
                   ` (19 more replies)
  0 siblings, 20 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 819 bytes --]


This is a patch series to implement support for the Armv8.1-M Mainline Security
Extensions. The specification can be found in:
https://developer.arm.com/docs/ddi0553/latest


Mihail Ionescu(10)
[PATCH, GCC/ARM, 1/10] Fix -mcmse check in libgcc
[PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline
[PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions
[PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
[PATCH, GCC/ARM, 5/10] Clear VFP registers with VSCCLRM
[PATCH, GCC/ARM, 6/10] Clear GPRs inline when calling nscall function
[PATCH, GCC/ARM, 7/10] Clear all VFP regs inline in hardfloat nscall functions
[PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall function
[PATCH, GCC/ARM, 9/10] Call nscall function with blxns
[PATCH, GCC/ARM, 10/10] Enable -mcmse

Regards,
Mihail

[-- Attachment #2: all-patches.tar.gz --]
[-- Type: application/gzip, Size: 36238 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
@ 2019-10-23 14:31 ` Mihail Ionescu
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 1/10] Fix -mcmse check in libgcc Mihail Ionescu
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 9364 bytes --]

[PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to enable
saving/restoring of nonsecure FP context in function with the
cmse_nonsecure_entry attribute.

=== Motivation ===

In Armv8-M Baseline and Mainline, the FP context is cleared on return from
nonsecure entry functions. This means the FP context might change when
calling a nonsecure entry function. This patch uses the new VLDR and
VSTR instructions available in Armv8.1-M Mainline to save/restore the FP
context when calling a nonsecure entry functionfrom nonsecure code.

=== Patch description ===

This patch consists mainly of creating 2 new instruction patterns to
push and pop special FP registers via vldm and vstr and using them in
prologue and epilogue. The patterns are defined as push/pop with an
unspecified operation on the memory accessed, with an unspecified
constant indicating what special FP register is being saved/restored.

Other aspects of the patch include:
  * defining the set of special registers that can be saved/restored and
    their name
  * reserving space in the stack frames for these push/pop
  * preventing return via pop
  * guarding the clearing of FPSCR to target architecture not having
    Armv8.1-M Mainline instructions.

ChangeLog entry is as follows:

*** gcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm.c (fp_sysreg_names): Declare and define.
	(use_return_insn): Also return false for Armv8.1-M Mainline.
	(output_return_instruction): Skip FPSCR clearing if Armv8.1-M
	Mainline instructions are available.
	(arm_compute_frame_layout): Allocate space in frame for FPCXTNS
	when targeting Armv8.1-M Mainline Security Extensions.
	(arm_expand_prologue): Save FPCXTNS if this is an Armv8.1-M
	Mainline entry function.
	(cmse_nonsecure_entry_clear_before_return): Clear IP and r4 if
	targeting Armv8.1-M Mainline or successor.
	(arm_expand_epilogue): Fix indentation of caller-saved register
	clearing.  Restore FPCXTNS if this is an Armv8.1-M Mainline
	entry function.
	* config/arm/arm.h (TARGET_HAVE_FP_CMSE): New macro.
	(FP_SYSREGS): Likewise.
	(enum vfp_sysregs_encoding): Define enum.
	(fp_sysreg_names): Declare.
	* config/arm/unspecs.md (VUNSPEC_VSTR_VLDR): New volatile unspec.
	* config/arm/vfp.md (push_fpsysreg_insn): New define_insn.
	(pop_fpsysreg_insn): Likewise.

*** gcc/testsuite/Changelog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/bitfield-1.c: add checks for VSTR and VLDR.
	* gcc.target/arm/cmse/bitfield-2.c: Likewise.
	* gcc.target/arm/cmse/bitfield-3.c: Likewise.
	* gcc.target/arm/cmse/cmse-1.c: Likewise.
	* gcc.target/arm/cmse/struct-1.c: Likewise.
	* gcc.target/arm/cmse/cmse.exp: Run existing Armv8-M Mainline tests
	from mainline/8m subdirectory and new Armv8.1-M Mainline tests from
	mainline/8_1m subdirectory.
	* gcc.target/arm/cmse/mainline/bitfield-4.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/bitfield-4.c: This.
	* gcc.target/arm/cmse/mainline/bitfield-5.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/bitfield-5.c: This.
	* gcc.target/arm/cmse/mainline/bitfield-6.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/bitfield-6.c: This.
	* gcc.target/arm/cmse/mainline/bitfield-7.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/bitfield-7.c: This.
	* gcc.target/arm/cmse/mainline/bitfield-8.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/bitfield-8.c: This.
	* gcc.target/arm/cmse/mainline/bitfield-9.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/bitfield-9.c: This.
	* gcc.target/arm/cmse/mainline/bitfield-and-union-1.c: Move and rename
	into ...
	* gcc.target/arm/cmse/mainline/8m/bitfield-and-union.c: This.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-13.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-5.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-7.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-8.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/hard/cmse-13.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/hard/cmse-5.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/hard/cmse-5.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/hard/cmse-7.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/hard/cmse-8.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/soft/cmse-13.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/soft/cmse-5.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/soft/cmse-5.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/soft/cmse-7.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/soft/cmse-8.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-5.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-7.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-8.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/softfp/cmse-5.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/softfp/cmse-5.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/softfp/cmse-7.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/softfp/cmse-8.c: This.  Clean up
	dg-skip-if directive for float ABI.
	* gcc.target/arm/cmse/mainline/union-1.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/union-1.c: This.
	* gcc.target/arm/cmse/mainline/union-2.c: Move into ...
	* gcc.target/arm/cmse/mainline/8m/union-2.c: This.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/union-1.c: New file.
	* gcc.target/arm/cmse/mainline/8_1m/union-2.c: New file.
	* lib/target-supports.exp (check_effective_target_arm_cmse_clear_ok):
	New procedure.

Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; testsuite shows no
regression.

Is this ok for trunk?

Best regards,

Mihail

[-- Attachment #2: diff02.patch.gz --]
[-- Type: application/gzip, Size: 9287 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
                   ` (3 preceding siblings ...)
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM Mihail Ionescu
@ 2019-10-23 14:31 ` Mihail Ionescu
  2019-10-23 14:33 ` [PATCH, GCC/ARM, 6/10] Clear GPRs inline when calling nscall function Mihail Ionescu
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 9240 bytes --]

[PATCH, GCC/ARM, 2/10] Add command line support

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to add
command-line support for that new architecture.

=== Patch description ===

Besides the expected enabling of the new value for the -march
command-line option (-march=armv8.1-m.main) and its extensions (see
below), this patch disables support of the Security Extensions for this
newly added architecture. This is done both by not including the cmse
bit in the architecture description and by throwing an error message
when user request Armv8.1-M Mainline Security Extensions. Note that
Armv8-M Baseline and Mainline Security Extensions are still enabled.

Only extensions for already supported instructions are implemented in
this patch. Other extensions (MVE integer and float) will be added in
separate patches. The following configurations are allowed for Armv8.1-M
Mainline with regards to FPU and implemented in this patch:
+ no FPU (+nofp)
+ single precision VFPv5 with FP16 (+fp)
+ double precision VFPv5 with FP16 (+fp.dp)

ChangeLog entry are as follow:

*** gcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm-cpus.in (armv8_1m_main): New feature.
	(ARMv4, ARMv4t, ARMv5t, ARMv5te, ARMv5tej, ARMv6, ARMv6j, ARMv6k,
	ARMv6z, ARMv6kz, ARMv6zk, ARMv6t2, ARMv6m, ARMv7, ARMv7a, ARMv7ve,
	ARMv7r, ARMv7m, ARMv7em, ARMv8a, ARMv8_1a, ARMv8_2a, ARMv8_3a,
	ARMv8_4a, ARMv8_5a, ARMv8m_base, ARMv8m_main, ARMv8r): Reindent.
	(ARMv8_1m_main): New feature group.
	(armv8.1-m.main): New architecture.
	* config/arm/arm-tables.opt: Regenerate.
	* config/arm/arm.c (arm_arch8_1m_main): Define and default initialize.
	(arm_option_reconfigure_globals): Initialize arm_arch8_1m_main.
	(arm_options_perform_arch_sanity_checks): Error out when targeting
	Armv8.1-M Mainline Security Extensions.
	* config/arm/arm.h (arm_arch8_1m_main): Declare.

*** gcc/testsuite/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* lib/target-supports.exp
	(check_effective_target_arm_arch_v8_1m_main_ok): Define.
	(add_options_for_arm_arch_v8_1m_main): Likewise.
	(check_effective_target_arm_arch_v8_1m_main_multilib): Likewise.

Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; testsuite
shows no regression.

Is this ok for trunk?

Best regards,

Mihail


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


diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
index f8a3b3db67a537163bfe787d78c8f2edc4253ab3..652f2a4be9388fd7a74f0ec4615a292fd1cfcd36 100644
--- a/gcc/config/arm/arm-cpus.in
+++ b/gcc/config/arm/arm-cpus.in
@@ -126,6 +126,9 @@ define feature armv8_5
 # M-Profile security extensions.
 define feature cmse
 
+# Architecture rel 8.1-M.
+define feature armv8_1m_main
+
 # Floating point and Neon extensions.
 # VFPv1 is not supported in GCC.
 
@@ -223,21 +226,21 @@ define fgroup ALL_FPU_INTERNAL	vfpv2 vfpv3 vfpv4 fpv5 fp16conv fp_dbl ALL_SIMD_I
 # -mfpu support.
 define fgroup ALL_FP	fp16 ALL_FPU_INTERNAL
 
-define fgroup ARMv4       armv4 notm
-define fgroup ARMv4t      ARMv4 thumb
-define fgroup ARMv5t      ARMv4t armv5t
-define fgroup ARMv5te     ARMv5t armv5te
-define fgroup ARMv5tej    ARMv5te
-define fgroup ARMv6       ARMv5te armv6 be8
-define fgroup ARMv6j      ARMv6
-define fgroup ARMv6k      ARMv6 armv6k
-define fgroup ARMv6z      ARMv6
-define fgroup ARMv6kz     ARMv6k quirk_armv6kz
-define fgroup ARMv6zk     ARMv6k
-define fgroup ARMv6t2     ARMv6 thumb2
+define fgroup ARMv4         armv4 notm
+define fgroup ARMv4t        ARMv4 thumb
+define fgroup ARMv5t        ARMv4t armv5t
+define fgroup ARMv5te       ARMv5t armv5te
+define fgroup ARMv5tej      ARMv5te
+define fgroup ARMv6         ARMv5te armv6 be8
+define fgroup ARMv6j        ARMv6
+define fgroup ARMv6k        ARMv6 armv6k
+define fgroup ARMv6z        ARMv6
+define fgroup ARMv6kz       ARMv6k quirk_armv6kz
+define fgroup ARMv6zk       ARMv6k
+define fgroup ARMv6t2       ARMv6 thumb2
 # This is suspect.  ARMv6-m doesn't really pull in any useful features
 # from ARMv5* or ARMv6.
-define fgroup ARMv6m      armv4 thumb armv5t armv5te armv6 be8
+define fgroup ARMv6m        armv4 thumb armv5t armv5te armv6 be8
 # This is suspect, the 'common' ARMv7 subset excludes the thumb2 'DSP' and
 # integer SIMD instructions that are in ARMv6T2.  */
 define fgroup ARMv7       ARMv6m thumb2 armv7
@@ -256,6 +259,10 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb predres
 define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
 define fgroup ARMv8m_main ARMv7m armv8 cmse
 define fgroup ARMv8r      ARMv8a
+# Feature cmse is omitted to disable Security Extensions support while secure
+# code compiled by GCC does not preserve FP context as allowed by Armv8.1-M
+# Mainline.
+define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
 
 # Useful combinations.
 define fgroup VFPv2	vfpv2
@@ -644,6 +651,17 @@ begin arch armv8-r
  option nofp remove ALL_FP
 end arch armv8-r
 
+begin arch armv8.1-m.main
+ tune for cortex-m7
+ tune flags CO_PROC
+ base 8M_MAIN
+ isa ARMv8_1m_main
+# fp => FPv5-sp-d16; fp.dp => FPv5-d16
+ option fp add FPv5 fp16
+ option fp.dp add FPv5 FP_DBL fp16
+ option nofp remove ALL_FP
+end arch armv8.1-m.main
+
 begin arch iwmmxt
  tune for iwmmxt
  tune flags LDSCHED STRONG XSCALE
diff --git a/gcc/config/arm/arm-tables.opt b/gcc/config/arm/arm-tables.opt
index aeb5b3fbf629e5cfae4d5f6d4d5f1a9c7752a511..d059969904cb39fbe583487e4fbb23d4f9838718 100644
--- a/gcc/config/arm/arm-tables.opt
+++ b/gcc/config/arm/arm-tables.opt
@@ -353,10 +353,13 @@ EnumValue
 Enum(arm_arch) String(armv8-r) Value(28)
 
 EnumValue
-Enum(arm_arch) String(iwmmxt) Value(29)
+Enum(arm_arch) String(armv8.1-m.main) Value(29)
 
 EnumValue
-Enum(arm_arch) String(iwmmxt2) Value(30)
+Enum(arm_arch) String(iwmmxt) Value(30)
+
+EnumValue
+Enum(arm_arch) String(iwmmxt2) Value(31)
 
 Enum
 Name(arm_fpu) Type(enum fpu_type)
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 8b67c9c3657b312be223ab60c01969958baa9ed3..307f1b59ba4456c901c8cb842d9961a740b6bb8d 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -456,6 +456,10 @@ extern int arm_arch8_3;
 /* Nonzero if this chip supports the ARM Architecture 8.4 extensions.  */
 extern int arm_arch8_4;
 
+/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
+   extensions.  */
+extern int arm_arch8_1m_main;
+
 /* Nonzero if this chip supports the FP16 instructions extension of ARM
    Architecture 8.2.  */
 extern int arm_fp16_inst;
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9f0975dc0710626ef46abecaa3a205e993821118..9aca9484a9cdc26d6afee25e81f06b4047df2174 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -903,6 +903,9 @@ int arm_arch8_3 = 0;
 
 /* Nonzero if this chip supports the ARM Architecture 8.4 extensions.  */
 int arm_arch8_4 = 0;
+/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
+   extensions.  */
+int arm_arch8_1m_main = 0;
 
 /* Nonzero if this chip supports the FP16 instructions extension of ARM
    Architecture 8.2.  */
@@ -3642,6 +3645,8 @@ arm_option_reconfigure_globals (void)
   arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_2);
   arm_arch8_3 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_3);
   arm_arch8_4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_4);
+  arm_arch8_1m_main = bitmap_bit_p (arm_active_target.isa,
+				    isa_bit_armv8_1m_main);
   arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
   arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb2);
   arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, isa_bit_xscale);
@@ -3727,6 +3732,9 @@ arm_options_perform_arch_sanity_checks (void)
   if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
     sorry ("__fp16 and no ldrh");
 
+  if (use_cmse && arm_arch8_1m_main)
+    error ("ARMv8.1-M Mainline Security Extensions are unsupported");
+
   if (use_cmse && !arm_arch_cmse)
     error ("target CPU does not support ARMv8-M Security Extensions");
 
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 6a1aaca9691b7fe9ae5e0e5b1874c7af34a3a6e3..5688aa7a6b7e8dad28aa553755b657464071a982 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -4242,10 +4242,11 @@ foreach { armfunc armflag armdefs } {
 	v8a "-march=armv8-a" __ARM_ARCH_8A__
 	v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
 	v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
+	v8r "-march=armv8-r" __ARM_ARCH_8R__
 	v8m_base "-march=armv8-m.base -mthumb -mfloat-abi=soft"
 		__ARM_ARCH_8M_BASE__
 	v8m_main "-march=armv8-m.main -mthumb" __ARM_ARCH_8M_MAIN__
-	v8r "-march=armv8-r" __ARM_ARCH_8R__ } {
+	v8_1m_main "-march=armv8.1-m.main -mthumb" __ARM_ARCH_8M_MAIN__ } {
     eval [string map [list FUNC $armfunc FLAG $armflag DEFS $armdefs ] {
 	proc check_effective_target_arm_arch_FUNC_ok { } {
 	    return [check_no_compiler_messages arm_arch_FUNC_ok assembly {


[-- Attachment #2: diff01.patch --]
[-- Type: text/plain, Size: 6617 bytes --]

diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
index f8a3b3db67a537163bfe787d78c8f2edc4253ab3..652f2a4be9388fd7a74f0ec4615a292fd1cfcd36 100644
--- a/gcc/config/arm/arm-cpus.in
+++ b/gcc/config/arm/arm-cpus.in
@@ -126,6 +126,9 @@ define feature armv8_5
 # M-Profile security extensions.
 define feature cmse
 
+# Architecture rel 8.1-M.
+define feature armv8_1m_main
+
 # Floating point and Neon extensions.
 # VFPv1 is not supported in GCC.
 
@@ -223,21 +226,21 @@ define fgroup ALL_FPU_INTERNAL	vfpv2 vfpv3 vfpv4 fpv5 fp16conv fp_dbl ALL_SIMD_I
 # -mfpu support.
 define fgroup ALL_FP	fp16 ALL_FPU_INTERNAL
 
-define fgroup ARMv4       armv4 notm
-define fgroup ARMv4t      ARMv4 thumb
-define fgroup ARMv5t      ARMv4t armv5t
-define fgroup ARMv5te     ARMv5t armv5te
-define fgroup ARMv5tej    ARMv5te
-define fgroup ARMv6       ARMv5te armv6 be8
-define fgroup ARMv6j      ARMv6
-define fgroup ARMv6k      ARMv6 armv6k
-define fgroup ARMv6z      ARMv6
-define fgroup ARMv6kz     ARMv6k quirk_armv6kz
-define fgroup ARMv6zk     ARMv6k
-define fgroup ARMv6t2     ARMv6 thumb2
+define fgroup ARMv4         armv4 notm
+define fgroup ARMv4t        ARMv4 thumb
+define fgroup ARMv5t        ARMv4t armv5t
+define fgroup ARMv5te       ARMv5t armv5te
+define fgroup ARMv5tej      ARMv5te
+define fgroup ARMv6         ARMv5te armv6 be8
+define fgroup ARMv6j        ARMv6
+define fgroup ARMv6k        ARMv6 armv6k
+define fgroup ARMv6z        ARMv6
+define fgroup ARMv6kz       ARMv6k quirk_armv6kz
+define fgroup ARMv6zk       ARMv6k
+define fgroup ARMv6t2       ARMv6 thumb2
 # This is suspect.  ARMv6-m doesn't really pull in any useful features
 # from ARMv5* or ARMv6.
-define fgroup ARMv6m      armv4 thumb armv5t armv5te armv6 be8
+define fgroup ARMv6m        armv4 thumb armv5t armv5te armv6 be8
 # This is suspect, the 'common' ARMv7 subset excludes the thumb2 'DSP' and
 # integer SIMD instructions that are in ARMv6T2.  */
 define fgroup ARMv7       ARMv6m thumb2 armv7
@@ -256,6 +259,10 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb predres
 define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
 define fgroup ARMv8m_main ARMv7m armv8 cmse
 define fgroup ARMv8r      ARMv8a
+# Feature cmse is omitted to disable Security Extensions support while secure
+# code compiled by GCC does not preserve FP context as allowed by Armv8.1-M
+# Mainline.
+define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
 
 # Useful combinations.
 define fgroup VFPv2	vfpv2
@@ -644,6 +651,17 @@ begin arch armv8-r
  option nofp remove ALL_FP
 end arch armv8-r
 
+begin arch armv8.1-m.main
+ tune for cortex-m7
+ tune flags CO_PROC
+ base 8M_MAIN
+ isa ARMv8_1m_main
+# fp => FPv5-sp-d16; fp.dp => FPv5-d16
+ option fp add FPv5 fp16
+ option fp.dp add FPv5 FP_DBL fp16
+ option nofp remove ALL_FP
+end arch armv8.1-m.main
+
 begin arch iwmmxt
  tune for iwmmxt
  tune flags LDSCHED STRONG XSCALE
diff --git a/gcc/config/arm/arm-tables.opt b/gcc/config/arm/arm-tables.opt
index aeb5b3fbf629e5cfae4d5f6d4d5f1a9c7752a511..d059969904cb39fbe583487e4fbb23d4f9838718 100644
--- a/gcc/config/arm/arm-tables.opt
+++ b/gcc/config/arm/arm-tables.opt
@@ -353,10 +353,13 @@ EnumValue
 Enum(arm_arch) String(armv8-r) Value(28)
 
 EnumValue
-Enum(arm_arch) String(iwmmxt) Value(29)
+Enum(arm_arch) String(armv8.1-m.main) Value(29)
 
 EnumValue
-Enum(arm_arch) String(iwmmxt2) Value(30)
+Enum(arm_arch) String(iwmmxt) Value(30)
+
+EnumValue
+Enum(arm_arch) String(iwmmxt2) Value(31)
 
 Enum
 Name(arm_fpu) Type(enum fpu_type)
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 8b67c9c3657b312be223ab60c01969958baa9ed3..307f1b59ba4456c901c8cb842d9961a740b6bb8d 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -456,6 +456,10 @@ extern int arm_arch8_3;
 /* Nonzero if this chip supports the ARM Architecture 8.4 extensions.  */
 extern int arm_arch8_4;
 
+/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
+   extensions.  */
+extern int arm_arch8_1m_main;
+
 /* Nonzero if this chip supports the FP16 instructions extension of ARM
    Architecture 8.2.  */
 extern int arm_fp16_inst;
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9f0975dc0710626ef46abecaa3a205e993821118..9aca9484a9cdc26d6afee25e81f06b4047df2174 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -903,6 +903,9 @@ int arm_arch8_3 = 0;
 
 /* Nonzero if this chip supports the ARM Architecture 8.4 extensions.  */
 int arm_arch8_4 = 0;
+/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
+   extensions.  */
+int arm_arch8_1m_main = 0;
 
 /* Nonzero if this chip supports the FP16 instructions extension of ARM
    Architecture 8.2.  */
@@ -3642,6 +3645,8 @@ arm_option_reconfigure_globals (void)
   arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_2);
   arm_arch8_3 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_3);
   arm_arch8_4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_4);
+  arm_arch8_1m_main = bitmap_bit_p (arm_active_target.isa,
+				    isa_bit_armv8_1m_main);
   arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
   arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb2);
   arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, isa_bit_xscale);
@@ -3727,6 +3732,9 @@ arm_options_perform_arch_sanity_checks (void)
   if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
     sorry ("__fp16 and no ldrh");
 
+  if (use_cmse && arm_arch8_1m_main)
+    error ("ARMv8.1-M Mainline Security Extensions are unsupported");
+
   if (use_cmse && !arm_arch_cmse)
     error ("target CPU does not support ARMv8-M Security Extensions");
 
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 6a1aaca9691b7fe9ae5e0e5b1874c7af34a3a6e3..5688aa7a6b7e8dad28aa553755b657464071a982 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -4242,10 +4242,11 @@ foreach { armfunc armflag armdefs } {
 	v8a "-march=armv8-a" __ARM_ARCH_8A__
 	v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
 	v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
+	v8r "-march=armv8-r" __ARM_ARCH_8R__
 	v8m_base "-march=armv8-m.base -mthumb -mfloat-abi=soft"
 		__ARM_ARCH_8M_BASE__
 	v8m_main "-march=armv8-m.main -mthumb" __ARM_ARCH_8M_MAIN__
-	v8r "-march=armv8-r" __ARM_ARCH_8R__ } {
+	v8_1m_main "-march=armv8.1-m.main -mthumb" __ARM_ARCH_8M_MAIN__ } {
     eval [string map [list FUNC $armfunc FLAG $armflag DEFS $armdefs ] {
 	proc check_effective_target_arm_arch_FUNC_ok { } {
 	    return [check_no_compiler_messages arm_arch_FUNC_ok assembly {


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
                   ` (2 preceding siblings ...)
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 5/10] Clear VFP registers with VSCCLRM Mihail Ionescu
@ 2019-10-23 14:31 ` Mihail Ionescu
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline Mihail Ionescu
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 49510 bytes --]

[PATCH, GCC/ARM, 4/10] Clear GPR with CLRM

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to improve
code density of functions with the cmse_nonsecure_entry attribute and
when calling function with the cmse_nonsecure_call attribute by using
CLRM to do all the general purpose registers clearing as well as
clearing the APSR register.

=== Patch description ===

This patch adds a new pattern for the CLRM instruction and guards the
current clearing code in output_return_instruction() and thumb_exit()
on Armv8.1-M Mainline instructions not being present.
cmse_clear_registers () is then modified to use the new CLRM instruction
when targeting Armv8.1-M Mainline while keeping Armv8-M register
clearing code for VFP registers.

For the CLRM instruction, which does not mandated APSR in the register
list, checking whether it is the right volatile unspec or a clearing
register is done in clear_operation_p.

Note that load/store multiple were deemed sufficiently different in
terms of RTX structure compared to the CLRM pattern for a different
function to be used to validate the match_parallel.

ChangeLog entries are as follows:

*** gcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm-protos.h (clear_operation_p): Declare.
	* config/arm/arm.c (clear_operation_p): New function.
	(cmse_clear_registers): Generate clear_multiple instruction pattern if
	targeting Armv8.1-M Mainline or successor.
	(output_return_instruction): Only output APSR register clearing if
	Armv8.1-M Mainline instructions not available.
	(thumb_exit): Likewise.
	* config/arm/predicates.md (clear_multiple_operation): New predicate.
	* config/arm/thumb2.md (clear_apsr): New define_insn.
	(clear_multiple): Likewise.
	* config/arm/unspecs.md (VUNSPEC_CLRM_APSR): New volatile unspec.

*** gcc/testsuite/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/bitfield-1.c: Add check for CLRM.
	* gcc.target/arm/cmse/bitfield-2.c: Likewise.
	* gcc.target/arm/cmse/bitfield-3.c: Likewise.
	* gcc.target/arm/cmse/struct-1.c: Likewise.
	* gcc.target/arm/cmse/cmse-14.c: Likewise.
	* gcc.target/arm/cmse/cmse-1.c: Likewise.  Restrict checks for Armv8-M
	GPR clearing when CLRM is not available.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.

Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
regression.

Is this ok for trunk?

Best regards,

Mihail


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


diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index f995974f9bb89ab3c7ff0888c394b0dfaf7da60c..1a948d2c97526ad7e67e8d4a610ac74cfdb13882 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -77,6 +77,7 @@ extern int thumb_legitimate_offset_p (machine_mode, HOST_WIDE_INT);
 extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
 extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
                                  bool, bool);
+extern bool clear_operation_p (rtx);
 extern int arm_const_double_rtx (rtx);
 extern int vfp3_const_double_rtx (rtx);
 extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, int *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index d485e80096c9d2eef2172d211a0a5ab63cdbb3c7..3a373cea33c3d0b966cbe700d26f66fe069e1efb 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -13499,6 +13499,66 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode,
   return true;
 }
 
+/* Checks whether OP is a valid parallel pattern for a CLRM insn.  To be a
+   valid CLRM pattern, OP must have the following form:
+
+   [(set (reg:SI <N>) (const_int 0))
+    (set (reg:SI <M>) (const_int 0))
+    ...
+    (unspec_volatile [(const_int 0)]
+		     VUNSPEC_CLRM_APSR)
+   ]
+
+   Any number (including 0) of set expressions is valid, the volatile unspec is
+   optional.  All registers but SP and PC are allowed and registers must be in
+   strict increasing order.  */
+
+bool
+clear_operation_p (rtx op)
+{
+  HOST_WIDE_INT i;
+  unsigned regno, last_regno;
+  rtx elt, reg, zero;
+  machine_mode mode;
+  HOST_WIDE_INT count = XVECLEN (op, 0);
+
+  for (i = 0; i < count; i++)
+    {
+      elt = XVECEXP (op, 0, i);
+
+      if (GET_CODE (elt) == UNSPEC_VOLATILE)
+	{
+	  if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
+	      || XVECLEN (elt, 0) != 1
+	      || XVECEXP (elt, 0, 0) != CONST0_RTX (SImode)
+	      || i != count - 1)
+	    return false;
+
+	  continue;
+	}
+
+      if (GET_CODE (elt) != SET)
+	return false;
+
+      reg = SET_DEST (elt);
+      regno = REGNO (reg);
+      mode = GET_MODE (reg);
+      zero = SET_SRC (elt);
+
+      if (!REG_P (reg)
+	  || GET_MODE (reg) != SImode
+	  || regno == SP_REGNUM
+	  || regno == PC_REGNUM
+	  || (i != 0 && regno <= last_regno)
+	  || zero != CONST0_RTX (SImode))
+	return false;
+
+      last_regno = REGNO (reg);
+    }
+
+  return true;
+}
+
 /* Return true iff it would be profitable to turn a sequence of NOPS loads
    or stores (depending on IS_STORE) into a load-multiple or store-multiple
    instruction.  ADD_OFFSET is nonzero if the base address register needs
@@ -17596,6 +17656,56 @@ cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
 
   /* Clear full registers.  */
 
+  if (TARGET_HAVE_FPCXT_CMSE)
+    {
+      rtvec vunspec_vec;
+      int i, j, k, nb_regs;
+      rtx use_seq, par, reg, set, vunspec;
+      int to_clear_bitmap_size = SBITMAP_SIZE (to_clear_bitmap);
+      auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
+      auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
+
+      /* Get set of core registers to clear.  */
+      bitmap_clear (core_regs_bitmap);
+      bitmap_set_range (core_regs_bitmap, R0_REGNUM,
+			IP_REGNUM - R0_REGNUM + 1);
+      bitmap_and (to_clear_core_bitmap, to_clear_bitmap,
+		  core_regs_bitmap);
+      gcc_assert (!bitmap_empty_p (to_clear_core_bitmap));
+
+      if (bitmap_empty_p (to_clear_core_bitmap))
+	return;
+
+      /* Create clrm RTX pattern.  */
+      nb_regs = bitmap_count_bits (to_clear_core_bitmap);
+      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 1));
+
+      /* Insert core register clearing RTX in the pattern.  */
+      start_sequence ();
+      for (j = 0, i = minregno; j < nb_regs; i++)
+	{
+	  if (!bitmap_bit_p (to_clear_core_bitmap, i))
+	    continue;
+
+	  reg = gen_rtx_REG (SImode, i);
+	  set = gen_rtx_SET (reg, const0_rtx);
+	  XVECEXP (par, 0, j++) = set;
+	  emit_use (reg);
+	}
+
+      /* Insert APSR register clearing RTX in the pattern.  */
+      vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
+      vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
+					 VUNSPEC_CLRM_APSR);
+      XVECEXP (par, 0, j) = vunspec;
+
+      use_seq = get_insns ();
+      end_sequence ();
+
+      emit_insn_after (use_seq, emit_insn (par));
+      minregno = FIRST_VFP_REGNUM;
+    }
+
   /* If not marked for clearing, clearing_reg already does not contain
      any secret.  */
   if (clearing_regno <= maxregno
@@ -20259,40 +20369,50 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
 	    {
-	      /* Check if we have to clear the 'GE bits' which is only used if
-		 parallel add and subtraction instructions are available.  */
-	      if (TARGET_INT_SIMD)
-		snprintf (instr, sizeof (instr),
-			  "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
-	      else
-		snprintf (instr, sizeof (instr),
-			  "msr%s\tAPSR_nzcvq, %%|lr", conditional);
-
-	      output_asm_insn (instr, & operand);
-	      /* Do not clear FPSCR if targeting Armv8.1-M Mainline, VLDR takes
-		 care of it.  */
-	      if (TARGET_HARD_FLOAT && ! TARGET_HAVE_FPCXT_CMSE)
+	      /* For Armv8.1-M, this is cleared as part of the CLRM instruction
+		 emitted by cmse_nonsecure_entry_clear_before_return () and the
+		 VSTR/VLDR instructions in the prologue and epilogue.  */
+	      if (!TARGET_HAVE_FPCXT_CMSE)
 		{
-		  /* Clear the cumulative exception-status bits (0-4,7) and the
-		     condition code bits (28-31) of the FPSCR.  We need to
-		     remember to clear the first scratch register used (IP) and
-		     save and restore the second (r4).  */
-		  snprintf (instr, sizeof (instr), "push\t{%%|r4}");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "vmrs\t%%|ip, fpscr");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "movw\t%%|r4, #65376");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "movt\t%%|r4, #4095");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "and\t%%|ip, %%|r4");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "vmsr\tfpscr, %%|ip");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "mov\t%%|ip, %%|lr");
+		  /* Check if we have to clear the 'GE bits' which is only used if
+		     parallel add and subtraction instructions are available.  */
+		  if (TARGET_INT_SIMD)
+		    snprintf (instr, sizeof (instr),
+			      "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
+		  else
+		    snprintf (instr, sizeof (instr),
+			      "msr%s\tAPSR_nzcvq, %%|lr", conditional);
+
 		  output_asm_insn (instr, & operand);
+		  /* Do not clear FPSCR if targeting Armv8.1-M Mainline, VLDR takes
+		     care of it.  */
+		  if (TARGET_HARD_FLOAT)
+		    {
+		      /* Clear the cumulative exception-status bits (0-4,7) and
+			 the condition code bits (28-31) of the FPSCR.  We need
+			 to remember to clear the first scratch register used
+			 (IP) and save and restore the second (r4).
+
+			 Important note: the length of the
+			 thumb2_cmse_entry_return insn pattern must account for
+			 the size of the below instructions.  */
+		      snprintf (instr, sizeof (instr), "push\t{%%|r4}");
+		      output_asm_insn (instr, & operand);
+		      snprintf (instr, sizeof (instr), "vmrs\t%%|ip, fpscr");
+		      output_asm_insn (instr, & operand);
+		      snprintf (instr, sizeof (instr), "movw\t%%|r4, #65376");
+		      output_asm_insn (instr, & operand);
+		      snprintf (instr, sizeof (instr), "movt\t%%|r4, #4095");
+		      output_asm_insn (instr, & operand);
+		      snprintf (instr, sizeof (instr), "and\t%%|ip, %%|r4");
+		      output_asm_insn (instr, & operand);
+		      snprintf (instr, sizeof (instr), "vmsr\tfpscr, %%|ip");
+		      output_asm_insn (instr, & operand);
+		      snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
+		      output_asm_insn (instr, & operand);
+		      snprintf (instr, sizeof (instr), "mov\t%%|ip, %%|lr");
+		      output_asm_insn (instr, & operand);
+		    }
 		}
 	      snprintf (instr, sizeof (instr), "bxns\t%%|lr");
 	    }
@@ -24690,8 +24810,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
 	{
-	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
-		       reg_containing_return_addr);
+	  /* For Armv8.1-M, this is cleared as part of the CLRM instruction
+	     emitted by cmse_nonsecure_entry_clear_before_return ().  */
+	  if (!TARGET_HAVE_FPCXT_CMSE)
+	    asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+			 reg_containing_return_addr);
 	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
 	}
       else
@@ -24931,11 +25054,14 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
          address.  It may therefore contain information that we might not want
 	 to leak, hence it must be cleared.  The value in R0 will never be a
 	 secret at this point, so it is safe to use it, see the clearing code
-	 in 'cmse_nonsecure_entry_clear_before_return'.  */
+	 in cmse_nonsecure_entry_clear_before_return ().  */
       if (reg_containing_return_addr != LR_REGNUM)
 	asm_fprintf (f, "\tmov\tlr, r0\n");
 
-      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
+      /* For Armv8.1-M, this is cleared as part of the CLRM instruction emitted
+	 by cmse_nonsecure_entry_clear_before_return ().  */
+      if (!TARGET_HAVE_FPCXT_CMSE)
+	asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
       asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
     }
   else
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index 8b36e7ee462235ad26e132f1ccf98d28c2487d67..e5c583ef3d167194e7a061d7c3e98d3b4bb5269c 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -510,6 +510,12 @@
 	    (match_test "satisfies_constraint_Dy (op)")
 	    (match_test "satisfies_constraint_G (op)"))))
 
+(define_special_predicate "clear_multiple_operation"
+  (match_code "parallel")
+{
+ return clear_operation_p (op);
+})
+
 (define_special_predicate "load_multiple_operation"
   (match_code "parallel")
 {
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index 6ccc875e2b4e7b8ce256e52da966dfe220c6f5d6..9994c0d59f741ef47d0ec43dd53a2324b031d048 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1599,3 +1599,39 @@
       FAIL;
  }")
 
+(define_insn "*clear_apsr"
+  [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)]
+  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
+  "clrm%?\\t{APSR}"
+  [(set_attr "predicable" "yes")]
+)
+
+;; The operands are validated through the clear_multiple_operation
+;; match_parallel predicate rather than through constraints so enable it only
+;; after reload.
+(define_insn "*clear_multiple"
+  [(match_parallel 0 "clear_multiple_operation"
+     [(set (match_operand:SI 1 "register_operand" "")
+	   (const_int 0))])]
+  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && reload_completed"
+  {
+    char pattern[100];
+    int i, num_saves = XVECLEN (operands[0], 0);
+
+    strcpy (pattern, \"clrm%?\\t{\");
+    for (i = 0; i < num_saves; i++)
+      {
+	if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
+	  strcat (pattern, \"APSR\");
+	else
+	  strcat (pattern,
+		  reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 0))]);
+	if (i < num_saves - 1)
+	  strcat (pattern, \", %|\");
+      }
+    strcat (pattern, \"}\");
+    output_asm_insn (pattern, operands);
+    return \"\";
+  }
+  [(set_attr "predicable" "yes")]
+)
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 324359be7127f04a80ebc0079ad0a9964dfd82a7..498bc0798dbaaa3ee73815ba27864ae92a2fd08e 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -174,6 +174,7 @@
   VUNSPEC_MRRC2		; Represent the coprocessor mrrc2 instruction.
   VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional speculation barrier.
   VUNSPEC_VSTR_VLDR	; Represent the vstr/vldr instruction.
+  VUNSPEC_CLRM_APSR	; Represent the clearing of APSR with clrm instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
index 6d611e130b6f3b544807b767927d99b89071343b..7036cb9508c27d56c4b2c01a81c44bf6f1f9c781 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -36,6 +36,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
index b7ec0a040319545b50590261278f1517bcb22796..50d4979470dd21738453e0d70c7a69ee0752ac41 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -33,6 +33,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
 /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
index 7b9c3f0fe061317f71d3122dea7a55ab5311f234..2b7507c900ab18705083ba1d86359e1ae36a50a2 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -34,5 +34,6 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
 /* { dg-final { scan-assembler "movt\tr1, 63" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index aa0ec8e0b0f0953a5a5cbc2db58413176c2505f3..35cab1f3233daac9fba50d25dac23364c798fb9c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -105,8 +105,10 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "bic" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! arm_cmse_clear_ok } } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
 
 int call_callback (void)
 {
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
index df1ea52bec533c36a738d7d3b2b2ff749b0f3713..1f5af7c2dba7747f6058d12af8ef80b4dd1b1431 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -9,5 +9,6 @@ int foo (void)
   return bar ();
 }
 
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
index 62c63b888ab49e99fba0a08b69941e73c9a8d33b..c52e1c14d9956743625e3b8a200e823f163924e3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
@@ -12,5 +12,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
index b718a70522b86e2bc58900681a781129543f8869..fdba955a32fc5ad492b74974185f98470bc49a7e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
@@ -10,6 +10,5 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
index 16536ab4f9ec5782463ab90f404a2e9f6f938850..85068ceaac6a5c0c60af4a54c0af0d20326fc18d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
@@ -13,5 +13,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
index 0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5..af69d38acf47d9d1d55480edba2b66f07e2d06ad 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
@@ -10,6 +10,5 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
index 914ea39626f2f72eac8c9c1cb495b0855e58f5e1..62201595549f07b046c7c5972d612ab155c4c38c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
@@ -13,5 +13,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
index 32435d255805331c7c56a096675b7a2af3286e5e..287f0d6faad113fbc8c30051280668baa58ab130 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
@@ -7,7 +7,5 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index eb655b5504e58dc842853c8cb874c5cef3b82aa6..7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
index ab266af7092afbce868792446124c291188e8a90..638643d0a6772d43f440df3942c6c723f1eff3ef 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
@@ -6,10 +6,6 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
@@ -26,7 +22,6 @@
 /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index fd1a24b3258e8403394dac98ff7c4712b0eb7a1b..9ec14d1a707839e4858bac72bc292fd0984bf86c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index d8f9b7758d50f74f777fcda22f3f6714ff28bb96..d375879ed02483c05d7853c95f9b9e15383ff321 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 4878c6ef9157abff003780fbf6401db8eb3ef2f3..e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
index 82aad2d13d6b170c92fd2c2345ab76f41e383013..7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
@@ -6,10 +6,6 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
@@ -19,7 +15,6 @@
 /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index 8e054c2aeebac4bd3f164b00ad867bc2d72cb674..d998b43a148250a15eb4aae9fb0ef6e4bf51203b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index e74cea7697ba1c12ebeef21636d1b8fd60b42677..e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index 4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d..d43a9f85a199ecdf7e018852b3af9b4cf36af81f 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -8,9 +8,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
index c684d79fae00feb8e15e9f142735f005473b6011..157bccb9ff3256056d496a0d0770374315b04d87 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
@@ -5,13 +5,8 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
-/* { dg-final { scan-assembler "mov\tip, lr" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index 4cb6a54a0a5b02954519e64503d7c2c4c0e4750d..02e48157a2c61b0a8bee77e949944acc2a4bee37 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -7,10 +7,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index 4764b2fadfb38661764b909cdb2c9cd109e24df0..c7a22a2ba464dce26b289635dd8dcc8213ae33d8 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -9,8 +9,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
index 9b2e7565d24ff52138b0fb90a1e6268aa4c515a0..2522a17a6316d76a21d8d241d4c44cdddf1981e0 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
@@ -8,9 +8,6 @@
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
@@ -27,7 +24,6 @@
 /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index 9e93d75c35de5e3dde1074fb99da94edc2648319..d34ca383236fdd31723966e6218ea918cf8c9122 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index 566889e66c8cea6ca32348f48742d2c325336995..ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -10,8 +10,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..ff9a7dfa5e696e3a6c4132343d0ee94c3068c208 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -9,8 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
-/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
index 5af1fdb934ce5aa5afd8d096122b6e9b55591bd9..eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
@@ -7,10 +7,6 @@
 
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
@@ -19,7 +15,6 @@
 /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 1c38290e79d18a8f94e44b974c54220e553a9a49..03d36aa650986b6069e2fe1c1f3f98fa9664d88a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index 39c2e72f968ce9f30d36bd347544ca26b3dfad8a..ce45e10688f855ca7b2a63777d2b3d3418815589 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -10,8 +10,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
index d51db020c7707fa714364b10dd3ec5896a9dad17..dbd1d34413ef36f2b03716c0d9cf46b024af0835 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
@@ -10,6 +10,5 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
index 131afbbf4289b238438c53ab9ea55d13b8567513..3edc7f1e259779a24e722d67ed544c0a673090c7 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
@@ -14,5 +14,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
index 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..3a72406df2492206c2cb8ac7b63e4242ec0ba598 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
@@ -9,8 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
-/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
index 5f6891a26d9be6edbb81c6c9e71897d1b49c8c60..90fdac18e30424edca60b6f884227adbf716899d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -29,5 +29,6 @@ main (void)
 /* { dg-final { scan-assembler "movs\tr1, #255" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */


[-- Attachment #2: diff03.patch.gz --]
[-- Type: application/gzip, Size: 7672 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 5/10] Clear VFP registers with VSCCLRM
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions Mihail Ionescu
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 1/10] Fix -mcmse check in libgcc Mihail Ionescu
@ 2019-10-23 14:31 ` Mihail Ionescu
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM Mihail Ionescu
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 35497 bytes --]

[PATCH, GCC/ARM, 5/10] Clear VFP registers with VSCCLRM

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to improve
code density of functions with the cmse_nonsecure_entry attribute and
when calling function with the cmse_nonsecure_call attribute by using
VSCCLRM to do all the VFP register clearing as well as clearing the VFP
register.

=== Patch description ===

This patch adds a new pattern for the VSCCLRM instruction.
cmse_clear_registers () is then modified to use the new VSCCLRM
instruction when targeting Armv8.1-M Mainline, thus, making the Armv8-M
register clearing code specific to Armv8-M.

Since the VSCCLRM instruction mandates VPR in the register list, the
pattern is encoded with a parallel which only requires an unspecified
VUNSPEC_CLRM_VPR constant modelling the APSR clearing. Other expression
in the parallel are expected to be set expression for clearing the VFP
registers.

ChangeLog entry is as follows:

*** gcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm-protos.h (clear_operation_p): Adapt prototype.
	* config/arm/arm.c (clear_operation_p): Extend to be able to check a
	clear_vfp_multiple pattern based on a new vfp parameter.
	(cmse_clear_registers): Generate VSCCLRM to clear VFP registers when
	targeting Armv8.1-M Mainline.
	(cmse_nonsecure_entry_clear_before_return): Clear VFP registers
	unconditionally when targeting Armv8.1-M Mainline architecture.  Check
	whether VFP registers are available before looking call_used_regs for a
	VFP register.
	* config/arm/predicates.md (clear_multiple_operation): Adapt to change
	of prototype of clear_operation_p.
	(clear_vfp_multiple_operation): New predicate.
	* config/arm/unspecs.md (VUNSPEC_VSCCLRM_VPR): New volatile unspec.
	* config/arm/vfp.md (clear_vfp_multiple): New define_insn.

*** gcc/testsuite/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/bitfield-1.c: Add check for VSCCLRM.
	* gcc.target/arm/cmse/bitfield-2.c: Likewise.
	* gcc.target/arm/cmse/bitfield-3.c: Likewise.
	* gcc.target/arm/cmse/cmse-1.c: Likewise.
	* gcc.target/arm/cmse/struct-1.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: Likewise.

Testing: Bootstrapped on arm-linux-gnueabihf and testsuite shows no
regression.

Is this ok for trunk?

Best regards,

Mihail


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


diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 1a948d2c97526ad7e67e8d4a610ac74cfdb13882..37a46982bbc1a8f17abe2fc76ba3cb7d65257c0d 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -77,7 +77,7 @@ extern int thumb_legitimate_offset_p (machine_mode, HOST_WIDE_INT);
 extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
 extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
                                  bool, bool);
-extern bool clear_operation_p (rtx);
+extern bool clear_operation_p (rtx, bool);
 extern int arm_const_double_rtx (rtx);
 extern int vfp3_const_double_rtx (rtx);
 extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, int *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index f1f730cecff0fb3da7115ea1147dc8b9ab7076b7..5f3ce5c4605f609d1a0e31c0f697871266bdf835 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -13499,8 +13499,9 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode,
   return true;
 }
 
-/* Checks whether OP is a valid parallel pattern for a CLRM insn.  To be a
-   valid CLRM pattern, OP must have the following form:
+/* Checks whether OP is a valid parallel pattern for a CLRM (if VFP is false)
+   or VSCCLRM (otherwise) insn.  To be a valid CLRM pattern, OP must have the
+   following form:
 
    [(set (reg:SI <N>) (const_int 0))
     (set (reg:SI <M>) (const_int 0))
@@ -13511,22 +13512,35 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode,
 
    Any number (including 0) of set expressions is valid, the volatile unspec is
    optional.  All registers but SP and PC are allowed and registers must be in
-   strict increasing order.  */
+   strict increasing order.
+
+   To be a valid VSCCLRM pattern, OP must have the following form:
+
+   [(unspec_volatile [(const_int 0)]
+		     VUNSPEC_VSCCLRM_VPR)
+    (set (reg:SF <N>) (const_int 0))
+    (set (reg:SF <M>) (const_int 0))
+    ...
+   ]
+
+   As with CLRM, any number (including 0) of set expressions is valid, however
+   the volatile unspec is mandatory here.  Any VFP single-precision register is
+   accepted but all registers must be consecutive and in increasing order.  */
 
 bool
-clear_operation_p (rtx op)
+clear_operation_p (rtx op, bool vfp)
 {
-  HOST_WIDE_INT i;
   unsigned regno, last_regno;
   rtx elt, reg, zero;
-  machine_mode mode;
   HOST_WIDE_INT count = XVECLEN (op, 0);
+  HOST_WIDE_INT i, first_set = vfp ? 1 : 0;
+  machine_mode expected_mode = vfp ? E_SFmode : E_SImode;
 
-  for (i = 0; i < count; i++)
+  for (i = first_set; i < count; i++)
     {
       elt = XVECEXP (op, 0, i);
 
-      if (GET_CODE (elt) == UNSPEC_VOLATILE)
+      if (!vfp && GET_CODE (elt) == UNSPEC_VOLATILE)
 	{
 	  if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
 	      || XVECLEN (elt, 0) != 1
@@ -13542,17 +13556,26 @@ clear_operation_p (rtx op)
 
       reg = SET_DEST (elt);
       regno = REGNO (reg);
-      mode = GET_MODE (reg);
       zero = SET_SRC (elt);
 
       if (!REG_P (reg)
-	  || GET_MODE (reg) != SImode
-	  || regno == SP_REGNUM
-	  || regno == PC_REGNUM
-	  || (i != 0 && regno <= last_regno)
+	  || GET_MODE (reg) != expected_mode
 	  || zero != CONST0_RTX (SImode))
 	return false;
 
+      if (vfp)
+	{
+	  if (i != 1 && regno != last_regno + 1)
+	    return false;
+	}
+      else
+	{
+	  if (regno == SP_REGNUM || regno == PC_REGNUM)
+	    return false;
+	  if (i != 0 && regno <= last_regno)
+	    return false;
+	}
+
       last_regno = REGNO (reg);
     }
 
@@ -17665,6 +17688,43 @@ cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
       auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
       auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
 
+      for (i = FIRST_VFP_REGNUM; i <= maxregno; i += nb_regs)
+	{
+	  /* Find next register to clear and exit if none.  */
+	  for (; i <= maxregno && !bitmap_bit_p (to_clear_bitmap, i); i++);
+	  if (i > maxregno)
+	    break;
+
+	  /* Compute number of consecutive registers to clear.  */
+	  for (j = i; j <= maxregno && bitmap_bit_p (to_clear_bitmap, j);
+	       j++);
+	  nb_regs = j - i;
+
+	  /* Create VSCCLRM RTX pattern.  */
+	  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 1));
+	  vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
+	  vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
+					     VUNSPEC_VSCCLRM_VPR);
+	  XVECEXP (par, 0, 0) = vunspec;
+
+	  /* Insert VFP register clearing RTX in the pattern.  */
+	  start_sequence ();
+	  for (k = 1, j = i; j <= maxregno && k < nb_regs + 1; j++)
+	    {
+	      if (!bitmap_bit_p (to_clear_bitmap, j))
+		continue;
+
+	      reg = gen_rtx_REG (SFmode, j);
+	      set = gen_rtx_SET (reg, const0_rtx);
+	      XVECEXP (par, 0, k++) = set;
+	      emit_use (reg);
+	    }
+	  use_seq = get_insns ();
+	  end_sequence ();
+
+	  emit_insn_after (use_seq, emit_insn (par));
+	}
+
       /* Get set of core registers to clear.  */
       bitmap_clear (core_regs_bitmap);
       bitmap_set_range (core_regs_bitmap, R0_REGNUM,
@@ -17703,49 +17763,50 @@ cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
       end_sequence ();
 
       emit_insn_after (use_seq, emit_insn (par));
-      minregno = FIRST_VFP_REGNUM;
-    }
-
-  /* If not marked for clearing, clearing_reg already does not contain
-     any secret.  */
-  if (clearing_regno <= maxregno
-      && bitmap_bit_p (to_clear_bitmap, clearing_regno))
-    {
-      emit_move_insn (clearing_reg, const0_rtx);
-      emit_use (clearing_reg);
-      bitmap_clear_bit (to_clear_bitmap, clearing_regno);
     }
-
-  for (regno = minregno; regno <= maxregno; regno++)
+  else
     {
-      if (!bitmap_bit_p (to_clear_bitmap, regno))
-	continue;
+      /* If not marked for clearing, clearing_reg already does not contain
+	 any secret.  */
+      if (clearing_regno <= maxregno
+	  && bitmap_bit_p (to_clear_bitmap, clearing_regno))
+	{
+	  emit_move_insn (clearing_reg, const0_rtx);
+	  emit_use (clearing_reg);
+	  bitmap_clear_bit (to_clear_bitmap, clearing_regno);
+	}
 
-      if (IS_VFP_REGNUM (regno))
+      for (regno = minregno; regno <= maxregno; regno++)
 	{
-	  /* If regno is an even vfp register and its successor is also to
-	     be cleared, use vmov.  */
-	  if (TARGET_VFP_DOUBLE
-	      && VFP_REGNO_OK_FOR_DOUBLE (regno)
-	      && bitmap_bit_p (to_clear_bitmap, regno + 1))
+	  if (!bitmap_bit_p (to_clear_bitmap, regno))
+	    continue;
+
+	  if (IS_VFP_REGNUM (regno))
 	    {
-	      emit_move_insn (gen_rtx_REG (DFmode, regno),
-			      CONST1_RTX (DFmode));
-	      emit_use (gen_rtx_REG (DFmode, regno));
-	      regno++;
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (TARGET_VFP_DOUBLE
+		  && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		  && bitmap_bit_p (to_clear_bitmap, regno + 1))
+		{
+		  emit_move_insn (gen_rtx_REG (DFmode, regno),
+				  CONST1_RTX (DFmode));
+		  emit_use (gen_rtx_REG (DFmode, regno));
+		  regno++;
+		}
+	      else
+		{
+		  emit_move_insn (gen_rtx_REG (SFmode, regno),
+				  CONST1_RTX (SFmode));
+		  emit_use (gen_rtx_REG (SFmode, regno));
+		}
 	    }
 	  else
 	    {
-	      emit_move_insn (gen_rtx_REG (SFmode, regno),
-			      CONST1_RTX (SFmode));
-	      emit_use (gen_rtx_REG (SFmode, regno));
+	      emit_move_insn (gen_rtx_REG (SImode, regno), clearing_reg);
+	      emit_use (gen_rtx_REG (SImode, regno));
 	    }
 	}
-      else
-	{
-	  emit_move_insn (gen_rtx_REG (SImode, regno), clearing_reg);
-	  emit_use (gen_rtx_REG (SImode, regno));
-	}
     }
 }
 
@@ -25948,7 +26009,8 @@ thumb1_expand_prologue (void)
 void
 cmse_nonsecure_entry_clear_before_return (void)
 {
-  int regno, maxregno = TARGET_HARD_FLOAT ? LAST_VFP_REGNUM : IP_REGNUM;
+  bool clear_vfpregs = TARGET_HARD_FLOAT || TARGET_HAVE_FPCTX_CMSE;
+  int regno, maxregno = clear_vfpregs ? LAST_VFP_REGNUM : IP_REGNUM;
   uint32_t padding_bits_to_clear = 0;
   auto_sbitmap to_clear_bitmap (maxregno + 1);
   rtx r1_reg, result_rtl, clearing_reg = NULL_RTX;
@@ -25960,7 +26022,7 @@ cmse_nonsecure_entry_clear_before_return (void)
 
   /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
      registers.  */
-  if (TARGET_HARD_FLOAT)
+  if (clear_vfpregs)
     {
       int float_bits = D7_VFP_REGNUM - FIRST_VFP_REGNUM + 1;
 
@@ -25989,7 +26051,9 @@ cmse_nonsecure_entry_clear_before_return (void)
 	continue;
       if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
 	continue;
-      if (call_used_or_fixed_reg_p (regno))
+      if (call_used_or_fixed_reg_p (regno)
+	  && (!IN_RANGE (regno, FIRST_VFP_REGNUM, LAST_VFP_REGNUM)
+	      || TARGET_HARD_FLOAT))
 	bitmap_set_bit (to_clear_bitmap, regno);
     }
 
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index e5c583ef3d167194e7a061d7c3e98d3b4bb5269c..69c10c06ff405e19efa172217a08a512c66cb902 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -513,7 +513,13 @@
 (define_special_predicate "clear_multiple_operation"
   (match_code "parallel")
 {
- return clear_operation_p (op);
+ return clear_operation_p (op, /*vfp*/false);
+})
+
+(define_special_predicate "clear_vfp_multiple_operation"
+  (match_code "parallel")
+{
+ return clear_operation_p (op, /*vfp*/true);
 })
 
 (define_special_predicate "load_multiple_operation"
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 498bc0798dbaaa3ee73815ba27864ae92a2fd08e..ad072705525cc3c4035a22b5f99546bcd0e79ec5 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -175,6 +175,8 @@
   VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional speculation barrier.
   VUNSPEC_VSTR_VLDR	; Represent the vstr/vldr instruction.
   VUNSPEC_CLRM_APSR	; Represent the clearing of APSR with clrm instruction.
+  VUNSPEC_VSCCLRM_VPR	; Represent the clearing of VPR with vscclrm
+			; instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index 027f0524430fd3af9e4d10cd98bd177141407841..2bf928f32626ce2731ebdfedffbbf64d806eff53 100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -1641,6 +1641,42 @@
    (set_attr "type" "load_4")]
 )
 
+;; The operands are validated through the clear_multiple_operation
+;; match_parallel predicate rather than through constraints so enable it only
+;; after reload.
+(define_insn "*clear_vfp_multiple"
+  [(match_parallel 0 "clear_vfp_multiple_operation"
+     [(unspec_volatile [(const_int 0)]
+		       VUNSPEC_VSCCLRM_VPR)])]
+  "TARGET_HAVE_FPCTX_CMSE && use_cmse && reload_completed"
+  {
+    int num_regs = XVECLEN (operands[0], 0);
+    char pattern[30];
+    const char *regname;
+    rtx reg;
+
+    strcpy (pattern, \"vscclrm%?\\t{%|\");
+    if (num_regs > 1)
+      {
+	reg = XEXP (XVECEXP (operands[0], 0, 1), 0);
+	strcat (pattern, reg_names[REGNO (reg)]);
+	if (num_regs > 2)
+	  {
+	    strcat (pattern, \"-%|\");
+	    reg = XEXP (XVECEXP (operands[0], 0, num_regs - 1), 0);
+	    strcat (pattern, reg_names[REGNO (reg)]);
+	  }
+	strcat (pattern, \", \");
+      }
+
+    strcat (pattern, \"VPR}\");
+    output_asm_insn (pattern, operands);
+    return \"\";
+  }
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "mov_reg")]
+)
+
 (define_insn_and_split "*cmpsf_split_vfp"
   [(set (reg:CCFP CC_REGNUM)
 	(compare:CCFP (match_operand:SF 0 "s_register_operand"  "t")
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
index 7036cb9508c27d56c4b2c01a81c44bf6f1f9c781..cae2f06140766176c9af6e4b2b4a3e722fbad67c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -36,6 +36,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
index 50d4979470dd21738453e0d70c7a69ee0752ac41..21a53cd85792e439314f5c88080d7f1c6fcdec66 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -33,6 +33,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
 /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
index 2b7507c900ab18705083ba1d86359e1ae36a50a2..e8f973e3f06881d33d661f81c0eb6671e48a0d01 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -34,6 +34,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
 /* { dg-final { scan-assembler "movt\tr1, 63" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index 35cab1f3233daac9fba50d25dac23364c798fb9c..29d78ddd6166321bdf0acabf011138b276151e85 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -105,6 +105,7 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "bic" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! arm_cmse_clear_ok } } } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index 7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97..9719f799229e245264d377c3726190ca768ca1dd 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -10,21 +10,10 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
index 638643d0a6772d43f440df3942c6c723f1eff3ef..dc62b742ba5ab9f7480ca93396e5eb354c5e64dd 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
@@ -6,22 +6,7 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s1-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index 9ec14d1a707839e4858bac72bc292fd0984bf86c..a6951d34afeed54c0ac2e937345cbfbbfb2c4b2d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -9,22 +9,7 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index d375879ed02483c05d7853c95f9b9e15383ff321..23db88dc66d584acbba64a10d3f6fd06f066b321 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -11,20 +11,7 @@
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0..2898efabb2b37e3c8dacaf029b5a40be8edcc624 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -9,18 +9,13 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
index 7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6..55e7a4f7ae0c4420a40a250f246a769eff28e6c7 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
@@ -6,15 +6,7 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s1-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index d998b43a148250a15eb4aae9fb0ef6e4bf51203b..a4520a9166e36b1d3220befb72a1863799b2f424 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -9,14 +9,7 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf..c79d3188026d9248abde7967671c05a09b75c49f 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -10,13 +10,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
index 157bccb9ff3256056d496a0d0770374315b04d87..d3a3a742b8b4ff99c973a8c9edd77297c7f37ae2 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
@@ -7,6 +7,7 @@
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
index 2522a17a6316d76a21d8d241d4c44cdddf1981e0..bbe16cee9c2c29e0701f54c3e393ad3c7efb8e87 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
@@ -8,22 +8,7 @@
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
index eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b..c7dda6a3d6088366358ff4bc1e6d83ad9b03ea6e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
@@ -7,14 +7,7 @@
 
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
index 90fdac18e30424edca60b6f884227adbf716899d..755564369ae7deecfb038e67591e679bb06f62b1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -29,6 +29,7 @@ main (void)
 /* { dg-final { scan-assembler "movs\tr1, #255" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */


[-- Attachment #2: diff04.patch --]
[-- Type: text/plain, Size: 32209 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 1a948d2c97526ad7e67e8d4a610ac74cfdb13882..37a46982bbc1a8f17abe2fc76ba3cb7d65257c0d 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -77,7 +77,7 @@ extern int thumb_legitimate_offset_p (machine_mode, HOST_WIDE_INT);
 extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
 extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
                                  bool, bool);
-extern bool clear_operation_p (rtx);
+extern bool clear_operation_p (rtx, bool);
 extern int arm_const_double_rtx (rtx);
 extern int vfp3_const_double_rtx (rtx);
 extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, int *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index f1f730cecff0fb3da7115ea1147dc8b9ab7076b7..5f3ce5c4605f609d1a0e31c0f697871266bdf835 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -13499,8 +13499,9 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode,
   return true;
 }
 
-/* Checks whether OP is a valid parallel pattern for a CLRM insn.  To be a
-   valid CLRM pattern, OP must have the following form:
+/* Checks whether OP is a valid parallel pattern for a CLRM (if VFP is false)
+   or VSCCLRM (otherwise) insn.  To be a valid CLRM pattern, OP must have the
+   following form:
 
    [(set (reg:SI <N>) (const_int 0))
     (set (reg:SI <M>) (const_int 0))
@@ -13511,22 +13512,35 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode,
 
    Any number (including 0) of set expressions is valid, the volatile unspec is
    optional.  All registers but SP and PC are allowed and registers must be in
-   strict increasing order.  */
+   strict increasing order.
+
+   To be a valid VSCCLRM pattern, OP must have the following form:
+
+   [(unspec_volatile [(const_int 0)]
+		     VUNSPEC_VSCCLRM_VPR)
+    (set (reg:SF <N>) (const_int 0))
+    (set (reg:SF <M>) (const_int 0))
+    ...
+   ]
+
+   As with CLRM, any number (including 0) of set expressions is valid, however
+   the volatile unspec is mandatory here.  Any VFP single-precision register is
+   accepted but all registers must be consecutive and in increasing order.  */
 
 bool
-clear_operation_p (rtx op)
+clear_operation_p (rtx op, bool vfp)
 {
-  HOST_WIDE_INT i;
   unsigned regno, last_regno;
   rtx elt, reg, zero;
-  machine_mode mode;
   HOST_WIDE_INT count = XVECLEN (op, 0);
+  HOST_WIDE_INT i, first_set = vfp ? 1 : 0;
+  machine_mode expected_mode = vfp ? E_SFmode : E_SImode;
 
-  for (i = 0; i < count; i++)
+  for (i = first_set; i < count; i++)
     {
       elt = XVECEXP (op, 0, i);
 
-      if (GET_CODE (elt) == UNSPEC_VOLATILE)
+      if (!vfp && GET_CODE (elt) == UNSPEC_VOLATILE)
 	{
 	  if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
 	      || XVECLEN (elt, 0) != 1
@@ -13542,17 +13556,26 @@ clear_operation_p (rtx op)
 
       reg = SET_DEST (elt);
       regno = REGNO (reg);
-      mode = GET_MODE (reg);
       zero = SET_SRC (elt);
 
       if (!REG_P (reg)
-	  || GET_MODE (reg) != SImode
-	  || regno == SP_REGNUM
-	  || regno == PC_REGNUM
-	  || (i != 0 && regno <= last_regno)
+	  || GET_MODE (reg) != expected_mode
 	  || zero != CONST0_RTX (SImode))
 	return false;
 
+      if (vfp)
+	{
+	  if (i != 1 && regno != last_regno + 1)
+	    return false;
+	}
+      else
+	{
+	  if (regno == SP_REGNUM || regno == PC_REGNUM)
+	    return false;
+	  if (i != 0 && regno <= last_regno)
+	    return false;
+	}
+
       last_regno = REGNO (reg);
     }
 
@@ -17665,6 +17688,43 @@ cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
       auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
       auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
 
+      for (i = FIRST_VFP_REGNUM; i <= maxregno; i += nb_regs)
+	{
+	  /* Find next register to clear and exit if none.  */
+	  for (; i <= maxregno && !bitmap_bit_p (to_clear_bitmap, i); i++);
+	  if (i > maxregno)
+	    break;
+
+	  /* Compute number of consecutive registers to clear.  */
+	  for (j = i; j <= maxregno && bitmap_bit_p (to_clear_bitmap, j);
+	       j++);
+	  nb_regs = j - i;
+
+	  /* Create VSCCLRM RTX pattern.  */
+	  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 1));
+	  vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
+	  vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
+					     VUNSPEC_VSCCLRM_VPR);
+	  XVECEXP (par, 0, 0) = vunspec;
+
+	  /* Insert VFP register clearing RTX in the pattern.  */
+	  start_sequence ();
+	  for (k = 1, j = i; j <= maxregno && k < nb_regs + 1; j++)
+	    {
+	      if (!bitmap_bit_p (to_clear_bitmap, j))
+		continue;
+
+	      reg = gen_rtx_REG (SFmode, j);
+	      set = gen_rtx_SET (reg, const0_rtx);
+	      XVECEXP (par, 0, k++) = set;
+	      emit_use (reg);
+	    }
+	  use_seq = get_insns ();
+	  end_sequence ();
+
+	  emit_insn_after (use_seq, emit_insn (par));
+	}
+
       /* Get set of core registers to clear.  */
       bitmap_clear (core_regs_bitmap);
       bitmap_set_range (core_regs_bitmap, R0_REGNUM,
@@ -17703,49 +17763,50 @@ cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
       end_sequence ();
 
       emit_insn_after (use_seq, emit_insn (par));
-      minregno = FIRST_VFP_REGNUM;
-    }
-
-  /* If not marked for clearing, clearing_reg already does not contain
-     any secret.  */
-  if (clearing_regno <= maxregno
-      && bitmap_bit_p (to_clear_bitmap, clearing_regno))
-    {
-      emit_move_insn (clearing_reg, const0_rtx);
-      emit_use (clearing_reg);
-      bitmap_clear_bit (to_clear_bitmap, clearing_regno);
     }
-
-  for (regno = minregno; regno <= maxregno; regno++)
+  else
     {
-      if (!bitmap_bit_p (to_clear_bitmap, regno))
-	continue;
+      /* If not marked for clearing, clearing_reg already does not contain
+	 any secret.  */
+      if (clearing_regno <= maxregno
+	  && bitmap_bit_p (to_clear_bitmap, clearing_regno))
+	{
+	  emit_move_insn (clearing_reg, const0_rtx);
+	  emit_use (clearing_reg);
+	  bitmap_clear_bit (to_clear_bitmap, clearing_regno);
+	}
 
-      if (IS_VFP_REGNUM (regno))
+      for (regno = minregno; regno <= maxregno; regno++)
 	{
-	  /* If regno is an even vfp register and its successor is also to
-	     be cleared, use vmov.  */
-	  if (TARGET_VFP_DOUBLE
-	      && VFP_REGNO_OK_FOR_DOUBLE (regno)
-	      && bitmap_bit_p (to_clear_bitmap, regno + 1))
+	  if (!bitmap_bit_p (to_clear_bitmap, regno))
+	    continue;
+
+	  if (IS_VFP_REGNUM (regno))
 	    {
-	      emit_move_insn (gen_rtx_REG (DFmode, regno),
-			      CONST1_RTX (DFmode));
-	      emit_use (gen_rtx_REG (DFmode, regno));
-	      regno++;
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (TARGET_VFP_DOUBLE
+		  && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		  && bitmap_bit_p (to_clear_bitmap, regno + 1))
+		{
+		  emit_move_insn (gen_rtx_REG (DFmode, regno),
+				  CONST1_RTX (DFmode));
+		  emit_use (gen_rtx_REG (DFmode, regno));
+		  regno++;
+		}
+	      else
+		{
+		  emit_move_insn (gen_rtx_REG (SFmode, regno),
+				  CONST1_RTX (SFmode));
+		  emit_use (gen_rtx_REG (SFmode, regno));
+		}
 	    }
 	  else
 	    {
-	      emit_move_insn (gen_rtx_REG (SFmode, regno),
-			      CONST1_RTX (SFmode));
-	      emit_use (gen_rtx_REG (SFmode, regno));
+	      emit_move_insn (gen_rtx_REG (SImode, regno), clearing_reg);
+	      emit_use (gen_rtx_REG (SImode, regno));
 	    }
 	}
-      else
-	{
-	  emit_move_insn (gen_rtx_REG (SImode, regno), clearing_reg);
-	  emit_use (gen_rtx_REG (SImode, regno));
-	}
     }
 }
 
@@ -25948,7 +26009,8 @@ thumb1_expand_prologue (void)
 void
 cmse_nonsecure_entry_clear_before_return (void)
 {
-  int regno, maxregno = TARGET_HARD_FLOAT ? LAST_VFP_REGNUM : IP_REGNUM;
+  bool clear_vfpregs = TARGET_HARD_FLOAT || TARGET_HAVE_FPCTX_CMSE;
+  int regno, maxregno = clear_vfpregs ? LAST_VFP_REGNUM : IP_REGNUM;
   uint32_t padding_bits_to_clear = 0;
   auto_sbitmap to_clear_bitmap (maxregno + 1);
   rtx r1_reg, result_rtl, clearing_reg = NULL_RTX;
@@ -25960,7 +26022,7 @@ cmse_nonsecure_entry_clear_before_return (void)
 
   /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
      registers.  */
-  if (TARGET_HARD_FLOAT)
+  if (clear_vfpregs)
     {
       int float_bits = D7_VFP_REGNUM - FIRST_VFP_REGNUM + 1;
 
@@ -25989,7 +26051,9 @@ cmse_nonsecure_entry_clear_before_return (void)
 	continue;
       if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
 	continue;
-      if (call_used_or_fixed_reg_p (regno))
+      if (call_used_or_fixed_reg_p (regno)
+	  && (!IN_RANGE (regno, FIRST_VFP_REGNUM, LAST_VFP_REGNUM)
+	      || TARGET_HARD_FLOAT))
 	bitmap_set_bit (to_clear_bitmap, regno);
     }
 
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index e5c583ef3d167194e7a061d7c3e98d3b4bb5269c..69c10c06ff405e19efa172217a08a512c66cb902 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -513,7 +513,13 @@
 (define_special_predicate "clear_multiple_operation"
   (match_code "parallel")
 {
- return clear_operation_p (op);
+ return clear_operation_p (op, /*vfp*/false);
+})
+
+(define_special_predicate "clear_vfp_multiple_operation"
+  (match_code "parallel")
+{
+ return clear_operation_p (op, /*vfp*/true);
 })
 
 (define_special_predicate "load_multiple_operation"
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 498bc0798dbaaa3ee73815ba27864ae92a2fd08e..ad072705525cc3c4035a22b5f99546bcd0e79ec5 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -175,6 +175,8 @@
   VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional speculation barrier.
   VUNSPEC_VSTR_VLDR	; Represent the vstr/vldr instruction.
   VUNSPEC_CLRM_APSR	; Represent the clearing of APSR with clrm instruction.
+  VUNSPEC_VSCCLRM_VPR	; Represent the clearing of VPR with vscclrm
+			; instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index 027f0524430fd3af9e4d10cd98bd177141407841..2bf928f32626ce2731ebdfedffbbf64d806eff53 100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -1641,6 +1641,42 @@
    (set_attr "type" "load_4")]
 )
 
+;; The operands are validated through the clear_multiple_operation
+;; match_parallel predicate rather than through constraints so enable it only
+;; after reload.
+(define_insn "*clear_vfp_multiple"
+  [(match_parallel 0 "clear_vfp_multiple_operation"
+     [(unspec_volatile [(const_int 0)]
+		       VUNSPEC_VSCCLRM_VPR)])]
+  "TARGET_HAVE_FPCTX_CMSE && use_cmse && reload_completed"
+  {
+    int num_regs = XVECLEN (operands[0], 0);
+    char pattern[30];
+    const char *regname;
+    rtx reg;
+
+    strcpy (pattern, \"vscclrm%?\\t{%|\");
+    if (num_regs > 1)
+      {
+	reg = XEXP (XVECEXP (operands[0], 0, 1), 0);
+	strcat (pattern, reg_names[REGNO (reg)]);
+	if (num_regs > 2)
+	  {
+	    strcat (pattern, \"-%|\");
+	    reg = XEXP (XVECEXP (operands[0], 0, num_regs - 1), 0);
+	    strcat (pattern, reg_names[REGNO (reg)]);
+	  }
+	strcat (pattern, \", \");
+      }
+
+    strcat (pattern, \"VPR}\");
+    output_asm_insn (pattern, operands);
+    return \"\";
+  }
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "mov_reg")]
+)
+
 (define_insn_and_split "*cmpsf_split_vfp"
   [(set (reg:CCFP CC_REGNUM)
 	(compare:CCFP (match_operand:SF 0 "s_register_operand"  "t")
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
index 7036cb9508c27d56c4b2c01a81c44bf6f1f9c781..cae2f06140766176c9af6e4b2b4a3e722fbad67c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -36,6 +36,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
index 50d4979470dd21738453e0d70c7a69ee0752ac41..21a53cd85792e439314f5c88080d7f1c6fcdec66 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -33,6 +33,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
 /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
index 2b7507c900ab18705083ba1d86359e1ae36a50a2..e8f973e3f06881d33d661f81c0eb6671e48a0d01 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -34,6 +34,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
 /* { dg-final { scan-assembler "movt\tr1, 63" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index 35cab1f3233daac9fba50d25dac23364c798fb9c..29d78ddd6166321bdf0acabf011138b276151e85 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -105,6 +105,7 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "bic" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! arm_cmse_clear_ok } } } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index 7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97..9719f799229e245264d377c3726190ca768ca1dd 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -10,21 +10,10 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
index 638643d0a6772d43f440df3942c6c723f1eff3ef..dc62b742ba5ab9f7480ca93396e5eb354c5e64dd 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
@@ -6,22 +6,7 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s1-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index 9ec14d1a707839e4858bac72bc292fd0984bf86c..a6951d34afeed54c0ac2e937345cbfbbfb2c4b2d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -9,22 +9,7 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index d375879ed02483c05d7853c95f9b9e15383ff321..23db88dc66d584acbba64a10d3f6fd06f066b321 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -11,20 +11,7 @@
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0..2898efabb2b37e3c8dacaf029b5a40be8edcc624 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -9,18 +9,13 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
index 7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6..55e7a4f7ae0c4420a40a250f246a769eff28e6c7 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
@@ -6,15 +6,7 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s1-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index d998b43a148250a15eb4aae9fb0ef6e4bf51203b..a4520a9166e36b1d3220befb72a1863799b2f424 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -9,14 +9,7 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf..c79d3188026d9248abde7967671c05a09b75c49f 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -10,13 +10,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
index 157bccb9ff3256056d496a0d0770374315b04d87..d3a3a742b8b4ff99c973a8c9edd77297c7f37ae2 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
@@ -7,6 +7,7 @@
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
index 2522a17a6316d76a21d8d241d4c44cdddf1981e0..bbe16cee9c2c29e0701f54c3e393ad3c7efb8e87 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
@@ -8,22 +8,7 @@
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
index eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b..c7dda6a3d6088366358ff4bc1e6d83ad9b03ea6e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
@@ -7,14 +7,7 @@
 
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
-/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
index 90fdac18e30424edca60b6f884227adbf716899d..755564369ae7deecfb038e67591e679bb06f62b1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -29,6 +29,7 @@ main (void)
 /* { dg-final { scan-assembler "movs\tr1, #255" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 1/10] Fix -mcmse check in libgcc
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions Mihail Ionescu
@ 2019-10-23 14:31 ` Mihail Ionescu
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 5/10] Clear VFP registers with VSCCLRM Mihail Ionescu
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 2266 bytes --]

[PATCH, GCC/ARM, 1/10] Fix -mcmse check in libgcc

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to fix the
check to determine whether -mcmse is supported by the host compiler.

=== Patch description ===

Code to detect whether cmse.c can be buit with -mcmse checks the output
of host GCC when invoked with -mcmse. However, an error from the
compiler does not prevent some minimal output so this always holds true.

This does not affect currently supported architectures since the test is
guarded by __ARM_FEATURE_CMSE which is only defined for Armv8-M Baseline
and Mainline and these two architectures accept -mcmse.

However, in the intermediate patches adding support for Armv8.1-M
Mainline, support for Security Extensions is disabled until fully
implemented. This leads to libgcc/config/arm/cmse.c being built with
-mcmse due to the broken test which fails in the intermediate commits.

This patch instead change the test to look at the return value of the
host gcc when invoked with -mcmse.


ChangeLog entry is as follows:

*** libgcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/t-arm: Check return value of gcc rather than lack of
	output.

Testing: Bootstrapped and tested on arm-none-eabi.
Without this patch, GCC stops building after the second patch
of this series.

Is this ok for trunk?

Best regards,

Mihail


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


diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 274bf2a8ef33c5e8a8ee2b246aba92d30297abe1..f2b927f3686a8c0a8e37abfe2d7768f2050d4fb3 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -3,7 +3,7 @@ LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
 	_thumb1_case_uhi _thumb1_case_si _speculation_barrier
 
 HAVE_CMSE:=$(findstring __ARM_FEATURE_CMSE,$(shell $(gcc_compile_bare) -dM -E - </dev/null))
-ifneq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null 2>/dev/null),)
+ifeq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null >/dev/null 2>/dev/null; echo $?),0)
 CMSE_OPTS:=-mcmse
 endif
 


[-- Attachment #2: diff00.patch --]
[-- Type: text/plain, Size: 652 bytes --]

diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 274bf2a8ef33c5e8a8ee2b246aba92d30297abe1..f2b927f3686a8c0a8e37abfe2d7768f2050d4fb3 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -3,7 +3,7 @@ LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
 	_thumb1_case_uhi _thumb1_case_si _speculation_barrier
 
 HAVE_CMSE:=$(findstring __ARM_FEATURE_CMSE,$(shell $(gcc_compile_bare) -dM -E - </dev/null))
-ifneq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null 2>/dev/null),)
+ifeq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null >/dev/null 2>/dev/null; echo $?),0)
 CMSE_OPTS:=-mcmse
 endif
 


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 6/10] Clear GPRs inline when calling nscall function
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
                   ` (4 preceding siblings ...)
  2019-10-23 14:31 ` [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline Mihail Ionescu
@ 2019-10-23 14:33 ` Mihail Ionescu
  2019-10-23 14:34 ` [PATCH, GCC/ARM, 9/10] Call nscall function with blxns Mihail Ionescu
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 35676 bytes --]

[PATCH, GCC/ARM, 6/10] Clear GPRs inline when calling nscall function

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to generate
inline callee-saved register clearing when calling a function with the
cmse_nonsecure_call attribute with the ultimate goal of having the whole
call sequence inline.

=== Patch description ===

Besides changing the set of registers that needs to be cleared inline,
this patch also generates the push and pop to save and restore
callee-saved registers without trusting the callee inline. To make the
code more future-proof, this (currently) Armv8.1-M specific behavior is
expressed in terms of clearing of callee-saved registers rather than
directly based on the targets.

The patch contains 1 subtlety:

Debug information is disabled for push and pop because the
REG_CFA_RESTORE notes used to describe popping of registers do not stack.
Instead, they just reset the debug state for the register to the one at
the beginning of the function, which is incorrect for a register that is
pushed twice (in prologue and before nonsecure call) and then popped for
the first time. In particular, this occasionally trips CFI note creation
code when there are two codepaths to the epilogue, one of which does not
go through the nonsecure call. Obviously this mean that debugging
between the push and pop is not reliable.

ChangeLog entries are as follows:

*** gcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm.c (arm_emit_multi_reg_pop): Declare early.
	(cmse_nonsecure_call_clear_caller_saved): Rename into ...
	(cmse_nonsecure_call_inline_register_clear): This.  Save and clear
	callee-saved GPRs as well as clear ip register before doing a nonsecure
	call then restore callee-saved GPRs after it when targeting
	Armv8.1-M Mainline.
	(arm_reorg): Adapt to function rename.

*** gcc/testsuite/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/cmse-1.c: Add check for PUSH and POP and update
	CLRM check.
	* gcc.target/arm/cmse/cmse-14.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft-sp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft-sp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/union-1.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/union-2.c: Likewise.

Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
regression.

Is this ok for trunk?

Best regards,

Mihail


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


diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index fca10801c87c5e635d573c0fbdc47a1ae229d0ef..12b4b42a66b0c5589690d9a2d8cf8e42712ca2c0 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -187,6 +187,7 @@ static int arm_memory_move_cost (machine_mode, reg_class_t, bool);
 static void emit_constant_insn (rtx cond, rtx pattern);
 static rtx_insn *emit_set_insn (rtx, rtx);
 static rtx emit_multi_reg_push (unsigned long, unsigned long);
+static void arm_emit_multi_reg_pop (unsigned long);
 static int arm_arg_partial_bytes (cumulative_args_t,
 				  const function_arg_info &);
 static rtx arm_function_arg (cumulative_args_t, const function_arg_info &);
@@ -17810,13 +17811,13 @@ cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
     }
 }
 
-/* Clears caller saved registers not used to pass arguments before a
-   cmse_nonsecure_call.  Saving, clearing and restoring of callee saved
-   registers is done in __gnu_cmse_nonsecure_call libcall.
-   See libgcc/config/arm/cmse_nonsecure_call.S.  */
+/* Clear core and caller-saved VFP registers not used to pass arguments before
+   a cmse_nonsecure_call.  Saving, clearing and restoring of VFP callee-saved
+   registers is done in the __gnu_cmse_nonsecure_call libcall.  See
+   libgcc/config/arm/cmse_nonsecure_call.S.  */
 
 static void
-cmse_nonsecure_call_clear_caller_saved (void)
+cmse_nonsecure_call_inline_register_clear (void)
 {
   basic_block bb;
 
@@ -17826,8 +17827,15 @@ cmse_nonsecure_call_clear_caller_saved (void)
 
       FOR_BB_INSNS (bb, insn)
 	{
-	  unsigned address_regnum, regno, maxregno =
-	    TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : NUM_ARG_REGS - 1;
+	  bool clear_callee_saved = TARGET_HAVE_FPCXT_CMSE;
+	  unsigned long callee_saved_mask
+	    = ((1 << (LAST_HI_REGNUM + 1)) - 1)
+	    & ~((1 << (LAST_ARG_REGNUM + 1)) - 1);
+	  unsigned address_regnum, regno;
+	  unsigned max_int_regno
+	    = clear_callee_saved ? IP_REGNUM : LAST_ARG_REGNUM;
+	  unsigned maxregno
+	    = TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : max_int_regno;
 	  auto_sbitmap to_clear_bitmap (maxregno + 1);
 	  rtx_insn *seq;
 	  rtx pat, call, unspec, clearing_reg, ip_reg, shift;
@@ -17859,9 +17867,11 @@ cmse_nonsecure_call_clear_caller_saved (void)
 	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
 	    continue;
 
-	  /* Determine the caller-saved registers we need to clear.  */
+	  /* Mark registers that needs to be cleared.  Those that holds a
+	     parameter are removed from the set further below.  */
 	  bitmap_clear (to_clear_bitmap);
-	  bitmap_set_range (to_clear_bitmap, R0_REGNUM, NUM_ARG_REGS);
+	  bitmap_set_range (to_clear_bitmap, R0_REGNUM,
+			    max_int_regno - R0_REGNUM + 1);
 
 	  /* Only look at the caller-saved floating point registers in case of
 	     -mfloat-abi=hard.  For -mfloat-abi=softfp we will be using the
@@ -17883,7 +17893,7 @@ cmse_nonsecure_call_clear_caller_saved (void)
 	  gcc_assert (MEM_P (address));
 	  gcc_assert (REG_P (XEXP (address, 0)));
 	  address_regnum = REGNO (XEXP (address, 0));
-	  if (address_regnum < R0_REGNUM + NUM_ARG_REGS)
+	  if (address_regnum <= max_int_regno)
 	    bitmap_clear_bit (to_clear_bitmap, address_regnum);
 
 	  /* Set basic block of call insn so that df rescan is performed on
@@ -17943,6 +17953,15 @@ cmse_nonsecure_call_clear_caller_saved (void)
 	  shift = gen_rtx_ASHIFT (SImode, clearing_reg, const1_rtx);
 	  emit_insn (gen_rtx_SET (clearing_reg, shift));
 
+	  if (clear_callee_saved)
+	    {
+	      rtx push_insn =
+		emit_multi_reg_push (callee_saved_mask, callee_saved_mask);
+	      /* Disable frame debug info in push because it needs to be
+		 disabled for pop (see below).  */
+	      RTX_FRAME_RELATED_P (push_insn) = 0;
+	    }
+
 	  /* Clear caller-saved registers that leak before doing a non-secure
 	     call.  */
 	  ip_reg = gen_rtx_REG (SImode, IP_REGNUM);
@@ -17952,6 +17971,36 @@ cmse_nonsecure_call_clear_caller_saved (void)
 	  seq = get_insns ();
 	  end_sequence ();
 	  emit_insn_before (seq, insn);
+
+	  if (TARGET_HAVE_FPCXT_CMSE)
+	    {
+	      rtx_insn *next, *pop_insn, *after = insn;
+
+	      start_sequence ();
+	      arm_emit_multi_reg_pop (callee_saved_mask);
+	      pop_insn = get_last_insn ();
+
+	      /* Disable frame debug info in pop because they reset the state
+		 of popped registers to what it was at the beginning of the
+		 function, before the prologue.  This leads to incorrect state
+		 when doing the pop after the nonsecure call for registers that
+		 are pushed both in prologue and before the nonsecure call.
+
+		 It also occasionally triggers an assert failure in CFI note
+		 creation code when there are two codepaths to the epilogue,
+		 one of which does not go through the nonsecure call.
+		 Obviously this mean that debugging between the push and pop is
+		 not reliable.  */
+	      RTX_FRAME_RELATED_P (pop_insn) = 0;
+
+	      end_sequence ();
+
+	      emit_insn_after (pop_insn, after);
+
+	      /* Skip pop we have just inserted after nonsecure call, we know
+		 it does not contain a nonsecure call.  */
+	      insn = pop_insn;
+	    }
 	}
     }
 }
@@ -18257,7 +18306,7 @@ arm_reorg (void)
   Mfix * fix;
 
   if (use_cmse)
-    cmse_nonsecure_call_clear_caller_saved ();
+    cmse_nonsecure_call_inline_register_clear ();
 
   /* We cannot run the Thumb passes for thunks because there is no CFG.  */
   if (cfun->is_thunk)
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index 29d78ddd6166321bdf0acabf011138b276151e85..9f36fa3b1d8b86b4e1827909fca4fee181ba1c61 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -109,7 +109,9 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! arm_cmse_clear_ok } } } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
 
 int call_callback (void)
 {
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
index 1f5af7c2dba7747f6058d12af8ef80b4dd1b1431..6d39afab44329e78a8ff2f693fd94fe6a501af5a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -9,6 +9,8 @@ int foo (void)
   return bar ();
 }
 
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
index c52e1c14d9956743625e3b8a200e823f163924e3..d4caf513ed2153370369bddbfcf6d2568d9f2f1e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
@@ -12,5 +12,7 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
index fdba955a32fc5ad492b74974185f98470bc49a7e..2b7655a2c9971fb0aad4e6c8a1fee72e21028fad 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
@@ -10,5 +10,7 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
index 85068ceaac6a5c0c60af4a54c0af0d20326fc18d..1a62076df9d6831d06f5ac6bdcb7deed0ecd23f8 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
@@ -13,5 +13,7 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
index af69d38acf47d9d1d55480edba2b66f07e2d06ad..1319ac9766bcd330f6d8f0f7754a64a1dcc105b1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
@@ -10,5 +10,7 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
index 62201595549f07b046c7c5972d612ab155c4c38c..9bb60175529d77a3b1868f62a5a4d5355f00b76b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
@@ -13,5 +13,7 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
index 287f0d6faad113fbc8c30051280668baa58ab130..11ca78bfdaf1ebe09f9699c278dc3db4fd20768c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
@@ -7,5 +7,7 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
index 68f9e2254c97d7b9817f24cb4dc4315dc876fb26..2f14c52715e0ad6e6ab69b01713ee13985a22653 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
@@ -17,4 +17,7 @@
 /* { dg-final { scan-assembler "and\tr3, r3, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index 9719f799229e245264d377c3726190ca768ca1dd..67ced090163bc4b40c09b00305d49d21084f7fb8 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -8,12 +8,14 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index a6951d34afeed54c0ac2e937345cbfbbfb2c4b2d..a6d9d14b63be8a226242512e36ba313849a3d35a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -8,8 +8,10 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index 23db88dc66d584acbba64a10d3f6fd06f066b321..ff4763529c7d280193d99ef695ce426038b7ceb9 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -8,10 +8,12 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 2898efabb2b37e3c8dacaf029b5a40be8edcc624..952010baee36cc404f1a85252c3bf9da7a6c3ce1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -8,7 +8,8 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
@@ -16,6 +17,7 @@
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index a4520a9166e36b1d3220befb72a1863799b2f424..ec1284117f8937026b263ba1bd623e9942527877 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -8,8 +8,10 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index c79d3188026d9248abde7967671c05a09b75c49f..d70a58a4c84c5d042f4efefbf36316d5401f770c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -8,9 +8,11 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index d43a9f85a199ecdf7e018852b3af9b4cf36af81f..07a6719b4f1a260a3461f7408e278dd6e71f60d3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -10,7 +10,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index 02e48157a2c61b0a8bee77e949944acc2a4bee37..ca2961ac18ccacec6907b1d1d217c6c2e28072e7 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -7,7 +7,9 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index c7a22a2ba464dce26b289635dd8dcc8213ae33d8..7a1abb51fcf9a62a24583e792953845f21bbed49 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -9,7 +9,9 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index d34ca383236fdd31723966e6218ea918cf8c9122..90aadffb7aa14ceeea22232148c11e9543eee0e7 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -8,7 +8,9 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250..28f2e86dfaa89902d1c04fc2890c5445b5bb0af5 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -10,7 +10,9 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index ff9a7dfa5e696e3a6c4132343d0ee94c3068c208..15d3b682c798dd6635ed6b90d9aa8e705fefa265 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 03d36aa650986b6069e2fe1c1f3f98fa9664d88a..3d48859028ab8dd22d9ffed7c95ece59c2ed937e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -8,7 +8,9 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index ce45e10688f855ca7b2a63777d2b3d3418815589..0e2dcae36927d2c7187ca2b60c935504268476bc 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -10,7 +10,9 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
index dbd1d34413ef36f2b03716c0d9cf46b024af0835..43e58ebde56ceb229edca2db25b720c42207c100 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
@@ -10,5 +10,7 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
index 3edc7f1e259779a24e722d67ed544c0a673090c7..6adf8fae5c3a56a6e50278919a2edbd2fda58f42 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
@@ -14,5 +14,7 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */


[-- Attachment #2: diff05.patch --]
[-- Type: text/plain, Size: 31724 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index fca10801c87c5e635d573c0fbdc47a1ae229d0ef..12b4b42a66b0c5589690d9a2d8cf8e42712ca2c0 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -187,6 +187,7 @@ static int arm_memory_move_cost (machine_mode, reg_class_t, bool);
 static void emit_constant_insn (rtx cond, rtx pattern);
 static rtx_insn *emit_set_insn (rtx, rtx);
 static rtx emit_multi_reg_push (unsigned long, unsigned long);
+static void arm_emit_multi_reg_pop (unsigned long);
 static int arm_arg_partial_bytes (cumulative_args_t,
 				  const function_arg_info &);
 static rtx arm_function_arg (cumulative_args_t, const function_arg_info &);
@@ -17810,13 +17811,13 @@ cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
     }
 }
 
-/* Clears caller saved registers not used to pass arguments before a
-   cmse_nonsecure_call.  Saving, clearing and restoring of callee saved
-   registers is done in __gnu_cmse_nonsecure_call libcall.
-   See libgcc/config/arm/cmse_nonsecure_call.S.  */
+/* Clear core and caller-saved VFP registers not used to pass arguments before
+   a cmse_nonsecure_call.  Saving, clearing and restoring of VFP callee-saved
+   registers is done in the __gnu_cmse_nonsecure_call libcall.  See
+   libgcc/config/arm/cmse_nonsecure_call.S.  */
 
 static void
-cmse_nonsecure_call_clear_caller_saved (void)
+cmse_nonsecure_call_inline_register_clear (void)
 {
   basic_block bb;
 
@@ -17826,8 +17827,15 @@ cmse_nonsecure_call_clear_caller_saved (void)
 
       FOR_BB_INSNS (bb, insn)
 	{
-	  unsigned address_regnum, regno, maxregno =
-	    TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : NUM_ARG_REGS - 1;
+	  bool clear_callee_saved = TARGET_HAVE_FPCXT_CMSE;
+	  unsigned long callee_saved_mask
+	    = ((1 << (LAST_HI_REGNUM + 1)) - 1)
+	    & ~((1 << (LAST_ARG_REGNUM + 1)) - 1);
+	  unsigned address_regnum, regno;
+	  unsigned max_int_regno
+	    = clear_callee_saved ? IP_REGNUM : LAST_ARG_REGNUM;
+	  unsigned maxregno
+	    = TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : max_int_regno;
 	  auto_sbitmap to_clear_bitmap (maxregno + 1);
 	  rtx_insn *seq;
 	  rtx pat, call, unspec, clearing_reg, ip_reg, shift;
@@ -17859,9 +17867,11 @@ cmse_nonsecure_call_clear_caller_saved (void)
 	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
 	    continue;
 
-	  /* Determine the caller-saved registers we need to clear.  */
+	  /* Mark registers that needs to be cleared.  Those that holds a
+	     parameter are removed from the set further below.  */
 	  bitmap_clear (to_clear_bitmap);
-	  bitmap_set_range (to_clear_bitmap, R0_REGNUM, NUM_ARG_REGS);
+	  bitmap_set_range (to_clear_bitmap, R0_REGNUM,
+			    max_int_regno - R0_REGNUM + 1);
 
 	  /* Only look at the caller-saved floating point registers in case of
 	     -mfloat-abi=hard.  For -mfloat-abi=softfp we will be using the
@@ -17883,7 +17893,7 @@ cmse_nonsecure_call_clear_caller_saved (void)
 	  gcc_assert (MEM_P (address));
 	  gcc_assert (REG_P (XEXP (address, 0)));
 	  address_regnum = REGNO (XEXP (address, 0));
-	  if (address_regnum < R0_REGNUM + NUM_ARG_REGS)
+	  if (address_regnum <= max_int_regno)
 	    bitmap_clear_bit (to_clear_bitmap, address_regnum);
 
 	  /* Set basic block of call insn so that df rescan is performed on
@@ -17943,6 +17953,15 @@ cmse_nonsecure_call_clear_caller_saved (void)
 	  shift = gen_rtx_ASHIFT (SImode, clearing_reg, const1_rtx);
 	  emit_insn (gen_rtx_SET (clearing_reg, shift));
 
+	  if (clear_callee_saved)
+	    {
+	      rtx push_insn =
+		emit_multi_reg_push (callee_saved_mask, callee_saved_mask);
+	      /* Disable frame debug info in push because it needs to be
+		 disabled for pop (see below).  */
+	      RTX_FRAME_RELATED_P (push_insn) = 0;
+	    }
+
 	  /* Clear caller-saved registers that leak before doing a non-secure
 	     call.  */
 	  ip_reg = gen_rtx_REG (SImode, IP_REGNUM);
@@ -17952,6 +17971,36 @@ cmse_nonsecure_call_clear_caller_saved (void)
 	  seq = get_insns ();
 	  end_sequence ();
 	  emit_insn_before (seq, insn);
+
+	  if (TARGET_HAVE_FPCXT_CMSE)
+	    {
+	      rtx_insn *next, *pop_insn, *after = insn;
+
+	      start_sequence ();
+	      arm_emit_multi_reg_pop (callee_saved_mask);
+	      pop_insn = get_last_insn ();
+
+	      /* Disable frame debug info in pop because they reset the state
+		 of popped registers to what it was at the beginning of the
+		 function, before the prologue.  This leads to incorrect state
+		 when doing the pop after the nonsecure call for registers that
+		 are pushed both in prologue and before the nonsecure call.
+
+		 It also occasionally triggers an assert failure in CFI note
+		 creation code when there are two codepaths to the epilogue,
+		 one of which does not go through the nonsecure call.
+		 Obviously this mean that debugging between the push and pop is
+		 not reliable.  */
+	      RTX_FRAME_RELATED_P (pop_insn) = 0;
+
+	      end_sequence ();
+
+	      emit_insn_after (pop_insn, after);
+
+	      /* Skip pop we have just inserted after nonsecure call, we know
+		 it does not contain a nonsecure call.  */
+	      insn = pop_insn;
+	    }
 	}
     }
 }
@@ -18257,7 +18306,7 @@ arm_reorg (void)
   Mfix * fix;
 
   if (use_cmse)
-    cmse_nonsecure_call_clear_caller_saved ();
+    cmse_nonsecure_call_inline_register_clear ();
 
   /* We cannot run the Thumb passes for thunks because there is no CFG.  */
   if (cfun->is_thunk)
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index 29d78ddd6166321bdf0acabf011138b276151e85..9f36fa3b1d8b86b4e1827909fca4fee181ba1c61 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -109,7 +109,9 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! arm_cmse_clear_ok } } } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
 
 int call_callback (void)
 {
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
index 1f5af7c2dba7747f6058d12af8ef80b4dd1b1431..6d39afab44329e78a8ff2f693fd94fe6a501af5a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -9,6 +9,8 @@ int foo (void)
   return bar ();
 }
 
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
index c52e1c14d9956743625e3b8a200e823f163924e3..d4caf513ed2153370369bddbfcf6d2568d9f2f1e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
@@ -12,5 +12,7 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
index fdba955a32fc5ad492b74974185f98470bc49a7e..2b7655a2c9971fb0aad4e6c8a1fee72e21028fad 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
@@ -10,5 +10,7 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
index 85068ceaac6a5c0c60af4a54c0af0d20326fc18d..1a62076df9d6831d06f5ac6bdcb7deed0ecd23f8 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
@@ -13,5 +13,7 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
index af69d38acf47d9d1d55480edba2b66f07e2d06ad..1319ac9766bcd330f6d8f0f7754a64a1dcc105b1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
@@ -10,5 +10,7 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
index 62201595549f07b046c7c5972d612ab155c4c38c..9bb60175529d77a3b1868f62a5a4d5355f00b76b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
@@ -13,5 +13,7 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
index 287f0d6faad113fbc8c30051280668baa58ab130..11ca78bfdaf1ebe09f9699c278dc3db4fd20768c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
@@ -7,5 +7,7 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
index 68f9e2254c97d7b9817f24cb4dc4315dc876fb26..2f14c52715e0ad6e6ab69b01713ee13985a22653 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
@@ -17,4 +17,7 @@
 /* { dg-final { scan-assembler "and\tr3, r3, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index 9719f799229e245264d377c3726190ca768ca1dd..67ced090163bc4b40c09b00305d49d21084f7fb8 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -8,12 +8,14 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index a6951d34afeed54c0ac2e937345cbfbbfb2c4b2d..a6d9d14b63be8a226242512e36ba313849a3d35a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -8,8 +8,10 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index 23db88dc66d584acbba64a10d3f6fd06f066b321..ff4763529c7d280193d99ef695ce426038b7ceb9 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -8,10 +8,12 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 2898efabb2b37e3c8dacaf029b5a40be8edcc624..952010baee36cc404f1a85252c3bf9da7a6c3ce1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -8,7 +8,8 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
@@ -16,6 +17,7 @@
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index a4520a9166e36b1d3220befb72a1863799b2f424..ec1284117f8937026b263ba1bd623e9942527877 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -8,8 +8,10 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index c79d3188026d9248abde7967671c05a09b75c49f..d70a58a4c84c5d042f4efefbf36316d5401f770c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -8,9 +8,11 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index d43a9f85a199ecdf7e018852b3af9b4cf36af81f..07a6719b4f1a260a3461f7408e278dd6e71f60d3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -10,7 +10,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index 02e48157a2c61b0a8bee77e949944acc2a4bee37..ca2961ac18ccacec6907b1d1d217c6c2e28072e7 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -7,7 +7,9 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index c7a22a2ba464dce26b289635dd8dcc8213ae33d8..7a1abb51fcf9a62a24583e792953845f21bbed49 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -9,7 +9,9 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index d34ca383236fdd31723966e6218ea918cf8c9122..90aadffb7aa14ceeea22232148c11e9543eee0e7 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -8,7 +8,9 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250..28f2e86dfaa89902d1c04fc2890c5445b5bb0af5 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -10,7 +10,9 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index ff9a7dfa5e696e3a6c4132343d0ee94c3068c208..15d3b682c798dd6635ed6b90d9aa8e705fefa265 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 03d36aa650986b6069e2fe1c1f3f98fa9664d88a..3d48859028ab8dd22d9ffed7c95ece59c2ed937e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -8,7 +8,9 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index ce45e10688f855ca7b2a63777d2b3d3418815589..0e2dcae36927d2c7187ca2b60c935504268476bc 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -10,7 +10,9 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
index dbd1d34413ef36f2b03716c0d9cf46b024af0835..43e58ebde56ceb229edca2db25b720c42207c100 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
@@ -10,5 +10,7 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
index 3edc7f1e259779a24e722d67ed544c0a673090c7..6adf8fae5c3a56a6e50278919a2edbd2fda58f42 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
@@ -14,5 +14,7 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 7/10] Clear all VFP regs inline in hardfloat nscall functions
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
                   ` (6 preceding siblings ...)
  2019-10-23 14:34 ` [PATCH, GCC/ARM, 9/10] Call nscall function with blxns Mihail Ionescu
@ 2019-10-23 14:34 ` Mihail Ionescu
  2019-10-23 14:34 ` [PATCH, GCC/ARM, 10/10] Enable -mcmse Mihail Ionescu
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 13503 bytes --]

[PATCH, GCC/ARM, 7/10] Clear all VFP regs inline in hardfloat nscall functions

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to generate
inline instructions to save, clear and restore callee-saved VFP
registers before doing a call to a function with the cmse_nonsecure_call
attribute.

=== Patch description ===

The patch is fairly straightforward in its approach and consist of the
following 3 logical changes:
- abstract the number of floating-point register to clear in
  max_fp_regno
- use max_fp_regno to decide how many registers to clear so that the
  same code works for Armv8-M and Armv8.1-M Mainline
- emit vpush and vpop instruction respectively before and after a
  nonsecure call

Note that as in the patch to clear GPRs inline, debug information has to
be disabled for VPUSH and VPOP due to VPOP adding CFA adjustment note
for SP when R7 is sometimes used as CFA.

ChangeLog entries are as follows:

*** gcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm.c (vfp_emit_fstmd): Declare early.
	(arm_emit_vfp_multi_reg_pop): Likewise.
	(cmse_nonsecure_call_inline_register_clear): Abstract number of VFP
	registers to clear in max_fp_regno.  Emit VPUSH and VPOP to save and
	restore callee-saved VFP registers.

*** gcc/testsuite/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Add check for
	VPUSH and VPOP and update expectation for VSCCLRM.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.

Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
regression.

Is this ok for trunk?

Best regards,

Mihail


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


diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index c24996897eb21c641914326f7064a26bbb363411..bcc86d50a10f11d9672258442089a0aa5c450b2f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -188,6 +188,8 @@ static void emit_constant_insn (rtx cond, rtx pattern);
 static rtx_insn *emit_set_insn (rtx, rtx);
 static rtx emit_multi_reg_push (unsigned long, unsigned long);
 static void arm_emit_multi_reg_pop (unsigned long);
+static int vfp_emit_fstmd (int, int);
+static void arm_emit_vfp_multi_reg_pop (int, int, rtx);
 static int arm_arg_partial_bytes (cumulative_args_t,
 				  const function_arg_info &);
 static rtx arm_function_arg (cumulative_args_t, const function_arg_info &);
@@ -17834,8 +17836,10 @@ cmse_nonsecure_call_inline_register_clear (void)
 	  unsigned address_regnum, regno;
 	  unsigned max_int_regno =
 	    clear_callee_saved ? IP_REGNUM : LAST_ARG_REGNUM;
+	  unsigned max_fp_regno =
+	    TARGET_HAVE_FPCTX_CMSE ? LAST_VFP_REGNUM : D7_VFP_REGNUM;
 	  unsigned maxregno =
-	    TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : max_int_regno;
+	    TARGET_HARD_FLOAT_ABI ? max_fp_regno : max_int_regno;
 	  auto_sbitmap to_clear_bitmap (maxregno + 1);
 	  rtx_insn *seq;
 	  rtx pat, call, unspec, clearing_reg, ip_reg, shift;
@@ -17883,7 +17887,7 @@ cmse_nonsecure_call_inline_register_clear (void)
 
 	      bitmap_clear (float_bitmap);
 	      bitmap_set_range (float_bitmap, FIRST_VFP_REGNUM,
-				D7_VFP_REGNUM - FIRST_VFP_REGNUM + 1);
+				max_fp_regno - FIRST_VFP_REGNUM + 1);
 	      bitmap_ior (to_clear_bitmap, to_clear_bitmap, float_bitmap);
 	    }
 
@@ -17960,6 +17964,16 @@ cmse_nonsecure_call_inline_register_clear (void)
 	      /* Disable frame debug info in push because it needs to be
 		 disabled for pop (see below).  */
 	      RTX_FRAME_RELATED_P (push_insn) = 0;
+
+	      /* Save VFP callee-saved registers.  */
+	      if (TARGET_HARD_FLOAT_ABI)
+		{
+		  vfp_emit_fstmd (D7_VFP_REGNUM + 1,
+				  (max_fp_regno - D7_VFP_REGNUM) / 2);
+		  /* Disable frame debug info in push because it needs to be
+		     disabled for vpop (see below).  */
+		  RTX_FRAME_RELATED_P (get_last_insn ()) = 0;
+		}
 	    }
 
 	  /* Clear caller-saved registers that leak before doing a non-secure
@@ -17974,9 +17988,25 @@ cmse_nonsecure_call_inline_register_clear (void)
 
 	  if (TARGET_HAVE_FPCTX_CMSE)
 	    {
-	      rtx_insn *next, *pop_insn, *after = insn;
+	      rtx_insn *next, *last, *pop_insn, *after = insn;
 
 	      start_sequence ();
+
+	      /* Restore VFP callee-saved registers.  */
+	      if (TARGET_HARD_FLOAT_ABI)
+		{
+		  int nb_callee_saved_vfp_regs =
+		    (max_fp_regno - D7_VFP_REGNUM) / 2;
+		  arm_emit_vfp_multi_reg_pop (D7_VFP_REGNUM + 1,
+					      nb_callee_saved_vfp_regs,
+					      stack_pointer_rtx);
+		  /* Disable frame debug info in vpop because the SP adjustment
+		     is made using a CFA adjustment note while CFA used is
+		     sometimes R7.  This then causes an assert failure in the
+		     CFI note creation code.  */
+		  RTX_FRAME_RELATED_P (get_last_insn ()) = 0;
+		}
+
 	      arm_emit_multi_reg_pop (callee_saved_mask);
 	      pop_insn = get_last_insn ();
 
@@ -17993,13 +18023,15 @@ cmse_nonsecure_call_inline_register_clear (void)
 		 not reliable.  */
 	      RTX_FRAME_RELATED_P (pop_insn) = 0;
 
+	      seq = get_insns ();
+	      last = get_last_insn ();
 	      end_sequence ();
 
-	      emit_insn_after (pop_insn, after);
+	      emit_insn_after (seq, after);
 
 	      /* Skip pop we have just inserted after nonsecure call, we know
 		 it does not contain a nonsecure call.  */
-	      insn = pop_insn;
+	      insn = last;
 	    }
 	}
     }
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index 67ced090163bc4b40c09b00305d49d21084f7fb8..e759db24fac27be2de664ad4faced7bb5d3be84a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -9,12 +9,14 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s4-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index a6d9d14b63be8a226242512e36ba313849a3d35a..9df7b5de3ad64e719fc97d7a67a4893398e87b32 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -9,8 +9,10 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index ff4763529c7d280193d99ef695ce426038b7ceb9..b36ff73cb9b46d4d3a91f854c022787dc000d9c3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -9,10 +9,12 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 952010baee36cc404f1a85252c3bf9da7a6c3ce1..72493f032355828bdf48b84dc98d8102becd1b36 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -9,6 +9,7 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
@@ -16,7 +17,8 @@
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s4-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index ec1284117f8937026b263ba1bd623e9942527877..112ed78d6f172be31d4a4f06840d32a90cdf3dd4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -9,8 +9,10 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index d70a58a4c84c5d042f4efefbf36316d5401f770c..f48e8a0a020cebed8c9fa124d352f047442979d6 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -9,9 +9,11 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */


[-- Attachment #2: diff06.patch --]
[-- Type: text/plain, Size: 11269 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index c24996897eb21c641914326f7064a26bbb363411..bcc86d50a10f11d9672258442089a0aa5c450b2f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -188,6 +188,8 @@ static void emit_constant_insn (rtx cond, rtx pattern);
 static rtx_insn *emit_set_insn (rtx, rtx);
 static rtx emit_multi_reg_push (unsigned long, unsigned long);
 static void arm_emit_multi_reg_pop (unsigned long);
+static int vfp_emit_fstmd (int, int);
+static void arm_emit_vfp_multi_reg_pop (int, int, rtx);
 static int arm_arg_partial_bytes (cumulative_args_t,
 				  const function_arg_info &);
 static rtx arm_function_arg (cumulative_args_t, const function_arg_info &);
@@ -17834,8 +17836,10 @@ cmse_nonsecure_call_inline_register_clear (void)
 	  unsigned address_regnum, regno;
 	  unsigned max_int_regno =
 	    clear_callee_saved ? IP_REGNUM : LAST_ARG_REGNUM;
+	  unsigned max_fp_regno =
+	    TARGET_HAVE_FPCTX_CMSE ? LAST_VFP_REGNUM : D7_VFP_REGNUM;
 	  unsigned maxregno =
-	    TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : max_int_regno;
+	    TARGET_HARD_FLOAT_ABI ? max_fp_regno : max_int_regno;
 	  auto_sbitmap to_clear_bitmap (maxregno + 1);
 	  rtx_insn *seq;
 	  rtx pat, call, unspec, clearing_reg, ip_reg, shift;
@@ -17883,7 +17887,7 @@ cmse_nonsecure_call_inline_register_clear (void)
 
 	      bitmap_clear (float_bitmap);
 	      bitmap_set_range (float_bitmap, FIRST_VFP_REGNUM,
-				D7_VFP_REGNUM - FIRST_VFP_REGNUM + 1);
+				max_fp_regno - FIRST_VFP_REGNUM + 1);
 	      bitmap_ior (to_clear_bitmap, to_clear_bitmap, float_bitmap);
 	    }
 
@@ -17960,6 +17964,16 @@ cmse_nonsecure_call_inline_register_clear (void)
 	      /* Disable frame debug info in push because it needs to be
 		 disabled for pop (see below).  */
 	      RTX_FRAME_RELATED_P (push_insn) = 0;
+
+	      /* Save VFP callee-saved registers.  */
+	      if (TARGET_HARD_FLOAT_ABI)
+		{
+		  vfp_emit_fstmd (D7_VFP_REGNUM + 1,
+				  (max_fp_regno - D7_VFP_REGNUM) / 2);
+		  /* Disable frame debug info in push because it needs to be
+		     disabled for vpop (see below).  */
+		  RTX_FRAME_RELATED_P (get_last_insn ()) = 0;
+		}
 	    }
 
 	  /* Clear caller-saved registers that leak before doing a non-secure
@@ -17974,9 +17988,25 @@ cmse_nonsecure_call_inline_register_clear (void)
 
 	  if (TARGET_HAVE_FPCTX_CMSE)
 	    {
-	      rtx_insn *next, *pop_insn, *after = insn;
+	      rtx_insn *next, *last, *pop_insn, *after = insn;
 
 	      start_sequence ();
+
+	      /* Restore VFP callee-saved registers.  */
+	      if (TARGET_HARD_FLOAT_ABI)
+		{
+		  int nb_callee_saved_vfp_regs =
+		    (max_fp_regno - D7_VFP_REGNUM) / 2;
+		  arm_emit_vfp_multi_reg_pop (D7_VFP_REGNUM + 1,
+					      nb_callee_saved_vfp_regs,
+					      stack_pointer_rtx);
+		  /* Disable frame debug info in vpop because the SP adjustment
+		     is made using a CFA adjustment note while CFA used is
+		     sometimes R7.  This then causes an assert failure in the
+		     CFI note creation code.  */
+		  RTX_FRAME_RELATED_P (get_last_insn ()) = 0;
+		}
+
 	      arm_emit_multi_reg_pop (callee_saved_mask);
 	      pop_insn = get_last_insn ();
 
@@ -17993,13 +18023,15 @@ cmse_nonsecure_call_inline_register_clear (void)
 		 not reliable.  */
 	      RTX_FRAME_RELATED_P (pop_insn) = 0;
 
+	      seq = get_insns ();
+	      last = get_last_insn ();
 	      end_sequence ();
 
-	      emit_insn_after (pop_insn, after);
+	      emit_insn_after (seq, after);
 
 	      /* Skip pop we have just inserted after nonsecure call, we know
 		 it does not contain a nonsecure call.  */
-	      insn = pop_insn;
+	      insn = last;
 	    }
 	}
     }
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index 67ced090163bc4b40c09b00305d49d21084f7fb8..e759db24fac27be2de664ad4faced7bb5d3be84a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -9,12 +9,14 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s4-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index a6d9d14b63be8a226242512e36ba313849a3d35a..9df7b5de3ad64e719fc97d7a67a4893398e87b32 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -9,8 +9,10 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index ff4763529c7d280193d99ef695ce426038b7ceb9..b36ff73cb9b46d4d3a91f854c022787dc000d9c3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -9,10 +9,12 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 952010baee36cc404f1a85252c3bf9da7a6c3ce1..72493f032355828bdf48b84dc98d8102becd1b36 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -9,6 +9,7 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
@@ -16,7 +17,8 @@
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s4-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index ec1284117f8937026b263ba1bd623e9942527877..112ed78d6f172be31d4a4f06840d32a90cdf3dd4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -9,8 +9,10 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index d70a58a4c84c5d042f4efefbf36316d5401f770c..f48e8a0a020cebed8c9fa124d352f047442979d6 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -9,9 +9,11 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
-/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
+/* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
+/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 9/10] Call nscall function with blxns
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
                   ` (5 preceding siblings ...)
  2019-10-23 14:33 ` [PATCH, GCC/ARM, 6/10] Clear GPRs inline when calling nscall function Mihail Ionescu
@ 2019-10-23 14:34 ` Mihail Ionescu
  2019-10-23 14:34 ` [PATCH, GCC/ARM, 7/10] Clear all VFP regs inline in hardfloat nscall functions Mihail Ionescu
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 58750 bytes --]

[PATCH, GCC/ARM, 9/10] Call nscall function with blxns

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to call
functions with the cmse_nonsecure_call attribute directly using blxns
with no undue restriction on the register used for that.

=== Patch description ===

This change to use BLXNS to call a nonsecure function from secure
directly (not using a libcall) is made in 2 steps:
- change nonsecure_call patterns to use blxns instead of calling
  __gnu_cmse_nonsecure_call
- loosen requirement for function address to allow any register when
  doing BLXNS.

The former is a straightforward check over whether instructions added in
Armv8.1-M Mainline are available while the latter consist in making the
nonsecure call pattern accept any register by using match_operand and
changing the nonsecure_call_internal expander to no force r4 when
targeting Armv8.1-M Mainline.

The tricky bit is actually in the test update, specifically how to check
that register lists for CLRM have all registers except for the one
holding parameters (already done) and the one holding the address used
by BLXNS. This is achieved with 3 scan-assembler directives.

1) The first one lists all registers that can appear in CLRM but make
   each of them optional.
   Property guaranteed: no wrong register is cleared and none appears
   twice in the register list.
2) The second directive check that the CLRM is made of a fixed number
   of the right registers to be cleared. The number used is the number
   of registers that could contain a secret minus one (used to hold the
   address of the function to call.
   Property guaranteed: register list has the right number of registers
   Cumulated property guaranteed: only registers with a potential secret
   are cleared and they are all listed but ont
3) The last directive checks that we cannot find a CLRM with a register
   in it that also appears in BLXNS. This is check via the use of a
   back-reference on any of the allowed register in CLRM, the
   back-reference enforcing that whatever register match in CLRM must be
   the same in the BLXNS.
   Property guaranteed: register used for BLXNS is different from
   registers cleared in CLRM.

Some more care needs to happen for the gcc.target/arm/cmse/cmse-1.c
testcase due to there being two CLRM generated. To ensure the third
directive match the right CLRM to the BLXNS, a negative lookahead is
used between the CLRM register list and the BLXNS. The way negative
lookahead work is by matching the *position* where a given regular
expression does not match. In this case, since it comes after the CLRM
register list it is requesting that what comes after the register list
does not have a CLRM again followed by BLXNS. This guarantees that the
.*blxns after only matches a blxns without another CLRM before.

ChangeLog entries are as follows:

*** gcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm.md (nonsecure_call_internal): Do not force memory
	address in r4 when targeting Armv8.1-M Mainline.
	(nonsecure_call_value_internal): Likewise.
	* config/arm/thumb2.md (nonsecure_call_reg_thumb2): Make memory address
	a register match_operand again.  Emit BLXNS when targeting
	Armv8.1-M Mainline.
	(nonsecure_call_value_reg_thumb2): Likewise.

*** gcc/testsuite/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/cmse-1.c: Add check for BLXNS when instructions
	introduced in Armv8.1-M Mainline Security Extensions are available and
	restrict checks for libcall to __gnu_cmse_nonsecure_call to Armv8-M
	targets only.  Adapt CLRM check to verify register used for BLXNS is
	not in the CLRM register list.
	* gcc.target/arm/cmse/cmse-14.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise and adapt
	check for LSB clearing bit to be using the same register as BLXNS when
	targeting Armv8.1-M Mainline.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.
	* gcc.target/arm/cmse/cmse-15.c: Count BLXNS when targeting Armv8.1-M
	Mainline and restrict libcall count to Armv8-M.

Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; testsuite shows no
regression.

Is this ok for trunk?

Best regards,

Mihail


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


diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index d607f88cb05ffa9cd8a47b8c8e0c53ea3a5ca411..b7af3c060427d972e3cd1c7a8055aec20335c02b 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -7561,12 +7561,15 @@
   "use_cmse"
   "
   {
-    rtx tmp;
-    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+    if (!TARGET_HAVE_FPCTX_CMSE)
+      {
+	rtx tmp =
+	  copy_to_suggested_reg (XEXP (operands[0], 0),
 				 gen_rtx_REG (SImode, R4_REGNUM),
 				 SImode);
 
-    operands[0] = replace_equiv_address (operands[0], tmp);
+	operands[0] = replace_equiv_address (operands[0], tmp);
+      }
   }")
 
 (define_insn "*call_reg_armv5"
@@ -7669,12 +7672,15 @@
   "use_cmse"
   "
   {
-    rtx tmp;
-    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+    if (!TARGET_HAVE_FPCTX_CMSE)
+      {
+	rtx tmp =
+	  copy_to_suggested_reg (XEXP (operands[1], 0),
 				 gen_rtx_REG (SImode, R4_REGNUM),
 				 SImode);
 
-    operands[1] = replace_equiv_address (operands[1], tmp);
+	operands[1] = replace_equiv_address (operands[1], tmp);
+      }
   }")
 
 (define_insn "*call_value_reg_armv5"
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index 19d25cfe9b97b9428e3a6daebbf8dfb5648f29ef..964b3e2afcd524bb342373b400e35d0a72c4bd7f 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -560,13 +560,18 @@
 )
 
 (define_insn "*nonsecure_call_reg_thumb2"
-  [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
 		    UNSPEC_NONSECURE_MEM)
-	 (match_operand 0 "" ""))
-   (use (match_operand 1 "" ""))
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_THUMB2 && use_cmse"
-  "bl\\t__gnu_cmse_nonsecure_call"
+  {
+    if (TARGET_HAVE_FPCTX_CMSE)
+      return "blxns\\t%0";
+    else
+      return "bl\\t__gnu_cmse_nonsecure_call";
+  }
   [(set_attr "length" "4")
    (set_attr "type" "call")]
 )
@@ -585,13 +590,18 @@
 (define_insn "*nonsecure_call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call
-	 (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
 		    UNSPEC_NONSECURE_MEM)
-	 (match_operand 1 "" "")))
-   (use (match_operand 2 "" ""))
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_THUMB2 && use_cmse"
-  "bl\t__gnu_cmse_nonsecure_call"
+  {
+    if (TARGET_HAVE_FPCTX_CMSE)
+      return "blxns\\t%1";
+    else
+      return "bl\\t__gnu_cmse_nonsecure_call";
+  }
   [(set_attr "length" "4")
    (set_attr "type" "call")]
 )
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index 9f36fa3b1d8b86b4e1827909fca4fee181ba1c61..ddfcfacab5f601a729319a9d2dab03e61ee56bca 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -110,7 +110,13 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! arm_cmse_clear_ok } } } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}(?!.*clrm.*blxns).*blxns\t\\1" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
 
 int call_callback (void)
@@ -120,4 +126,5 @@ int call_callback (void)
   else
     return default_callback ();
 }
-/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 1 } } */
+/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 1 { target { ! arm_cmse_clear_ok } } } } */
+/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
index 6d39afab44329e78a8ff2f693fd94fe6a501af5a..5ab97856066e14c0005b56210e62f2b7a59fd911 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -10,7 +10,15 @@ int foo (void)
 }
 
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" { target { ! arm_cmse_clear_ok } } } } */
+/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" { target { ! arm_cmse_clear_ok } } } } */
+/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler-not "^(.*\\s)?bl?(?!xns)\[^\\s]*\\s+bar" { target arm_cmse_clear_ok } } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
index 4e9ace1f3f33b8a8653797e29ca62eb3dd7ae918..0e37b50e004d74dc81f5a8bdc0c9ba21ceaca67d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
@@ -69,4 +69,9 @@ int secure5 (void)
 {
   return (*s_bar2) ();
 }
-/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 6 } } */
+
+/* ARMv8-M expectation.  */
+/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 6 { target { ! arm_cmse_clear_ok } } } } */
+
+/* ARMv8.1-M expectation.  */
+/* { dg-final { scan-assembler-times "blxns" 6 { target arm_cmse_clear_ok } } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
index d4caf513ed2153370369bddbfcf6d2568d9f2f1e..ff34edb21c36c9f114aa934fa86ea962d932f273 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
@@ -10,9 +10,16 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "mov\tip, #3" } } */
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
index 2b7655a2c9971fb0aad4e6c8a1fee72e21028fad..4d1407aba4418006463fdca59cbe90e768e78391 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
@@ -8,9 +8,16 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "movw\tip, #2047" } } */
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
index 1a62076df9d6831d06f5ac6bdcb7deed0ecd23f8..9b1227adfdc03457266573447c7996245a114110 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
@@ -11,9 +11,16 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "mov\tip, #255" } } */
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
index 1319ac9766bcd330f6d8f0f7754a64a1dcc105b1..aec958fc9b9d125c54022911ee34affa9dd81797 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
@@ -8,9 +8,16 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "movw\tip, #2047" } } */
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
index 9bb60175529d77a3b1868f62a5a4d5355f00b76b..ae039e292d55423b1dc1b19551278418224bbe5e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
@@ -11,9 +11,16 @@
 /* { dg-final { scan-assembler "movw\tip, #65535" } } */
 /* { dg-final { scan-assembler "movt\tip, 31" } } */
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
index 11ca78bfdaf1ebe09f9699c278dc3db4fd20768c..f455f8cf19b1d8f32bd6ca208d33c144da644c29 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
@@ -5,9 +5,16 @@
 
 /* { dg-final { scan-assembler "movw\tip, #1799" } } */
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[1-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[1-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[1-9\]|r10|fp|ip), ){11}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[1-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
index 2f14c52715e0ad6e6ab69b01713ee13985a22653..3e76364c40452a7946e3b97e2321fd6e6d204355 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
@@ -15,9 +15,16 @@
 /* { dg-final { scan-assembler "movw\tip, #65535" } } */
 /* { dg-final { scan-assembler "movt\tip, 31" } } */
 /* { dg-final { scan-assembler "and\tr3, r3, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[4-9\]|r10|fp|ip), ){8}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index e759db24fac27be2de664ad4faced7bb5d3be84a..0c49277389271321c7fd7faa6ae6aaee2c299def 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -6,11 +6,18 @@
 #include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
@@ -20,4 +27,4 @@
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index 9df7b5de3ad64e719fc97d7a67a4893398e87b32..3c66b0a8c6f1c7be6c8cf77b2c71916a08c7b357 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -6,14 +6,21 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
 /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index b36ff73cb9b46d4d3a91f854c022787dc000d9c3..7d456c39705b15fa5b55270ac6b4ed57f5c7e465 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -6,11 +6,18 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
@@ -18,4 +25,4 @@
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 72493f032355828bdf48b84dc98d8102becd1b36..ab95c83a1167aff9fd4c0e24fe5580895cfbf0bb 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -6,11 +6,18 @@
 #include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
@@ -22,4 +29,4 @@
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index 112ed78d6f172be31d4a4f06840d32a90cdf3dd4..cf58d547972e21e0816a1bdf74968d0b50d2bd08 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -6,14 +6,21 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
 /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index f48e8a0a020cebed8c9fa124d352f047442979d6..1854d03d0814c90f8014a28fb1c81c6866f0071d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -6,15 +6,22 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
 /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index 52d22427de79c6a76fbe32b8df7f76b4b286249c..1b207c394081e6ec9bf569961a4a059d5b47fe20 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -5,18 +5,25 @@
 #include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index 40026d5ee1cc62b4acf48be9619ccd69ef4ead7b..3ec639480868944ed29065936c1fab10aa9e0fed 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -5,15 +5,22 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index 6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4..5c1d245d4aa966812e52f327c7ceba5dabba2e18 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -5,17 +5,24 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index 8d05576add940c277e5a13f7aab99e6807c1553d..3228692c2686fcae8e1369f984aaa6c375ad6418 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -6,13 +6,20 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index 1f0a14742781b7340685338901dbfab9b700b779..1c60d97dabd99136533a61fef5ae099eae4bbc93 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -6,15 +6,22 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index 842794181087ddbd5ce59680035a0cb61ce5682e..c366f6ae4ccc65d943dbbf045925ca9c6e8921ca 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -6,16 +6,23 @@
 #include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 38c9d5457034d2427413bcce7e7be6bad80f7a67..186a4480f4e816bdb2413ecbc690470e1c2480e6 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -6,13 +6,20 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index 6a17bd322fcc4e7e00ea289ee7373db9d8c37a87..f0f74f06bbd1eed2f71b46bc8947c99ce1de0765 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -6,15 +6,22 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
index 43e58ebde56ceb229edca2db25b720c42207c100..4d58eed1ac21e32dfa893397736be45129af53b8 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
@@ -8,9 +8,16 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "movw\tip, #511" } } */
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
index 6adf8fae5c3a56a6e50278919a2edbd2fda58f42..95de458b50172f6e84ffc2625fc35eca8f65108a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
@@ -12,9 +12,16 @@
 /* { dg-final { scan-assembler "movw\tip, #65535" } } */
 /* { dg-final { scan-assembler "movt\tip, 31" } } */
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */


[-- Attachment #2: diff08.patch.gz --]
[-- Type: application/gzip, Size: 4481 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 10/10] Enable -mcmse
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
                   ` (7 preceding siblings ...)
  2019-10-23 14:34 ` [PATCH, GCC/ARM, 7/10] Clear all VFP regs inline in hardfloat nscall functions Mihail Ionescu
@ 2019-10-23 14:34 ` Mihail Ionescu
  2019-10-23 15:07 ` [PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall function Mihail Ionescu
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 14:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 2531 bytes --]

[PATCH, GCC/ARM, 10/10] Enable -mcmse

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to enable the
-mcmse option now that support for Armv8.1-M Security Extension is
complete.

=== Patch description ===

The patch is straightforward: it redefines ARMv8_1m_main as having the
same features as ARMv8m_main (and thus as having the cmse feature) with
the extra features represented by armv8_1m_main.  It also removes the
error for using -mcmse on Armv8.1-M Mainline.

ChangeLog entry is as follows:

*** gcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm-cpus.in (ARMv8_1m_main): Redefine as an extension to
	Armv8-M Mainline.
	* config/arm/arm.c (arm_options_perform_arch_sanity_checks): Remove
	error for using -mcmse when targeting Armv8.1-M Mainline.

Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
regression.

Is this ok for trunk?

Best regards,

Mihail


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


diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
index 652f2a4be9388fd7a74f0ec4615a292fd1cfcd36..a845dd2f83a38519a1387515a2d4646761fb405f 100644
--- a/gcc/config/arm/arm-cpus.in
+++ b/gcc/config/arm/arm-cpus.in
@@ -259,10 +259,7 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb predres
 define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
 define fgroup ARMv8m_main ARMv7m armv8 cmse
 define fgroup ARMv8r      ARMv8a
-# Feature cmse is omitted to disable Security Extensions support while secure
-# code compiled by GCC does not preserve FP context as allowed by Armv8.1-M
-# Mainline.
-define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
+define fgroup ARMv8_1m_main ARMv8m_main armv8_1m_main
 
 # Useful combinations.
 define fgroup VFPv2	vfpv2
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index cabcce8c8bd11c5ff3516c3102c0305b865b00cb..0f19b4eb4ec4fcca2df10e1b8e0b79d1a1e0a93d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3742,9 +3742,6 @@ arm_options_perform_arch_sanity_checks (void)
   if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
     sorry ("__fp16 and no ldrh");
 
-  if (use_cmse && arm_arch8_1m_main)
-    error ("ARMv8.1-M Mainline Security Extensions is unsupported");
-
   if (use_cmse && !arm_arch_cmse)
     error ("target CPU does not support ARMv8-M Security Extensions");
 


[-- Attachment #2: diff09.patch --]
[-- Type: text/plain, Size: 1362 bytes --]

diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
index 652f2a4be9388fd7a74f0ec4615a292fd1cfcd36..a845dd2f83a38519a1387515a2d4646761fb405f 100644
--- a/gcc/config/arm/arm-cpus.in
+++ b/gcc/config/arm/arm-cpus.in
@@ -259,10 +259,7 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb predres
 define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
 define fgroup ARMv8m_main ARMv7m armv8 cmse
 define fgroup ARMv8r      ARMv8a
-# Feature cmse is omitted to disable Security Extensions support while secure
-# code compiled by GCC does not preserve FP context as allowed by Armv8.1-M
-# Mainline.
-define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
+define fgroup ARMv8_1m_main ARMv8m_main armv8_1m_main
 
 # Useful combinations.
 define fgroup VFPv2	vfpv2
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index cabcce8c8bd11c5ff3516c3102c0305b865b00cb..0f19b4eb4ec4fcca2df10e1b8e0b79d1a1e0a93d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3742,9 +3742,6 @@ arm_options_perform_arch_sanity_checks (void)
   if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
     sorry ("__fp16 and no ldrh");
 
-  if (use_cmse && arm_arch8_1m_main)
-    error ("ARMv8.1-M Mainline Security Extensions is unsupported");
-
   if (use_cmse && !arm_arch_cmse)
     error ("target CPU does not support ARMv8-M Security Extensions");
 


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall function
  2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
                   ` (8 preceding siblings ...)
  2019-10-23 14:34 ` [PATCH, GCC/ARM, 10/10] Enable -mcmse Mihail Ionescu
@ 2019-10-23 15:07 ` Mihail Ionescu
       [not found] ` <27d47273-6c06-450c-81a3-cee0c7355577@VE1EUR03FT028.eop-EUR03.prod.protection.outlook.com>
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-10-23 15:07 UTC (permalink / raw)
  To: gcc-patches; +Cc: kyrylo.tkachov, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 15629 bytes --]

[PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall function

Hi,

=== Context ===

This patch is part of a patch series to add support for Armv8.1-M
Mainline Security Extensions architecture. Its purpose is to generate
lazy store and load instruction inline when calling a function with the
cmse_nonsecure_call attribute with the soft or softfp floating-point
ABI.

=== Patch description ===

This patch adds two new patterns for the VLSTM and VLLDM instructions.
cmse_nonsecure_call_inline_register_clear is then modified to
generate VLSTM and VLLDM respectively before and after calls to
functions with the cmse_nonsecure_call attribute in order to have lazy
saving, clearing and restoring of VFP registers. Since these
instructions do not do writeback of the base register, the stack is adjusted
prior the lazy store and after the lazy load with appropriate frame
debug notes to describe the effect on the CFA register.

As with CLRM, VSCCLRM and VSTR/VLDR, the instruction is modeled as an
unspecified operation to the memory pointed to by the base register.

ChangeLog entries are as follows:

*** gcc/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm.c (arm_add_cfa_adjust_cfa_note): Declare early.
	(cmse_nonsecure_call_inline_register_clear): Define new lazy_fpclear
	variable as true when floating-point ABI is not hard.  Replace
	check against TARGET_HARD_FLOAT_ABI by checks against lazy_fpclear.
	Generate VLSTM and VLLDM instruction respectively before and
	after a function call to cmse_nonsecure_call function.
	* config/arm/unspecs.md (VUNSPEC_VLSTM): Define unspec.
	(VUNSPEC_VLLDM): Likewise.
	* config/arm/vfp.md (lazy_store_multiple_insn): New define_insn.
	(lazy_load_multiple_insn): Likewise.

*** gcc/testsuite/ChangeLog ***

2019-10-23  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-10-23  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Add check for VLSTM and
	VLLDM.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: Likewise.
	* gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: Likewise.

Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
regression.

Is this ok for trunk?

Best regards,

Mihail


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


diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index bcc86d50a10f11d9672258442089a0aa5c450b2f..b10f996c023e830ca24ff83fcbab335caf85d4cb 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -186,6 +186,7 @@ static int arm_register_move_cost (machine_mode, reg_class_t, reg_class_t);
 static int arm_memory_move_cost (machine_mode, reg_class_t, bool);
 static void emit_constant_insn (rtx cond, rtx pattern);
 static rtx_insn *emit_set_insn (rtx, rtx);
+static void arm_add_cfa_adjust_cfa_note (rtx, int, rtx, rtx);
 static rtx emit_multi_reg_push (unsigned long, unsigned long);
 static void arm_emit_multi_reg_pop (unsigned long);
 static int vfp_emit_fstmd (int, int);
@@ -17830,6 +17831,9 @@ cmse_nonsecure_call_inline_register_clear (void)
       FOR_BB_INSNS (bb, insn)
 	{
 	  bool clear_callee_saved = TARGET_HAVE_FPCTX_CMSE;
+	  /* frame = VFP regs + FPSCR + VPR.  */
+	  unsigned lazy_store_stack_frame_size =
+	    (LAST_VFP_REGNUM - FIRST_VFP_REGNUM + 1 + 2) * UNITS_PER_WORD;
 	  unsigned long callee_saved_mask =
 	    ((1 << (LAST_HI_REGNUM + 1)) - 1)
 	    & ~((1 << (LAST_ARG_REGNUM + 1)) - 1);
@@ -17847,7 +17851,7 @@ cmse_nonsecure_call_inline_register_clear (void)
 	  CUMULATIVE_ARGS args_so_far_v;
 	  cumulative_args_t args_so_far;
 	  tree arg_type, fntype;
-	  bool first_param = true;
+	  bool first_param = true, lazy_fpclear = !TARGET_HARD_FLOAT_ABI;
 	  function_args_iterator args_iter;
 	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
 
@@ -17881,7 +17885,7 @@ cmse_nonsecure_call_inline_register_clear (void)
 	     -mfloat-abi=hard.  For -mfloat-abi=softfp we will be using the
 	     lazy store and loads which clear both caller- and callee-saved
 	     registers.  */
-	  if (TARGET_HARD_FLOAT_ABI)
+	  if (!lazy_fpclear)
 	    {
 	      auto_sbitmap float_bitmap (maxregno + 1);
 
@@ -17965,8 +17969,23 @@ cmse_nonsecure_call_inline_register_clear (void)
 		 disabled for pop (see below).  */
 	      RTX_FRAME_RELATED_P (push_insn) = 0;
 
+	      /* Lazy store multiple.  */
+	      if (lazy_fpclear)
+		{
+		  rtx imm;
+		  rtx_insn *add_insn;
+
+		  imm = gen_int_mode (- lazy_store_stack_frame_size, SImode);
+		  add_insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
+						    stack_pointer_rtx, imm));
+		  arm_add_cfa_adjust_cfa_note (add_insn,
+					       - lazy_store_stack_frame_size,
+					       stack_pointer_rtx,
+					       stack_pointer_rtx);
+		  emit_insn (gen_lazy_store_multiple_insn (stack_pointer_rtx));
+		}
 	      /* Save VFP callee-saved registers.  */
-	      if (TARGET_HARD_FLOAT_ABI)
+	      else
 		{
 		  vfp_emit_fstmd (D7_VFP_REGNUM + 1,
 				  (max_fp_regno - D7_VFP_REGNUM) / 2);
@@ -17992,8 +18011,21 @@ cmse_nonsecure_call_inline_register_clear (void)
 
 	      start_sequence ();
 
+	      /* Lazy load multiple done as part of libcall in Armv8-M.  */
+	      if (lazy_fpclear)
+		{
+		  rtx imm = gen_int_mode (lazy_store_stack_frame_size, SImode);
+		  emit_insn (gen_lazy_load_multiple_insn (stack_pointer_rtx));
+		  rtx_insn *add_insn =
+		    emit_insn (gen_addsi3 (stack_pointer_rtx,
+					   stack_pointer_rtx, imm));
+		  arm_add_cfa_adjust_cfa_note (add_insn,
+					       lazy_store_stack_frame_size,
+					       stack_pointer_rtx,
+					       stack_pointer_rtx);
+		}
 	      /* Restore VFP callee-saved registers.  */
-	      if (TARGET_HARD_FLOAT_ABI)
+	      else
 		{
 		  int nb_callee_saved_vfp_regs =
 		    (max_fp_regno - D7_VFP_REGNUM) / 2;
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index ad072705525cc3c4035a22b5f99546bcd0e79ec5..9c9a68ae4f0a3d45f4c730f274b85f0b1ff00348 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -177,6 +177,10 @@
   VUNSPEC_CLRM_APSR	; Represent the clearing of APSR with clrm instruction.
   VUNSPEC_VSCCLRM_VPR	; Represent the clearing of VPR with vscclrm
 			; instruction.
+  VUNSPEC_VLSTM		; Represent the lazy store multiple with vlstm
+			; instruction.
+  VUNSPEC_VLLDM		; Represent the lazy load multiple with vlldm
+			; instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index 2bf928f32626ce2731ebdfedffbbf64d806eff53..d3807acdd4d3691da63dcc5d6b3d5d8aad4bfe0e 100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -1677,6 +1677,30 @@
    (set_attr "type" "mov_reg")]
 )
 
+(define_insn "lazy_store_multiple_insn"
+  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
+	(plus:SI (match_dup 0) (const_int -4)))
+   (unspec_volatile [(const_int 0)
+		     (mem:SI (plus:SI (match_dup 0) (const_int -4)))]
+		    VUNSPEC_VLSTM)]
+  "use_cmse && reload_completed"
+  "vlstm%?\\t%0"
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "store_4")]
+)
+
+(define_insn "lazy_load_multiple_insn"
+  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
+	(plus:SI (match_dup 0) (const_int 4)))
+   (unspec_volatile:SI [(const_int 0)
+			(mem:SI (match_dup 0))]
+		       VUNSPEC_VLLDM)]
+  "use_cmse && reload_completed"
+  "vlldm%?\\t%0"
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "load_4")]
+)
+
 (define_insn_and_split "*cmpsf_split_vfp"
   [(set (reg:CCFP CC_REGNUM)
 	(compare:CCFP (match_operand:SF 0 "s_register_operand"  "t")
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index 07a6719b4f1a260a3461f7408e278dd6e71f60d3..52d22427de79c6a76fbe32b8df7f76b4b286249c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index ca2961ac18ccacec6907b1d1d217c6c2e28072e7..40026d5ee1cc62b4acf48be9619ccd69ef4ead7b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -8,7 +8,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index 7a1abb51fcf9a62a24583e792953845f21bbed49..6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -10,7 +10,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index 90aadffb7aa14ceeea22232148c11e9543eee0e7..8d05576add940c277e5a13f7aab99e6807c1553d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -9,7 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index 28f2e86dfaa89902d1c04fc2890c5445b5bb0af5..1f0a14742781b7340685338901dbfab9b700b779 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index 15d3b682c798dd6635ed6b90d9aa8e705fefa265..842794181087ddbd5ce59680035a0cb61ce5682e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -12,7 +12,9 @@
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 3d48859028ab8dd22d9ffed7c95ece59c2ed937e..38c9d5457034d2427413bcce7e7be6bad80f7a67 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -9,7 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index 0e2dcae36927d2c7187ca2b60c935504268476bc..6a17bd322fcc4e7e00ea289ee7373db9d8c37a87 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */


[-- Attachment #2: patch.patch --]
[-- Type: text/plain, Size: 12888 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index bcc86d50a10f11d9672258442089a0aa5c450b2f..b10f996c023e830ca24ff83fcbab335caf85d4cb 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -186,6 +186,7 @@ static int arm_register_move_cost (machine_mode, reg_class_t, reg_class_t);
 static int arm_memory_move_cost (machine_mode, reg_class_t, bool);
 static void emit_constant_insn (rtx cond, rtx pattern);
 static rtx_insn *emit_set_insn (rtx, rtx);
+static void arm_add_cfa_adjust_cfa_note (rtx, int, rtx, rtx);
 static rtx emit_multi_reg_push (unsigned long, unsigned long);
 static void arm_emit_multi_reg_pop (unsigned long);
 static int vfp_emit_fstmd (int, int);
@@ -17830,6 +17831,9 @@ cmse_nonsecure_call_inline_register_clear (void)
       FOR_BB_INSNS (bb, insn)
 	{
 	  bool clear_callee_saved = TARGET_HAVE_FPCTX_CMSE;
+	  /* frame = VFP regs + FPSCR + VPR.  */
+	  unsigned lazy_store_stack_frame_size =
+	    (LAST_VFP_REGNUM - FIRST_VFP_REGNUM + 1 + 2) * UNITS_PER_WORD;
 	  unsigned long callee_saved_mask =
 	    ((1 << (LAST_HI_REGNUM + 1)) - 1)
 	    & ~((1 << (LAST_ARG_REGNUM + 1)) - 1);
@@ -17847,7 +17851,7 @@ cmse_nonsecure_call_inline_register_clear (void)
 	  CUMULATIVE_ARGS args_so_far_v;
 	  cumulative_args_t args_so_far;
 	  tree arg_type, fntype;
-	  bool first_param = true;
+	  bool first_param = true, lazy_fpclear = !TARGET_HARD_FLOAT_ABI;
 	  function_args_iterator args_iter;
 	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
 
@@ -17881,7 +17885,7 @@ cmse_nonsecure_call_inline_register_clear (void)
 	     -mfloat-abi=hard.  For -mfloat-abi=softfp we will be using the
 	     lazy store and loads which clear both caller- and callee-saved
 	     registers.  */
-	  if (TARGET_HARD_FLOAT_ABI)
+	  if (!lazy_fpclear)
 	    {
 	      auto_sbitmap float_bitmap (maxregno + 1);
 
@@ -17965,8 +17969,23 @@ cmse_nonsecure_call_inline_register_clear (void)
 		 disabled for pop (see below).  */
 	      RTX_FRAME_RELATED_P (push_insn) = 0;
 
+	      /* Lazy store multiple.  */
+	      if (lazy_fpclear)
+		{
+		  rtx imm;
+		  rtx_insn *add_insn;
+
+		  imm = gen_int_mode (- lazy_store_stack_frame_size, SImode);
+		  add_insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
+						    stack_pointer_rtx, imm));
+		  arm_add_cfa_adjust_cfa_note (add_insn,
+					       - lazy_store_stack_frame_size,
+					       stack_pointer_rtx,
+					       stack_pointer_rtx);
+		  emit_insn (gen_lazy_store_multiple_insn (stack_pointer_rtx));
+		}
 	      /* Save VFP callee-saved registers.  */
-	      if (TARGET_HARD_FLOAT_ABI)
+	      else
 		{
 		  vfp_emit_fstmd (D7_VFP_REGNUM + 1,
 				  (max_fp_regno - D7_VFP_REGNUM) / 2);
@@ -17992,8 +18011,21 @@ cmse_nonsecure_call_inline_register_clear (void)
 
 	      start_sequence ();
 
+	      /* Lazy load multiple done as part of libcall in Armv8-M.  */
+	      if (lazy_fpclear)
+		{
+		  rtx imm = gen_int_mode (lazy_store_stack_frame_size, SImode);
+		  emit_insn (gen_lazy_load_multiple_insn (stack_pointer_rtx));
+		  rtx_insn *add_insn =
+		    emit_insn (gen_addsi3 (stack_pointer_rtx,
+					   stack_pointer_rtx, imm));
+		  arm_add_cfa_adjust_cfa_note (add_insn,
+					       lazy_store_stack_frame_size,
+					       stack_pointer_rtx,
+					       stack_pointer_rtx);
+		}
 	      /* Restore VFP callee-saved registers.  */
-	      if (TARGET_HARD_FLOAT_ABI)
+	      else
 		{
 		  int nb_callee_saved_vfp_regs =
 		    (max_fp_regno - D7_VFP_REGNUM) / 2;
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index ad072705525cc3c4035a22b5f99546bcd0e79ec5..9c9a68ae4f0a3d45f4c730f274b85f0b1ff00348 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -177,6 +177,10 @@
   VUNSPEC_CLRM_APSR	; Represent the clearing of APSR with clrm instruction.
   VUNSPEC_VSCCLRM_VPR	; Represent the clearing of VPR with vscclrm
 			; instruction.
+  VUNSPEC_VLSTM		; Represent the lazy store multiple with vlstm
+			; instruction.
+  VUNSPEC_VLLDM		; Represent the lazy load multiple with vlldm
+			; instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index 2bf928f32626ce2731ebdfedffbbf64d806eff53..d3807acdd4d3691da63dcc5d6b3d5d8aad4bfe0e 100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -1677,6 +1677,30 @@
    (set_attr "type" "mov_reg")]
 )
 
+(define_insn "lazy_store_multiple_insn"
+  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
+	(plus:SI (match_dup 0) (const_int -4)))
+   (unspec_volatile [(const_int 0)
+		     (mem:SI (plus:SI (match_dup 0) (const_int -4)))]
+		    VUNSPEC_VLSTM)]
+  "use_cmse && reload_completed"
+  "vlstm%?\\t%0"
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "store_4")]
+)
+
+(define_insn "lazy_load_multiple_insn"
+  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
+	(plus:SI (match_dup 0) (const_int 4)))
+   (unspec_volatile:SI [(const_int 0)
+			(mem:SI (match_dup 0))]
+		       VUNSPEC_VLLDM)]
+  "use_cmse && reload_completed"
+  "vlldm%?\\t%0"
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "load_4")]
+)
+
 (define_insn_and_split "*cmpsf_split_vfp"
   [(set (reg:CCFP CC_REGNUM)
 	(compare:CCFP (match_operand:SF 0 "s_register_operand"  "t")
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index 07a6719b4f1a260a3461f7408e278dd6e71f60d3..52d22427de79c6a76fbe32b8df7f76b4b286249c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index ca2961ac18ccacec6907b1d1d217c6c2e28072e7..40026d5ee1cc62b4acf48be9619ccd69ef4ead7b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -8,7 +8,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index 7a1abb51fcf9a62a24583e792953845f21bbed49..6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -10,7 +10,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index 90aadffb7aa14ceeea22232148c11e9543eee0e7..8d05576add940c277e5a13f7aab99e6807c1553d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -9,7 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index 28f2e86dfaa89902d1c04fc2890c5445b5bb0af5..1f0a14742781b7340685338901dbfab9b700b779 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index 15d3b682c798dd6635ed6b90d9aa8e705fefa265..842794181087ddbd5ce59680035a0cb61ce5682e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -12,7 +12,9 @@
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 3d48859028ab8dd22d9ffed7c95ece59c2ed937e..38c9d5457034d2427413bcce7e7be6bad80f7a67 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -9,7 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index 0e2dcae36927d2c7187ca2b60c935504268476bc..6a17bd322fcc4e7e00ea289ee7373db9d8c37a87 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 1/10] Fix -mcmse check in libgcc
       [not found] ` <27d47273-6c06-450c-81a3-cee0c7355577@VE1EUR03FT028.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-04 16:44   ` Kyrill Tkachov
  0 siblings, 0 replies; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-04 16:44 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 1/10] Fix -mcmse check in libgcc
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to fix the
> check to determine whether -mcmse is supported by the host compiler.
>
> === Patch description ===
>
> Code to detect whether cmse.c can be buit with -mcmse checks the output
> of host GCC when invoked with -mcmse. However, an error from the
> compiler does not prevent some minimal output so this always holds true.
>
> This does not affect currently supported architectures since the test is
> guarded by __ARM_FEATURE_CMSE which is only defined for Armv8-M Baseline
> and Mainline and these two architectures accept -mcmse.
>
> However, in the intermediate patches adding support for Armv8.1-M
> Mainline, support for Security Extensions is disabled until fully
> implemented. This leads to libgcc/config/arm/cmse.c being built with
> -mcmse due to the broken test which fails in the intermediate commits.
>
> This patch instead change the test to look at the return value of the
> host gcc when invoked with -mcmse.
>
>
> ChangeLog entry is as follows:
>
> *** libgcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/t-arm: Check return value of gcc rather than lack of
>         output.
>
> Testing: Bootstrapped and tested on arm-none-eabi.
> Without this patch, GCC stops building after the second patch
> of this series.
>
> Is this ok for trunk?
>
This looks ok to me and safe enough to go in on its own.

Thanks,

Kyrill


> Best regards,
>
> Mihail
>
>
> ###############     Attachment also inlined for ease of reply    
> ###############
>
>
> diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
> index 
> 274bf2a8ef33c5e8a8ee2b246aba92d30297abe1..f2b927f3686a8c0a8e37abfe2d7768f2050d4fb3 
> 100644
> --- a/libgcc/config/arm/t-arm
> +++ b/libgcc/config/arm/t-arm
> @@ -3,7 +3,7 @@ LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi 
> _thumb1_case_shi \
>          _thumb1_case_uhi _thumb1_case_si _speculation_barrier
>
>  HAVE_CMSE:=$(findstring __ARM_FEATURE_CMSE,$(shell 
> $(gcc_compile_bare) -dM -E - </dev/null))
> -ifneq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null 2>/dev/null),)
> +ifeq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null >/dev/null 
> 2>/dev/null; echo $?),0)
>  CMSE_OPTS:=-mcmse
>  endif
>
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline
       [not found] ` <b3358cc4-8ee5-4039-891d-229a653270cb@VE1EUR03FT005.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-04 16:49   ` Kyrill Tkachov
  2019-11-06 15:59     ` Kyrill Tkachov
  0 siblings, 1 reply; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-04 16:49 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 2/10] Add command line support
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to add
> command-line support for that new architecture.
>
> === Patch description ===
>
> Besides the expected enabling of the new value for the -march
> command-line option (-march=armv8.1-m.main) and its extensions (see
> below), this patch disables support of the Security Extensions for this
> newly added architecture. This is done both by not including the cmse
> bit in the architecture description and by throwing an error message
> when user request Armv8.1-M Mainline Security Extensions. Note that
> Armv8-M Baseline and Mainline Security Extensions are still enabled.
>
> Only extensions for already supported instructions are implemented in
> this patch. Other extensions (MVE integer and float) will be added in
> separate patches. The following configurations are allowed for Armv8.1-M
> Mainline with regards to FPU and implemented in this patch:
> + no FPU (+nofp)
> + single precision VFPv5 with FP16 (+fp)
> + double precision VFPv5 with FP16 (+fp.dp)
>
> ChangeLog entry are as follow:
>
> *** gcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/arm-cpus.in (armv8_1m_main): New feature.
>         (ARMv4, ARMv4t, ARMv5t, ARMv5te, ARMv5tej, ARMv6, ARMv6j, ARMv6k,
>         ARMv6z, ARMv6kz, ARMv6zk, ARMv6t2, ARMv6m, ARMv7, ARMv7a, ARMv7ve,
>         ARMv7r, ARMv7m, ARMv7em, ARMv8a, ARMv8_1a, ARMv8_2a, ARMv8_3a,
>         ARMv8_4a, ARMv8_5a, ARMv8m_base, ARMv8m_main, ARMv8r): Reindent.
>         (ARMv8_1m_main): New feature group.
>         (armv8.1-m.main): New architecture.
>         * config/arm/arm-tables.opt: Regenerate.
>         * config/arm/arm.c (arm_arch8_1m_main): Define and default 
> initialize.
>         (arm_option_reconfigure_globals): Initialize arm_arch8_1m_main.
>         (arm_options_perform_arch_sanity_checks): Error out when targeting
>         Armv8.1-M Mainline Security Extensions.
>         * config/arm/arm.h (arm_arch8_1m_main): Declare.
>
> *** gcc/testsuite/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * lib/target-supports.exp
>         (check_effective_target_arm_arch_v8_1m_main_ok): Define.
>         (add_options_for_arm_arch_v8_1m_main): Likewise.
> (check_effective_target_arm_arch_v8_1m_main_multilib): Likewise.
>
> Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; testsuite
> shows no regression.
>
> Is this ok for trunk?
>
Ok.

Thanks,

Kyrill


> Best regards,
>
> Mihail
>
>
> ###############     Attachment also inlined for ease of reply    
> ###############
>
>
> diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
> index 
> f8a3b3db67a537163bfe787d78c8f2edc4253ab3..652f2a4be9388fd7a74f0ec4615a292fd1cfcd36 
> 100644
> --- a/gcc/config/arm/arm-cpus.in
> +++ b/gcc/config/arm/arm-cpus.in
> @@ -126,6 +126,9 @@ define feature armv8_5
>  # M-Profile security extensions.
>  define feature cmse
>
> +# Architecture rel 8.1-M.
> +define feature armv8_1m_main
> +
>  # Floating point and Neon extensions.
>  # VFPv1 is not supported in GCC.
>
> @@ -223,21 +226,21 @@ define fgroup ALL_FPU_INTERNAL vfpv2 vfpv3 vfpv4 
> fpv5 fp16conv fp_dbl ALL_SIMD_I
>  # -mfpu support.
>  define fgroup ALL_FP    fp16 ALL_FPU_INTERNAL
>
> -define fgroup ARMv4       armv4 notm
> -define fgroup ARMv4t      ARMv4 thumb
> -define fgroup ARMv5t      ARMv4t armv5t
> -define fgroup ARMv5te     ARMv5t armv5te
> -define fgroup ARMv5tej    ARMv5te
> -define fgroup ARMv6       ARMv5te armv6 be8
> -define fgroup ARMv6j      ARMv6
> -define fgroup ARMv6k      ARMv6 armv6k
> -define fgroup ARMv6z      ARMv6
> -define fgroup ARMv6kz     ARMv6k quirk_armv6kz
> -define fgroup ARMv6zk     ARMv6k
> -define fgroup ARMv6t2     ARMv6 thumb2
> +define fgroup ARMv4         armv4 notm
> +define fgroup ARMv4t        ARMv4 thumb
> +define fgroup ARMv5t        ARMv4t armv5t
> +define fgroup ARMv5te       ARMv5t armv5te
> +define fgroup ARMv5tej      ARMv5te
> +define fgroup ARMv6         ARMv5te armv6 be8
> +define fgroup ARMv6j        ARMv6
> +define fgroup ARMv6k        ARMv6 armv6k
> +define fgroup ARMv6z        ARMv6
> +define fgroup ARMv6kz       ARMv6k quirk_armv6kz
> +define fgroup ARMv6zk       ARMv6k
> +define fgroup ARMv6t2       ARMv6 thumb2
>  # This is suspect.  ARMv6-m doesn't really pull in any useful features
>  # from ARMv5* or ARMv6.
> -define fgroup ARMv6m      armv4 thumb armv5t armv5te armv6 be8
> +define fgroup ARMv6m        armv4 thumb armv5t armv5te armv6 be8
>  # This is suspect, the 'common' ARMv7 subset excludes the thumb2 
> 'DSP' and
>  # integer SIMD instructions that are in ARMv6T2.  */
>  define fgroup ARMv7       ARMv6m thumb2 armv7
> @@ -256,6 +259,10 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb predres
>  define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
>  define fgroup ARMv8m_main ARMv7m armv8 cmse
>  define fgroup ARMv8r      ARMv8a
> +# Feature cmse is omitted to disable Security Extensions support 
> while secure
> +# code compiled by GCC does not preserve FP context as allowed by 
> Armv8.1-M
> +# Mainline.
> +define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
>
>  # Useful combinations.
>  define fgroup VFPv2     vfpv2
> @@ -644,6 +651,17 @@ begin arch armv8-r
>   option nofp remove ALL_FP
>  end arch armv8-r
>
> +begin arch armv8.1-m.main
> + tune for cortex-m7
> + tune flags CO_PROC
> + base 8M_MAIN
> + isa ARMv8_1m_main
> +# fp => FPv5-sp-d16; fp.dp => FPv5-d16
> + option fp add FPv5 fp16
> + option fp.dp add FPv5 FP_DBL fp16
> + option nofp remove ALL_FP
> +end arch armv8.1-m.main
> +
>  begin arch iwmmxt
>   tune for iwmmxt
>   tune flags LDSCHED STRONG XSCALE
> diff --git a/gcc/config/arm/arm-tables.opt b/gcc/config/arm/arm-tables.opt
> index 
> aeb5b3fbf629e5cfae4d5f6d4d5f1a9c7752a511..d059969904cb39fbe583487e4fbb23d4f9838718 
> 100644
> --- a/gcc/config/arm/arm-tables.opt
> +++ b/gcc/config/arm/arm-tables.opt
> @@ -353,10 +353,13 @@ EnumValue
>  Enum(arm_arch) String(armv8-r) Value(28)
>
>  EnumValue
> -Enum(arm_arch) String(iwmmxt) Value(29)
> +Enum(arm_arch) String(armv8.1-m.main) Value(29)
>
>  EnumValue
> -Enum(arm_arch) String(iwmmxt2) Value(30)
> +Enum(arm_arch) String(iwmmxt) Value(30)
> +
> +EnumValue
> +Enum(arm_arch) String(iwmmxt2) Value(31)
>
>  Enum
>  Name(arm_fpu) Type(enum fpu_type)
> diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
> index 
> 8b67c9c3657b312be223ab60c01969958baa9ed3..307f1b59ba4456c901c8cb842d9961a740b6bb8d 
> 100644
> --- a/gcc/config/arm/arm.h
> +++ b/gcc/config/arm/arm.h
> @@ -456,6 +456,10 @@ extern int arm_arch8_3;
>  /* Nonzero if this chip supports the ARM Architecture 8.4 extensions.  */
>  extern int arm_arch8_4;
>
> +/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
> +   extensions.  */
> +extern int arm_arch8_1m_main;
> +
>  /* Nonzero if this chip supports the FP16 instructions extension of ARM
>     Architecture 8.2.  */
>  extern int arm_fp16_inst;
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 
> 9f0975dc0710626ef46abecaa3a205e993821118..9aca9484a9cdc26d6afee25e81f06b4047df2174 
> 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -903,6 +903,9 @@ int arm_arch8_3 = 0;
>
>  /* Nonzero if this chip supports the ARM Architecture 8.4 extensions.  */
>  int arm_arch8_4 = 0;
> +/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
> +   extensions.  */
> +int arm_arch8_1m_main = 0;
>
>  /* Nonzero if this chip supports the FP16 instructions extension of ARM
>     Architecture 8.2.  */
> @@ -3642,6 +3645,8 @@ arm_option_reconfigure_globals (void)
>    arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_2);
>    arm_arch8_3 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_3);
>    arm_arch8_4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_4);
> +  arm_arch8_1m_main = bitmap_bit_p (arm_active_target.isa,
> +                                   isa_bit_armv8_1m_main);
>    arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
>    arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb2);
>    arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, isa_bit_xscale);
> @@ -3727,6 +3732,9 @@ arm_options_perform_arch_sanity_checks (void)
>    if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
>      sorry ("__fp16 and no ldrh");
>
> +  if (use_cmse && arm_arch8_1m_main)
> +    error ("ARMv8.1-M Mainline Security Extensions are unsupported");
> +
>    if (use_cmse && !arm_arch_cmse)
>      error ("target CPU does not support ARMv8-M Security Extensions");
>
> diff --git a/gcc/testsuite/lib/target-supports.exp 
> b/gcc/testsuite/lib/target-supports.exp
> index 
> 6a1aaca9691b7fe9ae5e0e5b1874c7af34a3a6e3..5688aa7a6b7e8dad28aa553755b657464071a982 
> 100644
> --- a/gcc/testsuite/lib/target-supports.exp
> +++ b/gcc/testsuite/lib/target-supports.exp
> @@ -4242,10 +4242,11 @@ foreach { armfunc armflag armdefs } {
>          v8a "-march=armv8-a" __ARM_ARCH_8A__
>          v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
>          v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
> +       v8r "-march=armv8-r" __ARM_ARCH_8R__
>          v8m_base "-march=armv8-m.base -mthumb -mfloat-abi=soft"
>                  __ARM_ARCH_8M_BASE__
>          v8m_main "-march=armv8-m.main -mthumb" __ARM_ARCH_8M_MAIN__
> -       v8r "-march=armv8-r" __ARM_ARCH_8R__ } {
> +       v8_1m_main "-march=armv8.1-m.main -mthumb" 
> __ARM_ARCH_8M_MAIN__ } {
>      eval [string map [list FUNC $armfunc FLAG $armflag DEFS $armdefs ] {
>          proc check_effective_target_arm_arch_FUNC_ok { } {
>              return [check_no_compiler_messages arm_arch_FUNC_ok 
> assembly {
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline
  2019-11-04 16:49   ` [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline Kyrill Tkachov
@ 2019-11-06 15:59     ` Kyrill Tkachov
  2019-12-16 18:29       ` Mihail Ionescu
  0 siblings, 1 reply; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-06 15:59 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 11/4/19 4:49 PM, Kyrill Tkachov wrote:
> Hi Mihail,
>
> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> > [PATCH, GCC/ARM, 2/10] Add command line support
> >
> > Hi,
> >
> > === Context ===
> >
> > This patch is part of a patch series to add support for Armv8.1-M
> > Mainline Security Extensions architecture. Its purpose is to add
> > command-line support for that new architecture.
> >
> > === Patch description ===
> >
> > Besides the expected enabling of the new value for the -march
> > command-line option (-march=armv8.1-m.main) and its extensions (see
> > below), this patch disables support of the Security Extensions for this
> > newly added architecture. This is done both by not including the cmse
> > bit in the architecture description and by throwing an error message
> > when user request Armv8.1-M Mainline Security Extensions. Note that
> > Armv8-M Baseline and Mainline Security Extensions are still enabled.
> >
> > Only extensions for already supported instructions are implemented in
> > this patch. Other extensions (MVE integer and float) will be added in
> > separate patches. The following configurations are allowed for Armv8.1-M
> > Mainline with regards to FPU and implemented in this patch:
> > + no FPU (+nofp)
> > + single precision VFPv5 with FP16 (+fp)
> > + double precision VFPv5 with FP16 (+fp.dp)
> >
> > ChangeLog entry are as follow:
> >
> > *** gcc/ChangeLog ***
> >
> > 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> > 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
> >
> >         * config/arm/arm-cpus.in (armv8_1m_main): New feature.
> >         (ARMv4, ARMv4t, ARMv5t, ARMv5te, ARMv5tej, ARMv6, ARMv6j, 
> ARMv6k,
> >         ARMv6z, ARMv6kz, ARMv6zk, ARMv6t2, ARMv6m, ARMv7, ARMv7a, 
> ARMv7ve,
> >         ARMv7r, ARMv7m, ARMv7em, ARMv8a, ARMv8_1a, ARMv8_2a, ARMv8_3a,
> >         ARMv8_4a, ARMv8_5a, ARMv8m_base, ARMv8m_main, ARMv8r): Reindent.
> >         (ARMv8_1m_main): New feature group.
> >         (armv8.1-m.main): New architecture.
> >         * config/arm/arm-tables.opt: Regenerate.
> >         * config/arm/arm.c (arm_arch8_1m_main): Define and default
> > initialize.
> >         (arm_option_reconfigure_globals): Initialize arm_arch8_1m_main.
> >         (arm_options_perform_arch_sanity_checks): Error out when 
> targeting
> >         Armv8.1-M Mainline Security Extensions.
> >         * config/arm/arm.h (arm_arch8_1m_main): Declare.
> >
> > *** gcc/testsuite/ChangeLog ***
> >
> > 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> > 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
> >
> >         * lib/target-supports.exp
> > (check_effective_target_arm_arch_v8_1m_main_ok): Define.
> >         (add_options_for_arm_arch_v8_1m_main): Likewise.
> > (check_effective_target_arm_arch_v8_1m_main_multilib): Likewise.
> >
> > Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; 
> testsuite
> > shows no regression.
> >
> > Is this ok for trunk?
> >
> Ok.
>

Something that I remembered last night upon reflection...

New command-line options (or arguments to them) need documentation in 
invoke.texi.

Please add some either as part of this patch or as a separate patch if 
you prefer.

Thanks,

Kyrill


> Thanks,
>
> Kyrill
>
>
> > Best regards,
> >
> > Mihail
> >
> >
> > ###############     Attachment also inlined for ease of reply
> > ###############
> >
> >
> > diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
> > index
> > 
> f8a3b3db67a537163bfe787d78c8f2edc4253ab3..652f2a4be9388fd7a74f0ec4615a292fd1cfcd36 
>
> > 100644
> > --- a/gcc/config/arm/arm-cpus.in
> > +++ b/gcc/config/arm/arm-cpus.in
> > @@ -126,6 +126,9 @@ define feature armv8_5
> >  # M-Profile security extensions.
> >  define feature cmse
> >
> > +# Architecture rel 8.1-M.
> > +define feature armv8_1m_main
> > +
> >  # Floating point and Neon extensions.
> >  # VFPv1 is not supported in GCC.
> >
> > @@ -223,21 +226,21 @@ define fgroup ALL_FPU_INTERNAL vfpv2 vfpv3 vfpv4
> > fpv5 fp16conv fp_dbl ALL_SIMD_I
> >  # -mfpu support.
> >  define fgroup ALL_FP    fp16 ALL_FPU_INTERNAL
> >
> > -define fgroup ARMv4       armv4 notm
> > -define fgroup ARMv4t      ARMv4 thumb
> > -define fgroup ARMv5t      ARMv4t armv5t
> > -define fgroup ARMv5te     ARMv5t armv5te
> > -define fgroup ARMv5tej    ARMv5te
> > -define fgroup ARMv6       ARMv5te armv6 be8
> > -define fgroup ARMv6j      ARMv6
> > -define fgroup ARMv6k      ARMv6 armv6k
> > -define fgroup ARMv6z      ARMv6
> > -define fgroup ARMv6kz     ARMv6k quirk_armv6kz
> > -define fgroup ARMv6zk     ARMv6k
> > -define fgroup ARMv6t2     ARMv6 thumb2
> > +define fgroup ARMv4         armv4 notm
> > +define fgroup ARMv4t        ARMv4 thumb
> > +define fgroup ARMv5t        ARMv4t armv5t
> > +define fgroup ARMv5te       ARMv5t armv5te
> > +define fgroup ARMv5tej      ARMv5te
> > +define fgroup ARMv6         ARMv5te armv6 be8
> > +define fgroup ARMv6j        ARMv6
> > +define fgroup ARMv6k        ARMv6 armv6k
> > +define fgroup ARMv6z        ARMv6
> > +define fgroup ARMv6kz       ARMv6k quirk_armv6kz
> > +define fgroup ARMv6zk       ARMv6k
> > +define fgroup ARMv6t2       ARMv6 thumb2
> >  # This is suspect.  ARMv6-m doesn't really pull in any useful features
> >  # from ARMv5* or ARMv6.
> > -define fgroup ARMv6m      armv4 thumb armv5t armv5te armv6 be8
> > +define fgroup ARMv6m        armv4 thumb armv5t armv5te armv6 be8
> >  # This is suspect, the 'common' ARMv7 subset excludes the thumb2
> > 'DSP' and
> >  # integer SIMD instructions that are in ARMv6T2.  */
> >  define fgroup ARMv7       ARMv6m thumb2 armv7
> > @@ -256,6 +259,10 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb 
> predres
> >  define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
> >  define fgroup ARMv8m_main ARMv7m armv8 cmse
> >  define fgroup ARMv8r      ARMv8a
> > +# Feature cmse is omitted to disable Security Extensions support
> > while secure
> > +# code compiled by GCC does not preserve FP context as allowed by
> > Armv8.1-M
> > +# Mainline.
> > +define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
> >
> >  # Useful combinations.
> >  define fgroup VFPv2     vfpv2
> > @@ -644,6 +651,17 @@ begin arch armv8-r
> >   option nofp remove ALL_FP
> >  end arch armv8-r
> >
> > +begin arch armv8.1-m.main
> > + tune for cortex-m7
> > + tune flags CO_PROC
> > + base 8M_MAIN
> > + isa ARMv8_1m_main
> > +# fp => FPv5-sp-d16; fp.dp => FPv5-d16
> > + option fp add FPv5 fp16
> > + option fp.dp add FPv5 FP_DBL fp16
> > + option nofp remove ALL_FP
> > +end arch armv8.1-m.main
> > +
> >  begin arch iwmmxt
> >   tune for iwmmxt
> >   tune flags LDSCHED STRONG XSCALE
> > diff --git a/gcc/config/arm/arm-tables.opt 
> b/gcc/config/arm/arm-tables.opt
> > index
> > 
> aeb5b3fbf629e5cfae4d5f6d4d5f1a9c7752a511..d059969904cb39fbe583487e4fbb23d4f9838718 
>
> > 100644
> > --- a/gcc/config/arm/arm-tables.opt
> > +++ b/gcc/config/arm/arm-tables.opt
> > @@ -353,10 +353,13 @@ EnumValue
> >  Enum(arm_arch) String(armv8-r) Value(28)
> >
> >  EnumValue
> > -Enum(arm_arch) String(iwmmxt) Value(29)
> > +Enum(arm_arch) String(armv8.1-m.main) Value(29)
> >
> >  EnumValue
> > -Enum(arm_arch) String(iwmmxt2) Value(30)
> > +Enum(arm_arch) String(iwmmxt) Value(30)
> > +
> > +EnumValue
> > +Enum(arm_arch) String(iwmmxt2) Value(31)
> >
> >  Enum
> >  Name(arm_fpu) Type(enum fpu_type)
> > diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
> > index
> > 
> 8b67c9c3657b312be223ab60c01969958baa9ed3..307f1b59ba4456c901c8cb842d9961a740b6bb8d 
>
> > 100644
> > --- a/gcc/config/arm/arm.h
> > +++ b/gcc/config/arm/arm.h
> > @@ -456,6 +456,10 @@ extern int arm_arch8_3;
> >  /* Nonzero if this chip supports the ARM Architecture 8.4 
> extensions.  */
> >  extern int arm_arch8_4;
> >
> > +/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
> > +   extensions.  */
> > +extern int arm_arch8_1m_main;
> > +
> >  /* Nonzero if this chip supports the FP16 instructions extension of ARM
> >     Architecture 8.2.  */
> >  extern int arm_fp16_inst;
> > diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> > index
> > 
> 9f0975dc0710626ef46abecaa3a205e993821118..9aca9484a9cdc26d6afee25e81f06b4047df2174 
>
> > 100644
> > --- a/gcc/config/arm/arm.c
> > +++ b/gcc/config/arm/arm.c
> > @@ -903,6 +903,9 @@ int arm_arch8_3 = 0;
> >
> >  /* Nonzero if this chip supports the ARM Architecture 8.4 
> extensions.  */
> >  int arm_arch8_4 = 0;
> > +/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
> > +   extensions.  */
> > +int arm_arch8_1m_main = 0;
> >
> >  /* Nonzero if this chip supports the FP16 instructions extension of ARM
> >     Architecture 8.2.  */
> > @@ -3642,6 +3645,8 @@ arm_option_reconfigure_globals (void)
> >    arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_2);
> >    arm_arch8_3 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_3);
> >    arm_arch8_4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_4);
> > +  arm_arch8_1m_main = bitmap_bit_p (arm_active_target.isa,
> > + isa_bit_armv8_1m_main);
> >    arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, 
> isa_bit_thumb);
> >    arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, 
> isa_bit_thumb2);
> >    arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, 
> isa_bit_xscale);
> > @@ -3727,6 +3732,9 @@ arm_options_perform_arch_sanity_checks (void)
> >    if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
> >      sorry ("__fp16 and no ldrh");
> >
> > +  if (use_cmse && arm_arch8_1m_main)
> > +    error ("ARMv8.1-M Mainline Security Extensions are unsupported");
> > +
> >    if (use_cmse && !arm_arch_cmse)
> >      error ("target CPU does not support ARMv8-M Security Extensions");
> >
> > diff --git a/gcc/testsuite/lib/target-supports.exp
> > b/gcc/testsuite/lib/target-supports.exp
> > index
> > 
> 6a1aaca9691b7fe9ae5e0e5b1874c7af34a3a6e3..5688aa7a6b7e8dad28aa553755b657464071a982 
>
> > 100644
> > --- a/gcc/testsuite/lib/target-supports.exp
> > +++ b/gcc/testsuite/lib/target-supports.exp
> > @@ -4242,10 +4242,11 @@ foreach { armfunc armflag armdefs } {
> >          v8a "-march=armv8-a" __ARM_ARCH_8A__
> >          v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
> >          v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
> > +       v8r "-march=armv8-r" __ARM_ARCH_8R__
> >          v8m_base "-march=armv8-m.base -mthumb -mfloat-abi=soft"
> >                  __ARM_ARCH_8M_BASE__
> >          v8m_main "-march=armv8-m.main -mthumb" __ARM_ARCH_8M_MAIN__
> > -       v8r "-march=armv8-r" __ARM_ARCH_8R__ } {
> > +       v8_1m_main "-march=armv8.1-m.main -mthumb"
> > __ARM_ARCH_8M_MAIN__ } {
> >      eval [string map [list FUNC $armfunc FLAG $armflag DEFS 
> $armdefs ] {
> >          proc check_effective_target_arm_arch_FUNC_ok { } {
> >              return [check_no_compiler_messages arm_arch_FUNC_ok
> > assembly {
> >

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions
       [not found] ` <38378aaf-a33f-40b1-8595-b65b16f74363@AM5EUR03FT051.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-06 16:12   ` Kyrill Tkachov
  2019-12-16 18:30     ` Mihail Ionescu
  0 siblings, 1 reply; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-06 16:12 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to enable
> saving/restoring of nonsecure FP context in function with the
> cmse_nonsecure_entry attribute.
>
> === Motivation ===
>
> In Armv8-M Baseline and Mainline, the FP context is cleared on return from
> nonsecure entry functions. This means the FP context might change when
> calling a nonsecure entry function. This patch uses the new VLDR and
> VSTR instructions available in Armv8.1-M Mainline to save/restore the FP
> context when calling a nonsecure entry functionfrom nonsecure code.
>
> === Patch description ===
>
> This patch consists mainly of creating 2 new instruction patterns to
> push and pop special FP registers via vldm and vstr and using them in
> prologue and epilogue. The patterns are defined as push/pop with an
> unspecified operation on the memory accessed, with an unspecified
> constant indicating what special FP register is being saved/restored.
>
> Other aspects of the patch include:
>   * defining the set of special registers that can be saved/restored and
>     their name
>   * reserving space in the stack frames for these push/pop
>   * preventing return via pop
>   * guarding the clearing of FPSCR to target architecture not having
>     Armv8.1-M Mainline instructions.
>
> ChangeLog entry is as follows:
>
> *** gcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/arm.c (fp_sysreg_names): Declare and define.
>         (use_return_insn): Also return false for Armv8.1-M Mainline.
>         (output_return_instruction): Skip FPSCR clearing if Armv8.1-M
>         Mainline instructions are available.
>         (arm_compute_frame_layout): Allocate space in frame for FPCXTNS
>         when targeting Armv8.1-M Mainline Security Extensions.
>         (arm_expand_prologue): Save FPCXTNS if this is an Armv8.1-M
>         Mainline entry function.
>         (cmse_nonsecure_entry_clear_before_return): Clear IP and r4 if
>         targeting Armv8.1-M Mainline or successor.
>         (arm_expand_epilogue): Fix indentation of caller-saved register
>         clearing.  Restore FPCXTNS if this is an Armv8.1-M Mainline
>         entry function.
>         * config/arm/arm.h (TARGET_HAVE_FP_CMSE): New macro.
>         (FP_SYSREGS): Likewise.
>         (enum vfp_sysregs_encoding): Define enum.
>         (fp_sysreg_names): Declare.
>         * config/arm/unspecs.md (VUNSPEC_VSTR_VLDR): New volatile unspec.
>         * config/arm/vfp.md (push_fpsysreg_insn): New define_insn.
>         (pop_fpsysreg_insn): Likewise.
>
> *** gcc/testsuite/Changelog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * gcc.target/arm/cmse/bitfield-1.c: add checks for VSTR and VLDR.
>         * gcc.target/arm/cmse/bitfield-2.c: Likewise.
>         * gcc.target/arm/cmse/bitfield-3.c: Likewise.
>         * gcc.target/arm/cmse/cmse-1.c: Likewise.
>         * gcc.target/arm/cmse/struct-1.c: Likewise.
>         * gcc.target/arm/cmse/cmse.exp: Run existing Armv8-M Mainline 
> tests
>         from mainline/8m subdirectory and new Armv8.1-M Mainline tests 
> from
>         mainline/8_1m subdirectory.
>         * gcc.target/arm/cmse/mainline/bitfield-4.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/bitfield-4.c: This.
>         * gcc.target/arm/cmse/mainline/bitfield-5.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/bitfield-5.c: This.
>         * gcc.target/arm/cmse/mainline/bitfield-6.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/bitfield-6.c: This.
>         * gcc.target/arm/cmse/mainline/bitfield-7.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/bitfield-7.c: This.
>         * gcc.target/arm/cmse/mainline/bitfield-8.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/bitfield-8.c: This.
>         * gcc.target/arm/cmse/mainline/bitfield-9.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/bitfield-9.c: This.
>         * gcc.target/arm/cmse/mainline/bitfield-and-union-1.c: Move 
> and rename
>         into ...
>         * gcc.target/arm/cmse/mainline/8m/bitfield-and-union.c: This.
>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-13.c: This.  
> Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-5.c: This.  
> Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-7.c: This.  
> Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-8.c: This.  
> Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/hard/cmse-13.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-13.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/hard/cmse-5.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-5.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/hard/cmse-7.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-7.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/hard/cmse-8.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-8.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/soft/cmse-13.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-13.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/soft/cmse-5.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-5.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/soft/cmse-7.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-7.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/soft/cmse-8.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-8.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-5.c: This. 
> Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-7.c: This. 
> Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-8.c: This. 
> Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/softfp/cmse-13.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c: This.  
> Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-5.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/softfp/cmse-7.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-7.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/softfp/cmse-8.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-8.c: This.  Clean up
>         dg-skip-if directive for float ABI.
>         * gcc.target/arm/cmse/mainline/union-1.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/union-1.c: This.
>         * gcc.target/arm/cmse/mainline/union-2.c: Move into ...
>         * gcc.target/arm/cmse/mainline/8m/union-2.c: This.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: New 
> file.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: New file.
>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: New file.
>         * lib/target-supports.exp 
> (check_effective_target_arm_cmse_clear_ok):
>         New procedure.
>
> Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; 
> testsuite shows no
> regression.
>
> Is this ok for trunk?
>
<snip>

+(define_insn "push_fpsysreg_insn"
+  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
+    (plus:SI (match_dup 0) (const_int -4)))
+   (unspec_volatile [(match_operand:SI 1 "const_int_operand" "n")
+             (mem:SI (plus:SI (match_dup 0) (const_int -4)))]
+            VUNSPEC_VSTR_VLDR)]
+  "TARGET_HAVE_FPCXT_CMSE && use_cmse"
+  {
+    static char buf[32];
+    int fp_sysreg_enum = INTVAL (operands[1]);
+
+    gcc_assert (IN_RANGE (fp_sysreg_enum, 0, NB_FP_SYSREGS - 1));
+
+    snprintf (buf, sizeof (buf), \"vstr%%?\\t%s, [%%0, #-4]!\",
+          fp_sysreg_names[fp_sysreg_enum]);
+    return buf;
+  }
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "store_4")]
+)

I'm a bit concerned by the RTL representation here. This is a memory 
store instruction but the MEM operand is just part of an UNSPEC.

Wouldn't this be more conveniently represented as a SET of a MEM to an 
unspec_volatile value where the address of the MEM uses a POST_INC 
addressing mode?


+
+(define_insn "pop_fpsysreg_insn"
+  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
+    (plus:SI (match_dup 0) (const_int 4)))
+   (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "n")
+            (mem:SI (match_dup 0))]
+               VUNSPEC_VSTR_VLDR)]
+  "TARGET_HAVE_FPCXT_CMSE && use_cmse"
+  {
+    static char buf[32];
+    int fp_sysreg_enum = INTVAL (operands[1]);
+
+    gcc_assert (IN_RANGE (fp_sysreg_enum, 0, NB_FP_SYSREGS - 1));
+
+    snprintf (buf, sizeof (buf), \"vldr%%?\\t%s, [%%0], #4\",
+          fp_sysreg_names[fp_sysreg_enum]);
+    return buf;
+  }
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "load_4")]
+)


Similarly here, can't we use one of the addressing modes that describe 
the address update?

Thanks,

Kyrill


> Best regards,
>
> Mihail

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
       [not found] ` <58a87082-6686-466f-84ed-1a8da281ecbb@DB5EUR03FT053.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-12  9:56   ` Kyrill Tkachov
  2019-12-16 19:16     ` Mihail Ionescu
  0 siblings, 1 reply; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-12  9:56 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to improve
> code density of functions with the cmse_nonsecure_entry attribute and
> when calling function with the cmse_nonsecure_call attribute by using
> CLRM to do all the general purpose registers clearing as well as
> clearing the APSR register.
>
> === Patch description ===
>
> This patch adds a new pattern for the CLRM instruction and guards the
> current clearing code in output_return_instruction() and thumb_exit()
> on Armv8.1-M Mainline instructions not being present.
> cmse_clear_registers () is then modified to use the new CLRM instruction
> when targeting Armv8.1-M Mainline while keeping Armv8-M register
> clearing code for VFP registers.
>
> For the CLRM instruction, which does not mandated APSR in the register
> list, checking whether it is the right volatile unspec or a clearing
> register is done in clear_operation_p.
>
> Note that load/store multiple were deemed sufficiently different in
> terms of RTX structure compared to the CLRM pattern for a different
> function to be used to validate the match_parallel.
>
> ChangeLog entries are as follows:
>
> *** gcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/arm-protos.h (clear_operation_p): Declare.
>         * config/arm/arm.c (clear_operation_p): New function.
>         (cmse_clear_registers): Generate clear_multiple instruction 
> pattern if
>         targeting Armv8.1-M Mainline or successor.
>         (output_return_instruction): Only output APSR register clearing if
>         Armv8.1-M Mainline instructions not available.
>         (thumb_exit): Likewise.
>         * config/arm/predicates.md (clear_multiple_operation): New 
> predicate.
>         * config/arm/thumb2.md (clear_apsr): New define_insn.
>         (clear_multiple): Likewise.
>         * config/arm/unspecs.md (VUNSPEC_CLRM_APSR): New volatile unspec.
>
> *** gcc/testsuite/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * gcc.target/arm/cmse/bitfield-1.c: Add check for CLRM.
>         * gcc.target/arm/cmse/bitfield-2.c: Likewise.
>         * gcc.target/arm/cmse/bitfield-3.c: Likewise.
>         * gcc.target/arm/cmse/struct-1.c: Likewise.
>         * gcc.target/arm/cmse/cmse-14.c: Likewise.
>         * gcc.target/arm/cmse/cmse-1.c: Likewise.  Restrict checks for 
> Armv8-M
>         GPR clearing when CLRM is not available.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.
>
> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
> regression.
>
> Is this ok for trunk?
>
> Best regards,
>
> Mihail
>
>
> ###############     Attachment also inlined for ease of reply    
> ###############
>
>
> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
> index 
> f995974f9bb89ab3c7ff0888c394b0dfaf7da60c..1a948d2c97526ad7e67e8d4a610ac74cfdb13882 
> 100644
> --- a/gcc/config/arm/arm-protos.h
> +++ b/gcc/config/arm/arm-protos.h
> @@ -77,6 +77,7 @@ extern int thumb_legitimate_offset_p (machine_mode, 
> HOST_WIDE_INT);
>  extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
>  extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
>                                   bool, bool);
> +extern bool clear_operation_p (rtx);
>  extern int arm_const_double_rtx (rtx);
>  extern int vfp3_const_double_rtx (rtx);
>  extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, 
> int *);
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 
> d485e80096c9d2eef2172d211a0a5ab63cdbb3c7..3a373cea33c3d0b966cbe700d26f66fe069e1efb 
> 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -13499,6 +13499,66 @@ ldm_stm_operation_p (rtx op, bool load, 
> machine_mode mode,
>    return true;
>  }
>
> +/* Checks whether OP is a valid parallel pattern for a CLRM insn.  To 
> be a
> +   valid CLRM pattern, OP must have the following form:
> +
> +   [(set (reg:SI <N>) (const_int 0))
> +    (set (reg:SI <M>) (const_int 0))
> +    ...
> +    (unspec_volatile [(const_int 0)]
> +                    VUNSPEC_CLRM_APSR)
> +   ]


If this clears the whole APSR than it also clobbers the condition flags, 
right?

Then it should also have a  (clobber (reg:CC CC_REGNUM)) in there.


> +
> +   Any number (including 0) of set expressions is valid, the volatile 
> unspec is
> +   optional.  All registers but SP and PC are allowed and registers 
> must be in
> +   strict increasing order.  */
> +
> +bool
> +clear_operation_p (rtx op)
> +{
> +  HOST_WIDE_INT i;
> +  unsigned regno, last_regno;
> +  rtx elt, reg, zero;
> +  machine_mode mode;
> +  HOST_WIDE_INT count = XVECLEN (op, 0);
> +
> +  for (i = 0; i < count; i++)
> +    {
> +      elt = XVECEXP (op, 0, i);
> +
> +      if (GET_CODE (elt) == UNSPEC_VOLATILE)
> +       {
> +         if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
> +             || XVECLEN (elt, 0) != 1
> +             || XVECEXP (elt, 0, 0) != CONST0_RTX (SImode)
> +             || i != count - 1)
> +           return false;
> +
> +         continue;
> +       }
> +
> +      if (GET_CODE (elt) != SET)
> +       return false;
> +
> +      reg = SET_DEST (elt);
> +      regno = REGNO (reg);
> +      mode = GET_MODE (reg);
> +      zero = SET_SRC (elt);
> +
> +      if (!REG_P (reg)
> +         || GET_MODE (reg) != SImode
> +         || regno == SP_REGNUM
> +         || regno == PC_REGNUM
> +         || (i != 0 && regno <= last_regno)
> +         || zero != CONST0_RTX (SImode))
> +       return false;
> +
> +      last_regno = REGNO (reg);
> +    }
> +
> +  return true;
> +}
> +
>  /* Return true iff it would be profitable to turn a sequence of NOPS 
> loads
>     or stores (depending on IS_STORE) into a load-multiple or 
> store-multiple
>     instruction.  ADD_OFFSET is nonzero if the base address register needs
> @@ -17596,6 +17656,56 @@ cmse_clear_registers (sbitmap 
> to_clear_bitmap, uint32_t *padding_bits_to_clear,
>
>    /* Clear full registers.  */
>
> +  if (TARGET_HAVE_FPCXT_CMSE)
> +    {
> +      rtvec vunspec_vec;
> +      int i, j, k, nb_regs;
> +      rtx use_seq, par, reg, set, vunspec;
> +      int to_clear_bitmap_size = SBITMAP_SIZE (to_clear_bitmap);
> +      auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
> +      auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
> +
> +      /* Get set of core registers to clear.  */
> +      bitmap_clear (core_regs_bitmap);
> +      bitmap_set_range (core_regs_bitmap, R0_REGNUM,
> +                       IP_REGNUM - R0_REGNUM + 1);
> +      bitmap_and (to_clear_core_bitmap, to_clear_bitmap,
> +                 core_regs_bitmap);
> +      gcc_assert (!bitmap_empty_p (to_clear_core_bitmap));
> +
> +      if (bitmap_empty_p (to_clear_core_bitmap))
> +       return;
> +
> +      /* Create clrm RTX pattern.  */
> +      nb_regs = bitmap_count_bits (to_clear_core_bitmap);
> +      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 1));
> +
> +      /* Insert core register clearing RTX in the pattern. */
> +      start_sequence ();
> +      for (j = 0, i = minregno; j < nb_regs; i++)
> +       {
> +         if (!bitmap_bit_p (to_clear_core_bitmap, i))
> +           continue;
> +
> +         reg = gen_rtx_REG (SImode, i);
> +         set = gen_rtx_SET (reg, const0_rtx);
> +         XVECEXP (par, 0, j++) = set;
> +         emit_use (reg);
> +       }
> +
> +      /* Insert APSR register clearing RTX in the pattern. */
> +      vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
> +      vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
> +                                        VUNSPEC_CLRM_APSR);
> +      XVECEXP (par, 0, j) = vunspec;
> +
> +      use_seq = get_insns ();
> +      end_sequence ();
> +
> +      emit_insn_after (use_seq, emit_insn (par));
> +      minregno = FIRST_VFP_REGNUM;
> +    }
> +
>    /* If not marked for clearing, clearing_reg already does not contain
>       any secret.  */
>    if (clearing_regno <= maxregno
> @@ -20259,40 +20369,50 @@ output_return_instruction (rtx operand, bool 
> really_return, bool reverse,
>          default:
>            if (IS_CMSE_ENTRY (func_type))
>              {
> -             /* Check if we have to clear the 'GE bits' which is only 
> used if
> -                parallel add and subtraction instructions are 
> available.  */
> -             if (TARGET_INT_SIMD)
> -               snprintf (instr, sizeof (instr),
> -                         "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
> -             else
> -               snprintf (instr, sizeof (instr),
> -                         "msr%s\tAPSR_nzcvq, %%|lr", conditional);
> -
> -             output_asm_insn (instr, & operand);
> -             /* Do not clear FPSCR if targeting Armv8.1-M Mainline, 
> VLDR takes
> -                care of it.  */
> -             if (TARGET_HARD_FLOAT && ! TARGET_HAVE_FPCXT_CMSE)
> +             /* For Armv8.1-M, this is cleared as part of the CLRM 
> instruction
> +                emitted by cmse_nonsecure_entry_clear_before_return 
> () and the
> +                VSTR/VLDR instructions in the prologue and epilogue.  */
> +             if (!TARGET_HAVE_FPCXT_CMSE)
>                  {
> -                 /* Clear the cumulative exception-status bits 
> (0-4,7) and the
> -                    condition code bits (28-31) of the FPSCR.  We need to
> -                    remember to clear the first scratch register used 
> (IP) and
> -                    save and restore the second (r4).  */
> -                 snprintf (instr, sizeof (instr), "push\t{%%|r4}");
> -                 output_asm_insn (instr, & operand);
> -                 snprintf (instr, sizeof (instr), "vmrs\t%%|ip, fpscr");
> -                 output_asm_insn (instr, & operand);
> -                 snprintf (instr, sizeof (instr), "movw\t%%|r4, #65376");
> -                 output_asm_insn (instr, & operand);
> -                 snprintf (instr, sizeof (instr), "movt\t%%|r4, #4095");
> -                 output_asm_insn (instr, & operand);
> -                 snprintf (instr, sizeof (instr), "and\t%%|ip, %%|r4");
> -                 output_asm_insn (instr, & operand);
> -                 snprintf (instr, sizeof (instr), "vmsr\tfpscr, %%|ip");
> -                 output_asm_insn (instr, & operand);
> -                 snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
> -                 output_asm_insn (instr, & operand);
> -                 snprintf (instr, sizeof (instr), "mov\t%%|ip, %%|lr");
> +                 /* Check if we have to clear the 'GE bits' which is 
> only used if
> +                    parallel add and subtraction instructions are 
> available.  */
> +                 if (TARGET_INT_SIMD)
> +                   snprintf (instr, sizeof (instr),
> +                             "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
> +                 else
> +                   snprintf (instr, sizeof (instr),
> +                             "msr%s\tAPSR_nzcvq, %%|lr", conditional);
> +
>                    output_asm_insn (instr, & operand);
> +                 /* Do not clear FPSCR if targeting Armv8.1-M 
> Mainline, VLDR takes
> +                    care of it.  */
> +                 if (TARGET_HARD_FLOAT)
> +                   {
> +                     /* Clear the cumulative exception-status bits 
> (0-4,7) and
> +                        the condition code bits (28-31) of the 
> FPSCR.  We need
> +                        to remember to clear the first scratch 
> register used
> +                        (IP) and save and restore the second (r4).
> +
> +                        Important note: the length of the
> +                        thumb2_cmse_entry_return insn pattern must 
> account for
> +                        the size of the below instructions.  */
> +                     snprintf (instr, sizeof (instr), "push\t{%%|r4}");
> +                     output_asm_insn (instr, & operand);


I know this is pre-existing in this function, but I think we should just 
use output_asm_insn directly here:
output_asm_insn ("push\t{%%|r4}", & operand);

and avoid all the snprintfs.


> +                     snprintf (instr, sizeof (instr), "vmrs\t%%|ip, 
> fpscr");
> +                     output_asm_insn (instr, & operand);
> +                     snprintf (instr, sizeof (instr), "movw\t%%|r4, 
> #65376");
> +                     output_asm_insn (instr, & operand);
> +                     snprintf (instr, sizeof (instr), "movt\t%%|r4, 
> #4095");
> +                     output_asm_insn (instr, & operand);
> +                     snprintf (instr, sizeof (instr), "and\t%%|ip, 
> %%|r4");
> +                     output_asm_insn (instr, & operand);
> +                     snprintf (instr, sizeof (instr), "vmsr\tfpscr, 
> %%|ip");
> +                     output_asm_insn (instr, & operand);
> +                     snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
> +                     output_asm_insn (instr, & operand);
> +                     snprintf (instr, sizeof (instr), "mov\t%%|ip, 
> %%|lr");
> +                     output_asm_insn (instr, & operand);
> +                   }
>                  }
>                snprintf (instr, sizeof (instr), "bxns\t%%|lr");
>              }
> @@ -24690,8 +24810,11 @@ thumb_exit (FILE *f, int 
> reg_containing_return_addr)
>
>        if (IS_CMSE_ENTRY (arm_current_func_type ()))
>          {
> -         asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
> -                      reg_containing_return_addr);
> +         /* For Armv8.1-M, this is cleared as part of the CLRM 
> instruction
> +            emitted by cmse_nonsecure_entry_clear_before_return ().  */
> +         if (!TARGET_HAVE_FPCXT_CMSE)
> +           asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
> +                        reg_containing_return_addr);
>            asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
>          }
>        else
> @@ -24931,11 +25054,14 @@ thumb_exit (FILE *f, int 
> reg_containing_return_addr)
>           address.  It may therefore contain information that we might 
> not want
>           to leak, hence it must be cleared.  The value in R0 will 
> never be a
>           secret at this point, so it is safe to use it, see the 
> clearing code
> -        in 'cmse_nonsecure_entry_clear_before_return'.  */
> +        in cmse_nonsecure_entry_clear_before_return ().  */
>        if (reg_containing_return_addr != LR_REGNUM)
>          asm_fprintf (f, "\tmov\tlr, r0\n");
>
> -      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
> reg_containing_return_addr);
> +      /* For Armv8.1-M, this is cleared as part of the CLRM 
> instruction emitted
> +        by cmse_nonsecure_entry_clear_before_return ().  */
> +      if (!TARGET_HAVE_FPCXT_CMSE)
> +       asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
> reg_containing_return_addr);
>        asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
>      }
>    else
> diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
> index 
> 8b36e7ee462235ad26e132f1ccf98d28c2487d67..e5c583ef3d167194e7a061d7c3e98d3b4bb5269c 
> 100644
> --- a/gcc/config/arm/predicates.md
> +++ b/gcc/config/arm/predicates.md
> @@ -510,6 +510,12 @@
>              (match_test "satisfies_constraint_Dy (op)")
>              (match_test "satisfies_constraint_G (op)"))))
>
> +(define_special_predicate "clear_multiple_operation"
> +  (match_code "parallel")
> +{
> + return clear_operation_p (op);
> +})
> +
>  (define_special_predicate "load_multiple_operation"
>    (match_code "parallel")
>  {
> diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
> index 
> 6ccc875e2b4e7b8ce256e52da966dfe220c6f5d6..9994c0d59f741ef47d0ec43dd53a2324b031d048 
> 100644
> --- a/gcc/config/arm/thumb2.md
> +++ b/gcc/config/arm/thumb2.md
> @@ -1599,3 +1599,39 @@
>        FAIL;
>   }")
>
> +(define_insn "*clear_apsr"
> +  [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)]
> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
> +  "clrm%?\\t{APSR}"
> +  [(set_attr "predicable" "yes")]
> +)


Similar to earlier, if this clears the whole APSR then it should also 
represent a clobber of the CC reg.


> +
> +;; The operands are validated through the clear_multiple_operation
> +;; match_parallel predicate rather than through constraints so enable 
> it only
> +;; after reload.
> +(define_insn "*clear_multiple"
> +  [(match_parallel 0 "clear_multiple_operation"
> +     [(set (match_operand:SI 1 "register_operand" "")
> +          (const_int 0))])]
> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && 
> reload_completed"
> +  {
> +    char pattern[100];
> +    int i, num_saves = XVECLEN (operands[0], 0);
> +
> +    strcpy (pattern, \"clrm%?\\t{\");
> +    for (i = 0; i < num_saves; i++)
> +      {
> +       if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
> +         strcat (pattern, \"APSR\");
> +       else
> +         strcat (pattern,
> +                 reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 
> 0))]);
> +       if (i < num_saves - 1)
> +         strcat (pattern, \", %|\");
> +      }
> +    strcat (pattern, \"}\");
> +    output_asm_insn (pattern, operands);
> +    return \"\";
> +  }
> +  [(set_attr "predicable" "yes")]
> +)
> diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
> index 
> 324359be7127f04a80ebc0079ad0a9964dfd82a7..498bc0798dbaaa3ee73815ba27864ae92a2fd08e 
> 100644
> --- a/gcc/config/arm/unspecs.md
> +++ b/gcc/config/arm/unspecs.md
> @@ -174,6 +174,7 @@
>    VUNSPEC_MRRC2                ; Represent the coprocessor mrrc2 
> instruction.
>    VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional 
> speculation barrier.
>    VUNSPEC_VSTR_VLDR    ; Represent the vstr/vldr instruction.
> +  VUNSPEC_CLRM_APSR    ; Represent the clearing of APSR with clrm 
> instruction.
>  ])
>
>  ;; Enumerators for NEON unspecs.
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
> index 
> 6d611e130b6f3b544807b767927d99b89071343b..7036cb9508c27d56c4b2c01a81c44bf6f1f9c781 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
> @@ -36,6 +36,7 @@ main (void)
>  /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bxns" } } */
>
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c 
> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
> index 
> b7ec0a040319545b50590261278f1517bcb22796..50d4979470dd21738453e0d70c7a69ee0752ac41 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
> @@ -33,6 +33,7 @@ main (void)
>  /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
>  /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bxns" } } */
>
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c 
> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
> index 
> 7b9c3f0fe061317f71d3122dea7a55ab5311f234..2b7507c900ab18705083ba1d86359e1ae36a50a2 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
> @@ -34,5 +34,6 @@ main (void)
>  /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
>  /* { dg-final { scan-assembler "movt\tr1, 63" } } */
>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> index 
> aa0ec8e0b0f0953a5a5cbc2db58413176c2505f3..35cab1f3233daac9fba50d25dac23364c798fb9c 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> @@ -105,8 +105,10 @@ qux (int_nsfunc_t * callback)
>  /* { dg-final { scan-assembler "bic" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { 
> target arm_cmse_clear_ok } } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
> +/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
> arm_cmse_clear_ok } } } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>
>  int call_callback (void)
>  {
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c 
> b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
> index 
> df1ea52bec533c36a738d7d3b2b2ff749b0f3713..1f5af7c2dba7747f6058d12af8ef80b4dd1b1431 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
> @@ -9,5 +9,6 @@ int foo (void)
>    return bar ();
>  }
>
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>  /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
> index 
> 62c63b888ab49e99fba0a08b69941e73c9a8d33b..c52e1c14d9956743625e3b8a200e823f163924e3 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
> @@ -12,5 +12,5 @@
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
> index 
> b718a70522b86e2bc58900681a781129543f8869..fdba955a32fc5ad492b74974185f98470bc49a7e 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
> @@ -10,6 +10,5 @@
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
> index 
> 16536ab4f9ec5782463ab90f404a2e9f6f938850..85068ceaac6a5c0c60af4a54c0af0d20326fc18d 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
> @@ -13,5 +13,5 @@
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
> index 
> 0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5..af69d38acf47d9d1d55480edba2b66f07e2d06ad 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
> @@ -10,6 +10,5 @@
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
> index 
> 914ea39626f2f72eac8c9c1cb495b0855e58f5e1..62201595549f07b046c7c5972d612ab155c4c38c 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
> @@ -13,5 +13,5 @@
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
> index 
> 32435d255805331c7c56a096675b7a2af3286e5e..287f0d6faad113fbc8c30051280668baa58ab130 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
> @@ -7,7 +7,5 @@
>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> index 
> eb655b5504e58dc842853c8cb874c5cef3b82aa6..7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> @@ -8,10 +8,7 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
> index 
> ab266af7092afbce868792446124c291188e8a90..638643d0a6772d43f440df3942c6c723f1eff3ef 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
> @@ -6,10 +6,6 @@
>  #include "../../../cmse-5.x"
>
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
> @@ -26,7 +22,6 @@
>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
> arm_dsp } } } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
> arm_dsp } } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } 
> } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> index 
> fd1a24b3258e8403394dac98ff7c4712b0eb7a1b..9ec14d1a707839e4858bac72bc292fd0984bf86c 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> @@ -8,10 +8,7 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> index 
> d8f9b7758d50f74f777fcda22f3f6714ff28bb96..d375879ed02483c05d7853c95f9b9e15383ff321 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> @@ -8,10 +8,7 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> index 
> 4878c6ef9157abff003780fbf6401db8eb3ef2f3..e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> @@ -8,10 +8,7 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
> index 
> 82aad2d13d6b170c92fd2c2345ab76f41e383013..7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
> @@ -6,10 +6,6 @@
>  #include "../../../cmse-5.x"
>
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
> @@ -19,7 +15,6 @@
>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
> arm_dsp } } } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
> arm_dsp } } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } 
> } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> index 
> 8e054c2aeebac4bd3f164b00ad867bc2d72cb674..d998b43a148250a15eb4aae9fb0ef6e4bf51203b 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> @@ -8,10 +8,7 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> index 
> e74cea7697ba1c12ebeef21636d1b8fd60b42677..e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> @@ -8,10 +8,7 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> index 
> 4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d..d43a9f85a199ecdf7e018852b3af9b4cf36af81f 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> @@ -8,9 +8,9 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
>
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
> index 
> c684d79fae00feb8e15e9f142735f005473b6011..157bccb9ff3256056d496a0d0770374315b04d87 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
> @@ -5,13 +5,8 @@
>  #include "../../../cmse-5.x"
>
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
> -/* { dg-final { scan-assembler "mov\tip, lr" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
> arm_dsp } } } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
> arm_dsp } } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> index 
> 4cb6a54a0a5b02954519e64503d7c2c4c0e4750d..02e48157a2c61b0a8bee77e949944acc2a4bee37 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> @@ -7,10 +7,7 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
>
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> index 
> 4764b2fadfb38661764b909cdb2c9cd109e24df0..c7a22a2ba464dce26b289635dd8dcc8213ae33d8 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> @@ -9,8 +9,7 @@
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
>
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
> index 
> 9b2e7565d24ff52138b0fb90a1e6268aa4c515a0..2522a17a6316d76a21d8d241d4c44cdddf1981e0 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
> @@ -8,9 +8,6 @@
>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
> @@ -27,7 +24,6 @@
>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
> arm_dsp } } } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
> arm_dsp } } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> index 
> 9e93d75c35de5e3dde1074fb99da94edc2648319..d34ca383236fdd31723966e6218ea918cf8c9122 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> @@ -8,10 +8,7 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> index 
> 566889e66c8cea6ca32348f48742d2c325336995..ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> @@ -10,8 +10,7 @@
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> index 
> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..ff9a7dfa5e696e3a6c4132343d0ee94c3068c208 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> @@ -9,8 +9,9 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } 
> } */
> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
> index 
> 5af1fdb934ce5aa5afd8d096122b6e9b55591bd9..eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
> @@ -7,10 +7,6 @@
>
>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
> -/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
> @@ -19,7 +15,6 @@
>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
> arm_dsp } } } } */
> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
> arm_dsp } } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> index 
> 1c38290e79d18a8f94e44b974c54220e553a9a49..03d36aa650986b6069e2fe1c1f3f98fa9664d88a 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> @@ -8,10 +8,7 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> index 
> 39c2e72f968ce9f30d36bd347544ca26b3dfad8a..ce45e10688f855ca7b2a63777d2b3d3418815589 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> @@ -10,8 +10,7 @@
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
> index 
> d51db020c7707fa714364b10dd3ec5896a9dad17..dbd1d34413ef36f2b03716c0d9cf46b024af0835 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
> @@ -10,6 +10,5 @@
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
> index 
> 131afbbf4289b238438c53ab9ea55d13b8567513..3edc7f1e259779a24e722d67ed544c0a673090c7 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
> @@ -14,5 +14,5 @@
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
> index 
> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..3a72406df2492206c2cb8ac7b63e4242ec0ba598 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
> @@ -9,8 +9,9 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } 
> } */
> +/* { dg-final { scan-assembler "mov\tr1, r4" } } */
> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
> index 
> 5f6891a26d9be6edbb81c6c9e71897d1b49c8c60..90fdac18e30424edca60b6f884227adbf716899d 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
> @@ -29,5 +29,6 @@ main (void)
>  /* { dg-final { scan-assembler "movs\tr1, #255" } } */
>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bxns" } } */
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 5/10] Clear VFP registers with VSCCLRM
       [not found] ` <b15c924d-b109-4221-aded-5d859a1c48c6@AM5EUR03FT012.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-12 10:13   ` Kyrill Tkachov
  0 siblings, 0 replies; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-12 10:13 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 5/10] Clear VFP registers with VSCCLRM
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to improve
> code density of functions with the cmse_nonsecure_entry attribute and
> when calling function with the cmse_nonsecure_call attribute by using
> VSCCLRM to do all the VFP register clearing as well as clearing the VFP
> register.
>
> === Patch description ===
>
> This patch adds a new pattern for the VSCCLRM instruction.
> cmse_clear_registers () is then modified to use the new VSCCLRM
> instruction when targeting Armv8.1-M Mainline, thus, making the Armv8-M
> register clearing code specific to Armv8-M.
>
> Since the VSCCLRM instruction mandates VPR in the register list, the
> pattern is encoded with a parallel which only requires an unspecified
> VUNSPEC_CLRM_VPR constant modelling the APSR clearing. Other expression
> in the parallel are expected to be set expression for clearing the VFP
> registers.
>
I see we don't represent the VPR here as a register and use an UNSPEC to 
represent its clearing.

That's okay for now but when we do add support for it for MVE we'll need 
to adjust the RTL representation here to show its clobbering.


> ChangeLog entry is as follows:
>
> *** gcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/arm-protos.h (clear_operation_p): Adapt prototype.
>         * config/arm/arm.c (clear_operation_p): Extend to be able to 
> check a
>         clear_vfp_multiple pattern based on a new vfp parameter.
>         (cmse_clear_registers): Generate VSCCLRM to clear VFP 
> registers when
>         targeting Armv8.1-M Mainline.
>         (cmse_nonsecure_entry_clear_before_return): Clear VFP registers
>         unconditionally when targeting Armv8.1-M Mainline 
> architecture.  Check
>         whether VFP registers are available before looking 
> call_used_regs for a
>         VFP register.
>         * config/arm/predicates.md (clear_multiple_operation): Adapt 
> to change
>         of prototype of clear_operation_p.
>         (clear_vfp_multiple_operation): New predicate.
>         * config/arm/unspecs.md (VUNSPEC_VSCCLRM_VPR): New volatile 
> unspec.
>         * config/arm/vfp.md (clear_vfp_multiple): New define_insn.
>
Ok.

Thanks,

kyrill



> *** gcc/testsuite/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * gcc.target/arm/cmse/bitfield-1.c: Add check for VSCCLRM.
>         * gcc.target/arm/cmse/bitfield-2.c: Likewise.
>         * gcc.target/arm/cmse/bitfield-3.c: Likewise.
>         * gcc.target/arm/cmse/cmse-1.c: Likewise.
>         * gcc.target/arm/cmse/struct-1.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: Likewise.
>
> Testing: Bootstrapped on arm-linux-gnueabihf and testsuite shows no
> regression.
>
> Is this ok for trunk?
>
> Best regards,
>
> Mihail
>
>
> ###############     Attachment also inlined for ease of reply    
> ###############
>
>
> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
> index 
> 1a948d2c97526ad7e67e8d4a610ac74cfdb13882..37a46982bbc1a8f17abe2fc76ba3cb7d65257c0d 
> 100644
> --- a/gcc/config/arm/arm-protos.h
> +++ b/gcc/config/arm/arm-protos.h
> @@ -77,7 +77,7 @@ extern int thumb_legitimate_offset_p (machine_mode, 
> HOST_WIDE_INT);
>  extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
>  extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
>                                   bool, bool);
> -extern bool clear_operation_p (rtx);
> +extern bool clear_operation_p (rtx, bool);
>  extern int arm_const_double_rtx (rtx);
>  extern int vfp3_const_double_rtx (rtx);
>  extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, 
> int *);
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 
> f1f730cecff0fb3da7115ea1147dc8b9ab7076b7..5f3ce5c4605f609d1a0e31c0f697871266bdf835 
> 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -13499,8 +13499,9 @@ ldm_stm_operation_p (rtx op, bool load, 
> machine_mode mode,
>    return true;
>  }
>
> -/* Checks whether OP is a valid parallel pattern for a CLRM insn.  To 
> be a
> -   valid CLRM pattern, OP must have the following form:
> +/* Checks whether OP is a valid parallel pattern for a CLRM (if VFP 
> is false)
> +   or VSCCLRM (otherwise) insn.  To be a valid CLRM pattern, OP must 
> have the
> +   following form:
>
>     [(set (reg:SI <N>) (const_int 0))
>      (set (reg:SI <M>) (const_int 0))
> @@ -13511,22 +13512,35 @@ ldm_stm_operation_p (rtx op, bool load, 
> machine_mode mode,
>
>     Any number (including 0) of set expressions is valid, the volatile 
> unspec is
>     optional.  All registers but SP and PC are allowed and registers 
> must be in
> -   strict increasing order.  */
> +   strict increasing order.
> +
> +   To be a valid VSCCLRM pattern, OP must have the following form:
> +
> +   [(unspec_volatile [(const_int 0)]
> +                    VUNSPEC_VSCCLRM_VPR)
> +    (set (reg:SF <N>) (const_int 0))
> +    (set (reg:SF <M>) (const_int 0))
> +    ...
> +   ]
> +
> +   As with CLRM, any number (including 0) of set expressions is 
> valid, however
> +   the volatile unspec is mandatory here.  Any VFP single-precision 
> register is
> +   accepted but all registers must be consecutive and in increasing 
> order.  */
>
>  bool
> -clear_operation_p (rtx op)
> +clear_operation_p (rtx op, bool vfp)
>  {
> -  HOST_WIDE_INT i;
>    unsigned regno, last_regno;
>    rtx elt, reg, zero;
> -  machine_mode mode;
>    HOST_WIDE_INT count = XVECLEN (op, 0);
> +  HOST_WIDE_INT i, first_set = vfp ? 1 : 0;
> +  machine_mode expected_mode = vfp ? E_SFmode : E_SImode;
>
> -  for (i = 0; i < count; i++)
> +  for (i = first_set; i < count; i++)
>      {
>        elt = XVECEXP (op, 0, i);
>
> -      if (GET_CODE (elt) == UNSPEC_VOLATILE)
> +      if (!vfp && GET_CODE (elt) == UNSPEC_VOLATILE)
>          {
>            if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
>                || XVECLEN (elt, 0) != 1
> @@ -13542,17 +13556,26 @@ clear_operation_p (rtx op)
>
>        reg = SET_DEST (elt);
>        regno = REGNO (reg);
> -      mode = GET_MODE (reg);
>        zero = SET_SRC (elt);
>
>        if (!REG_P (reg)
> -         || GET_MODE (reg) != SImode
> -         || regno == SP_REGNUM
> -         || regno == PC_REGNUM
> -         || (i != 0 && regno <= last_regno)
> +         || GET_MODE (reg) != expected_mode
>            || zero != CONST0_RTX (SImode))
>          return false;
>
> +      if (vfp)
> +       {
> +         if (i != 1 && regno != last_regno + 1)
> +           return false;
> +       }
> +      else
> +       {
> +         if (regno == SP_REGNUM || regno == PC_REGNUM)
> +           return false;
> +         if (i != 0 && regno <= last_regno)
> +           return false;
> +       }
> +
>        last_regno = REGNO (reg);
>      }
>
> @@ -17665,6 +17688,43 @@ cmse_clear_registers (sbitmap 
> to_clear_bitmap, uint32_t *padding_bits_to_clear,
>        auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
>        auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
>
> +      for (i = FIRST_VFP_REGNUM; i <= maxregno; i += nb_regs)
> +       {
> +         /* Find next register to clear and exit if none. */
> +         for (; i <= maxregno && !bitmap_bit_p (to_clear_bitmap, i); 
> i++);
> +         if (i > maxregno)
> +           break;
> +
> +         /* Compute number of consecutive registers to clear.  */
> +         for (j = i; j <= maxregno && bitmap_bit_p (to_clear_bitmap, j);
> +              j++);
> +         nb_regs = j - i;
> +
> +         /* Create VSCCLRM RTX pattern.  */
> +         par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 1));
> +         vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
> +         vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
> + VUNSPEC_VSCCLRM_VPR);
> +         XVECEXP (par, 0, 0) = vunspec;
> +
> +         /* Insert VFP register clearing RTX in the pattern.  */
> +         start_sequence ();
> +         for (k = 1, j = i; j <= maxregno && k < nb_regs + 1; j++)
> +           {
> +             if (!bitmap_bit_p (to_clear_bitmap, j))
> +               continue;
> +
> +             reg = gen_rtx_REG (SFmode, j);
> +             set = gen_rtx_SET (reg, const0_rtx);
> +             XVECEXP (par, 0, k++) = set;
> +             emit_use (reg);
> +           }
> +         use_seq = get_insns ();
> +         end_sequence ();
> +
> +         emit_insn_after (use_seq, emit_insn (par));
> +       }
> +
>        /* Get set of core registers to clear.  */
>        bitmap_clear (core_regs_bitmap);
>        bitmap_set_range (core_regs_bitmap, R0_REGNUM,
> @@ -17703,49 +17763,50 @@ cmse_clear_registers (sbitmap 
> to_clear_bitmap, uint32_t *padding_bits_to_clear,
>        end_sequence ();
>
>        emit_insn_after (use_seq, emit_insn (par));
> -      minregno = FIRST_VFP_REGNUM;
> -    }
> -
> -  /* If not marked for clearing, clearing_reg already does not contain
> -     any secret.  */
> -  if (clearing_regno <= maxregno
> -      && bitmap_bit_p (to_clear_bitmap, clearing_regno))
> -    {
> -      emit_move_insn (clearing_reg, const0_rtx);
> -      emit_use (clearing_reg);
> -      bitmap_clear_bit (to_clear_bitmap, clearing_regno);
>      }
> -
> -  for (regno = minregno; regno <= maxregno; regno++)
> +  else
>      {
> -      if (!bitmap_bit_p (to_clear_bitmap, regno))
> -       continue;
> +      /* If not marked for clearing, clearing_reg already does not 
> contain
> +        any secret.  */
> +      if (clearing_regno <= maxregno
> +         && bitmap_bit_p (to_clear_bitmap, clearing_regno))
> +       {
> +         emit_move_insn (clearing_reg, const0_rtx);
> +         emit_use (clearing_reg);
> +         bitmap_clear_bit (to_clear_bitmap, clearing_regno);
> +       }
>
> -      if (IS_VFP_REGNUM (regno))
> +      for (regno = minregno; regno <= maxregno; regno++)
>          {
> -         /* If regno is an even vfp register and its successor is also to
> -            be cleared, use vmov.  */
> -         if (TARGET_VFP_DOUBLE
> -             && VFP_REGNO_OK_FOR_DOUBLE (regno)
> -             && bitmap_bit_p (to_clear_bitmap, regno + 1))
> +         if (!bitmap_bit_p (to_clear_bitmap, regno))
> +           continue;
> +
> +         if (IS_VFP_REGNUM (regno))
>              {
> -             emit_move_insn (gen_rtx_REG (DFmode, regno),
> -                             CONST1_RTX (DFmode));
> -             emit_use (gen_rtx_REG (DFmode, regno));
> -             regno++;
> +             /* If regno is an even vfp register and its successor is 
> also to
> +                be cleared, use vmov.  */
> +             if (TARGET_VFP_DOUBLE
> +                 && VFP_REGNO_OK_FOR_DOUBLE (regno)
> +                 && bitmap_bit_p (to_clear_bitmap, regno + 1))
> +               {
> +                 emit_move_insn (gen_rtx_REG (DFmode, regno),
> +                                 CONST1_RTX (DFmode));
> +                 emit_use (gen_rtx_REG (DFmode, regno));
> +                 regno++;
> +               }
> +             else
> +               {
> +                 emit_move_insn (gen_rtx_REG (SFmode, regno),
> +                                 CONST1_RTX (SFmode));
> +                 emit_use (gen_rtx_REG (SFmode, regno));
> +               }
>              }
>            else
>              {
> -             emit_move_insn (gen_rtx_REG (SFmode, regno),
> -                             CONST1_RTX (SFmode));
> -             emit_use (gen_rtx_REG (SFmode, regno));
> +             emit_move_insn (gen_rtx_REG (SImode, regno), clearing_reg);
> +             emit_use (gen_rtx_REG (SImode, regno));
>              }
>          }
> -      else
> -       {
> -         emit_move_insn (gen_rtx_REG (SImode, regno), clearing_reg);
> -         emit_use (gen_rtx_REG (SImode, regno));
> -       }
>      }
>  }
>
> @@ -25948,7 +26009,8 @@ thumb1_expand_prologue (void)
>  void
>  cmse_nonsecure_entry_clear_before_return (void)
>  {
> -  int regno, maxregno = TARGET_HARD_FLOAT ? LAST_VFP_REGNUM : IP_REGNUM;
> +  bool clear_vfpregs = TARGET_HARD_FLOAT || TARGET_HAVE_FPCTX_CMSE;
> +  int regno, maxregno = clear_vfpregs ? LAST_VFP_REGNUM : IP_REGNUM;
>    uint32_t padding_bits_to_clear = 0;
>    auto_sbitmap to_clear_bitmap (maxregno + 1);
>    rtx r1_reg, result_rtl, clearing_reg = NULL_RTX;
> @@ -25960,7 +26022,7 @@ cmse_nonsecure_entry_clear_before_return (void)
>
>    /* If we are not dealing with -mfloat-abi=soft we will need to 
> clear VFP
>       registers.  */
> -  if (TARGET_HARD_FLOAT)
> +  if (clear_vfpregs)
>      {
>        int float_bits = D7_VFP_REGNUM - FIRST_VFP_REGNUM + 1;
>
> @@ -25989,7 +26051,9 @@ cmse_nonsecure_entry_clear_before_return (void)
>          continue;
>        if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
>          continue;
> -      if (call_used_or_fixed_reg_p (regno))
> +      if (call_used_or_fixed_reg_p (regno)
> +         && (!IN_RANGE (regno, FIRST_VFP_REGNUM, LAST_VFP_REGNUM)
> +             || TARGET_HARD_FLOAT))
>          bitmap_set_bit (to_clear_bitmap, regno);
>      }
>
> diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
> index 
> e5c583ef3d167194e7a061d7c3e98d3b4bb5269c..69c10c06ff405e19efa172217a08a512c66cb902 
> 100644
> --- a/gcc/config/arm/predicates.md
> +++ b/gcc/config/arm/predicates.md
> @@ -513,7 +513,13 @@
>  (define_special_predicate "clear_multiple_operation"
>    (match_code "parallel")
>  {
> - return clear_operation_p (op);
> + return clear_operation_p (op, /*vfp*/false);
> +})
> +
> +(define_special_predicate "clear_vfp_multiple_operation"
> +  (match_code "parallel")
> +{
> + return clear_operation_p (op, /*vfp*/true);
>  })
>
>  (define_special_predicate "load_multiple_operation"
> diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
> index 
> 498bc0798dbaaa3ee73815ba27864ae92a2fd08e..ad072705525cc3c4035a22b5f99546bcd0e79ec5 
> 100644
> --- a/gcc/config/arm/unspecs.md
> +++ b/gcc/config/arm/unspecs.md
> @@ -175,6 +175,8 @@
>    VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional 
> speculation barrier.
>    VUNSPEC_VSTR_VLDR    ; Represent the vstr/vldr instruction.
>    VUNSPEC_CLRM_APSR    ; Represent the clearing of APSR with clrm 
> instruction.
> +  VUNSPEC_VSCCLRM_VPR  ; Represent the clearing of VPR with vscclrm
> +                       ; instruction.
>  ])
>
>  ;; Enumerators for NEON unspecs.
> diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
> index 
> 027f0524430fd3af9e4d10cd98bd177141407841..2bf928f32626ce2731ebdfedffbbf64d806eff53 
> 100644
> --- a/gcc/config/arm/vfp.md
> +++ b/gcc/config/arm/vfp.md
> @@ -1641,6 +1641,42 @@
>     (set_attr "type" "load_4")]
>  )
>
> +;; The operands are validated through the clear_multiple_operation
> +;; match_parallel predicate rather than through constraints so enable 
> it only
> +;; after reload.
> +(define_insn "*clear_vfp_multiple"
> +  [(match_parallel 0 "clear_vfp_multiple_operation"
> +     [(unspec_volatile [(const_int 0)]
> +                      VUNSPEC_VSCCLRM_VPR)])]
> +  "TARGET_HAVE_FPCTX_CMSE && use_cmse && reload_completed"
> +  {
> +    int num_regs = XVECLEN (operands[0], 0);
> +    char pattern[30];
> +    const char *regname;
> +    rtx reg;
> +
> +    strcpy (pattern, \"vscclrm%?\\t{%|\");
> +    if (num_regs > 1)
> +      {
> +       reg = XEXP (XVECEXP (operands[0], 0, 1), 0);
> +       strcat (pattern, reg_names[REGNO (reg)]);
> +       if (num_regs > 2)
> +         {
> +           strcat (pattern, \"-%|\");
> +           reg = XEXP (XVECEXP (operands[0], 0, num_regs - 1), 0);
> +           strcat (pattern, reg_names[REGNO (reg)]);
> +         }
> +       strcat (pattern, \", \");
> +      }
> +
> +    strcat (pattern, \"VPR}\");
> +    output_asm_insn (pattern, operands);
> +    return \"\";
> +  }
> +  [(set_attr "predicable" "yes")
> +   (set_attr "type" "mov_reg")]
> +)
> +
>  (define_insn_and_split "*cmpsf_split_vfp"
>    [(set (reg:CCFP CC_REGNUM)
>          (compare:CCFP (match_operand:SF 0 "s_register_operand"  "t")
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
> index 
> 7036cb9508c27d56c4b2c01a81c44bf6f1f9c781..cae2f06140766176c9af6e4b2b4a3e722fbad67c 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
> @@ -36,6 +36,7 @@ main (void)
>  /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target 
> arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c 
> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
> index 
> 50d4979470dd21738453e0d70c7a69ee0752ac41..21a53cd85792e439314f5c88080d7f1c6fcdec66 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
> @@ -33,6 +33,7 @@ main (void)
>  /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
>  /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target 
> arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c 
> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
> index 
> 2b7507c900ab18705083ba1d86359e1ae36a50a2..e8f973e3f06881d33d661f81c0eb6671e48a0d01 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
> @@ -34,6 +34,7 @@ main (void)
>  /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
>  /* { dg-final { scan-assembler "movt\tr1, 63" } } */
>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target 
> arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> index 
> 35cab1f3233daac9fba50d25dac23364c798fb9c..29d78ddd6166321bdf0acabf011138b276151e85 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> @@ -105,6 +105,7 @@ qux (int_nsfunc_t * callback)
>  /* { dg-final { scan-assembler "bic" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { 
> target arm_cmse_clear_ok } } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target 
> arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
> arm_cmse_clear_ok } } } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> index 
> 7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97..9719f799229e245264d377c3726190ca768ca1dd 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> @@ -10,21 +10,10 @@
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
> index 
> 638643d0a6772d43f440df3942c6c723f1eff3ef..dc62b742ba5ab9f7480ca93396e5eb354c5e64dd 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
> @@ -6,22 +6,7 @@
>  #include "../../../cmse-5.x"
>
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
> -/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s1-s15, VPR\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } 
> } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> index 
> 9ec14d1a707839e4858bac72bc292fd0984bf86c..a6951d34afeed54c0ac2e937345cbfbbfb2c4b2d 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> @@ -9,22 +9,7 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> index 
> d375879ed02483c05d7853c95f9b9e15383ff321..23db88dc66d584acbba64a10d3f6fd06f066b321 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> @@ -11,20 +11,7 @@
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> index 
> e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0..2898efabb2b37e3c8dacaf029b5a40be8edcc624 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> @@ -9,18 +9,13 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
> index 
> 7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6..55e7a4f7ae0c4420a40a250f246a769eff28e6c7 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
> @@ -6,15 +6,7 @@
>  #include "../../../cmse-5.x"
>
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
> -/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s1-s15, VPR\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } 
> } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> index 
> d998b43a148250a15eb4aae9fb0ef6e4bf51203b..a4520a9166e36b1d3220befb72a1863799b2f424 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> @@ -9,14 +9,7 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> index 
> e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf..c79d3188026d9248abde7967671c05a09b75c49f 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> @@ -10,13 +10,7 @@
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
> index 
> 157bccb9ff3256056d496a0d0770374315b04d87..d3a3a742b8b4ff99c973a8c9edd77297c7f37ae2 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
> @@ -7,6 +7,7 @@
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
> index 
> 2522a17a6316d76a21d8d241d4c44cdddf1981e0..bbe16cee9c2c29e0701f54c3e393ad3c7efb8e87 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
> @@ -8,22 +8,7 @@
>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
> index 
> eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b..c7dda6a3d6088366358ff4bc1e6d83ad9b03ea6e 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
> @@ -7,14 +7,7 @@
>
>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
> -/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>  /* { dg-final { scan-assembler "bxns" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
> index 
> 90fdac18e30424edca60b6f884227adbf716899d..755564369ae7deecfb038e67591e679bb06f62b1 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
> @@ -29,6 +29,7 @@ main (void)
>  /* { dg-final { scan-assembler "movs\tr1, #255" } } */
>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" { target 
> arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bxns" } } */
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 6/10] Clear GPRs inline when calling nscall function
       [not found] ` <67d2e066-3981-4959-b56d-05d59d8afa12@VE1EUR03FT030.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-12 10:19   ` Kyrill Tkachov
  0 siblings, 0 replies; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-12 10:19 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 6/10] Clear GPRs inline when calling nscall function
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to generate
> inline callee-saved register clearing when calling a function with the
> cmse_nonsecure_call attribute with the ultimate goal of having the whole
> call sequence inline.
>
> === Patch description ===
>
> Besides changing the set of registers that needs to be cleared inline,
> this patch also generates the push and pop to save and restore
> callee-saved registers without trusting the callee inline. To make the
> code more future-proof, this (currently) Armv8.1-M specific behavior is
> expressed in terms of clearing of callee-saved registers rather than
> directly based on the targets.
>
> The patch contains 1 subtlety:
>
> Debug information is disabled for push and pop because the
> REG_CFA_RESTORE notes used to describe popping of registers do not stack.
> Instead, they just reset the debug state for the register to the one at
> the beginning of the function, which is incorrect for a register that is
> pushed twice (in prologue and before nonsecure call) and then popped for
> the first time. In particular, this occasionally trips CFI note creation
> code when there are two codepaths to the epilogue, one of which does not
> go through the nonsecure call. Obviously this mean that debugging
> between the push and pop is not reliable.
>
> ChangeLog entries are as follows:
>
> *** gcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/arm.c (arm_emit_multi_reg_pop): Declare early.
>         (cmse_nonsecure_call_clear_caller_saved): Rename into ...
>         (cmse_nonsecure_call_inline_register_clear): This. Save and clear
>         callee-saved GPRs as well as clear ip register before doing a 
> nonsecure
>         call then restore callee-saved GPRs after it when targeting
>         Armv8.1-M Mainline.
>         (arm_reorg): Adapt to function rename.
>
> *** gcc/testsuite/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * gcc.target/arm/cmse/cmse-1.c: Add check for PUSH and POP and 
> update
>         CLRM check.
>         * gcc.target/arm/cmse/cmse-14.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: 
> Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft-sp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft-sp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/union-1.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/union-2.c: Likewise.
>
> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
> regression.
>
> Is this ok for trunk?
>

This is ok.

I think you should get commit access to GCC by now.

Please fill in the form at https://sourceware.org/cgi-bin/pdw/ps_form.cgi

listing me as the approver (using my details from the MAINTAINERS file).

Of course, only commit this once the whole series is approved ;)

Thanks,

Kyrill


> Best regards,
>
> Mihail
>
>
> ###############     Attachment also inlined for ease of reply    
> ###############
>
>
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 
> fca10801c87c5e635d573c0fbdc47a1ae229d0ef..12b4b42a66b0c5589690d9a2d8cf8e42712ca2c0 
> 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -187,6 +187,7 @@ static int arm_memory_move_cost (machine_mode, 
> reg_class_t, bool);
>  static void emit_constant_insn (rtx cond, rtx pattern);
>  static rtx_insn *emit_set_insn (rtx, rtx);
>  static rtx emit_multi_reg_push (unsigned long, unsigned long);
> +static void arm_emit_multi_reg_pop (unsigned long);
>  static int arm_arg_partial_bytes (cumulative_args_t,
>                                    const function_arg_info &);
>  static rtx arm_function_arg (cumulative_args_t, const 
> function_arg_info &);
> @@ -17810,13 +17811,13 @@ cmse_clear_registers (sbitmap 
> to_clear_bitmap, uint32_t *padding_bits_to_clear,
>      }
>  }
>
> -/* Clears caller saved registers not used to pass arguments before a
> -   cmse_nonsecure_call.  Saving, clearing and restoring of callee saved
> -   registers is done in __gnu_cmse_nonsecure_call libcall.
> -   See libgcc/config/arm/cmse_nonsecure_call.S.  */
> +/* Clear core and caller-saved VFP registers not used to pass 
> arguments before
> +   a cmse_nonsecure_call.  Saving, clearing and restoring of VFP 
> callee-saved
> +   registers is done in the __gnu_cmse_nonsecure_call libcall.  See
> +   libgcc/config/arm/cmse_nonsecure_call.S.  */
>
>  static void
> -cmse_nonsecure_call_clear_caller_saved (void)
> +cmse_nonsecure_call_inline_register_clear (void)
>  {
>    basic_block bb;
>
> @@ -17826,8 +17827,15 @@ cmse_nonsecure_call_clear_caller_saved (void)
>
>        FOR_BB_INSNS (bb, insn)
>          {
> -         unsigned address_regnum, regno, maxregno =
> -           TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : NUM_ARG_REGS - 1;
> +         bool clear_callee_saved = TARGET_HAVE_FPCXT_CMSE;
> +         unsigned long callee_saved_mask
> +           = ((1 << (LAST_HI_REGNUM + 1)) - 1)
> +           & ~((1 << (LAST_ARG_REGNUM + 1)) - 1);
> +         unsigned address_regnum, regno;
> +         unsigned max_int_regno
> +           = clear_callee_saved ? IP_REGNUM : LAST_ARG_REGNUM;
> +         unsigned maxregno
> +           = TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : max_int_regno;
>            auto_sbitmap to_clear_bitmap (maxregno + 1);
>            rtx_insn *seq;
>            rtx pat, call, unspec, clearing_reg, ip_reg, shift;
> @@ -17859,9 +17867,11 @@ cmse_nonsecure_call_clear_caller_saved (void)
>                || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
>              continue;
>
> -         /* Determine the caller-saved registers we need to clear.  */
> +         /* Mark registers that needs to be cleared.  Those that holds a
> +            parameter are removed from the set further below.  */
>            bitmap_clear (to_clear_bitmap);
> -         bitmap_set_range (to_clear_bitmap, R0_REGNUM, NUM_ARG_REGS);
> +         bitmap_set_range (to_clear_bitmap, R0_REGNUM,
> +                           max_int_regno - R0_REGNUM + 1);
>
>            /* Only look at the caller-saved floating point registers 
> in case of
>               -mfloat-abi=hard.  For -mfloat-abi=softfp we will be 
> using the
> @@ -17883,7 +17893,7 @@ cmse_nonsecure_call_clear_caller_saved (void)
>            gcc_assert (MEM_P (address));
>            gcc_assert (REG_P (XEXP (address, 0)));
>            address_regnum = REGNO (XEXP (address, 0));
> -         if (address_regnum < R0_REGNUM + NUM_ARG_REGS)
> +         if (address_regnum <= max_int_regno)
>              bitmap_clear_bit (to_clear_bitmap, address_regnum);
>
>            /* Set basic block of call insn so that df rescan is 
> performed on
> @@ -17943,6 +17953,15 @@ cmse_nonsecure_call_clear_caller_saved (void)
>            shift = gen_rtx_ASHIFT (SImode, clearing_reg, const1_rtx);
>            emit_insn (gen_rtx_SET (clearing_reg, shift));
>
> +         if (clear_callee_saved)
> +           {
> +             rtx push_insn =
> +               emit_multi_reg_push (callee_saved_mask, 
> callee_saved_mask);
> +             /* Disable frame debug info in push because it needs to be
> +                disabled for pop (see below).  */
> +             RTX_FRAME_RELATED_P (push_insn) = 0;
> +           }
> +
>            /* Clear caller-saved registers that leak before doing a 
> non-secure
>               call.  */
>            ip_reg = gen_rtx_REG (SImode, IP_REGNUM);
> @@ -17952,6 +17971,36 @@ cmse_nonsecure_call_clear_caller_saved (void)
>            seq = get_insns ();
>            end_sequence ();
>            emit_insn_before (seq, insn);
> +
> +         if (TARGET_HAVE_FPCXT_CMSE)
> +           {
> +             rtx_insn *next, *pop_insn, *after = insn;
> +
> +             start_sequence ();
> +             arm_emit_multi_reg_pop (callee_saved_mask);
> +             pop_insn = get_last_insn ();
> +
> +             /* Disable frame debug info in pop because they reset 
> the state
> +                of popped registers to what it was at the beginning 
> of the
> +                function, before the prologue.  This leads to 
> incorrect state
> +                when doing the pop after the nonsecure call for 
> registers that
> +                are pushed both in prologue and before the nonsecure 
> call.
> +
> +                It also occasionally triggers an assert failure in 
> CFI note
> +                creation code when there are two codepaths to the 
> epilogue,
> +                one of which does not go through the nonsecure call.
> +                Obviously this mean that debugging between the push 
> and pop is
> +                not reliable.  */
> +             RTX_FRAME_RELATED_P (pop_insn) = 0;
> +
> +             end_sequence ();
> +
> +             emit_insn_after (pop_insn, after);
> +
> +             /* Skip pop we have just inserted after nonsecure call, 
> we know
> +                it does not contain a nonsecure call.  */
> +             insn = pop_insn;
> +           }
>          }
>      }
>  }
> @@ -18257,7 +18306,7 @@ arm_reorg (void)
>    Mfix * fix;
>
>    if (use_cmse)
> -    cmse_nonsecure_call_clear_caller_saved ();
> +    cmse_nonsecure_call_inline_register_clear ();
>
>    /* We cannot run the Thumb passes for thunks because there is no 
> CFG.  */
>    if (cfun->is_thunk)
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> index 
> 29d78ddd6166321bdf0acabf011138b276151e85..9f36fa3b1d8b86b4e1827909fca4fee181ba1c61 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> @@ -109,7 +109,9 @@ qux (int_nsfunc_t * callback)
>  /* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
> arm_cmse_clear_ok } } } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
> target arm_cmse_clear_ok } } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" { target arm_cmse_clear_ok } } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" { target arm_cmse_clear_ok } } } */
>
>  int call_callback (void)
>  {
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c 
> b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
> index 
> 1f5af7c2dba7747f6058d12af8ef80b4dd1b1431..6d39afab44329e78a8ff2f693fd94fe6a501af5a 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
> @@ -9,6 +9,8 @@ int foo (void)
>    return bar ();
>  }
>
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
> target arm_cmse_clear_ok } } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" { target arm_cmse_clear_ok } } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" { target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>  /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
> index 
> c52e1c14d9956743625e3b8a200e823f163924e3..d4caf513ed2153370369bddbfcf6d2568d9f2f1e 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
> @@ -12,5 +12,7 @@
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
> index 
> fdba955a32fc5ad492b74974185f98470bc49a7e..2b7655a2c9971fb0aad4e6c8a1fee72e21028fad 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
> @@ -10,5 +10,7 @@
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
> index 
> 85068ceaac6a5c0c60af4a54c0af0d20326fc18d..1a62076df9d6831d06f5ac6bdcb7deed0ecd23f8 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
> @@ -13,5 +13,7 @@
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
> index 
> af69d38acf47d9d1d55480edba2b66f07e2d06ad..1319ac9766bcd330f6d8f0f7754a64a1dcc105b1 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
> @@ -10,5 +10,7 @@
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
> index 
> 62201595549f07b046c7c5972d612ab155c4c38c..9bb60175529d77a3b1868f62a5a4d5355f00b76b 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
> @@ -13,5 +13,7 @@
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
> index 
> 287f0d6faad113fbc8c30051280668baa58ab130..11ca78bfdaf1ebe09f9699c278dc3db4fd20768c 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
> @@ -7,5 +7,7 @@
>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, r5, r6, r7, r8, 
> r9, r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
> index 
> 68f9e2254c97d7b9817f24cb4dc4315dc876fb26..2f14c52715e0ad6e6ab69b01713ee13985a22653 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
> @@ -17,4 +17,7 @@
>  /* { dg-final { scan-assembler "and\tr3, r3, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r5, r6, r7, r8, r9, r10, fp, 
> ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> index 
> 9719f799229e245264d377c3726190ca768ca1dd..67ced090163bc4b40c09b00305d49d21084f7fb8 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> @@ -8,12 +8,14 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> index 
> a6951d34afeed54c0ac2e937345cbfbbfb2c4b2d..a6d9d14b63be8a226242512e36ba313849a3d35a 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> @@ -8,8 +8,10 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> index 
> 23db88dc66d584acbba64a10d3f6fd06f066b321..ff4763529c7d280193d99ef695ce426038b7ceb9 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> @@ -8,10 +8,12 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> index 
> 2898efabb2b37e3c8dacaf029b5a40be8edcc624..952010baee36cc404f1a85252c3bf9da7a6c3ce1 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> @@ -8,7 +8,8 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
> @@ -16,6 +17,7 @@
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> index 
> a4520a9166e36b1d3220befb72a1863799b2f424..ec1284117f8937026b263ba1bd623e9942527877 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> @@ -8,8 +8,10 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> index 
> c79d3188026d9248abde7967671c05a09b75c49f..d70a58a4c84c5d042f4efefbf36316d5401f770c 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> @@ -8,9 +8,11 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> index 
> d43a9f85a199ecdf7e018852b3af9b4cf36af81f..07a6719b4f1a260a3461f7408e278dd6e71f60d3 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> @@ -10,7 +10,9 @@
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
>
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> index 
> 02e48157a2c61b0a8bee77e949944acc2a4bee37..ca2961ac18ccacec6907b1d1d217c6c2e28072e7 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> @@ -7,7 +7,9 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
>
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> index 
> c7a22a2ba464dce26b289635dd8dcc8213ae33d8..7a1abb51fcf9a62a24583e792953845f21bbed49 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> @@ -9,7 +9,9 @@
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
>
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> index 
> d34ca383236fdd31723966e6218ea918cf8c9122..90aadffb7aa14ceeea22232148c11e9543eee0e7 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> @@ -8,7 +8,9 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> index 
> ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250..28f2e86dfaa89902d1c04fc2890c5445b5bb0af5 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> @@ -10,7 +10,9 @@
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> index 
> ff9a7dfa5e696e3a6c4132343d0ee94c3068c208..15d3b682c798dd6635ed6b90d9aa8e705fefa265 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> @@ -11,7 +11,9 @@
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> index 
> 03d36aa650986b6069e2fe1c1f3f98fa9664d88a..3d48859028ab8dd22d9ffed7c95ece59c2ed937e 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> @@ -8,7 +8,9 @@
>  /* Checks for saving and clearing prior to function call. */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> index 
> ce45e10688f855ca7b2a63777d2b3d3418815589..0e2dcae36927d2c7187ca2b60c935504268476bc 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> @@ -10,7 +10,9 @@
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
> index 
> dbd1d34413ef36f2b03716c0d9cf46b024af0835..43e58ebde56ceb229edca2db25b720c42207c100 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
> @@ -10,5 +10,7 @@
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
> index 
> 3edc7f1e259779a24e722d67ed544c0a673090c7..6adf8fae5c3a56a6e50278919a2edbd2fda58f42 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
> @@ -14,5 +14,7 @@
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
> +/* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 7/10] Clear all VFP regs inline in hardfloat nscall functions
       [not found] ` <6f7c01d4-0459-41c8-bd16-928eb034c1be@VE1EUR03FT044.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-12 10:22   ` Kyrill Tkachov
  0 siblings, 0 replies; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-12 10:22 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw


On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 7/10] Clear all VFP regs inline in hardfloat nscall 
> functions
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to generate
> inline instructions to save, clear and restore callee-saved VFP
> registers before doing a call to a function with the cmse_nonsecure_call
> attribute.
>
> === Patch description ===
>
> The patch is fairly straightforward in its approach and consist of the
> following 3 logical changes:
> - abstract the number of floating-point register to clear in
>   max_fp_regno
> - use max_fp_regno to decide how many registers to clear so that the
>   same code works for Armv8-M and Armv8.1-M Mainline
> - emit vpush and vpop instruction respectively before and after a
>   nonsecure call
>
> Note that as in the patch to clear GPRs inline, debug information has to
> be disabled for VPUSH and VPOP due to VPOP adding CFA adjustment note
> for SP when R7 is sometimes used as CFA.
>
> ChangeLog entries are as follows:
>
> *** gcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/arm.c (vfp_emit_fstmd): Declare early.
>         (arm_emit_vfp_multi_reg_pop): Likewise.
>         (cmse_nonsecure_call_inline_register_clear): Abstract number 
> of VFP
>         registers to clear in max_fp_regno.  Emit VPUSH and VPOP to 
> save and
>         restore callee-saved VFP registers.
>
> *** gcc/testsuite/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Add 
> check for
>         VPUSH and VPOP and update expectation for VSCCLRM.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.
>
> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
> regression.
>
> Is this ok for trunk?
>
Ok.

Thanks,

Kyrill


> Best regards,
>
> Mihail
>
>
> ###############     Attachment also inlined for ease of reply    
> ###############
>
>
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 
> c24996897eb21c641914326f7064a26bbb363411..bcc86d50a10f11d9672258442089a0aa5c450b2f 
> 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -188,6 +188,8 @@ static void emit_constant_insn (rtx cond, rtx 
> pattern);
>  static rtx_insn *emit_set_insn (rtx, rtx);
>  static rtx emit_multi_reg_push (unsigned long, unsigned long);
>  static void arm_emit_multi_reg_pop (unsigned long);
> +static int vfp_emit_fstmd (int, int);
> +static void arm_emit_vfp_multi_reg_pop (int, int, rtx);
>  static int arm_arg_partial_bytes (cumulative_args_t,
>                                    const function_arg_info &);
>  static rtx arm_function_arg (cumulative_args_t, const 
> function_arg_info &);
> @@ -17834,8 +17836,10 @@ cmse_nonsecure_call_inline_register_clear (void)
>            unsigned address_regnum, regno;
>            unsigned max_int_regno =
>              clear_callee_saved ? IP_REGNUM : LAST_ARG_REGNUM;
> +         unsigned max_fp_regno =
> +           TARGET_HAVE_FPCTX_CMSE ? LAST_VFP_REGNUM : D7_VFP_REGNUM;
>            unsigned maxregno =
> -           TARGET_HARD_FLOAT_ABI ? D7_VFP_REGNUM : max_int_regno;
> +           TARGET_HARD_FLOAT_ABI ? max_fp_regno : max_int_regno;
>            auto_sbitmap to_clear_bitmap (maxregno + 1);
>            rtx_insn *seq;
>            rtx pat, call, unspec, clearing_reg, ip_reg, shift;
> @@ -17883,7 +17887,7 @@ cmse_nonsecure_call_inline_register_clear (void)
>
>                bitmap_clear (float_bitmap);
>                bitmap_set_range (float_bitmap, FIRST_VFP_REGNUM,
> -                               D7_VFP_REGNUM - FIRST_VFP_REGNUM + 1);
> +                               max_fp_regno - FIRST_VFP_REGNUM + 1);
>                bitmap_ior (to_clear_bitmap, to_clear_bitmap, 
> float_bitmap);
>              }
>
> @@ -17960,6 +17964,16 @@ cmse_nonsecure_call_inline_register_clear (void)
>                /* Disable frame debug info in push because it needs to be
>                   disabled for pop (see below).  */
>                RTX_FRAME_RELATED_P (push_insn) = 0;
> +
> +             /* Save VFP callee-saved registers.  */
> +             if (TARGET_HARD_FLOAT_ABI)
> +               {
> +                 vfp_emit_fstmd (D7_VFP_REGNUM + 1,
> +                                 (max_fp_regno - D7_VFP_REGNUM) / 2);
> +                 /* Disable frame debug info in push because it needs 
> to be
> +                    disabled for vpop (see below).  */
> +                 RTX_FRAME_RELATED_P (get_last_insn ()) = 0;
> +               }
>              }
>
>            /* Clear caller-saved registers that leak before doing a 
> non-secure
> @@ -17974,9 +17988,25 @@ cmse_nonsecure_call_inline_register_clear (void)
>
>            if (TARGET_HAVE_FPCTX_CMSE)
>              {
> -             rtx_insn *next, *pop_insn, *after = insn;
> +             rtx_insn *next, *last, *pop_insn, *after = insn;
>
>                start_sequence ();
> +
> +             /* Restore VFP callee-saved registers.  */
> +             if (TARGET_HARD_FLOAT_ABI)
> +               {
> +                 int nb_callee_saved_vfp_regs =
> +                   (max_fp_regno - D7_VFP_REGNUM) / 2;
> +                 arm_emit_vfp_multi_reg_pop (D7_VFP_REGNUM + 1,
> + nb_callee_saved_vfp_regs,
> + stack_pointer_rtx);
> +                 /* Disable frame debug info in vpop because the SP 
> adjustment
> +                    is made using a CFA adjustment note while CFA used is
> +                    sometimes R7.  This then causes an assert failure 
> in the
> +                    CFI note creation code.  */
> +                 RTX_FRAME_RELATED_P (get_last_insn ()) = 0;
> +               }
> +
>                arm_emit_multi_reg_pop (callee_saved_mask);
>                pop_insn = get_last_insn ();
>
> @@ -17993,13 +18023,15 @@ cmse_nonsecure_call_inline_register_clear (void)
>                   not reliable.  */
>                RTX_FRAME_RELATED_P (pop_insn) = 0;
>
> +             seq = get_insns ();
> +             last = get_last_insn ();
>                end_sequence ();
>
> -             emit_insn_after (pop_insn, after);
> +             emit_insn_after (seq, after);
>
>                /* Skip pop we have just inserted after nonsecure call, 
> we know
>                   it does not contain a nonsecure call.  */
> -             insn = pop_insn;
> +             insn = last;
>              }
>          }
>      }
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> index 
> 67ced090163bc4b40c09b00305d49d21084f7fb8..e759db24fac27be2de664ad4faced7bb5d3be84a 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> @@ -9,12 +9,14 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
> -/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s4-s31, VPR\}" } } */
> +/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> index 
> a6d9d14b63be8a226242512e36ba313849a3d35a..9df7b5de3ad64e719fc97d7a67a4893398e87b32 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> @@ -9,8 +9,10 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> -/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
> +/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> index 
> ff4763529c7d280193d99ef695ce426038b7ceb9..b36ff73cb9b46d4d3a91f854c022787dc000d9c3 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> @@ -9,10 +9,12 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
> -/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
> +/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> index 
> 952010baee36cc404f1a85252c3bf9da7a6c3ce1..72493f032355828bdf48b84dc98d8102becd1b36 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> @@ -9,6 +9,7 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
> @@ -16,7 +17,8 @@
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s1, VPR\}" } } */
> -/* { dg-final { scan-assembler "vscclrm\t\{s4-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s4-s31, VPR\}" } } */
> +/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> index 
> ec1284117f8937026b263ba1bd623e9942527877..112ed78d6f172be31d4a4f06840d32a90cdf3dd4 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> @@ -9,8 +9,10 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> -/* { dg-final { scan-assembler "vscclrm\t\{s0-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
> +/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> index 
> d70a58a4c84c5d042f4efefbf36316d5401f770c..f48e8a0a020cebed8c9fa124d352f047442979d6 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> @@ -9,9 +9,11 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
> -/* { dg-final { scan-assembler "vscclrm\t\{s2-s15, VPR\}" } } */
> +/* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
> +/* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall function
       [not found] ` <ad64c6ab-11ff-4aad-942e-04e0f6d1d705@VE1EUR03FT027.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-12 10:24   ` Kyrill Tkachov
  2019-12-18 13:39     ` Mihail Ionescu
  0 siblings, 1 reply; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-12 10:24 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 10/23/19 3:24 PM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall 
> function
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to generate
> lazy store and load instruction inline when calling a function with the
> cmse_nonsecure_call attribute with the soft or softfp floating-point
> ABI.
>
> === Patch description ===
>
> This patch adds two new patterns for the VLSTM and VLLDM instructions.
> cmse_nonsecure_call_inline_register_clear is then modified to
> generate VLSTM and VLLDM respectively before and after calls to
> functions with the cmse_nonsecure_call attribute in order to have lazy
> saving, clearing and restoring of VFP registers. Since these
> instructions do not do writeback of the base register, the stack is 
> adjusted
> prior the lazy store and after the lazy load with appropriate frame
> debug notes to describe the effect on the CFA register.
>
> As with CLRM, VSCCLRM and VSTR/VLDR, the instruction is modeled as an
> unspecified operation to the memory pointed to by the base register.
>
> ChangeLog entries are as follows:
>
> *** gcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/arm.c (arm_add_cfa_adjust_cfa_note): Declare early.
>         (cmse_nonsecure_call_inline_register_clear): Define new 
> lazy_fpclear
>         variable as true when floating-point ABI is not hard.  Replace
>         check against TARGET_HARD_FLOAT_ABI by checks against 
> lazy_fpclear.
>         Generate VLSTM and VLLDM instruction respectively before and
>         after a function call to cmse_nonsecure_call function.
>         * config/arm/unspecs.md (VUNSPEC_VLSTM): Define unspec.
>         (VUNSPEC_VLLDM): Likewise.
>         * config/arm/vfp.md (lazy_store_multiple_insn): New define_insn.
>         (lazy_load_multiple_insn): Likewise.
>
> *** gcc/testsuite/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Add check 
> for VLSTM and
>         VLLDM.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: Likewise.
>
> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
> regression.
>
> Is this ok for trunk?
>
> Best regards,
>
> Mihail
>
>
> ###############     Attachment also inlined for ease of reply    
> ###############
>
>
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 
> bcc86d50a10f11d9672258442089a0aa5c450b2f..b10f996c023e830ca24ff83fcbab335caf85d4cb 
> 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -186,6 +186,7 @@ static int arm_register_move_cost (machine_mode, 
> reg_class_t, reg_class_t);
>  static int arm_memory_move_cost (machine_mode, reg_class_t, bool);
>  static void emit_constant_insn (rtx cond, rtx pattern);
>  static rtx_insn *emit_set_insn (rtx, rtx);
> +static void arm_add_cfa_adjust_cfa_note (rtx, int, rtx, rtx);
>  static rtx emit_multi_reg_push (unsigned long, unsigned long);
>  static void arm_emit_multi_reg_pop (unsigned long);
>  static int vfp_emit_fstmd (int, int);
> @@ -17830,6 +17831,9 @@ cmse_nonsecure_call_inline_register_clear (void)
>        FOR_BB_INSNS (bb, insn)
>          {
>            bool clear_callee_saved = TARGET_HAVE_FPCTX_CMSE;
> +         /* frame = VFP regs + FPSCR + VPR.  */
> +         unsigned lazy_store_stack_frame_size =
> +           (LAST_VFP_REGNUM - FIRST_VFP_REGNUM + 1 + 2) * UNITS_PER_WORD;
>            unsigned long callee_saved_mask =
>              ((1 << (LAST_HI_REGNUM + 1)) - 1)
>              & ~((1 << (LAST_ARG_REGNUM + 1)) - 1);
> @@ -17847,7 +17851,7 @@ cmse_nonsecure_call_inline_register_clear (void)
>            CUMULATIVE_ARGS args_so_far_v;
>            cumulative_args_t args_so_far;
>            tree arg_type, fntype;
> -         bool first_param = true;
> +         bool first_param = true, lazy_fpclear = !TARGET_HARD_FLOAT_ABI;
>            function_args_iterator args_iter;
>            uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
>
> @@ -17881,7 +17885,7 @@ cmse_nonsecure_call_inline_register_clear (void)
>               -mfloat-abi=hard.  For -mfloat-abi=softfp we will be 
> using the
>               lazy store and loads which clear both caller- and 
> callee-saved
>               registers.  */
> -         if (TARGET_HARD_FLOAT_ABI)
> +         if (!lazy_fpclear)
>              {
>                auto_sbitmap float_bitmap (maxregno + 1);
>
> @@ -17965,8 +17969,23 @@ cmse_nonsecure_call_inline_register_clear (void)
>                   disabled for pop (see below).  */
>                RTX_FRAME_RELATED_P (push_insn) = 0;
>
> +             /* Lazy store multiple.  */
> +             if (lazy_fpclear)
> +               {
> +                 rtx imm;
> +                 rtx_insn *add_insn;
> +
> +                 imm = gen_int_mode (- lazy_store_stack_frame_size, 
> SImode);
> +                 add_insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
> + stack_pointer_rtx, imm));
> +                 arm_add_cfa_adjust_cfa_note (add_insn,
> +                                              - 
> lazy_store_stack_frame_size,
> + stack_pointer_rtx,
> + stack_pointer_rtx);
> +                 emit_insn (gen_lazy_store_multiple_insn 
> (stack_pointer_rtx));
> +               }
>                /* Save VFP callee-saved registers.  */
> -             if (TARGET_HARD_FLOAT_ABI)
> +             else
>                  {
>                    vfp_emit_fstmd (D7_VFP_REGNUM + 1,
>                                    (max_fp_regno - D7_VFP_REGNUM) / 2);
> @@ -17992,8 +18011,21 @@ cmse_nonsecure_call_inline_register_clear (void)
>
>                start_sequence ();
>
> +             /* Lazy load multiple done as part of libcall in 
> Armv8-M.  */
> +             if (lazy_fpclear)
> +               {
> +                 rtx imm = gen_int_mode (lazy_store_stack_frame_size, 
> SImode);
> +                 emit_insn (gen_lazy_load_multiple_insn 
> (stack_pointer_rtx));
> +                 rtx_insn *add_insn =
> +                   emit_insn (gen_addsi3 (stack_pointer_rtx,
> + stack_pointer_rtx, imm));
> +                 arm_add_cfa_adjust_cfa_note (add_insn,
> + lazy_store_stack_frame_size,
> + stack_pointer_rtx,
> + stack_pointer_rtx);
> +               }
>                /* Restore VFP callee-saved registers.  */
> -             if (TARGET_HARD_FLOAT_ABI)
> +             else
>                  {
>                    int nb_callee_saved_vfp_regs =
>                      (max_fp_regno - D7_VFP_REGNUM) / 2;
> diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
> index 
> ad072705525cc3c4035a22b5f99546bcd0e79ec5..9c9a68ae4f0a3d45f4c730f274b85f0b1ff00348 
> 100644
> --- a/gcc/config/arm/unspecs.md
> +++ b/gcc/config/arm/unspecs.md
> @@ -177,6 +177,10 @@
>    VUNSPEC_CLRM_APSR    ; Represent the clearing of APSR with clrm 
> instruction.
>    VUNSPEC_VSCCLRM_VPR  ; Represent the clearing of VPR with vscclrm
>                          ; instruction.
> +  VUNSPEC_VLSTM                ; Represent the lazy store multiple 
> with vlstm
> +                       ; instruction.
> +  VUNSPEC_VLLDM                ; Represent the lazy load multiple 
> with vlldm
> +                       ; instruction.
>  ])
>
>  ;; Enumerators for NEON unspecs.
> diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
> index 
> 2bf928f32626ce2731ebdfedffbbf64d806eff53..d3807acdd4d3691da63dcc5d6b3d5d8aad4bfe0e 
> 100644
> --- a/gcc/config/arm/vfp.md
> +++ b/gcc/config/arm/vfp.md
> @@ -1677,6 +1677,30 @@
>     (set_attr "type" "mov_reg")]
>  )
>
> +(define_insn "lazy_store_multiple_insn"
> +  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
> +       (plus:SI (match_dup 0) (const_int -4)))
> +   (unspec_volatile [(const_int 0)
> +                    (mem:SI (plus:SI (match_dup 0) (const_int -4)))]
> +                   VUNSPEC_VLSTM)]
> +  "use_cmse && reload_completed"
> +  "vlstm%?\\t%0"
> +  [(set_attr "predicable" "yes")
> +   (set_attr "type" "store_4")]
> +)
> +
> +(define_insn "lazy_load_multiple_insn"
> +  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
> +       (plus:SI (match_dup 0) (const_int 4)))
> +   (unspec_volatile:SI [(const_int 0)
> +                       (mem:SI (match_dup 0))]
> +                      VUNSPEC_VLLDM)]
> +  "use_cmse && reload_completed"
> +  "vlldm%?\\t%0"
> +  [(set_attr "predicable" "yes")
> +   (set_attr "type" "load_4")]
> +)
> +

Same question on the representation as for an earlier patch.

Why aren't we using one of the POST_INC addressing modes to represent this?

Patch looks good otherwise.

Thanks,

Kyrill



>  (define_insn_and_split "*cmpsf_split_vfp"
>    [(set (reg:CCFP CC_REGNUM)
>          (compare:CCFP (match_operand:SF 0 "s_register_operand"  "t")
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> index 
> 07a6719b4f1a260a3461f7408e278dd6e71f60d3..52d22427de79c6a76fbe32b8df7f76b4b286249c 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> @@ -11,7 +11,9 @@
>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> index 
> ca2961ac18ccacec6907b1d1d217c6c2e28072e7..40026d5ee1cc62b4acf48be9619ccd69ef4ead7b 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> @@ -8,7 +8,9 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> index 
> 7a1abb51fcf9a62a24583e792953845f21bbed49..6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> @@ -10,7 +10,9 @@
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> index 
> 90aadffb7aa14ceeea22232148c11e9543eee0e7..8d05576add940c277e5a13f7aab99e6807c1553d 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> @@ -9,7 +9,9 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> index 
> 28f2e86dfaa89902d1c04fc2890c5445b5bb0af5..1f0a14742781b7340685338901dbfab9b700b779 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> @@ -11,7 +11,9 @@
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> index 
> 15d3b682c798dd6635ed6b90d9aa8e705fefa265..842794181087ddbd5ce59680035a0cb61ce5682e 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> @@ -12,7 +12,9 @@
>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> index 
> 3d48859028ab8dd22d9ffed7c95ece59c2ed937e..38c9d5457034d2427413bcce7e7be6bad80f7a67 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> @@ -9,7 +9,9 @@
>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> index 
> 0e2dcae36927d2c7187ca2b60c935504268476bc..6a17bd322fcc4e7e00ea289ee7373db9d8c37a87 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> @@ -11,7 +11,9 @@
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>  /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 9/10] Call nscall function with blxns
       [not found] ` <c58f33d1-930f-4d24-9564-26b812bd8b07@VE1EUR03FT028.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-12 10:25   ` Kyrill Tkachov
  2019-12-18 13:52     ` Mihail Ionescu
  0 siblings, 1 reply; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-12 10:25 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw


On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 9/10] Call nscall function with blxns
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to call
> functions with the cmse_nonsecure_call attribute directly using blxns
> with no undue restriction on the register used for that.
>
> === Patch description ===
>
> This change to use BLXNS to call a nonsecure function from secure
> directly (not using a libcall) is made in 2 steps:
> - change nonsecure_call patterns to use blxns instead of calling
>   __gnu_cmse_nonsecure_call
> - loosen requirement for function address to allow any register when
>   doing BLXNS.
>
> The former is a straightforward check over whether instructions added in
> Armv8.1-M Mainline are available while the latter consist in making the
> nonsecure call pattern accept any register by using match_operand and
> changing the nonsecure_call_internal expander to no force r4 when
> targeting Armv8.1-M Mainline.
>
> The tricky bit is actually in the test update, specifically how to check
> that register lists for CLRM have all registers except for the one
> holding parameters (already done) and the one holding the address used
> by BLXNS. This is achieved with 3 scan-assembler directives.
>
> 1) The first one lists all registers that can appear in CLRM but make
>    each of them optional.
>    Property guaranteed: no wrong register is cleared and none appears
>    twice in the register list.
> 2) The second directive check that the CLRM is made of a fixed number
>    of the right registers to be cleared. The number used is the number
>    of registers that could contain a secret minus one (used to hold the
>    address of the function to call.
>    Property guaranteed: register list has the right number of registers
>    Cumulated property guaranteed: only registers with a potential secret
>    are cleared and they are all listed but ont
> 3) The last directive checks that we cannot find a CLRM with a register
>    in it that also appears in BLXNS. This is check via the use of a
>    back-reference on any of the allowed register in CLRM, the
>    back-reference enforcing that whatever register match in CLRM must be
>    the same in the BLXNS.
>    Property guaranteed: register used for BLXNS is different from
>    registers cleared in CLRM.
>
> Some more care needs to happen for the gcc.target/arm/cmse/cmse-1.c
> testcase due to there being two CLRM generated. To ensure the third
> directive match the right CLRM to the BLXNS, a negative lookahead is
> used between the CLRM register list and the BLXNS. The way negative
> lookahead work is by matching the *position* where a given regular
> expression does not match. In this case, since it comes after the CLRM
> register list it is requesting that what comes after the register list
> does not have a CLRM again followed by BLXNS. This guarantees that the
> .*blxns after only matches a blxns without another CLRM before.
>
> ChangeLog entries are as follows:
>
> *** gcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/arm.md (nonsecure_call_internal): Do not force memory
>         address in r4 when targeting Armv8.1-M Mainline.
>         (nonsecure_call_value_internal): Likewise.
>         * config/arm/thumb2.md (nonsecure_call_reg_thumb2): Make 
> memory address
>         a register match_operand again.  Emit BLXNS when targeting
>         Armv8.1-M Mainline.
>         (nonsecure_call_value_reg_thumb2): Likewise.
>
> *** gcc/testsuite/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * gcc.target/arm/cmse/cmse-1.c: Add check for BLXNS when 
> instructions
>         introduced in Armv8.1-M Mainline Security Extensions are 
> available and
>         restrict checks for libcall to __gnu_cmse_nonsecure_call to 
> Armv8-M
>         targets only.  Adapt CLRM check to verify register used for 
> BLXNS is
>         not in the CLRM register list.
>         * gcc.target/arm/cmse/cmse-14.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise and 
> adapt
>         check for LSB clearing bit to be using the same register as 
> BLXNS when
>         targeting Armv8.1-M Mainline.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: 
> Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.
>         * gcc.target/arm/cmse/cmse-15.c: Count BLXNS when targeting 
> Armv8.1-M
>         Mainline and restrict libcall count to Armv8-M.
>
> Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; 
> testsuite shows no
> regression.
>
> Is this ok for trunk?
>
Ok.

Thanks,

Kyrill


> Best regards,
>
> Mihail
>
>
> ###############     Attachment also inlined for ease of reply    
> ###############
>
>
> diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
> index 
> d607f88cb05ffa9cd8a47b8c8e0c53ea3a5ca411..b7af3c060427d972e3cd1c7a8055aec20335c02b 
> 100644
> --- a/gcc/config/arm/arm.md
> +++ b/gcc/config/arm/arm.md
> @@ -7561,12 +7561,15 @@
>    "use_cmse"
>    "
>    {
> -    rtx tmp;
> -    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
> +    if (!TARGET_HAVE_FPCTX_CMSE)
> +      {
> +       rtx tmp =
> +         copy_to_suggested_reg (XEXP (operands[0], 0),
>                                   gen_rtx_REG (SImode, R4_REGNUM),
>                                   SImode);
>
> -    operands[0] = replace_equiv_address (operands[0], tmp);
> +       operands[0] = replace_equiv_address (operands[0], tmp);
> +      }
>    }")
>
>  (define_insn "*call_reg_armv5"
> @@ -7669,12 +7672,15 @@
>    "use_cmse"
>    "
>    {
> -    rtx tmp;
> -    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
> +    if (!TARGET_HAVE_FPCTX_CMSE)
> +      {
> +       rtx tmp =
> +         copy_to_suggested_reg (XEXP (operands[1], 0),
>                                   gen_rtx_REG (SImode, R4_REGNUM),
>                                   SImode);
>
> -    operands[1] = replace_equiv_address (operands[1], tmp);
> +       operands[1] = replace_equiv_address (operands[1], tmp);
> +      }
>    }")
>
>  (define_insn "*call_value_reg_armv5"
> diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
> index 
> 19d25cfe9b97b9428e3a6daebbf8dfb5648f29ef..964b3e2afcd524bb342373b400e35d0a72c4bd7f 
> 100644
> --- a/gcc/config/arm/thumb2.md
> +++ b/gcc/config/arm/thumb2.md
> @@ -560,13 +560,18 @@
>  )
>
>  (define_insn "*nonsecure_call_reg_thumb2"
> -  [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
> +  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" 
> "r"))]
>                      UNSPEC_NONSECURE_MEM)
> -        (match_operand 0 "" ""))
> -   (use (match_operand 1 "" ""))
> +        (match_operand 1 "" ""))
> +   (use (match_operand 2 "" ""))
>     (clobber (reg:SI LR_REGNUM))]
>    "TARGET_THUMB2 && use_cmse"
> -  "bl\\t__gnu_cmse_nonsecure_call"
> +  {
> +    if (TARGET_HAVE_FPCTX_CMSE)
> +      return "blxns\\t%0";
> +    else
> +      return "bl\\t__gnu_cmse_nonsecure_call";
> +  }
>    [(set_attr "length" "4")
>     (set_attr "type" "call")]
>  )
> @@ -585,13 +590,18 @@
>  (define_insn "*nonsecure_call_value_reg_thumb2"
>    [(set (match_operand 0 "" "")
>          (call
> -        (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
> +        (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" 
> "l*r"))]
>                      UNSPEC_NONSECURE_MEM)
> -        (match_operand 1 "" "")))
> -   (use (match_operand 2 "" ""))
> +        (match_operand 2 "" "")))
> +   (use (match_operand 3 "" ""))
>     (clobber (reg:SI LR_REGNUM))]
>    "TARGET_THUMB2 && use_cmse"
> -  "bl\t__gnu_cmse_nonsecure_call"
> +  {
> +    if (TARGET_HAVE_FPCTX_CMSE)
> +      return "blxns\\t%1";
> +    else
> +      return "bl\\t__gnu_cmse_nonsecure_call";
> +  }
>    [(set_attr "length" "4")
>     (set_attr "type" "call")]
>  )
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> index 
> 9f36fa3b1d8b86b4e1827909fca4fee181ba1c61..ddfcfacab5f601a729319a9d2dab03e61ee56bca 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
> @@ -110,7 +110,13 @@ qux (int_nsfunc_t * callback)
>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
> arm_cmse_clear_ok } } } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" { target arm_cmse_clear_ok } } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" { target arm_cmse_clear_ok } } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" { target arm_cmse_clear_ok } } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}(?!.*clrm.*blxns).*blxns\t\\1" 
> { target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" { target arm_cmse_clear_ok } } } */
>
>  int call_callback (void)
> @@ -120,4 +126,5 @@ int call_callback (void)
>    else
>      return default_callback ();
>  }
> -/* { dg-final { scan-assembler-times 
> "bl\\s+__gnu_cmse_nonsecure_call" 1 } } */
> +/* { dg-final { scan-assembler-times 
> "bl\\s+__gnu_cmse_nonsecure_call" 1 { target { ! arm_cmse_clear_ok } } 
> } } */
> +/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } } 
> } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c 
> b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
> index 
> 6d39afab44329e78a8ff2f693fd94fe6a501af5a..5ab97856066e14c0005b56210e62f2b7a59fd911 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
> @@ -10,7 +10,15 @@ int foo (void)
>  }
>
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" { target arm_cmse_clear_ok } } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" { target arm_cmse_clear_ok } } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" { target arm_cmse_clear_ok } } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" { 
> target arm_cmse_clear_ok } } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" { target arm_cmse_clear_ok } } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> -/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
> +/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" { 
> target { ! arm_cmse_clear_ok } } } } */
> +/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" { 
> target { ! arm_cmse_clear_ok } } } } */
> +/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } } 
> } */
> +/* { dg-final { scan-assembler-not 
> "^(.*\\s)?bl?(?!xns)\[^\\s]*\\s+bar" { target arm_cmse_clear_ok } } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c 
> b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
> index 
> 4e9ace1f3f33b8a8653797e29ca62eb3dd7ae918..0e37b50e004d74dc81f5a8bdc0c9ba21ceaca67d 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
> @@ -69,4 +69,9 @@ int secure5 (void)
>  {
>    return (*s_bar2) ();
>  }
> -/* { dg-final { scan-assembler-times 
> "bl\\s+__gnu_cmse_nonsecure_call" 6 } } */
> +
> +/* ARMv8-M expectation.  */
> +/* { dg-final { scan-assembler-times 
> "bl\\s+__gnu_cmse_nonsecure_call" 6 { target { ! arm_cmse_clear_ok } } 
> } } */
> +
> +/* ARMv8.1-M expectation.  */
> +/* { dg-final { scan-assembler-times "blxns" 6 { target 
> arm_cmse_clear_ok } } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
> index 
> d4caf513ed2153370369bddbfcf6d2568d9f2f1e..ff34edb21c36c9f114aa934fa86ea962d932f273 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
> @@ -10,9 +10,16 @@
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>  /* { dg-final { scan-assembler "mov\tip, #3" } } */
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
> ){9}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
> index 
> 2b7655a2c9971fb0aad4e6c8a1fee72e21028fad..4d1407aba4418006463fdca59cbe90e768e78391 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
> @@ -8,9 +8,16 @@
>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>  /* { dg-final { scan-assembler "movw\tip, #2047" } } */
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
> ){10}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
> index 
> 1a62076df9d6831d06f5ac6bdcb7deed0ecd23f8..9b1227adfdc03457266573447c7996245a114110 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
> @@ -11,9 +11,16 @@
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>  /* { dg-final { scan-assembler "mov\tip, #255" } } */
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
> ){9}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
> index 
> 1319ac9766bcd330f6d8f0f7754a64a1dcc105b1..aec958fc9b9d125c54022911ee34affa9dd81797 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
> @@ -8,9 +8,16 @@
>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>  /* { dg-final { scan-assembler "movw\tip, #2047" } } */
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
> ){10}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
> index 
> 9bb60175529d77a3b1868f62a5a4d5355f00b76b..ae039e292d55423b1dc1b19551278418224bbe5e 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
> @@ -11,9 +11,16 @@
>  /* { dg-final { scan-assembler "movw\tip, #65535" } } */
>  /* { dg-final { scan-assembler "movt\tip, 31" } } */
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
> ){9}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
> index 
> 11ca78bfdaf1ebe09f9699c278dc3db4fd20768c..f455f8cf19b1d8f32bd6ca208d33c144da644c29 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
> @@ -5,9 +5,16 @@
>
>  /* { dg-final { scan-assembler "movw\tip, #1799" } } */
>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[1-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[1-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, r5, r6, r7, r8, 
> r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r2, )?(r3, )?(r4, 
> )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[1-9\]|r10|fp|ip), 
> ){11}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[1-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
> index 
> 2f14c52715e0ad6e6ab69b01713ee13985a22653..3e76364c40452a7946e3b97e2321fd6e6d204355 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
> @@ -15,9 +15,16 @@
>  /* { dg-final { scan-assembler "movw\tip, #65535" } } */
>  /* { dg-final { scan-assembler "movt\tip, 31" } } */
>  /* { dg-final { scan-assembler "and\tr3, r3, ip" } } */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[4-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[4-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r5, r6, r7, r8, r9, r10, fp, 
> ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r4, )?(r5, )?(r6, )?(r7, 
> )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[4-9\]|r10|fp|ip), 
> ){8}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> index 
> e759db24fac27be2de664ad4faced7bb5d3be84a..0c49277389271321c7fd7faa6ae6aaee2c299def 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
> @@ -6,11 +6,18 @@
>  #include "../../../cmse-13.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
> @@ -20,4 +27,4 @@
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> index 
> 9df7b5de3ad64e719fc97d7a67a4893398e87b32..3c66b0a8c6f1c7be6c8cf77b2c71916a08c7b357 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
> @@ -6,14 +6,21 @@
>  #include "../../../cmse-7.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
>  /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> index 
> b36ff73cb9b46d4d3a91f854c022787dc000d9c3..7d456c39705b15fa5b55270ac6b4ed57f5c7e465 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
> @@ -6,11 +6,18 @@
>  #include "../../../cmse-8.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
> @@ -18,4 +25,4 @@
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> index 
> 72493f032355828bdf48b84dc98d8102becd1b36..ab95c83a1167aff9fd4c0e24fe5580895cfbf0bb 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
> @@ -6,11 +6,18 @@
>  #include "../../../cmse-13.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
> @@ -22,4 +29,4 @@
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> index 
> 112ed78d6f172be31d4a4f06840d32a90cdf3dd4..cf58d547972e21e0816a1bdf74968d0b50d2bd08 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
> @@ -6,14 +6,21 @@
>  #include "../../../cmse-7.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
>  /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> index 
> f48e8a0a020cebed8c9fa124d352f047442979d6..1854d03d0814c90f8014a28fb1c81c6866f0071d 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
> @@ -6,15 +6,22 @@
>  #include "../../../cmse-8.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
> d13, d14, d15\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>  /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
>  /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> index 
> 52d22427de79c6a76fbe32b8df7f76b4b286249c..1b207c394081e6ec9bf569961a4a059d5b47fe20 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
> @@ -5,18 +5,25 @@
>  #include "../../../cmse-13.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, 
> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), 
> ){9}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> index 
> 40026d5ee1cc62b4acf48be9619ccd69ef4ead7b..3ec639480868944ed29065936c1fab10aa9e0fed 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
> @@ -5,15 +5,22 @@
>  #include "../../../cmse-7.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> index 
> 6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4..5c1d245d4aa966812e52f327c7ceba5dabba2e18 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
> @@ -5,17 +5,24 @@
>  #include "../../../cmse-8.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
> ){10}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler-not "vmov" } } */
>  /* { dg-final { scan-assembler-not "vmsr" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> index 
> 8d05576add940c277e5a13f7aab99e6807c1553d..3228692c2686fcae8e1369f984aaa6c375ad6418 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
> @@ -6,13 +6,20 @@
>  #include "../../../cmse-7.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> index 
> 1f0a14742781b7340685338901dbfab9b700b779..1c60d97dabd99136533a61fef5ae099eae4bbc93 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
> @@ -6,15 +6,22 @@
>  #include "../../../cmse-8.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
> ){10}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> index 
> 842794181087ddbd5ce59680035a0cb61ce5682e..c366f6ae4ccc65d943dbbf045925ca9c6e8921ca 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
> @@ -6,16 +6,23 @@
>  #include "../../../cmse-13.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, 
> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), 
> ){9}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> index 
> 38c9d5457034d2427413bcce7e7be6bad80f7a67..186a4480f4e816bdb2413ecbc690470e1c2480e6 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
> @@ -6,13 +6,20 @@
>  #include "../../../cmse-7.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
> r8, r9, r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
> )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
> ){12}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git 
> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> index 
> 6a17bd322fcc4e7e00ea289ee7373db9d8c37a87..f0f74f06bbd1eed2f71b46bc8947c99ce1de0765 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
> @@ -6,15 +6,22 @@
>  #include "../../../cmse-8.x"
>
>  /* Checks for saving and clearing prior to function call. */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
> ){10}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
>
>  /* Now we check that we use the correct intrinsic to call. */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
> index 
> 43e58ebde56ceb229edca2db25b720c42207c100..4d58eed1ac21e32dfa893397736be45129af53b8 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
> @@ -8,9 +8,16 @@
>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>  /* { dg-final { scan-assembler "movw\tip, #511" } } */
>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
> r10, fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
> ){10}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c 
> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
> index 
> 6adf8fae5c3a56a6e50278919a2edbd2fda58f42..95de458b50172f6e84ffc2625fc35eca8f65108a 
> 100644
> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
> @@ -12,9 +12,16 @@
>  /* { dg-final { scan-assembler "movw\tip, #65535" } } */
>  /* { dg-final { scan-assembler "movt\tip, 31" } } */
>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
> +/* Shift on the same register as blxns.  */
> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
> #1.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
> fp, ip, APSR\}" } } */
> +/* Check the right registers are cleared and none appears twice.  */
> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
> +/* Check that the right number of registers is cleared and thus only one
> +   register is missing.  */
> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
> ){9}APSR\}" } } */
> +/* Check that no cleared register is used for blxns.  */
> +/* { dg-final { scan-assembler-not 
> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
> fp\}" } } */
> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
> +/* { dg-final { scan-assembler "blxns" } } */
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 10/10] Enable -mcmse
       [not found] ` <e5be4cd4-6c85-48ba-809a-ee489e9da01a@AM5EUR03FT012.eop-EUR03.prod.protection.outlook.com>
@ 2019-11-12 10:31   ` Kyrill Tkachov
  0 siblings, 0 replies; 35+ messages in thread
From: Kyrill Tkachov @ 2019-11-12 10:31 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw


On 10/23/19 10:26 AM, Mihail Ionescu wrote:
> [PATCH, GCC/ARM, 10/10] Enable -mcmse
>
> Hi,
>
> === Context ===
>
> This patch is part of a patch series to add support for Armv8.1-M
> Mainline Security Extensions architecture. Its purpose is to enable the
> -mcmse option now that support for Armv8.1-M Security Extension is
> complete.
>
> === Patch description ===
>
> The patch is straightforward: it redefines ARMv8_1m_main as having the
> same features as ARMv8m_main (and thus as having the cmse feature) with
> the extra features represented by armv8_1m_main.  It also removes the
> error for using -mcmse on Armv8.1-M Mainline.
>
> ChangeLog entry is as follows:
>
> *** gcc/ChangeLog ***
>
> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>         * config/arm/arm-cpus.in (ARMv8_1m_main): Redefine as an 
> extension to
>         Armv8-M Mainline.
>         * config/arm/arm.c (arm_options_perform_arch_sanity_checks): 
> Remove
>         error for using -mcmse when targeting Armv8.1-M Mainline.
>
> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
> regression.
>
> Is this ok for trunk?
>
Ok once the rest of the series is in.

Does this need some documentation though?

Thanks,

Kyrill


> Best regards,
>
> Mihail
>
>
> ###############     Attachment also inlined for ease of reply    
> ###############
>
>
> diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
> index 
> 652f2a4be9388fd7a74f0ec4615a292fd1cfcd36..a845dd2f83a38519a1387515a2d4646761fb405f 
> 100644
> --- a/gcc/config/arm/arm-cpus.in
> +++ b/gcc/config/arm/arm-cpus.in
> @@ -259,10 +259,7 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb predres
>  define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
>  define fgroup ARMv8m_main ARMv7m armv8 cmse
>  define fgroup ARMv8r      ARMv8a
> -# Feature cmse is omitted to disable Security Extensions support 
> while secure
> -# code compiled by GCC does not preserve FP context as allowed by 
> Armv8.1-M
> -# Mainline.
> -define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
> +define fgroup ARMv8_1m_main ARMv8m_main armv8_1m_main
>
>  # Useful combinations.
>  define fgroup VFPv2     vfpv2
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 
> cabcce8c8bd11c5ff3516c3102c0305b865b00cb..0f19b4eb4ec4fcca2df10e1b8e0b79d1a1e0a93d 
> 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -3742,9 +3742,6 @@ arm_options_perform_arch_sanity_checks (void)
>    if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
>      sorry ("__fp16 and no ldrh");
>
> -  if (use_cmse && arm_arch8_1m_main)
> -    error ("ARMv8.1-M Mainline Security Extensions is unsupported");
> -
>    if (use_cmse && !arm_arch_cmse)
>      error ("target CPU does not support ARMv8-M Security Extensions");
>
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline
  2019-11-06 15:59     ` Kyrill Tkachov
@ 2019-12-16 18:29       ` Mihail Ionescu
  2019-12-17 10:24         ` Kyrill Tkachov
  0 siblings, 1 reply; 35+ messages in thread
From: Mihail Ionescu @ 2019-12-16 18:29 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 13060 bytes --]

Hi Kyrill

On 11/06/2019 03:59 PM, Kyrill Tkachov wrote:
> Hi Mihail,
> 
> On 11/4/19 4:49 PM, Kyrill Tkachov wrote:
>> Hi Mihail,
>>
>> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>> > [PATCH, GCC/ARM, 2/10] Add command line support
>> >
>> > Hi,
>> >
>> > === Context ===
>> >
>> > This patch is part of a patch series to add support for Armv8.1-M
>> > Mainline Security Extensions architecture. Its purpose is to add
>> > command-line support for that new architecture.
>> >
>> > === Patch description ===
>> >
>> > Besides the expected enabling of the new value for the -march
>> > command-line option (-march=armv8.1-m.main) and its extensions (see
>> > below), this patch disables support of the Security Extensions for this
>> > newly added architecture. This is done both by not including the cmse
>> > bit in the architecture description and by throwing an error message
>> > when user request Armv8.1-M Mainline Security Extensions. Note that
>> > Armv8-M Baseline and Mainline Security Extensions are still enabled.
>> >
>> > Only extensions for already supported instructions are implemented in
>> > this patch. Other extensions (MVE integer and float) will be added in
>> > separate patches. The following configurations are allowed for 
>> Armv8.1-M
>> > Mainline with regards to FPU and implemented in this patch:
>> > + no FPU (+nofp)
>> > + single precision VFPv5 with FP16 (+fp)
>> > + double precision VFPv5 with FP16 (+fp.dp)
>> >
>> > ChangeLog entry are as follow:
>> >
>> > *** gcc/ChangeLog ***
>> >
>> > 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> > 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>> >
>> >         * config/arm/arm-cpus.in (armv8_1m_main): New feature.
>> >         (ARMv4, ARMv4t, ARMv5t, ARMv5te, ARMv5tej, ARMv6, ARMv6j, 
>> ARMv6k,
>> >         ARMv6z, ARMv6kz, ARMv6zk, ARMv6t2, ARMv6m, ARMv7, ARMv7a, 
>> ARMv7ve,
>> >         ARMv7r, ARMv7m, ARMv7em, ARMv8a, ARMv8_1a, ARMv8_2a, ARMv8_3a,
>> >         ARMv8_4a, ARMv8_5a, ARMv8m_base, ARMv8m_main, ARMv8r): 
>> Reindent.
>> >         (ARMv8_1m_main): New feature group.
>> >         (armv8.1-m.main): New architecture.
>> >         * config/arm/arm-tables.opt: Regenerate.
>> >         * config/arm/arm.c (arm_arch8_1m_main): Define and default
>> > initialize.
>> >         (arm_option_reconfigure_globals): Initialize arm_arch8_1m_main.
>> >         (arm_options_perform_arch_sanity_checks): Error out when 
>> targeting
>> >         Armv8.1-M Mainline Security Extensions.
>> >         * config/arm/arm.h (arm_arch8_1m_main): Declare.
>> >
>> > *** gcc/testsuite/ChangeLog ***
>> >
>> > 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> > 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>> >
>> >         * lib/target-supports.exp
>> > (check_effective_target_arm_arch_v8_1m_main_ok): Define.
>> >         (add_options_for_arm_arch_v8_1m_main): Likewise.
>> > (check_effective_target_arm_arch_v8_1m_main_multilib): Likewise.
>> >
>> > Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; 
>> testsuite
>> > shows no regression.
>> >
>> > Is this ok for trunk?
>> >
>> Ok.
>>
> 
> Something that I remembered last night upon reflection...
> 
> New command-line options (or arguments to them) need documentation in 
> invoke.texi.
> 
> Please add some either as part of this patch or as a separate patch if 
> you prefer.
> 
I've added the missing cli options in invoke.texi.

Here's the updated ChangeLog:

2019-12-06  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* config/arm/arm-cpus.in (armv8_1m_main): New feature.
	(ARMv4, ARMv4t, ARMv5t, ARMv5te, ARMv5tej, ARMv6, ARMv6j, ARMv6k,
	ARMv6z, ARMv6kz, ARMv6zk, ARMv6t2, ARMv6m, ARMv7, ARMv7a, ARMv7ve,
	ARMv7r, ARMv7m, ARMv7em, ARMv8a, ARMv8_1a, ARMv8_2a, ARMv8_3a,
	ARMv8_4a, ARMv8_5a, ARMv8m_base, ARMv8m_main, ARMv8r): Reindent.
	(ARMv8_1m_main): New feature group.
	(armv8.1-m.main): New architecture.
	* config/arm/arm-tables.opt: Regenerate.
	* config/arm/arm.c (arm_arch8_1m_main): Define and default initialize.
	(arm_option_reconfigure_globals): Initialize arm_arch8_1m_main.
	(arm_options_perform_arch_sanity_checks): Error out when targeting
	Armv8.1-M Mainline Security Extensions.
	* config/arm/arm.h (arm_arch8_1m_main): Declare.
	* doc/invoke.texi: Document armv8.1-m.main.

*** gcc/testsuite/ChangeLog ***

2019-12-16  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
2019-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>

	* lib/target-supports.exp
	(check_effective_target_arm_arch_v8_1m_main_ok): Define.
	(add_options_for_arm_arch_v8_1m_main): Likewise.
	(check_effective_target_arm_arch_v8_1m_main_multilib): Likewise.


Regards,
Mihail

> Thanks,
> 
> Kyrill
> 
> 
>> Thanks,
>>
>> Kyrill
>>
>>
>> > Best regards,
>> >
>> > Mihail
>> >
>> >
>> > ###############     Attachment also inlined for ease of reply
>> > ###############
>> >
>> >
>> > diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
>> > index
>> > 
>> f8a3b3db67a537163bfe787d78c8f2edc4253ab3..652f2a4be9388fd7a74f0ec4615a292fd1cfcd36 
>>
>> > 100644
>> > --- a/gcc/config/arm/arm-cpus.in
>> > +++ b/gcc/config/arm/arm-cpus.in
>> > @@ -126,6 +126,9 @@ define feature armv8_5
>> >  # M-Profile security extensions.
>> >  define feature cmse
>> >
>> > +# Architecture rel 8.1-M.
>> > +define feature armv8_1m_main
>> > +
>> >  # Floating point and Neon extensions.
>> >  # VFPv1 is not supported in GCC.
>> >
>> > @@ -223,21 +226,21 @@ define fgroup ALL_FPU_INTERNAL vfpv2 vfpv3 vfpv4
>> > fpv5 fp16conv fp_dbl ALL_SIMD_I
>> >  # -mfpu support.
>> >  define fgroup ALL_FP    fp16 ALL_FPU_INTERNAL
>> >
>> > -define fgroup ARMv4       armv4 notm
>> > -define fgroup ARMv4t      ARMv4 thumb
>> > -define fgroup ARMv5t      ARMv4t armv5t
>> > -define fgroup ARMv5te     ARMv5t armv5te
>> > -define fgroup ARMv5tej    ARMv5te
>> > -define fgroup ARMv6       ARMv5te armv6 be8
>> > -define fgroup ARMv6j      ARMv6
>> > -define fgroup ARMv6k      ARMv6 armv6k
>> > -define fgroup ARMv6z      ARMv6
>> > -define fgroup ARMv6kz     ARMv6k quirk_armv6kz
>> > -define fgroup ARMv6zk     ARMv6k
>> > -define fgroup ARMv6t2     ARMv6 thumb2
>> > +define fgroup ARMv4         armv4 notm
>> > +define fgroup ARMv4t        ARMv4 thumb
>> > +define fgroup ARMv5t        ARMv4t armv5t
>> > +define fgroup ARMv5te       ARMv5t armv5te
>> > +define fgroup ARMv5tej      ARMv5te
>> > +define fgroup ARMv6         ARMv5te armv6 be8
>> > +define fgroup ARMv6j        ARMv6
>> > +define fgroup ARMv6k        ARMv6 armv6k
>> > +define fgroup ARMv6z        ARMv6
>> > +define fgroup ARMv6kz       ARMv6k quirk_armv6kz
>> > +define fgroup ARMv6zk       ARMv6k
>> > +define fgroup ARMv6t2       ARMv6 thumb2
>> >  # This is suspect.  ARMv6-m doesn't really pull in any useful features
>> >  # from ARMv5* or ARMv6.
>> > -define fgroup ARMv6m      armv4 thumb armv5t armv5te armv6 be8
>> > +define fgroup ARMv6m        armv4 thumb armv5t armv5te armv6 be8
>> >  # This is suspect, the 'common' ARMv7 subset excludes the thumb2
>> > 'DSP' and
>> >  # integer SIMD instructions that are in ARMv6T2.  */
>> >  define fgroup ARMv7       ARMv6m thumb2 armv7
>> > @@ -256,6 +259,10 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb 
>> predres
>> >  define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
>> >  define fgroup ARMv8m_main ARMv7m armv8 cmse
>> >  define fgroup ARMv8r      ARMv8a
>> > +# Feature cmse is omitted to disable Security Extensions support
>> > while secure
>> > +# code compiled by GCC does not preserve FP context as allowed by
>> > Armv8.1-M
>> > +# Mainline.
>> > +define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
>> >
>> >  # Useful combinations.
>> >  define fgroup VFPv2     vfpv2
>> > @@ -644,6 +651,17 @@ begin arch armv8-r
>> >   option nofp remove ALL_FP
>> >  end arch armv8-r
>> >
>> > +begin arch armv8.1-m.main
>> > + tune for cortex-m7
>> > + tune flags CO_PROC
>> > + base 8M_MAIN
>> > + isa ARMv8_1m_main
>> > +# fp => FPv5-sp-d16; fp.dp => FPv5-d16
>> > + option fp add FPv5 fp16
>> > + option fp.dp add FPv5 FP_DBL fp16
>> > + option nofp remove ALL_FP
>> > +end arch armv8.1-m.main
>> > +
>> >  begin arch iwmmxt
>> >   tune for iwmmxt
>> >   tune flags LDSCHED STRONG XSCALE
>> > diff --git a/gcc/config/arm/arm-tables.opt 
>> b/gcc/config/arm/arm-tables.opt
>> > index
>> > 
>> aeb5b3fbf629e5cfae4d5f6d4d5f1a9c7752a511..d059969904cb39fbe583487e4fbb23d4f9838718 
>>
>> > 100644
>> > --- a/gcc/config/arm/arm-tables.opt
>> > +++ b/gcc/config/arm/arm-tables.opt
>> > @@ -353,10 +353,13 @@ EnumValue
>> >  Enum(arm_arch) String(armv8-r) Value(28)
>> >
>> >  EnumValue
>> > -Enum(arm_arch) String(iwmmxt) Value(29)
>> > +Enum(arm_arch) String(armv8.1-m.main) Value(29)
>> >
>> >  EnumValue
>> > -Enum(arm_arch) String(iwmmxt2) Value(30)
>> > +Enum(arm_arch) String(iwmmxt) Value(30)
>> > +
>> > +EnumValue
>> > +Enum(arm_arch) String(iwmmxt2) Value(31)
>> >
>> >  Enum
>> >  Name(arm_fpu) Type(enum fpu_type)
>> > diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
>> > index
>> > 
>> 8b67c9c3657b312be223ab60c01969958baa9ed3..307f1b59ba4456c901c8cb842d9961a740b6bb8d 
>>
>> > 100644
>> > --- a/gcc/config/arm/arm.h
>> > +++ b/gcc/config/arm/arm.h
>> > @@ -456,6 +456,10 @@ extern int arm_arch8_3;
>> >  /* Nonzero if this chip supports the ARM Architecture 8.4 
>> extensions.  */
>> >  extern int arm_arch8_4;
>> >
>> > +/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
>> > +   extensions.  */
>> > +extern int arm_arch8_1m_main;
>> > +
>> >  /* Nonzero if this chip supports the FP16 instructions extension of 
>> ARM
>> >     Architecture 8.2.  */
>> >  extern int arm_fp16_inst;
>> > diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>> > index
>> > 
>> 9f0975dc0710626ef46abecaa3a205e993821118..9aca9484a9cdc26d6afee25e81f06b4047df2174 
>>
>> > 100644
>> > --- a/gcc/config/arm/arm.c
>> > +++ b/gcc/config/arm/arm.c
>> > @@ -903,6 +903,9 @@ int arm_arch8_3 = 0;
>> >
>> >  /* Nonzero if this chip supports the ARM Architecture 8.4 
>> extensions.  */
>> >  int arm_arch8_4 = 0;
>> > +/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
>> > +   extensions.  */
>> > +int arm_arch8_1m_main = 0;
>> >
>> >  /* Nonzero if this chip supports the FP16 instructions extension of 
>> ARM
>> >     Architecture 8.2.  */
>> > @@ -3642,6 +3645,8 @@ arm_option_reconfigure_globals (void)
>> >    arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_2);
>> >    arm_arch8_3 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_3);
>> >    arm_arch8_4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_4);
>> > +  arm_arch8_1m_main = bitmap_bit_p (arm_active_target.isa,
>> > + isa_bit_armv8_1m_main);
>> >    arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, 
>> isa_bit_thumb);
>> >    arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, 
>> isa_bit_thumb2);
>> >    arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, 
>> isa_bit_xscale);
>> > @@ -3727,6 +3732,9 @@ arm_options_perform_arch_sanity_checks (void)
>> >    if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
>> >      sorry ("__fp16 and no ldrh");
>> >
>> > +  if (use_cmse && arm_arch8_1m_main)
>> > +    error ("ARMv8.1-M Mainline Security Extensions are unsupported");
>> > +
>> >    if (use_cmse && !arm_arch_cmse)
>> >      error ("target CPU does not support ARMv8-M Security Extensions");
>> >
>> > diff --git a/gcc/testsuite/lib/target-supports.exp
>> > b/gcc/testsuite/lib/target-supports.exp
>> > index
>> > 
>> 6a1aaca9691b7fe9ae5e0e5b1874c7af34a3a6e3..5688aa7a6b7e8dad28aa553755b657464071a982 
>>
>> > 100644
>> > --- a/gcc/testsuite/lib/target-supports.exp
>> > +++ b/gcc/testsuite/lib/target-supports.exp
>> > @@ -4242,10 +4242,11 @@ foreach { armfunc armflag armdefs } {
>> >          v8a "-march=armv8-a" __ARM_ARCH_8A__
>> >          v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
>> >          v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
>> > +       v8r "-march=armv8-r" __ARM_ARCH_8R__
>> >          v8m_base "-march=armv8-m.base -mthumb -mfloat-abi=soft"
>> >                  __ARM_ARCH_8M_BASE__
>> >          v8m_main "-march=armv8-m.main -mthumb" __ARM_ARCH_8M_MAIN__
>> > -       v8r "-march=armv8-r" __ARM_ARCH_8R__ } {
>> > +       v8_1m_main "-march=armv8.1-m.main -mthumb"
>> > __ARM_ARCH_8M_MAIN__ } {
>> >      eval [string map [list FUNC $armfunc FLAG $armflag DEFS 
>> $armdefs ] {
>> >          proc check_effective_target_arm_arch_FUNC_ok { } {
>> >              return [check_no_compiler_messages arm_arch_FUNC_ok
>> > assembly {
>> >

[-- Attachment #2: diff2.patch --]
[-- Type: text/x-patch, Size: 7548 bytes --]

diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
index 50379a0a10a96c7fd501b401adbd679737b7a322..b3e4c69c78c8e8390f01b83caf9e4811482ba0c0 100644
--- a/gcc/config/arm/arm-cpus.in
+++ b/gcc/config/arm/arm-cpus.in
@@ -126,6 +126,9 @@ define feature armv8_5
 # M-Profile security extensions.
 define feature cmse
 
+# Architecture rel 8.1-M.
+define feature armv8_1m_main
+
 # Floating point and Neon extensions.
 # VFPv1 is not supported in GCC.
 
@@ -223,21 +226,21 @@ define fgroup ALL_FPU_INTERNAL	vfpv2 vfpv3 vfpv4 fpv5 fp16conv fp_dbl ALL_SIMD_I
 # -mfpu support.
 define fgroup ALL_FP	fp16 ALL_FPU_INTERNAL
 
-define fgroup ARMv4       armv4 notm
-define fgroup ARMv4t      ARMv4 thumb
-define fgroup ARMv5t      ARMv4t armv5t
-define fgroup ARMv5te     ARMv5t armv5te
-define fgroup ARMv5tej    ARMv5te
-define fgroup ARMv6       ARMv5te armv6 be8
-define fgroup ARMv6j      ARMv6
-define fgroup ARMv6k      ARMv6 armv6k
-define fgroup ARMv6z      ARMv6
-define fgroup ARMv6kz     ARMv6k quirk_armv6kz
-define fgroup ARMv6zk     ARMv6k
-define fgroup ARMv6t2     ARMv6 thumb2
+define fgroup ARMv4         armv4 notm
+define fgroup ARMv4t        ARMv4 thumb
+define fgroup ARMv5t        ARMv4t armv5t
+define fgroup ARMv5te       ARMv5t armv5te
+define fgroup ARMv5tej      ARMv5te
+define fgroup ARMv6         ARMv5te armv6 be8
+define fgroup ARMv6j        ARMv6
+define fgroup ARMv6k        ARMv6 armv6k
+define fgroup ARMv6z        ARMv6
+define fgroup ARMv6kz       ARMv6k quirk_armv6kz
+define fgroup ARMv6zk       ARMv6k
+define fgroup ARMv6t2       ARMv6 thumb2
 # This is suspect.  ARMv6-m doesn't really pull in any useful features
 # from ARMv5* or ARMv6.
-define fgroup ARMv6m      armv4 thumb armv5t armv5te armv6 be8
+define fgroup ARMv6m        armv4 thumb armv5t armv5te armv6 be8
 # This is suspect, the 'common' ARMv7 subset excludes the thumb2 'DSP' and
 # integer SIMD instructions that are in ARMv6T2.  */
 define fgroup ARMv7       ARMv6m thumb2 armv7
@@ -256,6 +259,10 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb predres
 define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
 define fgroup ARMv8m_main ARMv7m armv8 cmse
 define fgroup ARMv8r      ARMv8a
+# Feature cmse is omitted to disable Security Extensions support while secure
+# code compiled by GCC does not preserve FP context as allowed by Armv8.1-M
+# Mainline.
+define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
 
 # Useful combinations.
 define fgroup VFPv2	vfpv2
@@ -644,6 +651,17 @@ begin arch armv8-r
  option nofp remove ALL_FP
 end arch armv8-r
 
+begin arch armv8.1-m.main
+ tune for cortex-m7
+ tune flags CO_PROC
+ base 8M_MAIN
+ isa ARMv8_1m_main
+# fp => FPv5-sp-d16; fp.dp => FPv5-d16
+ option fp add FPv5 fp16
+ option fp.dp add FPv5 FP_DBL fp16
+ option nofp remove ALL_FP
+end arch armv8.1-m.main
+
 begin arch iwmmxt
  tune for iwmmxt
  tune flags LDSCHED STRONG XSCALE
diff --git a/gcc/config/arm/arm-tables.opt b/gcc/config/arm/arm-tables.opt
index aeb5b3fbf629e5cfae4d5f6d4d5f1a9c7752a511..d059969904cb39fbe583487e4fbb23d4f9838718 100644
--- a/gcc/config/arm/arm-tables.opt
+++ b/gcc/config/arm/arm-tables.opt
@@ -353,10 +353,13 @@ EnumValue
 Enum(arm_arch) String(armv8-r) Value(28)
 
 EnumValue
-Enum(arm_arch) String(iwmmxt) Value(29)
+Enum(arm_arch) String(armv8.1-m.main) Value(29)
 
 EnumValue
-Enum(arm_arch) String(iwmmxt2) Value(30)
+Enum(arm_arch) String(iwmmxt) Value(30)
+
+EnumValue
+Enum(arm_arch) String(iwmmxt2) Value(31)
 
 Enum
 Name(arm_fpu) Type(enum fpu_type)
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 5fad1e5bcc2bc448489fdc8239c676246bbc8879..2d1b2e1ec07c1b74faca51bd65d0a1b701ab7b58 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -456,6 +456,10 @@ extern int arm_arch8_3;
 /* Nonzero if this chip supports the ARM Architecture 8.4 extensions.  */
 extern int arm_arch8_4;
 
+/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
+   extensions.  */
+extern int arm_arch8_1m_main;
+
 /* Nonzero if this chip supports the FP16 instructions extension of ARM
    Architecture 8.2.  */
 extern int arm_fp16_inst;
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index eddd3ca93ed62915bee3a3f5a396f0be069bd31f..250929f1d65a183ff1416f722b9f308353718f07 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -906,6 +906,9 @@ int arm_arch8_3 = 0;
 
 /* Nonzero if this chip supports the ARM Architecture 8.4 extensions.  */
 int arm_arch8_4 = 0;
+/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
+   extensions.  */
+int arm_arch8_1m_main = 0;
 
 /* Nonzero if this chip supports the FP16 instructions extension of ARM
    Architecture 8.2.  */
@@ -3640,6 +3643,8 @@ arm_option_reconfigure_globals (void)
   arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_2);
   arm_arch8_3 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_3);
   arm_arch8_4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_4);
+  arm_arch8_1m_main = bitmap_bit_p (arm_active_target.isa,
+				    isa_bit_armv8_1m_main);
   arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
   arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb2);
   arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, isa_bit_xscale);
@@ -3725,6 +3730,9 @@ arm_options_perform_arch_sanity_checks (void)
   if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
     sorry ("__fp16 and no ldrh");
 
+  if (use_cmse && arm_arch8_1m_main)
+    error ("Armv8.1-M Mainline Security Extensions are unsupported");
+
   if (use_cmse && !arm_arch_cmse)
     error ("target CPU does not support ARMv8-M Security Extensions");
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index bf3ea3f6c046f652f81dd104ef0a4d03e26fff9a..fb4e7d1a4be341587dea8afc3a3c0b356fe09022 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -17385,6 +17385,7 @@ Permissible names are:
 @samp{armv6-m}, @samp{armv6s-m},
 @samp{armv7-m}, @samp{armv7e-m},
 @samp{armv8-m.base}, @samp{armv8-m.main},
+@samp{armv8.1-m.main},
 @samp{iwmmxt} and @samp{iwmmxt2}.
 
 Additionally, the following architectures, which lack support for the
@@ -17720,6 +17721,18 @@ The single- and double-precision FPv5 floating-point instructions.
 Disable the floating-point extensions.
 @end table
 
+@item  armv8.1-m.main
+@table @samp
+@item +fp
+The single-precision floating-point instructions.
+
+@item +fp.dp
+The single- and double-precision floating-point instructions.
+
+@item +nofp
+Disable the floating-point extension.
+@end table
+
 @item  armv8-m.main
 @table @samp
 @item +dsp
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 6f224fa81416e9f3f402abe3525e86df02313e6a..5451a9f33c1f5d30b7bc4fea3552f27ff6cab791 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -4281,10 +4281,11 @@ foreach { armfunc armflag armdefs } {
 	v8a "-march=armv8-a" __ARM_ARCH_8A__
 	v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
 	v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
+	v8r "-march=armv8-r" __ARM_ARCH_8R__
 	v8m_base "-march=armv8-m.base -mthumb -mfloat-abi=soft"
 		__ARM_ARCH_8M_BASE__
 	v8m_main "-march=armv8-m.main -mthumb" __ARM_ARCH_8M_MAIN__
-	v8r "-march=armv8-r" __ARM_ARCH_8R__ } {
+	v8_1m_main "-march=armv8.1-m.main -mthumb" __ARM_ARCH_8M_MAIN__ } {
     eval [string map [list FUNC $armfunc FLAG $armflag DEFS $armdefs ] {
 	proc check_effective_target_arm_arch_FUNC_ok { } {
 	    return [check_no_compiler_messages arm_arch_FUNC_ok assembly {

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions
  2019-11-06 16:12   ` [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions Kyrill Tkachov
@ 2019-12-16 18:30     ` Mihail Ionescu
  2019-12-17 10:26       ` Kyrill Tkachov
  0 siblings, 1 reply; 35+ messages in thread
From: Mihail Ionescu @ 2019-12-16 18:30 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 14114 bytes --]


Hi Kyrill,

On 11/06/2019 04:12 PM, Kyrill Tkachov wrote:
> Hi Mihail,
> 
> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>> [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions
>>
>> Hi,
>>
>> === Context ===
>>
>> This patch is part of a patch series to add support for Armv8.1-M
>> Mainline Security Extensions architecture. Its purpose is to enable
>> saving/restoring of nonsecure FP context in function with the
>> cmse_nonsecure_entry attribute.
>>
>> === Motivation ===
>>
>> In Armv8-M Baseline and Mainline, the FP context is cleared on return 
>> from
>> nonsecure entry functions. This means the FP context might change when
>> calling a nonsecure entry function. This patch uses the new VLDR and
>> VSTR instructions available in Armv8.1-M Mainline to save/restore the FP
>> context when calling a nonsecure entry functionfrom nonsecure code.
>>
>> === Patch description ===
>>
>> This patch consists mainly of creating 2 new instruction patterns to
>> push and pop special FP registers via vldm and vstr and using them in
>> prologue and epilogue. The patterns are defined as push/pop with an
>> unspecified operation on the memory accessed, with an unspecified
>> constant indicating what special FP register is being saved/restored.
>>
>> Other aspects of the patch include:
>>   * defining the set of special registers that can be saved/restored and
>>     their name
>>   * reserving space in the stack frames for these push/pop
>>   * preventing return via pop
>>   * guarding the clearing of FPSCR to target architecture not having
>>     Armv8.1-M Mainline instructions.
>>
>> ChangeLog entry is as follows:
>>
>> *** gcc/ChangeLog ***
>>
>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm.c (fp_sysreg_names): Declare and define.
>>         (use_return_insn): Also return false for Armv8.1-M Mainline.
>>         (output_return_instruction): Skip FPSCR clearing if Armv8.1-M
>>         Mainline instructions are available.
>>         (arm_compute_frame_layout): Allocate space in frame for FPCXTNS
>>         when targeting Armv8.1-M Mainline Security Extensions.
>>         (arm_expand_prologue): Save FPCXTNS if this is an Armv8.1-M
>>         Mainline entry function.
>>         (cmse_nonsecure_entry_clear_before_return): Clear IP and r4 if
>>         targeting Armv8.1-M Mainline or successor.
>>         (arm_expand_epilogue): Fix indentation of caller-saved register
>>         clearing.  Restore FPCXTNS if this is an Armv8.1-M Mainline
>>         entry function.
>>         * config/arm/arm.h (TARGET_HAVE_FP_CMSE): New macro.
>>         (FP_SYSREGS): Likewise.
>>         (enum vfp_sysregs_encoding): Define enum.
>>         (fp_sysreg_names): Declare.
>>         * config/arm/unspecs.md (VUNSPEC_VSTR_VLDR): New volatile unspec.
>>         * config/arm/vfp.md (push_fpsysreg_insn): New define_insn.
>>         (pop_fpsysreg_insn): Likewise.
>>
>> *** gcc/testsuite/Changelog ***
>>
>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/bitfield-1.c: add checks for VSTR and VLDR.
>>         * gcc.target/arm/cmse/bitfield-2.c: Likewise.
>>         * gcc.target/arm/cmse/bitfield-3.c: Likewise.
>>         * gcc.target/arm/cmse/cmse-1.c: Likewise.
>>         * gcc.target/arm/cmse/struct-1.c: Likewise.
>>         * gcc.target/arm/cmse/cmse.exp: Run existing Armv8-M Mainline 
>> tests
>>         from mainline/8m subdirectory and new Armv8.1-M Mainline tests 
>> from
>>         mainline/8_1m subdirectory.
>>         * gcc.target/arm/cmse/mainline/bitfield-4.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/bitfield-4.c: This.
>>         * gcc.target/arm/cmse/mainline/bitfield-5.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/bitfield-5.c: This.
>>         * gcc.target/arm/cmse/mainline/bitfield-6.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/bitfield-6.c: This.
>>         * gcc.target/arm/cmse/mainline/bitfield-7.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/bitfield-7.c: This.
>>         * gcc.target/arm/cmse/mainline/bitfield-8.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/bitfield-8.c: This.
>>         * gcc.target/arm/cmse/mainline/bitfield-9.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/bitfield-9.c: This.
>>         * gcc.target/arm/cmse/mainline/bitfield-and-union-1.c: Move 
>> and rename
>>         into ...
>>         * gcc.target/arm/cmse/mainline/8m/bitfield-and-union.c: This.
>>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-13.c: This. 
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-5.c: This. 
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-7.c: This. 
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-8.c: This. 
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/hard/cmse-13.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-13.c: This.  Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/hard/cmse-5.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-5.c: This.  Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/hard/cmse-7.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-7.c: This.  Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/hard/cmse-8.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-8.c: This.  Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/soft/cmse-13.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-13.c: This.  Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/soft/cmse-5.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-5.c: This.  Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/soft/cmse-7.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-7.c: This.  Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/soft/cmse-8.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-8.c: This.  Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-5.c: This. 
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-7.c: This. 
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-8.c: This. 
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/softfp/cmse-13.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c: This. 
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-5.c: This.  
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/softfp/cmse-7.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-7.c: This.  
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/softfp/cmse-8.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-8.c: This.  
>> Clean up
>>         dg-skip-if directive for float ABI.
>>         * gcc.target/arm/cmse/mainline/union-1.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/union-1.c: This.
>>         * gcc.target/arm/cmse/mainline/union-2.c: Move into ...
>>         * gcc.target/arm/cmse/mainline/8m/union-2.c: This.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: New 
>> file.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: New file.
>>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: New file.
>>         * lib/target-supports.exp 
>> (check_effective_target_arm_cmse_clear_ok):
>>         New procedure.
>>
>> Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; 
>> testsuite shows no
>> regression.
>>
>> Is this ok for trunk?
>>
> <snip>
> 
> +(define_insn "push_fpsysreg_insn"
> +  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
> +    (plus:SI (match_dup 0) (const_int -4)))
> +   (unspec_volatile [(match_operand:SI 1 "const_int_operand" "n")
> +             (mem:SI (plus:SI (match_dup 0) (const_int -4)))]
> +            VUNSPEC_VSTR_VLDR)]
> +  "TARGET_HAVE_FPCXT_CMSE && use_cmse"
> +  {
> +    static char buf[32];
> +    int fp_sysreg_enum = INTVAL (operands[1]);
> +
> +    gcc_assert (IN_RANGE (fp_sysreg_enum, 0, NB_FP_SYSREGS - 1));
> +
> +    snprintf (buf, sizeof (buf), \"vstr%%?\\t%s, [%%0, #-4]!\",
> +          fp_sysreg_names[fp_sysreg_enum]);
> +    return buf;
> +  }
> +  [(set_attr "predicable" "yes")
> +   (set_attr "type" "store_4")]
> +)
> 
> I'm a bit concerned by the RTL representation here. This is a memory 
> store instruction but the MEM operand is just part of an UNSPEC.
> 
> Wouldn't this be more conveniently represented as a SET of a MEM to an 
> unspec_volatile value where the address of the MEM uses a POST_INC 
> addressing mode?
> 
> 
> +
> +(define_insn "pop_fpsysreg_insn"
> +  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
> +    (plus:SI (match_dup 0) (const_int 4)))
> +   (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "n")
> +            (mem:SI (match_dup 0))]
> +               VUNSPEC_VSTR_VLDR)]
> +  "TARGET_HAVE_FPCXT_CMSE && use_cmse"
> +  {
> +    static char buf[32];
> +    int fp_sysreg_enum = INTVAL (operands[1]);
> +
> +    gcc_assert (IN_RANGE (fp_sysreg_enum, 0, NB_FP_SYSREGS - 1));
> +
> +    snprintf (buf, sizeof (buf), \"vldr%%?\\t%s, [%%0], #4\",
> +          fp_sysreg_names[fp_sysreg_enum]);
> +    return buf;
> +  }
> +  [(set_attr "predicable" "yes")
> +   (set_attr "type" "load_4")]
> +)
> 
> 
> Similarly here, can't we use one of the addressing modes that describe 
> the address update?
> 

I've updated the two unspec patterns to represent the operation more 
accurately.

Regards,
Mihail

> Thanks,
> 
> Kyrill
> 
> 
>> Best regards,
>>
>> Mihail

[-- Attachment #2: diff3.patch --]
[-- Type: text/x-patch, Size: 86524 bytes --]

diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 2d1b2e1ec07c1b74faca51bd65d0a1b701ab7b58..64c292f2862514fb600a4faeaddfeacb2b69180b 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -306,6 +306,10 @@ emission of floating point pcs attributes.  */
 /* Nonzero if this chip provides the CBZ and CBNZ instructions.  */
 #define TARGET_HAVE_CBZ		(arm_arch_thumb2 || arm_arch8)
 
+/* Nonzero if this chip provides Armv8.1-M Mainline Security extensions
+   instructions (most are floating-point related).  */
+#define TARGET_HAVE_FPCXT_CMSE	(arm_arch8_1m_main)
+
 /* Nonzero if integer division instructions supported.  */
 #define TARGET_IDIV	((TARGET_ARM && arm_arch_arm_hwdiv)	\
 			 || (TARGET_THUMB && arm_arch_thumb_hwdiv))
@@ -1161,6 +1165,22 @@ enum reg_class
   { 0xFFFF7FFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000000F }  /* ALL_REGS */	\
 }
 
+#define FP_SYSREGS \
+  DEF_FP_SYSREG (FPSCR) \
+  DEF_FP_SYSREG (FPSCR_nzcvqc) \
+  DEF_FP_SYSREG (VPR) \
+  DEF_FP_SYSREG (P0) \
+  DEF_FP_SYSREG (FPCXTNS) \
+  DEF_FP_SYSREG (FPCXTS)
+
+#define DEF_FP_SYSREG(reg) reg ## _ENUM,
+enum vfp_sysregs_encoding {
+  FP_SYSREGS
+  NB_FP_SYSREGS
+};
+#undef DEF_FP_SYSREG
+extern const char *fp_sysreg_names[NB_FP_SYSREGS];
+
 /* Any of the VFP register classes.  */
 #define IS_VFP_CLASS(X) \
   ((X) == VFP_D0_D7_REGS || (X) == VFP_LO_REGS \
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 250929f1d65a183ff1416f722b9f308353718f07..68c8779245e56be0c8e808a8c98d631eee3f325c 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -1007,6 +1007,12 @@ int arm_regs_in_sequence[] =
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
 };
 
+#define DEF_FP_SYSREG(reg) #reg,
+const char *fp_sysreg_names[NB_FP_SYSREGS] = {
+  FP_SYSREGS
+};
+#undef DEF_FP_SYSREG
+
 #define ARM_LSL_NAME "lsl"
 #define streq(string1, string2) (strcmp (string1, string2) == 0)
 
@@ -4208,8 +4214,9 @@ use_return_insn (int iscond, rtx sibling)
     }
 
   /* ARMv8-M nonsecure entry function need to use bxns to return and thus need
-     several instructions if anything needs to be popped.  */
-  if (saved_int_regs && IS_CMSE_ENTRY (func_type))
+     several instructions if anything needs to be popped.  Armv8.1-M Mainline
+     also needs several instructions to save and restore FP context.  */
+  if (IS_CMSE_ENTRY (func_type) && (saved_int_regs || TARGET_HAVE_FPCXT_CMSE))
     return 0;
 
   /* If there are saved registers but the LR isn't saved, then we need
@@ -20630,7 +20637,9 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 			  "msr%s\tAPSR_nzcvq, %%|lr", conditional);
 
 	      output_asm_insn (instr, & operand);
-	      if (TARGET_HARD_FLOAT)
+	      /* Do not clear FPSCR if targeting Armv8.1-M Mainline, VLDR takes
+		 care of it.  */
+	      if (TARGET_HARD_FLOAT && ! TARGET_HAVE_FPCXT_CMSE)
 		{
 		  /* Clear the cumulative exception-status bits (0-4,7) and the
 		     condition code bits (28-31) of the FPSCR.  We need to
@@ -21922,6 +21931,11 @@ arm_compute_frame_layout (void)
       if (! IS_VOLATILE (func_type)
 	  && TARGET_HARD_FLOAT)
 	saved += arm_get_vfp_saved_size ();
+
+      /* Allocate space for saving/restoring FPCXTNS in Armv8.1-M Mainline
+	 nonecure entry functions with VSTR/VLDR.  */
+      if (TARGET_HAVE_FPCXT_CMSE && IS_CMSE_ENTRY (func_type))
+	saved += 4;
     }
   else /* TARGET_THUMB1 */
     {
@@ -22623,6 +22637,15 @@ arm_expand_prologue (void)
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
+  /* Armv8.1-M Mainline nonsecure entry: save FPCXTNS on stack using VSTR.  */
+  if (TARGET_HAVE_FPCXT_CMSE && IS_CMSE_ENTRY (func_type))
+    {
+      saved_regs += 4;
+      insn = emit_insn (gen_push_fpsysreg_insn (stack_pointer_rtx,
+						GEN_INT (FPCXTNS_ENUM)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+
   if (args_to_push)
     {
       /* Push the argument registers, or reserve space for them.  */
@@ -26186,12 +26209,15 @@ cmse_nonsecure_entry_clear_before_return (void)
 
       bitmap_set_range (to_clear_bitmap, FIRST_VFP_REGNUM, float_bits);
 
-      /* Make sure we don't clear the two scratch registers used to clear the
-	 relevant FPSCR bits in output_return_instruction.  */
-      emit_use (gen_rtx_REG (SImode, IP_REGNUM));
-      bitmap_clear_bit (to_clear_bitmap, IP_REGNUM);
-      emit_use (gen_rtx_REG (SImode, 4));
-      bitmap_clear_bit (to_clear_bitmap, 4);
+      if (!TARGET_HAVE_FPCXT_CMSE)
+	{
+	  /* Make sure we don't clear the two scratch registers used to clear
+	     the relevant FPSCR bits in output_return_instruction.  */
+	  emit_use (gen_rtx_REG (SImode, IP_REGNUM));
+	  bitmap_clear_bit (to_clear_bitmap, IP_REGNUM);
+	  emit_use (gen_rtx_REG (SImode, 4));
+	  bitmap_clear_bit (to_clear_bitmap, 4);
+	}
     }
 
   /* If the user has defined registers to be caller saved, these are no longer
@@ -26801,12 +26827,23 @@ arm_expand_epilogue (bool really_return)
 				   stack_pointer_rtx, stack_pointer_rtx);
     }
 
-    /* Clear all caller-saved regs that are not used to return.  */
-    if (IS_CMSE_ENTRY (arm_current_func_type ()))
-      {
-	/* CMSE_ENTRY always returns.  */
-	gcc_assert (really_return);
-	cmse_nonsecure_entry_clear_before_return ();
+  if (IS_CMSE_ENTRY (func_type))
+    {
+      /* CMSE_ENTRY always returns.  */
+      gcc_assert (really_return);
+      /* Clear all caller-saved regs that are not used to return.  */
+      cmse_nonsecure_entry_clear_before_return ();
+
+      /* Armv8.1-M Mainline nonsecure entry: restore FPCXTNS from stack using
+	 VLDR.  */
+      if (TARGET_HAVE_FPCXT_CMSE)
+	{
+	  rtx_insn *insn;
+
+	  insn = emit_insn (gen_pop_fpsysreg_insn (stack_pointer_rtx,
+						   GEN_INT (FPCXTNS_ENUM)));
+	  RTX_FRAME_RELATED_P (insn) = 1;
+	}
       }
 
   if (!really_return)
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 78f88d5fa09f424a9ab638053cc4fe068aa19368..59d354e9a918187ab2f747d5e5f8f7edd9ad7082 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -211,6 +211,7 @@
   VUNSPEC_MRRC		; Represent the coprocessor mrrc instruction.
   VUNSPEC_MRRC2		; Represent the coprocessor mrrc2 instruction.
   VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional speculation barrier.
+  VUNSPEC_VSTR_VLDR	; Represent the vstr/vldr instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index 1979aa6fdb423450a22ecf31f019b8c7ba15c903..6f8cf6fc65100ead57e75a639e4e0506b2493d17 100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -1599,6 +1599,44 @@
    (set_attr "type" "f_flag")]
 )
 
+(define_insn "push_fpsysreg_insn"
+  [(set (mem:SI (post_dec:SI (match_operand:SI 0 "s_register_operand" "+&rk")))
+   (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "n")]
+		       VUNSPEC_VSTR_VLDR))]
+  "TARGET_HAVE_FPCXT_CMSE && use_cmse"
+  {
+    static char buf[32];
+    int fp_sysreg_enum = INTVAL (operands[1]);
+
+    gcc_assert (IN_RANGE (fp_sysreg_enum, 0, NB_FP_SYSREGS - 1));
+
+    snprintf (buf, sizeof (buf), \"vstr%%?\\t%s, [%%0, #-4]!\",
+	      fp_sysreg_names[fp_sysreg_enum]);
+    return buf;
+  }
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "store_4")]
+)
+
+(define_insn "pop_fpsysreg_insn"
+  [(set (mem:SI (post_inc:SI (match_operand:SI 0 "s_register_operand" "+&rk")))
+   (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "n")]
+		       VUNSPEC_VSTR_VLDR))]
+  "TARGET_HAVE_FPCXT_CMSE && use_cmse"
+  {
+    static char buf[32];
+    int fp_sysreg_enum = INTVAL (operands[1]);
+
+    gcc_assert (IN_RANGE (fp_sysreg_enum, 0, NB_FP_SYSREGS - 1));
+
+    snprintf (buf, sizeof (buf), \"vldr%%?\\t%s, [%%0], #4\",
+	      fp_sysreg_names[fp_sysreg_enum]);
+    return buf;
+  }
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "load_4")]
+)
+
 (define_insn_and_split "*cmpsf_split_vfp"
   [(set (reg:CCFP CC_REGNUM)
 	(compare:CCFP (match_operand:SF 0 "s_register_operand"  "t")
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
index 0fc191ea1bf3fd9edeb46168123b53f8d51510b4..6d611e130b6f3b544807b767927d99b89071343b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -32,8 +32,10 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
index f8327c8d7b21b32bd58993de03c25d60d6aabfac..b7ec0a040319545b50590261278f1517bcb22796 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -29,8 +29,10 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
 /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
index d0550db378af7d4233bf86159fc74125864cc18b..7b9c3f0fe061317f71d3122dea7a55ab5311f234 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -30,8 +30,9 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
 /* { dg-final { scan-assembler "movt\tr1, 63" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index f764153cb17b796ccd0d20abb78d5cf56be52911..aa0ec8e0b0f0953a5a5cbc2db58413176c2505f3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -104,6 +104,8 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "__acle_se_qux:" } } */
 /* { dg-final { scan-assembler "bic" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
 
 int call_callback (void)
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 91bba807ee748a4c04aeb2ccafbac22fb6159a39..823242393aa21330654afa7d9a485927dc6c1cc9 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -51,20 +51,37 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
-    set MAINLINE_FLAGS [add_options_for_arm_arch_v8m_main ""]
-    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
-	    "$MAINLINE_FLAGS" $DEFAULT_CFLAGS
+    set MAINLINE_8M_FLAGS [add_options_for_arm_arch_v8m_main ""]
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8m/*.c]] \
+	    "$MAINLINE_8M_FLAGS" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
-    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
-	    "$MAINLINE_FLAGS -mfloat-abi=soft" $DEFAULT_CFLAGS
-    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp/*.c]] \
-	    "$MAINLINE_FLAGS" $DEFAULT_CFLAGS
-    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp-sp/*.c]] \
-	    "$MAINLINE_FLAGS" $DEFAULT_CFLAGS
-    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard/*.c]] \
-	    "$MAINLINE_FLAGS" $DEFAULT_CFLAGS
-    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard-sp/*.c]] \
-	    "$MAINLINE_FLAGS" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8m/soft/*.c]] \
+	    "$MAINLINE_8M_FLAGS -mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8m/softfp/*.c]] \
+	    "$MAINLINE_8M_FLAGS" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8m/softfp-sp/*.c]] \
+	    "$MAINLINE_8M_FLAGS" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8m/hard/*.c]] \
+	    "$MAINLINE_8M_FLAGS" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8m/hard-sp/*.c]] \
+	    "$MAINLINE_8M_FLAGS" $DEFAULT_CFLAGS
+}
+
+if {[check_effective_target_arm_arch_v8_1m_main_ok]} then {
+    set MAINLINE_8_1M_FLAGS [add_options_for_arm_arch_v8_1m_main ""]
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8_1m/*.c]] \
+	    "$MAINLINE_8_1M_FLAGS" $DEFAULT_CFLAGS
+    # Mainline -mfloat-abi=soft
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8_1m/soft/*.c]] \
+	    "$MAINLINE_8_1M_FLAGS -mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8_1m/softfp/*.c]] \
+	    "$MAINLINE_8_1M_FLAGS" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8_1m/softfp-sp/*.c]] \
+	    "$MAINLINE_8_1M_FLAGS" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8_1m/hard/*.c]] \
+	    "$MAINLINE_8_1M_FLAGS" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/8_1m/hard-sp/*.c]] \
+	    "$MAINLINE_8_1M_FLAGS" $DEFAULT_CFLAGS
 }
 
 set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..ab266af7092afbce868792446124c291188e8a90
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+
+#include "../../../cmse-5.x"
+
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
+/* { dg-final { scan-assembler "mov\tr0, lr" } } */
+/* { dg-final { scan-assembler "mov\tr1, lr" } } */
+/* { dg-final { scan-assembler "mov\tr2, lr" } } */
+/* { dg-final { scan-assembler "mov\tr3, lr" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..82aad2d13d6b170c92fd2c2345ab76f41e383013
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+
+#include "../../../cmse-5.x"
+
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
+/* { dg-final { scan-assembler "mov\tr0, lr" } } */
+/* { dg-final { scan-assembler "mov\tr1, lr" } } */
+/* { dg-final { scan-assembler "mov\tr2, lr" } } */
+/* { dg-final { scan-assembler "mov\tr3, lr" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..c684d79fae00feb8e15e9f142735f005473b6011
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=soft" } } */
+
+#include "../../../cmse-5.x"
+
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
+/* { dg-final { scan-assembler "mov\tr1, lr" } } */
+/* { dg-final { scan-assembler "mov\tr2, lr" } } */
+/* { dg-final { scan-assembler "mov\tr3, lr" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler-not "vmov" } } */
+/* { dg-final { scan-assembler-not "vmsr" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b2e7565d24ff52138b0fb90a1e6268aa4c515a0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+
+#include "../../../cmse-5.x"
+
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
+/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
+/* { dg-final { scan-assembler "mov\tr1, lr" } } */
+/* { dg-final { scan-assembler "mov\tr2, lr" } } */
+/* { dg-final { scan-assembler "mov\tr3, lr" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..5af1fdb934ce5aa5afd8d096122b6e9b55591bd9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+
+#include "../../../cmse-5.x"
+
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
+/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
+/* { dg-final { scan-assembler "mov\tr1, lr" } } */
+/* { dg-final { scan-assembler "mov\tr2, lr" } } */
+/* { dg-final { scan-assembler "mov\tr3, lr" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..62c63b888ab49e99fba0a08b69941e73c9a8d33b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-4.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+#include "../../bitfield-4.x"
+
+/* { dg-final { scan-assembler "movw\tip, #65535" } } */
+/* { dg-final { scan-assembler "movt\tip, 255" } } */
+/* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
+/* { dg-final { scan-assembler "mov\tip, #255" } } */
+/* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
+/* { dg-final { scan-assembler "mov\tip, #3" } } */
+/* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..b718a70522b86e2bc58900681a781129543f8869
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-5.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+#include "../../bitfield-5.x"
+
+/* { dg-final { scan-assembler "movw\tip, #8191" } } */
+/* { dg-final { scan-assembler "movt\tip, 255" } } */
+/* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
+/* { dg-final { scan-assembler "movw\tip, #2047" } } */
+/* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..16536ab4f9ec5782463ab90f404a2e9f6f938850
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-6.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+#include "../../bitfield-6.x"
+
+/* { dg-final { scan-assembler "movw\tip, #65535" } } */
+/* { dg-final { scan-assembler "movt\tip, 1023" } } */
+/* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
+/* { dg-final { scan-assembler "mov\tip, #3" } } */
+/* { dg-final { scan-assembler "movt\tip, 32767" } } */
+/* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
+/* { dg-final { scan-assembler "mov\tip, #255" } } */
+/* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-7.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+#include "../../bitfield-7.x"
+
+/* { dg-final { scan-assembler "movw\tip, #8191" } } */
+/* { dg-final { scan-assembler "movt\tip, 255" } } */
+/* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
+/* { dg-final { scan-assembler "movw\tip, #2047" } } */
+/* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..914ea39626f2f72eac8c9c1cb495b0855e58f5e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-8.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+#include "../../bitfield-8.x"
+
+/* { dg-final { scan-assembler "mov\tip, #255" } } */
+/* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
+/* { dg-final { scan-assembler "mov\tip, #1" } } */
+/* { dg-final { scan-assembler "movt\tip, 65535" } } */
+/* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
+/* { dg-final { scan-assembler "movw\tip, #65535" } } */
+/* { dg-final { scan-assembler "movt\tip, 31" } } */
+/* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..32435d255805331c7c56a096675b7a2af3286e5e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-9.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+#include "../../bitfield-9.x"
+
+/* { dg-final { scan-assembler "movw\tip, #1799" } } */
+/* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-and-union.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-and-union.c
new file mode 100644
index 0000000000000000000000000000000000000000..68f9e2254c97d7b9817f24cb4dc4315dc876fb26
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/bitfield-and-union.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+#include "../../bitfield-and-union.x"
+
+/* { dg-final { scan-assembler "movw\tip, #7939" } } */
+/* { dg-final { scan-assembler "movt\tip, 15" } } */
+/* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
+/* { dg-final { scan-assembler "movw\tip, #65535" } } */
+/* { dg-final { scan-assembler "movt\tip, 2047" } } */
+/* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
+/* { dg-final { scan-assembler "mov\tip, #1" } } */
+/* { dg-final { scan-assembler "movt\tip, 65535" } } */
+/* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
+/* { dg-final { scan-assembler "movw\tip, #65535" } } */
+/* { dg-final { scan-assembler "movt\tip, 31" } } */
+/* { dg-final { scan-assembler "and\tr3, r3, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..eb655b5504e58dc842853c8cb874c5cef3b82aa6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-13.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+
+#include "../../../cmse-13.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fd1a24b3258e8403394dac98ff7c4712b0eb7a1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-7.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+
+#include "../../../cmse-7.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..d8f9b7758d50f74f777fcda22f3f6714ff28bb96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+
+#include "../../../cmse-8.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts7, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts8, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts9, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts10, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts11, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts12, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4878c6ef9157abff003780fbf6401db8eb3ef2f3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-13.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+
+#include "../../../cmse-13.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
+/* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
+/* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
+/* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..8e054c2aeebac4bd3f164b00ad867bc2d72cb674
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-7.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+
+#include "../../../cmse-7.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..e74cea7697ba1c12ebeef21636d1b8fd60b42677
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+
+#include "../../../cmse-8.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td3, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td4, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
+/* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-13.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=soft" } } */
+
+#include "../../../cmse-13.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler-not "vmov" } } */
+/* { dg-final { scan-assembler-not "vmsr" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..4cb6a54a0a5b02954519e64503d7c2c4c0e4750d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-7.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=soft" } } */
+
+#include "../../../cmse-7.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler-not "vmov" } } */
+/* { dg-final { scan-assembler-not "vmsr" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..4764b2fadfb38661764b909cdb2c9cd109e24df0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-8.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=soft" } } */
+
+#include "../../../cmse-8.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler-not "vmov" } } */
+/* { dg-final { scan-assembler-not "vmsr" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..9e93d75c35de5e3dde1074fb99da94edc2648319
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-7.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+
+#include "../../../cmse-7.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..566889e66c8cea6ca32348f48742d2c325336995
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-8.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+
+#include "../../../cmse-8.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..0ee28de4123c5e09df7c5d1046e0bd555af6f0fa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+
+#include "../../../cmse-13.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..1c38290e79d18a8f94e44b974c54220e553a9a49
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-7.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+
+#include "../../../cmse-7.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..39c2e72f968ce9f30d36bd347544ca26b3dfad8a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-8.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+
+#include "../../../cmse-8.x"
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+
+/* Now we check that we use the correct intrinsic to call.  */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51db020c7707fa714364b10dd3ec5896a9dad17
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/union-1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+#include "../../union-1.x"
+
+/* { dg-final { scan-assembler "movw\tip, #8063" } } */
+/* { dg-final { scan-assembler "movt\tip, 63" } } */
+/* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
+/* { dg-final { scan-assembler "movw\tip, #511" } } */
+/* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..131afbbf4289b238438c53ab9ea55d13b8567513
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/union-2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+#include "../../union-2.x"
+
+/* { dg-final { scan-assembler "movw\tip, #8191" } } */
+/* { dg-final { scan-assembler "movt\tip, 63" } } */
+/* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
+/* { dg-final { scan-assembler "movw\tip, #511" } } */
+/* { dg-final { scan-assembler "movt\tip, 65535" } } */
+/* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
+/* { dg-final { scan-assembler "movw\tip, #65535" } } */
+/* { dg-final { scan-assembler "movt\tip, 31" } } */
+/* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
similarity index 95%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
index 55da2a0c62237f3072ea155fde1e4a38f849dd6f..62c63b888ab49e99fba0a08b69941e73c9a8d33b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse" } */
 
-#include "../bitfield-4.x"
+#include "../../bitfield-4.x"
 
 /* { dg-final { scan-assembler "movw\tip, #65535" } } */
 /* { dg-final { scan-assembler "movt\tip, 255" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
similarity index 95%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
index 383363233e632189058559f4f569cd2f23fd3638..b718a70522b86e2bc58900681a781129543f8869 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse" } */
 
-#include "../bitfield-5.x"
+#include "../../bitfield-5.x"
 
 /* { dg-final { scan-assembler "movw\tip, #8191" } } */
 /* { dg-final { scan-assembler "movt\tip, 255" } } */
@@ -13,4 +13,3 @@
 /* { dg-final { scan-assembler "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
similarity index 96%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
index 03c294ea323a7da7fa365b806db8b15e57ed7695..16536ab4f9ec5782463ab90f404a2e9f6f938850 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse" } */
 
-#include "../bitfield-6.x"
+#include "../../bitfield-6.x"
 
 /* { dg-final { scan-assembler "movw\tip, #65535" } } */
 /* { dg-final { scan-assembler "movt\tip, 1023" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
similarity index 95%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
index 7692a69b1598857eba0c7c72c16596eb34e672da..0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse" } */
 
-#include "../bitfield-7.x"
+#include "../../bitfield-7.x"
 
 /* { dg-final { scan-assembler "movw\tip, #8191" } } */
 /* { dg-final { scan-assembler "movt\tip, 255" } } */
@@ -13,4 +13,3 @@
 /* { dg-final { scan-assembler "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
similarity index 96%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
index a0a488775fe39ec282f9162714ba78d0217a08e1..914ea39626f2f72eac8c9c1cb495b0855e58f5e1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse" } */
 
-#include "../bitfield-8.x"
+#include "../../bitfield-8.x"
 
 /* { dg-final { scan-assembler "mov\tip, #255" } } */
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
similarity index 94%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
index 8bfeeb0bbf61591783b60ec3858bed44efbaca89..32435d255805331c7c56a096675b7a2af3286e5e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse" } */
 
-#include "../bitfield-9.x"
+#include "../../bitfield-9.x"
 
 /* { dg-final { scan-assembler "movw\tip, #1799" } } */
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
similarity index 95%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
index aac5ae1a052deb90d9f9b40e2054e8831bea4a7e..68f9e2254c97d7b9817f24cb4dc4315dc876fb26 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse" } */
 
-#include "../bitfield-and-union.x"
+#include "../../bitfield-and-union.x"
 
 /* { dg-final { scan-assembler "movw\tip, #7939" } } */
 /* { dg-final { scan-assembler "movt\tip, 15" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
similarity index 91%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index 70a0258c482e5a81513207f0edd4fe314821775b..eb655b5504e58dc842853c8cb874c5cef3b82aa6 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
 /* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
 
-#include "../../cmse-13.x"
+#include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
@@ -31,4 +31,3 @@
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-5.c
similarity index 93%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-5.c
index e946276bab71ffb5bad580c42e114b839086f2d3..3b73c0ee2fbb178910e87662eb22d8a7950d76e4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-5.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
 /* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
 
-#include "../../cmse-5.x"
+#include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "mov\tr0, lr" } } */
 /* { dg-final { scan-assembler "mov\tr1, lr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
similarity index 91%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index 2c9dfcfb562e2d2a7f7cc3084998e9850f5a480c..fd1a24b3258e8403394dac98ff7c4712b0eb7a1b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
 /* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
 
-#include "../../cmse-7.x"
+#include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
@@ -31,4 +31,3 @@
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
similarity index 91%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index b46585ebcf192c58721363307686f8649a4f8a4a..d8f9b7758d50f74f777fcda22f3f6714ff28bb96 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
 /* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
 
-#include "../../cmse-8.x"
+#include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
similarity index 90%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 576013a74422861ed0d6cb7b5e59aa7779026443..4878c6ef9157abff003780fbf6401db8eb3ef2f3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
 /* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
 
-#include "../../cmse-13.x"
+#include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-5.c
similarity index 91%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-5.c
index 863b412f9161b9acd4bb1b3f6d84d64a71bf8643..d6e758cc98e1a66bc6116e371caa62f2f2854c06 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/hard/cmse-5.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
 /* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
 
-#include "../../cmse-5.x"
+#include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "mov\tr0, lr" } } */
 /* { dg-final { scan-assembler "mov\tr1, lr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
similarity index 88%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index 3e502a2c84be94c8767c1e6e97a5864f9aa63ccb..8e054c2aeebac4bd3f164b00ad867bc2d72cb674 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
 /* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
 
-#include "../../cmse-7.x"
+#include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
@@ -23,4 +23,3 @@
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
similarity index 88%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index 5ed3e7a3fd8f51b2813e7affe4da944d938ac1d6..e74cea7697ba1c12ebeef21636d1b8fd60b42677 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" } } */
 /* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
 
-#include "../../cmse-8.x"
+#include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
similarity index 82%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index 778801f8efeff35c6d81359dcab38fd103b75f77..4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -1,8 +1,8 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=soft" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=soft" } } */
 
-#include "../../cmse-13.x"
+#include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
@@ -16,4 +16,3 @@
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-5.c
similarity index 79%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-5.c
index 6c326edd6c7a60b9d77b73fd84a2922c04ab216a..71971b094c0dd7226659adeb49e788ab85e63206 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/soft/cmse-5.c
@@ -1,8 +1,8 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=soft" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=soft" } } */
 
-#include "../../cmse-5.x"
+#include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "mov\tr1, lr" } } */
 /* { dg-final { scan-assembler "mov\tr2, lr" } } */
@@ -13,4 +13,3 @@
 /* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
 /* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
 /* { dg-final { scan-assembler "bxns" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
similarity index 82%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index 5c9539fcf0391026c34c2ebb8c31662d04cff51c..4cb6a54a0a5b02954519e64503d7c2c4c0e4750d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -1,8 +1,8 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=soft" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=soft" } } */
 
-#include "../../cmse-7.x"
+#include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
@@ -16,4 +16,3 @@
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
similarity index 82%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index 0947c9bf35bfeda4e93e18101e4a6144716da68f..4764b2fadfb38661764b909cdb2c9cd109e24df0 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -1,8 +1,8 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=soft" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=soft" } } */
 
-#include "../../cmse-8.x"
+#include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-5.c
similarity index 93%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-5.c
index 9f5466dfd784a6bf46db52bc0aea91a73011f965..f550b77f616315d3eae6e1fa81161750a810f321 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-5.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
 /* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
 
-#include "../../cmse-5.x"
+#include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
similarity index 82%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index 792d444d0c0d1da3b4c213029fe4eb7d3a9a2180..9e93d75c35de5e3dde1074fb99da94edc2648319 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
 /* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
 
-#include "../../cmse-7.x"
+#include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
@@ -15,4 +15,3 @@
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
similarity index 82%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index 2d9797b2b9304c72cde548cd24cd83d9d30990a0..566889e66c8cea6ca32348f48742d2c325336995 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
 /* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
 
-#include "../../cmse-8.x"
+#include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
similarity index 81%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index 56b88f893d02d6c1fc0a4fc7b9ef92137a764018..0ee28de4123c5e09df7c5d1046e0bd555af6f0fa 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
 /* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
 
-#include "../../cmse-13.x"
+#include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
@@ -14,4 +14,3 @@
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-5.c
similarity index 91%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-5.c
index 7aa35f03a6875143ce342f24ac37c2c304395dba..cf8f3ab135a80f03bd3c5cf0276bb1ae31b2f436 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-5.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
 /* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
 
-#include "../../cmse-5.x"
+#include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
similarity index 82%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 45be75f5e0a0f61f2dba1182bd3b8922c756ced6..1c38290e79d18a8f94e44b974c54220e553a9a49 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
 /* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
 
-#include "../../cmse-7.x"
+#include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
@@ -15,4 +15,3 @@
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
similarity index 82%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index f98e9db8274a61457911c6c9e24ce63cdbde84e4..39c2e72f968ce9f30d36bd347544ca26b3dfad8a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -1,9 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
-/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Incompatible float ABI" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=softfp" } } */
 /* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
 
-#include "../../cmse-8.x"
+#include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
similarity index 95%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
index 071955f206c04c13ec04bbe7034edb4754c47563..d51db020c7707fa714364b10dd3ec5896a9dad17 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse" } */
 
-#include "../union-1.x"
+#include "../../union-1.x"
 
 /* { dg-final { scan-assembler "movw\tip, #8063" } } */
 /* { dg-final { scan-assembler "movt\tip, 63" } } */
@@ -13,4 +13,3 @@
 /* { dg-final { scan-assembler "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
similarity index 96%
rename from gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
rename to gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
index c7431930ff95215361feea6b28e981ed6d5cb824..131afbbf4289b238438c53ab9ea55d13b8567513 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mcmse" } */
 
-#include "../union-2.x"
+#include "../../union-2.x"
 
 /* { dg-final { scan-assembler "movw\tip, #8191" } } */
 /* { dg-final { scan-assembler "movt\tip, 63" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
index 874da3ca8248e501bd73178acad7b9e70252b047..5f6891a26d9be6edbb81c6c9e71897d1b49c8c60 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -25,9 +25,9 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "movs\tr1, #255" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
-
-
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 5451a9f33c1f5d30b7bc4fea3552f27ff6cab791..fba3154585299b2a4f284d3ea1559cc556dd584c 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -4454,6 +4454,19 @@ proc check_effective_target_arm_cmse_ok {} {
     } "-mcmse"];
 }
 
+# Return 1 if this is an ARM target where ARMv8-M Security Extensions with
+# clearing instructions (clrm, vscclrm, vstr/vldr with FPCXT) is available.
+
+proc check_effective_target_arm_cmse_clear_ok {} {
+    return [check_no_compiler_messages arm_cmse_clear object {
+	int
+	foo (void)
+	{
+	  asm ("clrm {r1, r2}");
+	}
+    } "-mcmse"];
+}
+
 # Return 1 if this compilation turns on string_ops_prefer_neon on.
 
 proc check_effective_target_arm_tune_string_ops_prefer_neon { } {

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
  2019-11-12  9:56   ` [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM Kyrill Tkachov
@ 2019-12-16 19:16     ` Mihail Ionescu
  2019-12-17 10:27       ` Kyrill Tkachov
  0 siblings, 1 reply; 35+ messages in thread
From: Mihail Ionescu @ 2019-12-16 19:16 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 58534 bytes --]

Hi Kyrill,

On 11/12/2019 09:55 AM, Kyrill Tkachov wrote:
> Hi Mihail,
> 
> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>> [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
>>
>> Hi,
>>
>> === Context ===
>>
>> This patch is part of a patch series to add support for Armv8.1-M
>> Mainline Security Extensions architecture. Its purpose is to improve
>> code density of functions with the cmse_nonsecure_entry attribute and
>> when calling function with the cmse_nonsecure_call attribute by using
>> CLRM to do all the general purpose registers clearing as well as
>> clearing the APSR register.
>>
>> === Patch description ===
>>
>> This patch adds a new pattern for the CLRM instruction and guards the
>> current clearing code in output_return_instruction() and thumb_exit()
>> on Armv8.1-M Mainline instructions not being present.
>> cmse_clear_registers () is then modified to use the new CLRM instruction
>> when targeting Armv8.1-M Mainline while keeping Armv8-M register
>> clearing code for VFP registers.
>>
>> For the CLRM instruction, which does not mandated APSR in the register
>> list, checking whether it is the right volatile unspec or a clearing
>> register is done in clear_operation_p.
>>
>> Note that load/store multiple were deemed sufficiently different in
>> terms of RTX structure compared to the CLRM pattern for a different
>> function to be used to validate the match_parallel.
>>
>> ChangeLog entries are as follows:
>>
>> *** gcc/ChangeLog ***
>>
>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm-protos.h (clear_operation_p): Declare.
>>         * config/arm/arm.c (clear_operation_p): New function.
>>         (cmse_clear_registers): Generate clear_multiple instruction 
>> pattern if
>>         targeting Armv8.1-M Mainline or successor.
>>         (output_return_instruction): Only output APSR register 
>> clearing if
>>         Armv8.1-M Mainline instructions not available.
>>         (thumb_exit): Likewise.
>>         * config/arm/predicates.md (clear_multiple_operation): New 
>> predicate.
>>         * config/arm/thumb2.md (clear_apsr): New define_insn.
>>         (clear_multiple): Likewise.
>>         * config/arm/unspecs.md (VUNSPEC_CLRM_APSR): New volatile unspec.
>>
>> *** gcc/testsuite/ChangeLog ***
>>
>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/bitfield-1.c: Add check for CLRM.
>>         * gcc.target/arm/cmse/bitfield-2.c: Likewise.
>>         * gcc.target/arm/cmse/bitfield-3.c: Likewise.
>>         * gcc.target/arm/cmse/struct-1.c: Likewise.
>>         * gcc.target/arm/cmse/cmse-14.c: Likewise.
>>         * gcc.target/arm/cmse/cmse-1.c: Likewise.  Restrict checks for 
>> Armv8-M
>>         GPR clearing when CLRM is not available.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.
>>
>> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
>> regression.
>>
>> Is this ok for trunk?
>>
>> Best regards,
>>
>> Mihail
>>
>>
>> ###############     Attachment also inlined for ease of reply 
>> ###############
>>
>>
>> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
>> index 
>> f995974f9bb89ab3c7ff0888c394b0dfaf7da60c..1a948d2c97526ad7e67e8d4a610ac74cfdb13882 
>> 100644
>> --- a/gcc/config/arm/arm-protos.h
>> +++ b/gcc/config/arm/arm-protos.h
>> @@ -77,6 +77,7 @@ extern int thumb_legitimate_offset_p (machine_mode, 
>> HOST_WIDE_INT);
>>  extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
>>  extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
>>                                   bool, bool);
>> +extern bool clear_operation_p (rtx);
>>  extern int arm_const_double_rtx (rtx);
>>  extern int vfp3_const_double_rtx (rtx);
>>  extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, 
>> int *);
>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>> index 
>> d485e80096c9d2eef2172d211a0a5ab63cdbb3c7..3a373cea33c3d0b966cbe700d26f66fe069e1efb 
>> 100644
>> --- a/gcc/config/arm/arm.c
>> +++ b/gcc/config/arm/arm.c
>> @@ -13499,6 +13499,66 @@ ldm_stm_operation_p (rtx op, bool load, 
>> machine_mode mode,
>>    return true;
>>  }
>>
>> +/* Checks whether OP is a valid parallel pattern for a CLRM insn.  To 
>> be a
>> +   valid CLRM pattern, OP must have the following form:
>> +
>> +   [(set (reg:SI <N>) (const_int 0))
>> +    (set (reg:SI <M>) (const_int 0))
>> +    ...
>> +    (unspec_volatile [(const_int 0)]
>> +                    VUNSPEC_CLRM_APSR)
>> +   ]
> 
> 
> If this clears the whole APSR than it also clobbers the condition flags, 
> right?
> 
> Then it should also have a  (clobber (reg:CC CC_REGNUM)) in there.
> Yes -- it should also clobber the condition flags, thanks for catching 
this. I've updated the patch to include the CC clobbering.

Regards,
Mihail
> 
>> +
>> +   Any number (including 0) of set expressions is valid, the volatile 
>> unspec is
>> +   optional.  All registers but SP and PC are allowed and registers 
>> must be in
>> +   strict increasing order.  */
>> +
>> +bool
>> +clear_operation_p (rtx op)
>> +{
>> +  HOST_WIDE_INT i;
>> +  unsigned regno, last_regno;
>> +  rtx elt, reg, zero;
>> +  machine_mode mode;
>> +  HOST_WIDE_INT count = XVECLEN (op, 0);
>> +
>> +  for (i = 0; i < count; i++)
>> +    {
>> +      elt = XVECEXP (op, 0, i);
>> +
>> +      if (GET_CODE (elt) == UNSPEC_VOLATILE)
>> +       {
>> +         if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
>> +             || XVECLEN (elt, 0) != 1
>> +             || XVECEXP (elt, 0, 0) != CONST0_RTX (SImode)
>> +             || i != count - 1)
>> +           return false;
>> +
>> +         continue;
>> +       }
>> +
>> +      if (GET_CODE (elt) != SET)
>> +       return false;
>> +
>> +      reg = SET_DEST (elt);
>> +      regno = REGNO (reg);
>> +      mode = GET_MODE (reg);
>> +      zero = SET_SRC (elt);
>> +
>> +      if (!REG_P (reg)
>> +         || GET_MODE (reg) != SImode
>> +         || regno == SP_REGNUM
>> +         || regno == PC_REGNUM
>> +         || (i != 0 && regno <= last_regno)
>> +         || zero != CONST0_RTX (SImode))
>> +       return false;
>> +
>> +      last_regno = REGNO (reg);
>> +    }
>> +
>> +  return true;
>> +}
>> +
>>  /* Return true iff it would be profitable to turn a sequence of NOPS 
>> loads
>>     or stores (depending on IS_STORE) into a load-multiple or 
>> store-multiple
>>     instruction.  ADD_OFFSET is nonzero if the base address register 
>> needs
>> @@ -17596,6 +17656,56 @@ cmse_clear_registers (sbitmap 
>> to_clear_bitmap, uint32_t *padding_bits_to_clear,
>>
>>    /* Clear full registers.  */
>>
>> +  if (TARGET_HAVE_FPCXT_CMSE)
>> +    {
>> +      rtvec vunspec_vec;
>> +      int i, j, k, nb_regs;
>> +      rtx use_seq, par, reg, set, vunspec;
>> +      int to_clear_bitmap_size = SBITMAP_SIZE (to_clear_bitmap);
>> +      auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
>> +      auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
>> +
>> +      /* Get set of core registers to clear.  */
>> +      bitmap_clear (core_regs_bitmap);
>> +      bitmap_set_range (core_regs_bitmap, R0_REGNUM,
>> +                       IP_REGNUM - R0_REGNUM + 1);
>> +      bitmap_and (to_clear_core_bitmap, to_clear_bitmap,
>> +                 core_regs_bitmap);
>> +      gcc_assert (!bitmap_empty_p (to_clear_core_bitmap));
>> +
>> +      if (bitmap_empty_p (to_clear_core_bitmap))
>> +       return;
>> +
>> +      /* Create clrm RTX pattern.  */
>> +      nb_regs = bitmap_count_bits (to_clear_core_bitmap);
>> +      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 1));
>> +
>> +      /* Insert core register clearing RTX in the pattern. */
>> +      start_sequence ();
>> +      for (j = 0, i = minregno; j < nb_regs; i++)
>> +       {
>> +         if (!bitmap_bit_p (to_clear_core_bitmap, i))
>> +           continue;
>> +
>> +         reg = gen_rtx_REG (SImode, i);
>> +         set = gen_rtx_SET (reg, const0_rtx);
>> +         XVECEXP (par, 0, j++) = set;
>> +         emit_use (reg);
>> +       }
>> +
>> +      /* Insert APSR register clearing RTX in the pattern. */
>> +      vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
>> +      vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
>> +                                        VUNSPEC_CLRM_APSR);
>> +      XVECEXP (par, 0, j) = vunspec;
>> +
>> +      use_seq = get_insns ();
>> +      end_sequence ();
>> +
>> +      emit_insn_after (use_seq, emit_insn (par));
>> +      minregno = FIRST_VFP_REGNUM;
>> +    }
>> +
>>    /* If not marked for clearing, clearing_reg already does not contain
>>       any secret.  */
>>    if (clearing_regno <= maxregno
>> @@ -20259,40 +20369,50 @@ output_return_instruction (rtx operand, bool 
>> really_return, bool reverse,
>>          default:
>>            if (IS_CMSE_ENTRY (func_type))
>>              {
>> -             /* Check if we have to clear the 'GE bits' which is only 
>> used if
>> -                parallel add and subtraction instructions are 
>> available.  */
>> -             if (TARGET_INT_SIMD)
>> -               snprintf (instr, sizeof (instr),
>> -                         "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
>> -             else
>> -               snprintf (instr, sizeof (instr),
>> -                         "msr%s\tAPSR_nzcvq, %%|lr", conditional);
>> -
>> -             output_asm_insn (instr, & operand);
>> -             /* Do not clear FPSCR if targeting Armv8.1-M Mainline, 
>> VLDR takes
>> -                care of it.  */
>> -             if (TARGET_HARD_FLOAT && ! TARGET_HAVE_FPCXT_CMSE)
>> +             /* For Armv8.1-M, this is cleared as part of the CLRM 
>> instruction
>> +                emitted by cmse_nonsecure_entry_clear_before_return 
>> () and the
>> +                VSTR/VLDR instructions in the prologue and epilogue.  */
>> +             if (!TARGET_HAVE_FPCXT_CMSE)
>>                  {
>> -                 /* Clear the cumulative exception-status bits 
>> (0-4,7) and the
>> -                    condition code bits (28-31) of the FPSCR.  We 
>> need to
>> -                    remember to clear the first scratch register used 
>> (IP) and
>> -                    save and restore the second (r4).  */
>> -                 snprintf (instr, sizeof (instr), "push\t{%%|r4}");
>> -                 output_asm_insn (instr, & operand);
>> -                 snprintf (instr, sizeof (instr), "vmrs\t%%|ip, fpscr");
>> -                 output_asm_insn (instr, & operand);
>> -                 snprintf (instr, sizeof (instr), "movw\t%%|r4, 
>> #65376");
>> -                 output_asm_insn (instr, & operand);
>> -                 snprintf (instr, sizeof (instr), "movt\t%%|r4, #4095");
>> -                 output_asm_insn (instr, & operand);
>> -                 snprintf (instr, sizeof (instr), "and\t%%|ip, %%|r4");
>> -                 output_asm_insn (instr, & operand);
>> -                 snprintf (instr, sizeof (instr), "vmsr\tfpscr, %%|ip");
>> -                 output_asm_insn (instr, & operand);
>> -                 snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
>> -                 output_asm_insn (instr, & operand);
>> -                 snprintf (instr, sizeof (instr), "mov\t%%|ip, %%|lr");
>> +                 /* Check if we have to clear the 'GE bits' which is 
>> only used if
>> +                    parallel add and subtraction instructions are 
>> available.  */
>> +                 if (TARGET_INT_SIMD)
>> +                   snprintf (instr, sizeof (instr),
>> +                             "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
>> +                 else
>> +                   snprintf (instr, sizeof (instr),
>> +                             "msr%s\tAPSR_nzcvq, %%|lr", conditional);
>> +
>>                    output_asm_insn (instr, & operand);
>> +                 /* Do not clear FPSCR if targeting Armv8.1-M 
>> Mainline, VLDR takes
>> +                    care of it.  */
>> +                 if (TARGET_HARD_FLOAT)
>> +                   {
>> +                     /* Clear the cumulative exception-status bits 
>> (0-4,7) and
>> +                        the condition code bits (28-31) of the 
>> FPSCR.  We need
>> +                        to remember to clear the first scratch 
>> register used
>> +                        (IP) and save and restore the second (r4).
>> +
>> +                        Important note: the length of the
>> +                        thumb2_cmse_entry_return insn pattern must 
>> account for
>> +                        the size of the below instructions.  */
>> +                     snprintf (instr, sizeof (instr), "push\t{%%|r4}");
>> +                     output_asm_insn (instr, & operand);
> 
> 
> I know this is pre-existing in this function, but I think we should just 
> use output_asm_insn directly here:
> output_asm_insn ("push\t{%%|r4}", & operand);
> 
> and avoid all the snprintfs.
> 
> 
>> +                     snprintf (instr, sizeof (instr), "vmrs\t%%|ip, 
>> fpscr");
>> +                     output_asm_insn (instr, & operand);
>> +                     snprintf (instr, sizeof (instr), "movw\t%%|r4, 
>> #65376");
>> +                     output_asm_insn (instr, & operand);
>> +                     snprintf (instr, sizeof (instr), "movt\t%%|r4, 
>> #4095");
>> +                     output_asm_insn (instr, & operand);
>> +                     snprintf (instr, sizeof (instr), "and\t%%|ip, 
>> %%|r4");
>> +                     output_asm_insn (instr, & operand);
>> +                     snprintf (instr, sizeof (instr), "vmsr\tfpscr, 
>> %%|ip");
>> +                     output_asm_insn (instr, & operand);
>> +                     snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
>> +                     output_asm_insn (instr, & operand);
>> +                     snprintf (instr, sizeof (instr), "mov\t%%|ip, 
>> %%|lr");
>> +                     output_asm_insn (instr, & operand);
>> +                   }
>>                  }
>>                snprintf (instr, sizeof (instr), "bxns\t%%|lr");
>>              }
>> @@ -24690,8 +24810,11 @@ thumb_exit (FILE *f, int 
>> reg_containing_return_addr)
>>
>>        if (IS_CMSE_ENTRY (arm_current_func_type ()))
>>          {
>> -         asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
>> -                      reg_containing_return_addr);
>> +         /* For Armv8.1-M, this is cleared as part of the CLRM 
>> instruction
>> +            emitted by cmse_nonsecure_entry_clear_before_return ().  */
>> +         if (!TARGET_HAVE_FPCXT_CMSE)
>> +           asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
>> +                        reg_containing_return_addr);
>>            asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
>>          }
>>        else
>> @@ -24931,11 +25054,14 @@ thumb_exit (FILE *f, int 
>> reg_containing_return_addr)
>>           address.  It may therefore contain information that we might 
>> not want
>>           to leak, hence it must be cleared.  The value in R0 will 
>> never be a
>>           secret at this point, so it is safe to use it, see the 
>> clearing code
>> -        in 'cmse_nonsecure_entry_clear_before_return'.  */
>> +        in cmse_nonsecure_entry_clear_before_return ().  */
>>        if (reg_containing_return_addr != LR_REGNUM)
>>          asm_fprintf (f, "\tmov\tlr, r0\n");
>>
>> -      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
>> reg_containing_return_addr);
>> +      /* For Armv8.1-M, this is cleared as part of the CLRM 
>> instruction emitted
>> +        by cmse_nonsecure_entry_clear_before_return ().  */
>> +      if (!TARGET_HAVE_FPCXT_CMSE)
>> +       asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
>> reg_containing_return_addr);
>>        asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
>>      }
>>    else
>> diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
>> index 
>> 8b36e7ee462235ad26e132f1ccf98d28c2487d67..e5c583ef3d167194e7a061d7c3e98d3b4bb5269c 
>> 100644
>> --- a/gcc/config/arm/predicates.md
>> +++ b/gcc/config/arm/predicates.md
>> @@ -510,6 +510,12 @@
>>              (match_test "satisfies_constraint_Dy (op)")
>>              (match_test "satisfies_constraint_G (op)"))))
>>
>> +(define_special_predicate "clear_multiple_operation"
>> +  (match_code "parallel")
>> +{
>> + return clear_operation_p (op);
>> +})
>> +
>>  (define_special_predicate "load_multiple_operation"
>>    (match_code "parallel")
>>  {
>> diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
>> index 
>> 6ccc875e2b4e7b8ce256e52da966dfe220c6f5d6..9994c0d59f741ef47d0ec43dd53a2324b031d048 
>> 100644
>> --- a/gcc/config/arm/thumb2.md
>> +++ b/gcc/config/arm/thumb2.md
>> @@ -1599,3 +1599,39 @@
>>        FAIL;
>>   }")
>>
>> +(define_insn "*clear_apsr"
>> +  [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)]
>> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
>> +  "clrm%?\\t{APSR}"
>> +  [(set_attr "predicable" "yes")]
>> +)
> 
> 
> Similar to earlier, if this clears the whole APSR then it should also 
> represent a clobber of the CC reg.
> 
> 
>> +
>> +;; The operands are validated through the clear_multiple_operation
>> +;; match_parallel predicate rather than through constraints so enable 
>> it only
>> +;; after reload.
>> +(define_insn "*clear_multiple"
>> +  [(match_parallel 0 "clear_multiple_operation"
>> +     [(set (match_operand:SI 1 "register_operand" "")
>> +          (const_int 0))])]
>> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && 
>> reload_completed"
>> +  {
>> +    char pattern[100];
>> +    int i, num_saves = XVECLEN (operands[0], 0);
>> +
>> +    strcpy (pattern, \"clrm%?\\t{\");
>> +    for (i = 0; i < num_saves; i++)
>> +      {
>> +       if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
>> +         strcat (pattern, \"APSR\");
>> +       else
>> +         strcat (pattern,
>> +                 reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 
>> 0))]);
>> +       if (i < num_saves - 1)
>> +         strcat (pattern, \", %|\");
>> +      }
>> +    strcat (pattern, \"}\");
>> +    output_asm_insn (pattern, operands);
>> +    return \"\";
>> +  }
>> +  [(set_attr "predicable" "yes")]
>> +)
>> diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
>> index 
>> 324359be7127f04a80ebc0079ad0a9964dfd82a7..498bc0798dbaaa3ee73815ba27864ae92a2fd08e 
>> 100644
>> --- a/gcc/config/arm/unspecs.md
>> +++ b/gcc/config/arm/unspecs.md
>> @@ -174,6 +174,7 @@
>>    VUNSPEC_MRRC2                ; Represent the coprocessor mrrc2 
>> instruction.
>>    VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional 
>> speculation barrier.
>>    VUNSPEC_VSTR_VLDR    ; Represent the vstr/vldr instruction.
>> +  VUNSPEC_CLRM_APSR    ; Represent the clearing of APSR with clrm 
>> instruction.
>>  ])
>>
>>  ;; Enumerators for NEON unspecs.
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>> index 
>> 6d611e130b6f3b544807b767927d99b89071343b..7036cb9508c27d56c4b2c01a81c44bf6f1f9c781 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>> @@ -36,6 +36,7 @@ main (void)
>>  /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
>>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "bxns" } } */
>>
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>> index 
>> b7ec0a040319545b50590261278f1517bcb22796..50d4979470dd21738453e0d70c7a69ee0752ac41 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>> @@ -33,6 +33,7 @@ main (void)
>>  /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
>>  /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "bxns" } } */
>>
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>> index 
>> 7b9c3f0fe061317f71d3122dea7a55ab5311f234..2b7507c900ab18705083ba1d86359e1ae36a50a2 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>> @@ -34,5 +34,6 @@ main (void)
>>  /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
>>  /* { dg-final { scan-assembler "movt\tr1, 63" } } */
>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "bxns" } } */
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>> index 
>> aa0ec8e0b0f0953a5a5cbc2db58413176c2505f3..35cab1f3233daac9fba50d25dac23364c798fb9c 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>> @@ -105,8 +105,10 @@ qux (int_nsfunc_t * callback)
>>  /* { dg-final { scan-assembler "bic" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { 
>> target arm_cmse_clear_ok } } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>> target arm_cmse_clear_ok } } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
>> +/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
>> arm_cmse_clear_ok } } } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
>> target arm_cmse_clear_ok } } } */
>>
>>  int call_callback (void)
>>  {
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>> index 
>> df1ea52bec533c36a738d7d3b2b2ff749b0f3713..1f5af7c2dba7747f6058d12af8ef80b4dd1b1431 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>> @@ -9,5 +9,6 @@ int foo (void)
>>    return bar ();
>>  }
>>
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>  /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>> index 
>> 62c63b888ab49e99fba0a08b69941e73c9a8d33b..c52e1c14d9956743625e3b8a200e823f163924e3 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>> @@ -12,5 +12,5 @@
>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>> index 
>> b718a70522b86e2bc58900681a781129543f8869..fdba955a32fc5ad492b74974185f98470bc49a7e 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>> @@ -10,6 +10,5 @@
>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>> index 
>> 16536ab4f9ec5782463ab90f404a2e9f6f938850..85068ceaac6a5c0c60af4a54c0af0d20326fc18d 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>> @@ -13,5 +13,5 @@
>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>> index 
>> 0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5..af69d38acf47d9d1d55480edba2b66f07e2d06ad 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>> @@ -10,6 +10,5 @@
>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>> index 
>> 914ea39626f2f72eac8c9c1cb495b0855e58f5e1..62201595549f07b046c7c5972d612ab155c4c38c 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>> @@ -13,5 +13,5 @@
>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>> index 
>> 32435d255805331c7c56a096675b7a2af3286e5e..287f0d6faad113fbc8c30051280668baa58ab130 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>> @@ -7,7 +7,5 @@
>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>> index 
>> eb655b5504e58dc842853c8cb874c5cef3b82aa6..7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>> @@ -8,10 +8,7 @@
>>  /* Checks for saving and clearing prior to function call. */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>> index 
>> ab266af7092afbce868792446124c291188e8a90..638643d0a6772d43f440df3942c6c723f1eff3ef 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>> @@ -6,10 +6,6 @@
>>  #include "../../../cmse-5.x"
>>
>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>> @@ -26,7 +22,6 @@
>>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>> arm_dsp } } } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>> arm_dsp } } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } 
>> } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>  /* { dg-final { scan-assembler "bxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>> index 
>> fd1a24b3258e8403394dac98ff7c4712b0eb7a1b..9ec14d1a707839e4858bac72bc292fd0984bf86c 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>> @@ -8,10 +8,7 @@
>>  /* Checks for saving and clearing prior to function call. */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>> index 
>> d8f9b7758d50f74f777fcda22f3f6714ff28bb96..d375879ed02483c05d7853c95f9b9e15383ff321 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>> @@ -8,10 +8,7 @@
>>  /* Checks for saving and clearing prior to function call. */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>> index 
>> 4878c6ef9157abff003780fbf6401db8eb3ef2f3..e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>> @@ -8,10 +8,7 @@
>>  /* Checks for saving and clearing prior to function call. */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>> index 
>> 82aad2d13d6b170c92fd2c2345ab76f41e383013..7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>> @@ -6,10 +6,6 @@
>>  #include "../../../cmse-5.x"
>>
>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>> @@ -19,7 +15,6 @@
>>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>> arm_dsp } } } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>> arm_dsp } } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } 
>> } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>  /* { dg-final { scan-assembler "bxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>> index 
>> 8e054c2aeebac4bd3f164b00ad867bc2d72cb674..d998b43a148250a15eb4aae9fb0ef6e4bf51203b 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>> @@ -8,10 +8,7 @@
>>  /* Checks for saving and clearing prior to function call. */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>> index 
>> e74cea7697ba1c12ebeef21636d1b8fd60b42677..e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>> @@ -8,10 +8,7 @@
>>  /* Checks for saving and clearing prior to function call. */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>> index 
>> 4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d..d43a9f85a199ecdf7e018852b3af9b4cf36af81f 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>> @@ -8,9 +8,9 @@
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>> index 
>> c684d79fae00feb8e15e9f142735f005473b6011..157bccb9ff3256056d496a0d0770374315b04d87 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>> @@ -5,13 +5,8 @@
>>  #include "../../../cmse-5.x"
>>
>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tip, lr" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>> arm_dsp } } } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>> arm_dsp } } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>  /* { dg-final { scan-assembler "bxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>> index 
>> 4cb6a54a0a5b02954519e64503d7c2c4c0e4750d..02e48157a2c61b0a8bee77e949944acc2a4bee37 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>> @@ -7,10 +7,7 @@
>>  /* Checks for saving and clearing prior to function call. */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>> index 
>> 4764b2fadfb38661764b909cdb2c9cd109e24df0..c7a22a2ba464dce26b289635dd8dcc8213ae33d8 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>> @@ -9,8 +9,7 @@
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>> index 
>> 9b2e7565d24ff52138b0fb90a1e6268aa4c515a0..2522a17a6316d76a21d8d241d4c44cdddf1981e0 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>> @@ -8,9 +8,6 @@
>>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>> @@ -27,7 +24,6 @@
>>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>> arm_dsp } } } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>> arm_dsp } } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>  /* { dg-final { scan-assembler "bxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>> index 
>> 9e93d75c35de5e3dde1074fb99da94edc2648319..d34ca383236fdd31723966e6218ea918cf8c9122 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>> @@ -8,10 +8,7 @@
>>  /* Checks for saving and clearing prior to function call. */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>> index 
>> 566889e66c8cea6ca32348f48742d2c325336995..ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>> @@ -10,8 +10,7 @@
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>> index 
>> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..ff9a7dfa5e696e3a6c4132343d0ee94c3068c208 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>> @@ -9,8 +9,9 @@
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } 
>> } */
>> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>> index 
>> 5af1fdb934ce5aa5afd8d096122b6e9b55591bd9..eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>> @@ -7,10 +7,6 @@
>>
>>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
>> -/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>> @@ -19,7 +15,6 @@
>>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>> arm_dsp } } } } */
>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>> arm_dsp } } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>  /* { dg-final { scan-assembler "bxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>> index 
>> 1c38290e79d18a8f94e44b974c54220e553a9a49..03d36aa650986b6069e2fe1c1f3f98fa9664d88a 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>> @@ -8,10 +8,7 @@
>>  /* Checks for saving and clearing prior to function call. */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>> index 
>> 39c2e72f968ce9f30d36bd347544ca26b3dfad8a..ce45e10688f855ca7b2a63777d2b3d3418815589 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>> @@ -10,8 +10,7 @@
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>> index 
>> d51db020c7707fa714364b10dd3ec5896a9dad17..dbd1d34413ef36f2b03716c0d9cf46b024af0835 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>> @@ -10,6 +10,5 @@
>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>> index 
>> 131afbbf4289b238438c53ab9ea55d13b8567513..3edc7f1e259779a24e722d67ed544c0a673090c7 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>> @@ -14,5 +14,5 @@
>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>> index 
>> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..3a72406df2492206c2cb8ac7b63e4242ec0ba598 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>> @@ -9,8 +9,9 @@
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
>> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } 
>> } */
>> +/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>> index 
>> 5f6891a26d9be6edbb81c6c9e71897d1b49c8c60..90fdac18e30424edca60b6f884227adbf716899d 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>> @@ -29,5 +29,6 @@ main (void)
>>  /* { dg-final { scan-assembler "movs\tr1, #255" } } */
>>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "bxns" } } */
>>

[-- Attachment #2: diff4.patch --]
[-- Type: text/x-patch, Size: 45826 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index c685bcbf99c81210a34192cc31db055fa7b2d605..1db1ff001a5b9d4d7796f0de9355d2b46030c96e 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -78,6 +78,7 @@ extern int thumb_legitimate_offset_p (machine_mode, HOST_WIDE_INT);
 extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
 extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
                                  bool, bool);
+extern bool clear_operation_p (rtx);
 extern int arm_const_double_rtx (rtx);
 extern int vfp3_const_double_rtx (rtx);
 extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, int *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 68c8779245e56be0c8e808a8c98d631eee3f325c..d10ff0736fed4baa92fab0ff978db62c05c6dc7f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -13634,6 +13634,70 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode,
   return true;
 }
 
+/* Checks whether OP is a valid parallel pattern for a CLRM insn.  To be a
+   valid CLRM pattern, OP must have the following form:
+
+   [(set (reg:SI <N>) (const_int 0))
+    (set (reg:SI <M>) (const_int 0))
+    ...
+    (unspec_volatile [(const_int 0)]
+		     VUNSPEC_CLRM_APSR)
+    (clobber (reg:CC CC_REGNUM))
+   ]
+
+   Any number (including 0) of set expressions is valid, the volatile unspec is
+   optional.  All registers but SP and PC are allowed and registers must be in
+   strict increasing order.  */
+
+bool
+clear_operation_p (rtx op)
+{
+  HOST_WIDE_INT i;
+  unsigned regno, last_regno;
+  rtx elt, reg, zero;
+  machine_mode mode;
+  HOST_WIDE_INT count = XVECLEN (op, 0);
+
+  for (i = 0; i < count; i++)
+    {
+      elt = XVECEXP (op, 0, i);
+
+      if (GET_CODE (elt) == UNSPEC_VOLATILE)
+	{
+	  if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
+	      || XVECLEN (elt, 0) != 1
+	      || XVECEXP (elt, 0, 0) != CONST0_RTX (SImode)
+	      || i != count - 2)
+	    return false;
+
+	  continue;
+	}
+
+      if (GET_CODE (elt) == CLOBBER)
+	continue;
+
+      if (GET_CODE (elt) != SET)
+	return false;
+
+      reg = SET_DEST (elt);
+      regno = REGNO (reg);
+      mode = GET_MODE (reg);
+      zero = SET_SRC (elt);
+
+      if (!REG_P (reg)
+	  || GET_MODE (reg) != SImode
+	  || regno == SP_REGNUM
+	  || regno == PC_REGNUM
+	  || (i != 0 && regno <= last_regno)
+	  || zero != CONST0_RTX (SImode))
+	return false;
+
+      last_regno = REGNO (reg);
+    }
+
+  return true;
+}
+
 /* Return true iff it would be profitable to turn a sequence of NOPS loads
    or stores (depending on IS_STORE) into a load-multiple or store-multiple
    instruction.  ADD_OFFSET is nonzero if the base address register needs
@@ -17964,6 +18028,62 @@ cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
 
   /* Clear full registers.  */
 
+  if (TARGET_HAVE_FPCXT_CMSE)
+    {
+      rtvec vunspec_vec;
+      int i, j, k, nb_regs;
+      rtx use_seq, par, reg, set, vunspec;
+      int to_clear_bitmap_size = SBITMAP_SIZE (to_clear_bitmap);
+      auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
+      auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
+
+      /* Get set of core registers to clear.  */
+      bitmap_clear (core_regs_bitmap);
+      bitmap_set_range (core_regs_bitmap, R0_REGNUM,
+			IP_REGNUM - R0_REGNUM + 1);
+      bitmap_and (to_clear_core_bitmap, to_clear_bitmap,
+		  core_regs_bitmap);
+      gcc_assert (!bitmap_empty_p (to_clear_core_bitmap));
+
+      if (bitmap_empty_p (to_clear_core_bitmap))
+	return;
+
+      /* Create clrm RTX pattern.  */
+      nb_regs = bitmap_count_bits (to_clear_core_bitmap);
+      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 2));
+
+      /* Insert core register clearing RTX in the pattern.  */
+      start_sequence ();
+      for (j = 0, i = minregno; j < nb_regs; i++)
+	{
+	  if (!bitmap_bit_p (to_clear_core_bitmap, i))
+	    continue;
+
+	  reg = gen_rtx_REG (SImode, i);
+	  set = gen_rtx_SET (reg, const0_rtx);
+	  XVECEXP (par, 0, j++) = set;
+	  emit_use (reg);
+	}
+
+      /* Insert APSR register clearing RTX in the pattern
+       * along with clobbering CC.  */
+      vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
+      vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
+					 VUNSPEC_CLRM_APSR);
+
+      XVECEXP (par, 0, j++) = vunspec;
+
+      rtx ccreg = gen_rtx_REG (CCmode, CC_REGNUM);
+      rtx clobber = gen_rtx_CLOBBER (VOIDmode, ccreg);
+      XVECEXP (par, 0, j) = clobber;
+
+      use_seq = get_insns ();
+      end_sequence ();
+
+      emit_insn_after (use_seq, emit_insn (par));
+      minregno = FIRST_VFP_REGNUM;
+    }
+
   /* If not marked for clearing, clearing_reg already does not contain
      any secret.  */
   if (clearing_regno <= maxregno
@@ -20627,40 +20747,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
 	    {
-	      /* Check if we have to clear the 'GE bits' which is only used if
-		 parallel add and subtraction instructions are available.  */
-	      if (TARGET_INT_SIMD)
-		snprintf (instr, sizeof (instr),
-			  "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
-	      else
-		snprintf (instr, sizeof (instr),
-			  "msr%s\tAPSR_nzcvq, %%|lr", conditional);
-
-	      output_asm_insn (instr, & operand);
-	      /* Do not clear FPSCR if targeting Armv8.1-M Mainline, VLDR takes
-		 care of it.  */
-	      if (TARGET_HARD_FLOAT && ! TARGET_HAVE_FPCXT_CMSE)
+	      /* For Armv8.1-M, this is cleared as part of the CLRM instruction
+		 emitted by cmse_nonsecure_entry_clear_before_return () and the
+		 VSTR/VLDR instructions in the prologue and epilogue.  */
+	      if (!TARGET_HAVE_FPCXT_CMSE)
 		{
-		  /* Clear the cumulative exception-status bits (0-4,7) and the
-		     condition code bits (28-31) of the FPSCR.  We need to
-		     remember to clear the first scratch register used (IP) and
-		     save and restore the second (r4).  */
-		  snprintf (instr, sizeof (instr), "push\t{%%|r4}");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "vmrs\t%%|ip, fpscr");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "movw\t%%|r4, #65376");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "movt\t%%|r4, #4095");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "and\t%%|ip, %%|r4");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "vmsr\tfpscr, %%|ip");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "mov\t%%|ip, %%|lr");
+		  /* Check if we have to clear the 'GE bits' which is only used if
+		     parallel add and subtraction instructions are available.  */
+		  if (TARGET_INT_SIMD)
+		    snprintf (instr, sizeof (instr),
+			      "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
+		  else
+		    snprintf (instr, sizeof (instr),
+			      "msr%s\tAPSR_nzcvq, %%|lr", conditional);
+
 		  output_asm_insn (instr, & operand);
+		  /* Do not clear FPSCR if targeting Armv8.1-M Mainline, VLDR takes
+		     care of it.  */
+		  if (TARGET_HARD_FLOAT)
+		    {
+		      /* Clear the cumulative exception-status bits (0-4,7) and
+			 the condition code bits (28-31) of the FPSCR.  We need
+			 to remember to clear the first scratch register used
+			 (IP) and save and restore the second (r4).
+
+			 Important note: the length of the
+			 thumb2_cmse_entry_return insn pattern must account for
+			 the size of the below instructions.  */
+		      output_asm_insn ("push\t{%|r4}", & operand);
+		      output_asm_insn ("vmrs\t%|ip, fpscr", & operand);
+		      output_asm_insn ("movw\t%|r4, #65376", & operand);
+		      output_asm_insn ("movt\t%|r4, #4095", & operand);
+		      output_asm_insn ("and\t%|ip, %|r4", & operand);
+		      output_asm_insn ("vmsr\tfpscr, %|ip", & operand);
+		      output_asm_insn ("pop\t{%|r4}", & operand);
+		      output_asm_insn ("mov\t%|ip, %|lr", & operand);
+		    }
 		}
 	      snprintf (instr, sizeof (instr), "bxns\t%%|lr");
 	    }
@@ -22643,6 +22765,9 @@ arm_expand_prologue (void)
       saved_regs += 4;
       insn = emit_insn (gen_push_fpsysreg_insn (stack_pointer_rtx,
 						GEN_INT (FPCXTNS_ENUM)));
+      rtx dwarf = gen_rtx_SET (stack_pointer_rtx,
+			  plus_constant (Pmode, stack_pointer_rtx, -4));
+      add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
@@ -25059,8 +25184,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
 	{
-	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
-		       reg_containing_return_addr);
+	  /* For Armv8.1-M, this is cleared as part of the CLRM instruction
+	     emitted by cmse_nonsecure_entry_clear_before_return ().  */
+	  if (!TARGET_HAVE_FPCXT_CMSE)
+	    asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+			 reg_containing_return_addr);
 	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
 	}
       else
@@ -25300,11 +25428,14 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
          address.  It may therefore contain information that we might not want
 	 to leak, hence it must be cleared.  The value in R0 will never be a
 	 secret at this point, so it is safe to use it, see the clearing code
-	 in 'cmse_nonsecure_entry_clear_before_return'.  */
+	 in cmse_nonsecure_entry_clear_before_return ().  */
       if (reg_containing_return_addr != LR_REGNUM)
 	asm_fprintf (f, "\tmov\tlr, r0\n");
 
-      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
+      /* For Armv8.1-M, this is cleared as part of the CLRM instruction emitted
+	 by cmse_nonsecure_entry_clear_before_return ().  */
+      if (!TARGET_HAVE_FPCXT_CMSE)
+	asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
       asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
     }
   else
@@ -26842,6 +26973,9 @@ arm_expand_epilogue (bool really_return)
 
 	  insn = emit_insn (gen_pop_fpsysreg_insn (stack_pointer_rtx,
 						   GEN_INT (FPCXTNS_ENUM)));
+	  rtx dwarf = gen_rtx_SET (stack_pointer_rtx,
+				  plus_constant (Pmode, stack_pointer_rtx, 4));
+	  add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
 	  RTX_FRAME_RELATED_P (insn) = 1;
 	}
       }
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index 267c446c03e8903c21a0d74e43ae589ffcf689f4..3668c45081f116d1648ba08bab87aed9eab971c3 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -537,6 +537,12 @@
 	    (match_test "satisfies_constraint_Dy (op)")
 	    (match_test "satisfies_constraint_G (op)"))))
 
+(define_special_predicate "clear_multiple_operation"
+  (match_code "parallel")
+{
+ return clear_operation_p (op);
+})
+
 (define_special_predicate "load_multiple_operation"
   (match_code "parallel")
 {
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index 7fce50b045b40f0d29ba792dce05e43072dad3b0..ea60005db0409058b1611d399d6a6cc96a933b41 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1576,3 +1576,44 @@
       FAIL;
  }")
 
+(define_insn "*clear_apsr"
+  [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)
+  (clobber (reg:CC CC_REGNUM))]
+  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
+  "clrm%?\\t{APSR}"
+  [(set_attr "predicable" "yes")]
+)
+
+;; The operands are validated through the clear_multiple_operation
+;; match_parallel predicate rather than through constraints so enable it only
+;; after reload.
+(define_insn "*clear_multiple"
+  [(match_parallel 0 "clear_multiple_operation"
+     [(set (match_operand:SI 1 "register_operand" "")
+	   (const_int 0))])]
+  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && reload_completed"
+  {
+    char pattern[100];
+    int i, num_saves = XVECLEN (operands[0], 0);
+
+    strcpy (pattern, \"clrm%?\\t{\");
+    for (i = 0; i < num_saves; i++)
+      {
+	if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
+	  {
+	    strcat (pattern, \"APSR\");
+	    // Skip clobber
+	    ++i;
+	  }
+	else
+	  strcat (pattern,
+		  reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 0))]);
+	if (i < num_saves - 1)
+	  strcat (pattern, \", %|\");
+      }
+    strcat (pattern, \"}\");
+    output_asm_insn (pattern, operands);
+    return \"\";
+  }
+  [(set_attr "predicable" "yes")]
+)
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 59d354e9a918187ab2f747d5e5f8f7edd9ad7082..4dcdcc6fc3fd3ea396e1d5479c8ce0b37db065f1 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -212,6 +212,7 @@
   VUNSPEC_MRRC2		; Represent the coprocessor mrrc2 instruction.
   VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional speculation barrier.
   VUNSPEC_VSTR_VLDR	; Represent the vstr/vldr instruction.
+  VUNSPEC_CLRM_APSR	; Represent the clearing of APSR with clrm instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
index 6d611e130b6f3b544807b767927d99b89071343b..7036cb9508c27d56c4b2c01a81c44bf6f1f9c781 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -36,6 +36,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
index b7ec0a040319545b50590261278f1517bcb22796..50d4979470dd21738453e0d70c7a69ee0752ac41 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -33,6 +33,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
 /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
index 7b9c3f0fe061317f71d3122dea7a55ab5311f234..2b7507c900ab18705083ba1d86359e1ae36a50a2 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -34,5 +34,6 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
 /* { dg-final { scan-assembler "movt\tr1, 63" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index aa0ec8e0b0f0953a5a5cbc2db58413176c2505f3..35cab1f3233daac9fba50d25dac23364c798fb9c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -105,8 +105,10 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "bic" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! arm_cmse_clear_ok } } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
 
 int call_callback (void)
 {
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
index df1ea52bec533c36a738d7d3b2b2ff749b0f3713..1f5af7c2dba7747f6058d12af8ef80b4dd1b1431 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -9,5 +9,6 @@ int foo (void)
   return bar ();
 }
 
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
index 62c63b888ab49e99fba0a08b69941e73c9a8d33b..c52e1c14d9956743625e3b8a200e823f163924e3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
@@ -12,5 +12,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
index b718a70522b86e2bc58900681a781129543f8869..fdba955a32fc5ad492b74974185f98470bc49a7e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
@@ -10,6 +10,5 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
index 16536ab4f9ec5782463ab90f404a2e9f6f938850..85068ceaac6a5c0c60af4a54c0af0d20326fc18d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
@@ -13,5 +13,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
index 0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5..af69d38acf47d9d1d55480edba2b66f07e2d06ad 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
@@ -10,6 +10,5 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
index 914ea39626f2f72eac8c9c1cb495b0855e58f5e1..62201595549f07b046c7c5972d612ab155c4c38c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
@@ -13,5 +13,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
index 32435d255805331c7c56a096675b7a2af3286e5e..287f0d6faad113fbc8c30051280668baa58ab130 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
@@ -7,7 +7,5 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index eb655b5504e58dc842853c8cb874c5cef3b82aa6..7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
index ab266af7092afbce868792446124c291188e8a90..638643d0a6772d43f440df3942c6c723f1eff3ef 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
@@ -6,10 +6,6 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
@@ -26,7 +22,6 @@
 /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index fd1a24b3258e8403394dac98ff7c4712b0eb7a1b..9ec14d1a707839e4858bac72bc292fd0984bf86c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index d8f9b7758d50f74f777fcda22f3f6714ff28bb96..d375879ed02483c05d7853c95f9b9e15383ff321 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 4878c6ef9157abff003780fbf6401db8eb3ef2f3..e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
index 82aad2d13d6b170c92fd2c2345ab76f41e383013..7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
@@ -6,10 +6,6 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
@@ -19,7 +15,6 @@
 /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index 8e054c2aeebac4bd3f164b00ad867bc2d72cb674..d998b43a148250a15eb4aae9fb0ef6e4bf51203b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index e74cea7697ba1c12ebeef21636d1b8fd60b42677..e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index 4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d..d43a9f85a199ecdf7e018852b3af9b4cf36af81f 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -8,9 +8,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
index c684d79fae00feb8e15e9f142735f005473b6011..157bccb9ff3256056d496a0d0770374315b04d87 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
@@ -5,13 +5,8 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
-/* { dg-final { scan-assembler "mov\tip, lr" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index 4cb6a54a0a5b02954519e64503d7c2c4c0e4750d..02e48157a2c61b0a8bee77e949944acc2a4bee37 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -7,10 +7,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index 4764b2fadfb38661764b909cdb2c9cd109e24df0..c7a22a2ba464dce26b289635dd8dcc8213ae33d8 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -9,8 +9,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
index 9b2e7565d24ff52138b0fb90a1e6268aa4c515a0..2522a17a6316d76a21d8d241d4c44cdddf1981e0 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
@@ -8,9 +8,6 @@
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
@@ -27,7 +24,6 @@
 /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index 9e93d75c35de5e3dde1074fb99da94edc2648319..d34ca383236fdd31723966e6218ea918cf8c9122 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index 566889e66c8cea6ca32348f48742d2c325336995..ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -10,8 +10,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..ff9a7dfa5e696e3a6c4132343d0ee94c3068c208 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -9,8 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
-/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
index 5af1fdb934ce5aa5afd8d096122b6e9b55591bd9..eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
@@ -7,10 +7,6 @@
 
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
@@ -19,7 +15,6 @@
 /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 1c38290e79d18a8f94e44b974c54220e553a9a49..03d36aa650986b6069e2fe1c1f3f98fa9664d88a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index 39c2e72f968ce9f30d36bd347544ca26b3dfad8a..ce45e10688f855ca7b2a63777d2b3d3418815589 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -10,8 +10,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
index d51db020c7707fa714364b10dd3ec5896a9dad17..dbd1d34413ef36f2b03716c0d9cf46b024af0835 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
@@ -10,6 +10,5 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
index 131afbbf4289b238438c53ab9ea55d13b8567513..3edc7f1e259779a24e722d67ed544c0a673090c7 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
@@ -14,5 +14,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
index 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..3a72406df2492206c2cb8ac7b63e4242ec0ba598 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
@@ -9,8 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
-/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
index 5f6891a26d9be6edbb81c6c9e71897d1b49c8c60..90fdac18e30424edca60b6f884227adbf716899d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -29,5 +29,6 @@ main (void)
 /* { dg-final { scan-assembler "movs\tr1, #255" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline
  2019-12-16 18:29       ` Mihail Ionescu
@ 2019-12-17 10:24         ` Kyrill Tkachov
  0 siblings, 0 replies; 35+ messages in thread
From: Kyrill Tkachov @ 2019-12-17 10:24 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 12/16/19 6:28 PM, Mihail Ionescu wrote:
> Hi Kyrill
>
> On 11/06/2019 03:59 PM, Kyrill Tkachov wrote:
>> Hi Mihail,
>>
>> On 11/4/19 4:49 PM, Kyrill Tkachov wrote:
>>> Hi Mihail,
>>>
>>> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>>> > [PATCH, GCC/ARM, 2/10] Add command line support
>>> >
>>> > Hi,
>>> >
>>> > === Context ===
>>> >
>>> > This patch is part of a patch series to add support for Armv8.1-M
>>> > Mainline Security Extensions architecture. Its purpose is to add
>>> > command-line support for that new architecture.
>>> >
>>> > === Patch description ===
>>> >
>>> > Besides the expected enabling of the new value for the -march
>>> > command-line option (-march=armv8.1-m.main) and its extensions (see
>>> > below), this patch disables support of the Security Extensions for 
>>> this
>>> > newly added architecture. This is done both by not including the cmse
>>> > bit in the architecture description and by throwing an error message
>>> > when user request Armv8.1-M Mainline Security Extensions. Note that
>>> > Armv8-M Baseline and Mainline Security Extensions are still enabled.
>>> >
>>> > Only extensions for already supported instructions are implemented in
>>> > this patch. Other extensions (MVE integer and float) will be added in
>>> > separate patches. The following configurations are allowed for 
>>> Armv8.1-M
>>> > Mainline with regards to FPU and implemented in this patch:
>>> > + no FPU (+nofp)
>>> > + single precision VFPv5 with FP16 (+fp)
>>> > + double precision VFPv5 with FP16 (+fp.dp)
>>> >
>>> > ChangeLog entry are as follow:
>>> >
>>> > *** gcc/ChangeLog ***
>>> >
>>> > 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>> > 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>> >
>>> >         * config/arm/arm-cpus.in (armv8_1m_main): New feature.
>>> >         (ARMv4, ARMv4t, ARMv5t, ARMv5te, ARMv5tej, ARMv6, ARMv6j, 
>>> ARMv6k,
>>> >         ARMv6z, ARMv6kz, ARMv6zk, ARMv6t2, ARMv6m, ARMv7, ARMv7a, 
>>> ARMv7ve,
>>> >         ARMv7r, ARMv7m, ARMv7em, ARMv8a, ARMv8_1a, ARMv8_2a, 
>>> ARMv8_3a,
>>> >         ARMv8_4a, ARMv8_5a, ARMv8m_base, ARMv8m_main, ARMv8r): 
>>> Reindent.
>>> >         (ARMv8_1m_main): New feature group.
>>> >         (armv8.1-m.main): New architecture.
>>> >         * config/arm/arm-tables.opt: Regenerate.
>>> >         * config/arm/arm.c (arm_arch8_1m_main): Define and default
>>> > initialize.
>>> >         (arm_option_reconfigure_globals): Initialize 
>>> arm_arch8_1m_main.
>>> >         (arm_options_perform_arch_sanity_checks): Error out when 
>>> targeting
>>> >         Armv8.1-M Mainline Security Extensions.
>>> >         * config/arm/arm.h (arm_arch8_1m_main): Declare.
>>> >
>>> > *** gcc/testsuite/ChangeLog ***
>>> >
>>> > 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>> > 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>> >
>>> >         * lib/target-supports.exp
>>> > (check_effective_target_arm_arch_v8_1m_main_ok): Define.
>>> >         (add_options_for_arm_arch_v8_1m_main): Likewise.
>>> > (check_effective_target_arm_arch_v8_1m_main_multilib): Likewise.
>>> >
>>> > Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; 
>>> testsuite
>>> > shows no regression.
>>> >
>>> > Is this ok for trunk?
>>> >
>>> Ok.
>>>
>>
>> Something that I remembered last night upon reflection...
>>
>> New command-line options (or arguments to them) need documentation in 
>> invoke.texi.
>>
>> Please add some either as part of this patch or as a separate patch 
>> if you prefer.
>>
> I've added the missing cli options in invoke.texi.
>
> Here's the updated ChangeLog:
>
> 2019-12-06  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
> 2019-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>     * config/arm/arm-cpus.in (armv8_1m_main): New feature.
>     (ARMv4, ARMv4t, ARMv5t, ARMv5te, ARMv5tej, ARMv6, ARMv6j, ARMv6k,
>     ARMv6z, ARMv6kz, ARMv6zk, ARMv6t2, ARMv6m, ARMv7, ARMv7a, ARMv7ve,
>     ARMv7r, ARMv7m, ARMv7em, ARMv8a, ARMv8_1a, ARMv8_2a, ARMv8_3a,
>     ARMv8_4a, ARMv8_5a, ARMv8m_base, ARMv8m_main, ARMv8r): Reindent.
>     (ARMv8_1m_main): New feature group.
>     (armv8.1-m.main): New architecture.
>     * config/arm/arm-tables.opt: Regenerate.
>     * config/arm/arm.c (arm_arch8_1m_main): Define and default 
> initialize.
>     (arm_option_reconfigure_globals): Initialize arm_arch8_1m_main.
>     (arm_options_perform_arch_sanity_checks): Error out when targeting
>     Armv8.1-M Mainline Security Extensions.
>     * config/arm/arm.h (arm_arch8_1m_main): Declare.
>     * doc/invoke.texi: Document armv8.1-m.main.
>
> *** gcc/testsuite/ChangeLog ***
>
> 2019-12-16  Mihail-Calin Ionescu  <mihail.ionescu@arm.com>
> 2019-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>     * lib/target-supports.exp
>     (check_effective_target_arm_arch_v8_1m_main_ok): Define.
>     (add_options_for_arm_arch_v8_1m_main): Likewise.
>     (check_effective_target_arm_arch_v8_1m_main_multilib): Likewise.
>
>
Thanks, this is ok.

Kyrill



> Regards,
> Mihail
>
>> Thanks,
>>
>> Kyrill
>>
>>
>>> Thanks,
>>>
>>> Kyrill
>>>
>>>
>>> > Best regards,
>>> >
>>> > Mihail
>>> >
>>> >
>>> > ###############     Attachment also inlined for ease of reply
>>> > ###############
>>> >
>>> >
>>> > diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
>>> > index
>>> > 
>>> f8a3b3db67a537163bfe787d78c8f2edc4253ab3..652f2a4be9388fd7a74f0ec4615a292fd1cfcd36 
>>>
>>> > 100644
>>> > --- a/gcc/config/arm/arm-cpus.in
>>> > +++ b/gcc/config/arm/arm-cpus.in
>>> > @@ -126,6 +126,9 @@ define feature armv8_5
>>> >  # M-Profile security extensions.
>>> >  define feature cmse
>>> >
>>> > +# Architecture rel 8.1-M.
>>> > +define feature armv8_1m_main
>>> > +
>>> >  # Floating point and Neon extensions.
>>> >  # VFPv1 is not supported in GCC.
>>> >
>>> > @@ -223,21 +226,21 @@ define fgroup ALL_FPU_INTERNAL vfpv2 vfpv3 
>>> vfpv4
>>> > fpv5 fp16conv fp_dbl ALL_SIMD_I
>>> >  # -mfpu support.
>>> >  define fgroup ALL_FP    fp16 ALL_FPU_INTERNAL
>>> >
>>> > -define fgroup ARMv4       armv4 notm
>>> > -define fgroup ARMv4t      ARMv4 thumb
>>> > -define fgroup ARMv5t      ARMv4t armv5t
>>> > -define fgroup ARMv5te     ARMv5t armv5te
>>> > -define fgroup ARMv5tej    ARMv5te
>>> > -define fgroup ARMv6       ARMv5te armv6 be8
>>> > -define fgroup ARMv6j      ARMv6
>>> > -define fgroup ARMv6k      ARMv6 armv6k
>>> > -define fgroup ARMv6z      ARMv6
>>> > -define fgroup ARMv6kz     ARMv6k quirk_armv6kz
>>> > -define fgroup ARMv6zk     ARMv6k
>>> > -define fgroup ARMv6t2     ARMv6 thumb2
>>> > +define fgroup ARMv4         armv4 notm
>>> > +define fgroup ARMv4t        ARMv4 thumb
>>> > +define fgroup ARMv5t        ARMv4t armv5t
>>> > +define fgroup ARMv5te       ARMv5t armv5te
>>> > +define fgroup ARMv5tej      ARMv5te
>>> > +define fgroup ARMv6         ARMv5te armv6 be8
>>> > +define fgroup ARMv6j        ARMv6
>>> > +define fgroup ARMv6k        ARMv6 armv6k
>>> > +define fgroup ARMv6z        ARMv6
>>> > +define fgroup ARMv6kz       ARMv6k quirk_armv6kz
>>> > +define fgroup ARMv6zk       ARMv6k
>>> > +define fgroup ARMv6t2       ARMv6 thumb2
>>> >  # This is suspect.  ARMv6-m doesn't really pull in any useful 
>>> features
>>> >  # from ARMv5* or ARMv6.
>>> > -define fgroup ARMv6m      armv4 thumb armv5t armv5te armv6 be8
>>> > +define fgroup ARMv6m        armv4 thumb armv5t armv5te armv6 be8
>>> >  # This is suspect, the 'common' ARMv7 subset excludes the thumb2
>>> > 'DSP' and
>>> >  # integer SIMD instructions that are in ARMv6T2.  */
>>> >  define fgroup ARMv7       ARMv6m thumb2 armv7
>>> > @@ -256,6 +259,10 @@ define fgroup ARMv8_5a    ARMv8_4a armv8_5 sb 
>>> predres
>>> >  define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
>>> >  define fgroup ARMv8m_main ARMv7m armv8 cmse
>>> >  define fgroup ARMv8r      ARMv8a
>>> > +# Feature cmse is omitted to disable Security Extensions support
>>> > while secure
>>> > +# code compiled by GCC does not preserve FP context as allowed by
>>> > Armv8.1-M
>>> > +# Mainline.
>>> > +define fgroup ARMv8_1m_main ARMv7m armv8 armv8_1m_main
>>> >
>>> >  # Useful combinations.
>>> >  define fgroup VFPv2     vfpv2
>>> > @@ -644,6 +651,17 @@ begin arch armv8-r
>>> >   option nofp remove ALL_FP
>>> >  end arch armv8-r
>>> >
>>> > +begin arch armv8.1-m.main
>>> > + tune for cortex-m7
>>> > + tune flags CO_PROC
>>> > + base 8M_MAIN
>>> > + isa ARMv8_1m_main
>>> > +# fp => FPv5-sp-d16; fp.dp => FPv5-d16
>>> > + option fp add FPv5 fp16
>>> > + option fp.dp add FPv5 FP_DBL fp16
>>> > + option nofp remove ALL_FP
>>> > +end arch armv8.1-m.main
>>> > +
>>> >  begin arch iwmmxt
>>> >   tune for iwmmxt
>>> >   tune flags LDSCHED STRONG XSCALE
>>> > diff --git a/gcc/config/arm/arm-tables.opt 
>>> b/gcc/config/arm/arm-tables.opt
>>> > index
>>> > 
>>> aeb5b3fbf629e5cfae4d5f6d4d5f1a9c7752a511..d059969904cb39fbe583487e4fbb23d4f9838718 
>>>
>>> > 100644
>>> > --- a/gcc/config/arm/arm-tables.opt
>>> > +++ b/gcc/config/arm/arm-tables.opt
>>> > @@ -353,10 +353,13 @@ EnumValue
>>> >  Enum(arm_arch) String(armv8-r) Value(28)
>>> >
>>> >  EnumValue
>>> > -Enum(arm_arch) String(iwmmxt) Value(29)
>>> > +Enum(arm_arch) String(armv8.1-m.main) Value(29)
>>> >
>>> >  EnumValue
>>> > -Enum(arm_arch) String(iwmmxt2) Value(30)
>>> > +Enum(arm_arch) String(iwmmxt) Value(30)
>>> > +
>>> > +EnumValue
>>> > +Enum(arm_arch) String(iwmmxt2) Value(31)
>>> >
>>> >  Enum
>>> >  Name(arm_fpu) Type(enum fpu_type)
>>> > diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
>>> > index
>>> > 
>>> 8b67c9c3657b312be223ab60c01969958baa9ed3..307f1b59ba4456c901c8cb842d9961a740b6bb8d 
>>>
>>> > 100644
>>> > --- a/gcc/config/arm/arm.h
>>> > +++ b/gcc/config/arm/arm.h
>>> > @@ -456,6 +456,10 @@ extern int arm_arch8_3;
>>> >  /* Nonzero if this chip supports the ARM Architecture 8.4 
>>> extensions.  */
>>> >  extern int arm_arch8_4;
>>> >
>>> > +/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
>>> > +   extensions.  */
>>> > +extern int arm_arch8_1m_main;
>>> > +
>>> >  /* Nonzero if this chip supports the FP16 instructions extension 
>>> of ARM
>>> >     Architecture 8.2.  */
>>> >  extern int arm_fp16_inst;
>>> > diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>> > index
>>> > 
>>> 9f0975dc0710626ef46abecaa3a205e993821118..9aca9484a9cdc26d6afee25e81f06b4047df2174 
>>>
>>> > 100644
>>> > --- a/gcc/config/arm/arm.c
>>> > +++ b/gcc/config/arm/arm.c
>>> > @@ -903,6 +903,9 @@ int arm_arch8_3 = 0;
>>> >
>>> >  /* Nonzero if this chip supports the ARM Architecture 8.4 
>>> extensions.  */
>>> >  int arm_arch8_4 = 0;
>>> > +/* Nonzero if this chip supports the ARM Architecture 8.1-M Mainline
>>> > +   extensions.  */
>>> > +int arm_arch8_1m_main = 0;
>>> >
>>> >  /* Nonzero if this chip supports the FP16 instructions extension 
>>> of ARM
>>> >     Architecture 8.2.  */
>>> > @@ -3642,6 +3645,8 @@ arm_option_reconfigure_globals (void)
>>> >    arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, 
>>> isa_bit_armv8_2);
>>> >    arm_arch8_3 = bitmap_bit_p (arm_active_target.isa, 
>>> isa_bit_armv8_3);
>>> >    arm_arch8_4 = bitmap_bit_p (arm_active_target.isa, 
>>> isa_bit_armv8_4);
>>> > +  arm_arch8_1m_main = bitmap_bit_p (arm_active_target.isa,
>>> > + isa_bit_armv8_1m_main);
>>> >    arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, 
>>> isa_bit_thumb);
>>> >    arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, 
>>> isa_bit_thumb2);
>>> >    arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, 
>>> isa_bit_xscale);
>>> > @@ -3727,6 +3732,9 @@ arm_options_perform_arch_sanity_checks (void)
>>> >    if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
>>> >      sorry ("__fp16 and no ldrh");
>>> >
>>> > +  if (use_cmse && arm_arch8_1m_main)
>>> > +    error ("ARMv8.1-M Mainline Security Extensions are 
>>> unsupported");
>>> > +
>>> >    if (use_cmse && !arm_arch_cmse)
>>> >      error ("target CPU does not support ARMv8-M Security 
>>> Extensions");
>>> >
>>> > diff --git a/gcc/testsuite/lib/target-supports.exp
>>> > b/gcc/testsuite/lib/target-supports.exp
>>> > index
>>> > 
>>> 6a1aaca9691b7fe9ae5e0e5b1874c7af34a3a6e3..5688aa7a6b7e8dad28aa553755b657464071a982 
>>>
>>> > 100644
>>> > --- a/gcc/testsuite/lib/target-supports.exp
>>> > +++ b/gcc/testsuite/lib/target-supports.exp
>>> > @@ -4242,10 +4242,11 @@ foreach { armfunc armflag armdefs } {
>>> >          v8a "-march=armv8-a" __ARM_ARCH_8A__
>>> >          v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
>>> >          v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
>>> > +       v8r "-march=armv8-r" __ARM_ARCH_8R__
>>> >          v8m_base "-march=armv8-m.base -mthumb -mfloat-abi=soft"
>>> >                  __ARM_ARCH_8M_BASE__
>>> >          v8m_main "-march=armv8-m.main -mthumb" __ARM_ARCH_8M_MAIN__
>>> > -       v8r "-march=armv8-r" __ARM_ARCH_8R__ } {
>>> > +       v8_1m_main "-march=armv8.1-m.main -mthumb"
>>> > __ARM_ARCH_8M_MAIN__ } {
>>> >      eval [string map [list FUNC $armfunc FLAG $armflag DEFS 
>>> $armdefs ] {
>>> >          proc check_effective_target_arm_arch_FUNC_ok { } {
>>> >              return [check_no_compiler_messages arm_arch_FUNC_ok
>>> > assembly {
>>> >

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions
  2019-12-16 18:30     ` Mihail Ionescu
@ 2019-12-17 10:26       ` Kyrill Tkachov
  0 siblings, 0 replies; 35+ messages in thread
From: Kyrill Tkachov @ 2019-12-17 10:26 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 12/16/19 6:29 PM, Mihail Ionescu wrote:
>
> Hi Kyrill,
>
> On 11/06/2019 04:12 PM, Kyrill Tkachov wrote:
>> Hi Mihail,
>>
>> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>>> [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions
>>>
>>> Hi,
>>>
>>> === Context ===
>>>
>>> This patch is part of a patch series to add support for Armv8.1-M
>>> Mainline Security Extensions architecture. Its purpose is to enable
>>> saving/restoring of nonsecure FP context in function with the
>>> cmse_nonsecure_entry attribute.
>>>
>>> === Motivation ===
>>>
>>> In Armv8-M Baseline and Mainline, the FP context is cleared on 
>>> return from
>>> nonsecure entry functions. This means the FP context might change when
>>> calling a nonsecure entry function. This patch uses the new VLDR and
>>> VSTR instructions available in Armv8.1-M Mainline to save/restore 
>>> the FP
>>> context when calling a nonsecure entry functionfrom nonsecure code.
>>>
>>> === Patch description ===
>>>
>>> This patch consists mainly of creating 2 new instruction patterns to
>>> push and pop special FP registers via vldm and vstr and using them in
>>> prologue and epilogue. The patterns are defined as push/pop with an
>>> unspecified operation on the memory accessed, with an unspecified
>>> constant indicating what special FP register is being saved/restored.
>>>
>>> Other aspects of the patch include:
>>>   * defining the set of special registers that can be saved/restored 
>>> and
>>>     their name
>>>   * reserving space in the stack frames for these push/pop
>>>   * preventing return via pop
>>>   * guarding the clearing of FPSCR to target architecture not having
>>>     Armv8.1-M Mainline instructions.
>>>
>>> ChangeLog entry is as follows:
>>>
>>> *** gcc/ChangeLog ***
>>>
>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>
>>>         * config/arm/arm.c (fp_sysreg_names): Declare and define.
>>>         (use_return_insn): Also return false for Armv8.1-M Mainline.
>>>         (output_return_instruction): Skip FPSCR clearing if Armv8.1-M
>>>         Mainline instructions are available.
>>>         (arm_compute_frame_layout): Allocate space in frame for FPCXTNS
>>>         when targeting Armv8.1-M Mainline Security Extensions.
>>>         (arm_expand_prologue): Save FPCXTNS if this is an Armv8.1-M
>>>         Mainline entry function.
>>>         (cmse_nonsecure_entry_clear_before_return): Clear IP and r4 if
>>>         targeting Armv8.1-M Mainline or successor.
>>>         (arm_expand_epilogue): Fix indentation of caller-saved register
>>>         clearing.  Restore FPCXTNS if this is an Armv8.1-M Mainline
>>>         entry function.
>>>         * config/arm/arm.h (TARGET_HAVE_FP_CMSE): New macro.
>>>         (FP_SYSREGS): Likewise.
>>>         (enum vfp_sysregs_encoding): Define enum.
>>>         (fp_sysreg_names): Declare.
>>>         * config/arm/unspecs.md (VUNSPEC_VSTR_VLDR): New volatile 
>>> unspec.
>>>         * config/arm/vfp.md (push_fpsysreg_insn): New define_insn.
>>>         (pop_fpsysreg_insn): Likewise.
>>>
>>> *** gcc/testsuite/Changelog ***
>>>
>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>
>>>         * gcc.target/arm/cmse/bitfield-1.c: add checks for VSTR and 
>>> VLDR.
>>>         * gcc.target/arm/cmse/bitfield-2.c: Likewise.
>>>         * gcc.target/arm/cmse/bitfield-3.c: Likewise.
>>>         * gcc.target/arm/cmse/cmse-1.c: Likewise.
>>>         * gcc.target/arm/cmse/struct-1.c: Likewise.
>>>         * gcc.target/arm/cmse/cmse.exp: Run existing Armv8-M 
>>> Mainline tests
>>>         from mainline/8m subdirectory and new Armv8.1-M Mainline 
>>> tests from
>>>         mainline/8_1m subdirectory.
>>>         * gcc.target/arm/cmse/mainline/bitfield-4.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/bitfield-4.c: This.
>>>         * gcc.target/arm/cmse/mainline/bitfield-5.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/bitfield-5.c: This.
>>>         * gcc.target/arm/cmse/mainline/bitfield-6.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/bitfield-6.c: This.
>>>         * gcc.target/arm/cmse/mainline/bitfield-7.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/bitfield-7.c: This.
>>>         * gcc.target/arm/cmse/mainline/bitfield-8.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/bitfield-8.c: This.
>>>         * gcc.target/arm/cmse/mainline/bitfield-9.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/bitfield-9.c: This.
>>>         * gcc.target/arm/cmse/mainline/bitfield-and-union-1.c: Move 
>>> and rename
>>>         into ...
>>>         * gcc.target/arm/cmse/mainline/8m/bitfield-and-union.c: This.
>>>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-13.c: This. 
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-5.c: This. 
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-7.c: This. 
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/hard-sp/cmse-8.c: This. 
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/hard/cmse-13.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-13.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/hard/cmse-5.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-5.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/hard/cmse-7.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-7.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/hard/cmse-8.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/hard/cmse-8.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/soft/cmse-13.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-13.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/soft/cmse-5.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-5.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/soft/cmse-7.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-7.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/soft/cmse-8.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/soft/cmse-8.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: Move into 
>>> ...
>>>         * gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-5.c: This. 
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: Move into 
>>> ...
>>>         * gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-7.c: This. 
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: Move into 
>>> ...
>>>         * gcc.target/arm/cmse/mainline/8m/softfp-sp/cmse-8.c: This. 
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/softfp/cmse-13.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c: This. 
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-5.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/softfp/cmse-7.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-7.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/softfp/cmse-8.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/softfp/cmse-8.c: This.  
>>> Clean up
>>>         dg-skip-if directive for float ABI.
>>>         * gcc.target/arm/cmse/mainline/union-1.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/union-1.c: This.
>>>         * gcc.target/arm/cmse/mainline/union-2.c: Move into ...
>>>         * gcc.target/arm/cmse/mainline/8m/union-2.c: This.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: 
>>> New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: New 
>>> file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: New 
>>> file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: New 
>>> file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: New 
>>> file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: New file.
>>>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: New file.
>>>         * lib/target-supports.exp 
>>> (check_effective_target_arm_cmse_clear_ok):
>>>         New procedure.
>>>
>>> Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; 
>>> testsuite shows no
>>> regression.
>>>
>>> Is this ok for trunk?
>>>
>> <snip>
>>
>> +(define_insn "push_fpsysreg_insn"
>> +  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
>> +    (plus:SI (match_dup 0) (const_int -4)))
>> +   (unspec_volatile [(match_operand:SI 1 "const_int_operand" "n")
>> +             (mem:SI (plus:SI (match_dup 0) (const_int -4)))]
>> +            VUNSPEC_VSTR_VLDR)]
>> +  "TARGET_HAVE_FPCXT_CMSE && use_cmse"
>> +  {
>> +    static char buf[32];
>> +    int fp_sysreg_enum = INTVAL (operands[1]);
>> +
>> +    gcc_assert (IN_RANGE (fp_sysreg_enum, 0, NB_FP_SYSREGS - 1));
>> +
>> +    snprintf (buf, sizeof (buf), \"vstr%%?\\t%s, [%%0, #-4]!\",
>> +          fp_sysreg_names[fp_sysreg_enum]);
>> +    return buf;
>> +  }
>> +  [(set_attr "predicable" "yes")
>> +   (set_attr "type" "store_4")]
>> +)
>>
>> I'm a bit concerned by the RTL representation here. This is a memory 
>> store instruction but the MEM operand is just part of an UNSPEC.
>>
>> Wouldn't this be more conveniently represented as a SET of a MEM to 
>> an unspec_volatile value where the address of the MEM uses a POST_INC 
>> addressing mode?
>>
>>
>> +
>> +(define_insn "pop_fpsysreg_insn"
>> +  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
>> +    (plus:SI (match_dup 0) (const_int 4)))
>> +   (unspec_volatile:SI [(match_operand:SI 1 "const_int_operand" "n")
>> +            (mem:SI (match_dup 0))]
>> +               VUNSPEC_VSTR_VLDR)]
>> +  "TARGET_HAVE_FPCXT_CMSE && use_cmse"
>> +  {
>> +    static char buf[32];
>> +    int fp_sysreg_enum = INTVAL (operands[1]);
>> +
>> +    gcc_assert (IN_RANGE (fp_sysreg_enum, 0, NB_FP_SYSREGS - 1));
>> +
>> +    snprintf (buf, sizeof (buf), \"vldr%%?\\t%s, [%%0], #4\",
>> +          fp_sysreg_names[fp_sysreg_enum]);
>> +    return buf;
>> +  }
>> +  [(set_attr "predicable" "yes")
>> +   (set_attr "type" "load_4")]
>> +)
>>
>>
>> Similarly here, can't we use one of the addressing modes that 
>> describe the address update?
>>
>
> I've updated the two unspec patterns to represent the operation more 
> accurately.
>
Ok.

Thanks,

Kyrill



> Regards,
> Mihail
>
>> Thanks,
>>
>> Kyrill
>>
>>
>>> Best regards,
>>>
>>> Mihail

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
  2019-12-16 19:16     ` Mihail Ionescu
@ 2019-12-17 10:27       ` Kyrill Tkachov
  2019-12-18 13:29         ` Mihail Ionescu
  0 siblings, 1 reply; 35+ messages in thread
From: Kyrill Tkachov @ 2019-12-17 10:27 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw

Hi Mihail,

On 12/16/19 6:29 PM, Mihail Ionescu wrote:
> Hi Kyrill,
>
> On 11/12/2019 09:55 AM, Kyrill Tkachov wrote:
>> Hi Mihail,
>>
>> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>>> [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
>>>
>>> Hi,
>>>
>>> === Context ===
>>>
>>> This patch is part of a patch series to add support for Armv8.1-M
>>> Mainline Security Extensions architecture. Its purpose is to improve
>>> code density of functions with the cmse_nonsecure_entry attribute and
>>> when calling function with the cmse_nonsecure_call attribute by using
>>> CLRM to do all the general purpose registers clearing as well as
>>> clearing the APSR register.
>>>
>>> === Patch description ===
>>>
>>> This patch adds a new pattern for the CLRM instruction and guards the
>>> current clearing code in output_return_instruction() and thumb_exit()
>>> on Armv8.1-M Mainline instructions not being present.
>>> cmse_clear_registers () is then modified to use the new CLRM 
>>> instruction
>>> when targeting Armv8.1-M Mainline while keeping Armv8-M register
>>> clearing code for VFP registers.
>>>
>>> For the CLRM instruction, which does not mandated APSR in the register
>>> list, checking whether it is the right volatile unspec or a clearing
>>> register is done in clear_operation_p.
>>>
>>> Note that load/store multiple were deemed sufficiently different in
>>> terms of RTX structure compared to the CLRM pattern for a different
>>> function to be used to validate the match_parallel.
>>>
>>> ChangeLog entries are as follows:
>>>
>>> *** gcc/ChangeLog ***
>>>
>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>
>>>         * config/arm/arm-protos.h (clear_operation_p): Declare.
>>>         * config/arm/arm.c (clear_operation_p): New function.
>>>         (cmse_clear_registers): Generate clear_multiple instruction 
>>> pattern if
>>>         targeting Armv8.1-M Mainline or successor.
>>>         (output_return_instruction): Only output APSR register 
>>> clearing if
>>>         Armv8.1-M Mainline instructions not available.
>>>         (thumb_exit): Likewise.
>>>         * config/arm/predicates.md (clear_multiple_operation): New 
>>> predicate.
>>>         * config/arm/thumb2.md (clear_apsr): New define_insn.
>>>         (clear_multiple): Likewise.
>>>         * config/arm/unspecs.md (VUNSPEC_CLRM_APSR): New volatile 
>>> unspec.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>>
>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>
>>>         * gcc.target/arm/cmse/bitfield-1.c: Add check for CLRM.
>>>         * gcc.target/arm/cmse/bitfield-2.c: Likewise.
>>>         * gcc.target/arm/cmse/bitfield-3.c: Likewise.
>>>         * gcc.target/arm/cmse/struct-1.c: Likewise.
>>>         * gcc.target/arm/cmse/cmse-14.c: Likewise.
>>>         * gcc.target/arm/cmse/cmse-1.c: Likewise.  Restrict checks 
>>> for Armv8-M
>>>         GPR clearing when CLRM is not available.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: 
>>> Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: 
>>> Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: 
>>> Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: 
>>> Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.
>>>
>>> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
>>> regression.
>>>
>>> Is this ok for trunk?
>>>
>>> Best regards,
>>>
>>> Mihail
>>>
>>>
>>> ###############     Attachment also inlined for ease of reply 
>>> ###############
>>>
>>>
>>> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
>>> index 
>>> f995974f9bb89ab3c7ff0888c394b0dfaf7da60c..1a948d2c97526ad7e67e8d4a610ac74cfdb13882 
>>> 100644
>>> --- a/gcc/config/arm/arm-protos.h
>>> +++ b/gcc/config/arm/arm-protos.h
>>> @@ -77,6 +77,7 @@ extern int thumb_legitimate_offset_p 
>>> (machine_mode, HOST_WIDE_INT);
>>>  extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
>>>  extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
>>>                                   bool, bool);
>>> +extern bool clear_operation_p (rtx);
>>>  extern int arm_const_double_rtx (rtx);
>>>  extern int vfp3_const_double_rtx (rtx);
>>>  extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, 
>>> int *);
>>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>> index 
>>> d485e80096c9d2eef2172d211a0a5ab63cdbb3c7..3a373cea33c3d0b966cbe700d26f66fe069e1efb 
>>> 100644
>>> --- a/gcc/config/arm/arm.c
>>> +++ b/gcc/config/arm/arm.c
>>> @@ -13499,6 +13499,66 @@ ldm_stm_operation_p (rtx op, bool load, 
>>> machine_mode mode,
>>>    return true;
>>>  }
>>>
>>> +/* Checks whether OP is a valid parallel pattern for a CLRM insn.  
>>> To be a
>>> +   valid CLRM pattern, OP must have the following form:
>>> +
>>> +   [(set (reg:SI <N>) (const_int 0))
>>> +    (set (reg:SI <M>) (const_int 0))
>>> +    ...
>>> +    (unspec_volatile [(const_int 0)]
>>> +                    VUNSPEC_CLRM_APSR)
>>> +   ]
>>
>>
>> If this clears the whole APSR than it also clobbers the condition 
>> flags, right?
>>
>> Then it should also have a  (clobber (reg:CC CC_REGNUM)) in there.
>> Yes -- it should also clobber the condition flags, thanks for catching 
> this. I've updated the patch to include the CC clobbering.
>
> Regards,
> Mihail
>>
>>> +
>>> +   Any number (including 0) of set expressions is valid, the 
>>> volatile unspec is
>>> +   optional.  All registers but SP and PC are allowed and registers 
>>> must be in
>>> +   strict increasing order.  */
>>> +
>>> +bool
>>> +clear_operation_p (rtx op)
>>> +{
>>> +  HOST_WIDE_INT i;
>>> +  unsigned regno, last_regno;
>>> +  rtx elt, reg, zero;
>>> +  machine_mode mode;
>>> +  HOST_WIDE_INT count = XVECLEN (op, 0);
>>> +
>>> +  for (i = 0; i < count; i++)
>>> +    {
>>> +      elt = XVECEXP (op, 0, i);
>>> +
>>> +      if (GET_CODE (elt) == UNSPEC_VOLATILE)
>>> +       {
>>> +         if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
>>> +             || XVECLEN (elt, 0) != 1
>>> +             || XVECEXP (elt, 0, 0) != CONST0_RTX (SImode)
>>> +             || i != count - 1)
>>> +           return false;
>>> +
>>> +         continue;
>>> +       }
>>> +
>>> +      if (GET_CODE (elt) != SET)
>>> +       return false;
>>> +
>>> +      reg = SET_DEST (elt);
>>> +      regno = REGNO (reg);
>>> +      mode = GET_MODE (reg);
>>> +      zero = SET_SRC (elt);
>>> +
>>> +      if (!REG_P (reg)
>>> +         || GET_MODE (reg) != SImode
>>> +         || regno == SP_REGNUM
>>> +         || regno == PC_REGNUM
>>> +         || (i != 0 && regno <= last_regno)
>>> +         || zero != CONST0_RTX (SImode))
>>> +       return false;
>>> +
>>> +      last_regno = REGNO (reg);
>>> +    }
>>> +
>>> +  return true;
>>> +}
>>> +
>>>  /* Return true iff it would be profitable to turn a sequence of 
>>> NOPS loads
>>>     or stores (depending on IS_STORE) into a load-multiple or 
>>> store-multiple
>>>     instruction.  ADD_OFFSET is nonzero if the base address register 
>>> needs
>>> @@ -17596,6 +17656,56 @@ cmse_clear_registers (sbitmap 
>>> to_clear_bitmap, uint32_t *padding_bits_to_clear,
>>>
>>>    /* Clear full registers.  */
>>>
>>> +  if (TARGET_HAVE_FPCXT_CMSE)
>>> +    {
>>> +      rtvec vunspec_vec;
>>> +      int i, j, k, nb_regs;
>>> +      rtx use_seq, par, reg, set, vunspec;
>>> +      int to_clear_bitmap_size = SBITMAP_SIZE (to_clear_bitmap);
>>> +      auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
>>> +      auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
>>> +
>>> +      /* Get set of core registers to clear.  */
>>> +      bitmap_clear (core_regs_bitmap);
>>> +      bitmap_set_range (core_regs_bitmap, R0_REGNUM,
>>> +                       IP_REGNUM - R0_REGNUM + 1);
>>> +      bitmap_and (to_clear_core_bitmap, to_clear_bitmap,
>>> +                 core_regs_bitmap);
>>> +      gcc_assert (!bitmap_empty_p (to_clear_core_bitmap));
>>> +
>>> +      if (bitmap_empty_p (to_clear_core_bitmap))
>>> +       return;
>>> +
>>> +      /* Create clrm RTX pattern.  */
>>> +      nb_regs = bitmap_count_bits (to_clear_core_bitmap);
>>> +      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 1));
>>> +
>>> +      /* Insert core register clearing RTX in the pattern. */
>>> +      start_sequence ();
>>> +      for (j = 0, i = minregno; j < nb_regs; i++)
>>> +       {
>>> +         if (!bitmap_bit_p (to_clear_core_bitmap, i))
>>> +           continue;
>>> +
>>> +         reg = gen_rtx_REG (SImode, i);
>>> +         set = gen_rtx_SET (reg, const0_rtx);
>>> +         XVECEXP (par, 0, j++) = set;
>>> +         emit_use (reg);
>>> +       }
>>> +
>>> +      /* Insert APSR register clearing RTX in the pattern. */
>>> +      vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
>>> +      vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
>>> +                                        VUNSPEC_CLRM_APSR);
>>> +      XVECEXP (par, 0, j) = vunspec;
>>> +
>>> +      use_seq = get_insns ();
>>> +      end_sequence ();
>>> +
>>> +      emit_insn_after (use_seq, emit_insn (par));
>>> +      minregno = FIRST_VFP_REGNUM;
>>> +    }
>>> +
>>>    /* If not marked for clearing, clearing_reg already does not contain
>>>       any secret.  */
>>>    if (clearing_regno <= maxregno
>>> @@ -20259,40 +20369,50 @@ output_return_instruction (rtx operand, 
>>> bool really_return, bool reverse,
>>>          default:
>>>            if (IS_CMSE_ENTRY (func_type))
>>>              {
>>> -             /* Check if we have to clear the 'GE bits' which is 
>>> only used if
>>> -                parallel add and subtraction instructions are 
>>> available.  */
>>> -             if (TARGET_INT_SIMD)
>>> -               snprintf (instr, sizeof (instr),
>>> -                         "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
>>> -             else
>>> -               snprintf (instr, sizeof (instr),
>>> -                         "msr%s\tAPSR_nzcvq, %%|lr", conditional);
>>> -
>>> -             output_asm_insn (instr, & operand);
>>> -             /* Do not clear FPSCR if targeting Armv8.1-M Mainline, 
>>> VLDR takes
>>> -                care of it.  */
>>> -             if (TARGET_HARD_FLOAT && ! TARGET_HAVE_FPCXT_CMSE)
>>> +             /* For Armv8.1-M, this is cleared as part of the CLRM 
>>> instruction
>>> +                emitted by cmse_nonsecure_entry_clear_before_return 
>>> () and the
>>> +                VSTR/VLDR instructions in the prologue and 
>>> epilogue.  */
>>> +             if (!TARGET_HAVE_FPCXT_CMSE)
>>>                  {
>>> -                 /* Clear the cumulative exception-status bits 
>>> (0-4,7) and the
>>> -                    condition code bits (28-31) of the FPSCR.  We 
>>> need to
>>> -                    remember to clear the first scratch register 
>>> used (IP) and
>>> -                    save and restore the second (r4).  */
>>> -                 snprintf (instr, sizeof (instr), "push\t{%%|r4}");
>>> -                 output_asm_insn (instr, & operand);
>>> -                 snprintf (instr, sizeof (instr), "vmrs\t%%|ip, 
>>> fpscr");
>>> -                 output_asm_insn (instr, & operand);
>>> -                 snprintf (instr, sizeof (instr), "movw\t%%|r4, 
>>> #65376");
>>> -                 output_asm_insn (instr, & operand);
>>> -                 snprintf (instr, sizeof (instr), "movt\t%%|r4, 
>>> #4095");
>>> -                 output_asm_insn (instr, & operand);
>>> -                 snprintf (instr, sizeof (instr), "and\t%%|ip, 
>>> %%|r4");
>>> -                 output_asm_insn (instr, & operand);
>>> -                 snprintf (instr, sizeof (instr), "vmsr\tfpscr, 
>>> %%|ip");
>>> -                 output_asm_insn (instr, & operand);
>>> -                 snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
>>> -                 output_asm_insn (instr, & operand);
>>> -                 snprintf (instr, sizeof (instr), "mov\t%%|ip, 
>>> %%|lr");
>>> +                 /* Check if we have to clear the 'GE bits' which 
>>> is only used if
>>> +                    parallel add and subtraction instructions are 
>>> available.  */
>>> +                 if (TARGET_INT_SIMD)
>>> +                   snprintf (instr, sizeof (instr),
>>> +                             "msr%s\tAPSR_nzcvqg, %%|lr", 
>>> conditional);
>>> +                 else
>>> +                   snprintf (instr, sizeof (instr),
>>> +                             "msr%s\tAPSR_nzcvq, %%|lr", conditional);
>>> +
>>>                    output_asm_insn (instr, & operand);
>>> +                 /* Do not clear FPSCR if targeting Armv8.1-M 
>>> Mainline, VLDR takes
>>> +                    care of it.  */
>>> +                 if (TARGET_HARD_FLOAT)
>>> +                   {
>>> +                     /* Clear the cumulative exception-status bits 
>>> (0-4,7) and
>>> +                        the condition code bits (28-31) of the 
>>> FPSCR.  We need
>>> +                        to remember to clear the first scratch 
>>> register used
>>> +                        (IP) and save and restore the second (r4).
>>> +
>>> +                        Important note: the length of the
>>> +                        thumb2_cmse_entry_return insn pattern must 
>>> account for
>>> +                        the size of the below instructions. */
>>> +                     snprintf (instr, sizeof (instr), 
>>> "push\t{%%|r4}");
>>> +                     output_asm_insn (instr, & operand);
>>
>>
>> I know this is pre-existing in this function, but I think we should 
>> just use output_asm_insn directly here:
>> output_asm_insn ("push\t{%%|r4}", & operand);
>>
>> and avoid all the snprintfs.
>>
>>
>>> +                     snprintf (instr, sizeof (instr), "vmrs\t%%|ip, 
>>> fpscr");
>>> +                     output_asm_insn (instr, & operand);
>>> +                     snprintf (instr, sizeof (instr), "movw\t%%|r4, 
>>> #65376");
>>> +                     output_asm_insn (instr, & operand);
>>> +                     snprintf (instr, sizeof (instr), "movt\t%%|r4, 
>>> #4095");
>>> +                     output_asm_insn (instr, & operand);
>>> +                     snprintf (instr, sizeof (instr), "and\t%%|ip, 
>>> %%|r4");
>>> +                     output_asm_insn (instr, & operand);
>>> +                     snprintf (instr, sizeof (instr), "vmsr\tfpscr, 
>>> %%|ip");
>>> +                     output_asm_insn (instr, & operand);
>>> +                     snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
>>> +                     output_asm_insn (instr, & operand);
>>> +                     snprintf (instr, sizeof (instr), "mov\t%%|ip, 
>>> %%|lr");
>>> +                     output_asm_insn (instr, & operand);
>>> +                   }
>>>                  }
>>>                snprintf (instr, sizeof (instr), "bxns\t%%|lr");
>>>              }
>>> @@ -24690,8 +24810,11 @@ thumb_exit (FILE *f, int 
>>> reg_containing_return_addr)
>>>
>>>        if (IS_CMSE_ENTRY (arm_current_func_type ()))
>>>          {
>>> -         asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
>>> -                      reg_containing_return_addr);
>>> +         /* For Armv8.1-M, this is cleared as part of the CLRM 
>>> instruction
>>> +            emitted by cmse_nonsecure_entry_clear_before_return 
>>> ().  */
>>> +         if (!TARGET_HAVE_FPCXT_CMSE)
>>> +           asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
>>> +                        reg_containing_return_addr);
>>>            asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
>>>          }
>>>        else
>>> @@ -24931,11 +25054,14 @@ thumb_exit (FILE *f, int 
>>> reg_containing_return_addr)
>>>           address.  It may therefore contain information that we 
>>> might not want
>>>           to leak, hence it must be cleared.  The value in R0 will 
>>> never be a
>>>           secret at this point, so it is safe to use it, see the 
>>> clearing code
>>> -        in 'cmse_nonsecure_entry_clear_before_return'.  */
>>> +        in cmse_nonsecure_entry_clear_before_return ().  */
>>>        if (reg_containing_return_addr != LR_REGNUM)
>>>          asm_fprintf (f, "\tmov\tlr, r0\n");
>>>
>>> -      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
>>> reg_containing_return_addr);
>>> +      /* For Armv8.1-M, this is cleared as part of the CLRM 
>>> instruction emitted
>>> +        by cmse_nonsecure_entry_clear_before_return ().  */
>>> +      if (!TARGET_HAVE_FPCXT_CMSE)
>>> +       asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
>>> reg_containing_return_addr);
>>>        asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
>>>      }
>>>    else
>>> diff --git a/gcc/config/arm/predicates.md 
>>> b/gcc/config/arm/predicates.md
>>> index 
>>> 8b36e7ee462235ad26e132f1ccf98d28c2487d67..e5c583ef3d167194e7a061d7c3e98d3b4bb5269c 
>>> 100644
>>> --- a/gcc/config/arm/predicates.md
>>> +++ b/gcc/config/arm/predicates.md
>>> @@ -510,6 +510,12 @@
>>>              (match_test "satisfies_constraint_Dy (op)")
>>>              (match_test "satisfies_constraint_G (op)"))))
>>>
>>> +(define_special_predicate "clear_multiple_operation"
>>> +  (match_code "parallel")
>>> +{
>>> + return clear_operation_p (op);
>>> +})
>>> +
>>>  (define_special_predicate "load_multiple_operation"
>>>    (match_code "parallel")
>>>  {
>>> diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
>>> index 
>>> 6ccc875e2b4e7b8ce256e52da966dfe220c6f5d6..9994c0d59f741ef47d0ec43dd53a2324b031d048 
>>> 100644
>>> --- a/gcc/config/arm/thumb2.md
>>> +++ b/gcc/config/arm/thumb2.md
>>> @@ -1599,3 +1599,39 @@
>>>        FAIL;
>>>   }")
>>>
>>> +(define_insn "*clear_apsr"
>>> +  [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)]
>>> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
>>> +  "clrm%?\\t{APSR}"
>>> +  [(set_attr "predicable" "yes")]
>>> +)
>>
>>
>> Similar to earlier, if this clears the whole APSR then it should also 
>> represent a clobber of the CC reg.
>>
>>
>>> +
>>> +;; The operands are validated through the clear_multiple_operation
>>> +;; match_parallel predicate rather than through constraints so 
>>> enable it only
>>> +;; after reload.
>>> +(define_insn "*clear_multiple"
>>> +  [(match_parallel 0 "clear_multiple_operation"
>>> +     [(set (match_operand:SI 1 "register_operand" "")
>>> +          (const_int 0))])]
>>> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && 
>>> reload_completed"
>>> +  {
>>> +    char pattern[100];
>>> +    int i, num_saves = XVECLEN (operands[0], 0);
>>> +
>>> +    strcpy (pattern, \"clrm%?\\t{\");
>>> +    for (i = 0; i < num_saves; i++)
>>> +      {
>>> +       if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
>>> +         strcat (pattern, \"APSR\");
>>> +       else
>>> +         strcat (pattern,
>>> +                 reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, 
>>> i), 0))]);
>>> +       if (i < num_saves - 1)
>>> +         strcat (pattern, \", %|\");
>>> +      }
>>> +    strcat (pattern, \"}\");
>>> +    output_asm_insn (pattern, operands);
>>> +    return \"\";
>>> +  }
>>> +  [(set_attr "predicable" "yes")]
>>> +)
>>> diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
>>> index 
>>> 324359be7127f04a80ebc0079ad0a9964dfd82a7..498bc0798dbaaa3ee73815ba27864ae92a2fd08e 
>>> 100644
>>> --- a/gcc/config/arm/unspecs.md
>>> +++ b/gcc/config/arm/unspecs.md
>>> @@ -174,6 +174,7 @@
>>>    VUNSPEC_MRRC2                ; Represent the coprocessor mrrc2 
>>> instruction.
>>>    VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional 
>>> speculation barrier.
>>>    VUNSPEC_VSTR_VLDR    ; Represent the vstr/vldr instruction.
>>> +  VUNSPEC_CLRM_APSR    ; Represent the clearing of APSR with clrm 
>>> instruction.
>>>  ])
>>>
>>>  ;; Enumerators for NEON unspecs.
>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>>> index 
>>> 6d611e130b6f3b544807b767927d99b89071343b..7036cb9508c27d56c4b2c01a81c44bf6f1f9c781 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>>> @@ -36,6 +36,7 @@ main (void)
>>>  /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
>>>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>
>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>>> index 
>>> b7ec0a040319545b50590261278f1517bcb22796..50d4979470dd21738453e0d70c7a69ee0752ac41 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>>> @@ -33,6 +33,7 @@ main (void)
>>>  /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
>>>  /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>
>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>>> index 
>>> 7b9c3f0fe061317f71d3122dea7a55ab5311f234..2b7507c900ab18705083ba1d86359e1ae36a50a2 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>>> @@ -34,5 +34,6 @@ main (void)
>>>  /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
>>>  /* { dg-final { scan-assembler "movt\tr1, 63" } } */
>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "bxns" } } */
>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>> index 
>>> aa0ec8e0b0f0953a5a5cbc2db58413176c2505f3..35cab1f3233daac9fba50d25dac23364c798fb9c 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>> @@ -105,8 +105,10 @@ qux (int_nsfunc_t * callback)
>>>  /* { dg-final { scan-assembler "bic" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { 
>>> target arm_cmse_clear_ok } } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>> target arm_cmse_clear_ok } } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
>>> +/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
>>> arm_cmse_clear_ok } } } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
>>> target arm_cmse_clear_ok } } } */
>>>
>>>  int call_callback (void)
>>>  {
>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>> index 
>>> df1ea52bec533c36a738d7d3b2b2ff749b0f3713..1f5af7c2dba7747f6058d12af8ef80b4dd1b1431 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>> @@ -9,5 +9,6 @@ int foo (void)
>>>    return bar ();
>>>  }
>>>
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>  /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } 
>>> } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>> index 
>>> 62c63b888ab49e99fba0a08b69941e73c9a8d33b..c52e1c14d9956743625e3b8a200e823f163924e3 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>> @@ -12,5 +12,5 @@
>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>> index 
>>> b718a70522b86e2bc58900681a781129543f8869..fdba955a32fc5ad492b74974185f98470bc49a7e 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>> @@ -10,6 +10,5 @@
>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>> index 
>>> 16536ab4f9ec5782463ab90f404a2e9f6f938850..85068ceaac6a5c0c60af4a54c0af0d20326fc18d 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>> @@ -13,5 +13,5 @@
>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>> index 
>>> 0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5..af69d38acf47d9d1d55480edba2b66f07e2d06ad 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>> @@ -10,6 +10,5 @@
>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>> index 
>>> 914ea39626f2f72eac8c9c1cb495b0855e58f5e1..62201595549f07b046c7c5972d612ab155c4c38c 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>> @@ -13,5 +13,5 @@
>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>> index 
>>> 32435d255805331c7c56a096675b7a2af3286e5e..287f0d6faad113fbc8c30051280668baa58ab130 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>> @@ -7,7 +7,5 @@
>>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>> index 
>>> eb655b5504e58dc842853c8cb874c5cef3b82aa6..7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>> @@ -8,10 +8,7 @@
>>>  /* Checks for saving and clearing prior to function call. */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>>> index 
>>> ab266af7092afbce868792446124c291188e8a90..638643d0a6772d43f440df3942c6c723f1eff3ef 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>>> @@ -6,10 +6,6 @@
>>>  #include "../../../cmse-5.x"
>>>
>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>> } */
>>> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>> @@ -26,7 +22,6 @@
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>> arm_dsp } } } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>> arm_dsp } } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" 
>>> } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>  /* { dg-final { scan-assembler "bxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>> index 
>>> fd1a24b3258e8403394dac98ff7c4712b0eb7a1b..9ec14d1a707839e4858bac72bc292fd0984bf86c 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>> @@ -8,10 +8,7 @@
>>>  /* Checks for saving and clearing prior to function call. */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>> index 
>>> d8f9b7758d50f74f777fcda22f3f6714ff28bb96..d375879ed02483c05d7853c95f9b9e15383ff321 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>> @@ -8,10 +8,7 @@
>>>  /* Checks for saving and clearing prior to function call. */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>> index 
>>> 4878c6ef9157abff003780fbf6401db8eb3ef2f3..e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>> @@ -8,10 +8,7 @@
>>>  /* Checks for saving and clearing prior to function call. */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>>> index 
>>> 82aad2d13d6b170c92fd2c2345ab76f41e383013..7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>>> @@ -6,10 +6,6 @@
>>>  #include "../../../cmse-5.x"
>>>
>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>> } */
>>> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>> @@ -19,7 +15,6 @@
>>>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>> arm_dsp } } } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>> arm_dsp } } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" 
>>> } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>  /* { dg-final { scan-assembler "bxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>> index 
>>> 8e054c2aeebac4bd3f164b00ad867bc2d72cb674..d998b43a148250a15eb4aae9fb0ef6e4bf51203b 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>> @@ -8,10 +8,7 @@
>>>  /* Checks for saving and clearing prior to function call. */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>> index 
>>> e74cea7697ba1c12ebeef21636d1b8fd60b42677..e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>> @@ -8,10 +8,7 @@
>>>  /* Checks for saving and clearing prior to function call. */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>> index 
>>> 4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d..d43a9f85a199ecdf7e018852b3af9b4cf36af81f 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>> @@ -8,9 +8,9 @@
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>>> index 
>>> c684d79fae00feb8e15e9f142735f005473b6011..157bccb9ff3256056d496a0d0770374315b04d87 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>>> @@ -5,13 +5,8 @@
>>>  #include "../../../cmse-5.x"
>>>
>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>> } */
>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tip, lr" } } */
>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>> arm_dsp } } } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>> arm_dsp } } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>  /* { dg-final { scan-assembler "bxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>> index 
>>> 4cb6a54a0a5b02954519e64503d7c2c4c0e4750d..02e48157a2c61b0a8bee77e949944acc2a4bee37 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>> @@ -7,10 +7,7 @@
>>>  /* Checks for saving and clearing prior to function call. */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>> index 
>>> 4764b2fadfb38661764b909cdb2c9cd109e24df0..c7a22a2ba464dce26b289635dd8dcc8213ae33d8 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>> @@ -9,8 +9,7 @@
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>>> index 
>>> 9b2e7565d24ff52138b0fb90a1e6268aa4c515a0..2522a17a6316d76a21d8d241d4c44cdddf1981e0 
>>> 100644
>>> --- 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>>> +++ 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>>> @@ -8,9 +8,6 @@
>>>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>> } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>> @@ -27,7 +24,6 @@
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>> arm_dsp } } } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>> arm_dsp } } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>  /* { dg-final { scan-assembler "bxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>> index 
>>> 9e93d75c35de5e3dde1074fb99da94edc2648319..d34ca383236fdd31723966e6218ea918cf8c9122 
>>> 100644
>>> --- 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>> +++ 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>> @@ -8,10 +8,7 @@
>>>  /* Checks for saving and clearing prior to function call. */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>> index 
>>> 566889e66c8cea6ca32348f48742d2c325336995..ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250 
>>> 100644
>>> --- 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>> +++ 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>> @@ -10,8 +10,7 @@
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>> index 
>>> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..ff9a7dfa5e696e3a6c4132343d0ee94c3068c208 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>> @@ -9,8 +9,9 @@
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" 
>>> } } */
>>> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>>> index 
>>> 5af1fdb934ce5aa5afd8d096122b6e9b55591bd9..eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>>> @@ -7,10 +7,6 @@
>>>
>>>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>> } */
>>> -/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>>> @@ -19,7 +15,6 @@
>>>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>> arm_dsp } } } } */
>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>> arm_dsp } } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>  /* { dg-final { scan-assembler "bxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>> index 
>>> 1c38290e79d18a8f94e44b974c54220e553a9a49..03d36aa650986b6069e2fe1c1f3f98fa9664d88a 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>> @@ -8,10 +8,7 @@
>>>  /* Checks for saving and clearing prior to function call. */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>> index 
>>> 39c2e72f968ce9f30d36bd347544ca26b3dfad8a..ce45e10688f855ca7b2a63777d2b3d3418815589 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>> @@ -10,8 +10,7 @@
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>> index 
>>> d51db020c7707fa714364b10dd3ec5896a9dad17..dbd1d34413ef36f2b03716c0d9cf46b024af0835 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>> @@ -10,6 +10,5 @@
>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>> index 
>>> 131afbbf4289b238438c53ab9ea55d13b8567513..3edc7f1e259779a24e722d67ed544c0a673090c7 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>> @@ -14,5 +14,5 @@
>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>>> index 
>>> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..3a72406df2492206c2cb8ac7b63e4242ec0ba598 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>>> @@ -9,8 +9,9 @@
>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
>>> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" 
>>> } } */
>>> +/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>>> index 
>>> 5f6891a26d9be6edbb81c6c9e71897d1b49c8c60..90fdac18e30424edca60b6f884227adbf716899d 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>>> @@ -29,5 +29,6 @@ main (void)
>>>  /* { dg-final { scan-assembler "movs\tr1, #255" } } */
>>>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>

+;; The operands are validated through the clear_multiple_operation
+;; match_parallel predicate rather than through constraints so enable it only
+;; after reload.
+(define_insn "*clear_multiple"
+  [(match_parallel 0 "clear_multiple_operation"
+     [(set (match_operand:SI 1 "register_operand" "")
+	   (const_int 0))])]
+  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && reload_completed"
+  {
+    char pattern[100];
+    int i, num_saves = XVECLEN (operands[0], 0);
+
+    strcpy (pattern, \"clrm%?\\t{\");
+    for (i = 0; i < num_saves; i++)
+      {
+	if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
+	  {
+	    strcat (pattern, \"APSR\");
+	    // Skip clobber


I don't think this comment is useful. If you want to keep it, convert it to C-style /**/.


Otherwise ok.
Thanks!
Kyrill



+	    ++i;
+	  }
+	else
+	  strcat (pattern,
+		  reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 0))]);
+	if (i < num_saves - 1)
+	  strcat (pattern, \", %|\");
+      }
+    strcat (pattern, \"}\");
+    output_asm_insn (pattern, operands);
+    return \"\";
+  }
+  [(set_attr "predicable" "yes")]
+)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
  2019-12-17 10:27       ` Kyrill Tkachov
@ 2019-12-18 13:29         ` Mihail Ionescu
  2020-01-13 17:30           ` Kyrill Tkachov
  0 siblings, 1 reply; 35+ messages in thread
From: Mihail Ionescu @ 2019-12-18 13:29 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 62639 bytes --]

Hi Kyrill,

On 12/17/2019 10:26 AM, Kyrill Tkachov wrote:
> Hi Mihail,
> 
> On 12/16/19 6:29 PM, Mihail Ionescu wrote:
>> Hi Kyrill,
>>
>> On 11/12/2019 09:55 AM, Kyrill Tkachov wrote:
>>> Hi Mihail,
>>>
>>> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>>>> [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
>>>>
>>>> Hi,
>>>>
>>>> === Context ===
>>>>
>>>> This patch is part of a patch series to add support for Armv8.1-M
>>>> Mainline Security Extensions architecture. Its purpose is to improve
>>>> code density of functions with the cmse_nonsecure_entry attribute and
>>>> when calling function with the cmse_nonsecure_call attribute by using
>>>> CLRM to do all the general purpose registers clearing as well as
>>>> clearing the APSR register.
>>>>
>>>> === Patch description ===
>>>>
>>>> This patch adds a new pattern for the CLRM instruction and guards the
>>>> current clearing code in output_return_instruction() and thumb_exit()
>>>> on Armv8.1-M Mainline instructions not being present.
>>>> cmse_clear_registers () is then modified to use the new CLRM 
>>>> instruction
>>>> when targeting Armv8.1-M Mainline while keeping Armv8-M register
>>>> clearing code for VFP registers.
>>>>
>>>> For the CLRM instruction, which does not mandated APSR in the register
>>>> list, checking whether it is the right volatile unspec or a clearing
>>>> register is done in clear_operation_p.
>>>>
>>>> Note that load/store multiple were deemed sufficiently different in
>>>> terms of RTX structure compared to the CLRM pattern for a different
>>>> function to be used to validate the match_parallel.
>>>>
>>>> ChangeLog entries are as follows:
>>>>
>>>> *** gcc/ChangeLog ***
>>>>
>>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>
>>>>         * config/arm/arm-protos.h (clear_operation_p): Declare.
>>>>         * config/arm/arm.c (clear_operation_p): New function.
>>>>         (cmse_clear_registers): Generate clear_multiple instruction 
>>>> pattern if
>>>>         targeting Armv8.1-M Mainline or successor.
>>>>         (output_return_instruction): Only output APSR register 
>>>> clearing if
>>>>         Armv8.1-M Mainline instructions not available.
>>>>         (thumb_exit): Likewise.
>>>>         * config/arm/predicates.md (clear_multiple_operation): New 
>>>> predicate.
>>>>         * config/arm/thumb2.md (clear_apsr): New define_insn.
>>>>         (clear_multiple): Likewise.
>>>>         * config/arm/unspecs.md (VUNSPEC_CLRM_APSR): New volatile 
>>>> unspec.
>>>>
>>>> *** gcc/testsuite/ChangeLog ***
>>>>
>>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>
>>>>         * gcc.target/arm/cmse/bitfield-1.c: Add check for CLRM.
>>>>         * gcc.target/arm/cmse/bitfield-2.c: Likewise.
>>>>         * gcc.target/arm/cmse/bitfield-3.c: Likewise.
>>>>         * gcc.target/arm/cmse/struct-1.c: Likewise.
>>>>         * gcc.target/arm/cmse/cmse-14.c: Likewise.
>>>>         * gcc.target/arm/cmse/cmse-1.c: Likewise.  Restrict checks 
>>>> for Armv8-M
>>>>         GPR clearing when CLRM is not available.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: 
>>>> Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: 
>>>> Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: 
>>>> Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: 
>>>> Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
>>>>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.
>>>>
>>>> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
>>>> regression.
>>>>
>>>> Is this ok for trunk?
>>>>
>>>> Best regards,
>>>>
>>>> Mihail
>>>>
>>>>
>>>> ###############     Attachment also inlined for ease of reply 
>>>> ###############
>>>>
>>>>
>>>> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
>>>> index 
>>>> f995974f9bb89ab3c7ff0888c394b0dfaf7da60c..1a948d2c97526ad7e67e8d4a610ac74cfdb13882 
>>>> 100644
>>>> --- a/gcc/config/arm/arm-protos.h
>>>> +++ b/gcc/config/arm/arm-protos.h
>>>> @@ -77,6 +77,7 @@ extern int thumb_legitimate_offset_p 
>>>> (machine_mode, HOST_WIDE_INT);
>>>>  extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
>>>>  extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
>>>>                                   bool, bool);
>>>> +extern bool clear_operation_p (rtx);
>>>>  extern int arm_const_double_rtx (rtx);
>>>>  extern int vfp3_const_double_rtx (rtx);
>>>>  extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, 
>>>> int *);
>>>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>>> index 
>>>> d485e80096c9d2eef2172d211a0a5ab63cdbb3c7..3a373cea33c3d0b966cbe700d26f66fe069e1efb 
>>>> 100644
>>>> --- a/gcc/config/arm/arm.c
>>>> +++ b/gcc/config/arm/arm.c
>>>> @@ -13499,6 +13499,66 @@ ldm_stm_operation_p (rtx op, bool load, 
>>>> machine_mode mode,
>>>>    return true;
>>>>  }
>>>>
>>>> +/* Checks whether OP is a valid parallel pattern for a CLRM insn. 
>>>> To be a
>>>> +   valid CLRM pattern, OP must have the following form:
>>>> +
>>>> +   [(set (reg:SI <N>) (const_int 0))
>>>> +    (set (reg:SI <M>) (const_int 0))
>>>> +    ...
>>>> +    (unspec_volatile [(const_int 0)]
>>>> +                    VUNSPEC_CLRM_APSR)
>>>> +   ]
>>>
>>>
>>> If this clears the whole APSR than it also clobbers the condition 
>>> flags, right?
>>>
>>> Then it should also have a  (clobber (reg:CC CC_REGNUM)) in there.
>>> Yes -- it should also clobber the condition flags, thanks for catching 
>> this. I've updated the patch to include the CC clobbering.
>>
>> Regards,
>> Mihail
>>>
>>>> +
>>>> +   Any number (including 0) of set expressions is valid, the 
>>>> volatile unspec is
>>>> +   optional.  All registers but SP and PC are allowed and registers 
>>>> must be in
>>>> +   strict increasing order.  */
>>>> +
>>>> +bool
>>>> +clear_operation_p (rtx op)
>>>> +{
>>>> +  HOST_WIDE_INT i;
>>>> +  unsigned regno, last_regno;
>>>> +  rtx elt, reg, zero;
>>>> +  machine_mode mode;
>>>> +  HOST_WIDE_INT count = XVECLEN (op, 0);
>>>> +
>>>> +  for (i = 0; i < count; i++)
>>>> +    {
>>>> +      elt = XVECEXP (op, 0, i);
>>>> +
>>>> +      if (GET_CODE (elt) == UNSPEC_VOLATILE)
>>>> +       {
>>>> +         if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
>>>> +             || XVECLEN (elt, 0) != 1
>>>> +             || XVECEXP (elt, 0, 0) != CONST0_RTX (SImode)
>>>> +             || i != count - 1)
>>>> +           return false;
>>>> +
>>>> +         continue;
>>>> +       }
>>>> +
>>>> +      if (GET_CODE (elt) != SET)
>>>> +       return false;
>>>> +
>>>> +      reg = SET_DEST (elt);
>>>> +      regno = REGNO (reg);
>>>> +      mode = GET_MODE (reg);
>>>> +      zero = SET_SRC (elt);
>>>> +
>>>> +      if (!REG_P (reg)
>>>> +         || GET_MODE (reg) != SImode
>>>> +         || regno == SP_REGNUM
>>>> +         || regno == PC_REGNUM
>>>> +         || (i != 0 && regno <= last_regno)
>>>> +         || zero != CONST0_RTX (SImode))
>>>> +       return false;
>>>> +
>>>> +      last_regno = REGNO (reg);
>>>> +    }
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>>  /* Return true iff it would be profitable to turn a sequence of 
>>>> NOPS loads
>>>>     or stores (depending on IS_STORE) into a load-multiple or 
>>>> store-multiple
>>>>     instruction.  ADD_OFFSET is nonzero if the base address register 
>>>> needs
>>>> @@ -17596,6 +17656,56 @@ cmse_clear_registers (sbitmap 
>>>> to_clear_bitmap, uint32_t *padding_bits_to_clear,
>>>>
>>>>    /* Clear full registers.  */
>>>>
>>>> +  if (TARGET_HAVE_FPCXT_CMSE)
>>>> +    {
>>>> +      rtvec vunspec_vec;
>>>> +      int i, j, k, nb_regs;
>>>> +      rtx use_seq, par, reg, set, vunspec;
>>>> +      int to_clear_bitmap_size = SBITMAP_SIZE (to_clear_bitmap);
>>>> +      auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
>>>> +      auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
>>>> +
>>>> +      /* Get set of core registers to clear.  */
>>>> +      bitmap_clear (core_regs_bitmap);
>>>> +      bitmap_set_range (core_regs_bitmap, R0_REGNUM,
>>>> +                       IP_REGNUM - R0_REGNUM + 1);
>>>> +      bitmap_and (to_clear_core_bitmap, to_clear_bitmap,
>>>> +                 core_regs_bitmap);
>>>> +      gcc_assert (!bitmap_empty_p (to_clear_core_bitmap));
>>>> +
>>>> +      if (bitmap_empty_p (to_clear_core_bitmap))
>>>> +       return;
>>>> +
>>>> +      /* Create clrm RTX pattern.  */
>>>> +      nb_regs = bitmap_count_bits (to_clear_core_bitmap);
>>>> +      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 1));
>>>> +
>>>> +      /* Insert core register clearing RTX in the pattern. */
>>>> +      start_sequence ();
>>>> +      for (j = 0, i = minregno; j < nb_regs; i++)
>>>> +       {
>>>> +         if (!bitmap_bit_p (to_clear_core_bitmap, i))
>>>> +           continue;
>>>> +
>>>> +         reg = gen_rtx_REG (SImode, i);
>>>> +         set = gen_rtx_SET (reg, const0_rtx);
>>>> +         XVECEXP (par, 0, j++) = set;
>>>> +         emit_use (reg);
>>>> +       }
>>>> +
>>>> +      /* Insert APSR register clearing RTX in the pattern. */
>>>> +      vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
>>>> +      vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
>>>> +                                        VUNSPEC_CLRM_APSR);
>>>> +      XVECEXP (par, 0, j) = vunspec;
>>>> +
>>>> +      use_seq = get_insns ();
>>>> +      end_sequence ();
>>>> +
>>>> +      emit_insn_after (use_seq, emit_insn (par));
>>>> +      minregno = FIRST_VFP_REGNUM;
>>>> +    }
>>>> +
>>>>    /* If not marked for clearing, clearing_reg already does not contain
>>>>       any secret.  */
>>>>    if (clearing_regno <= maxregno
>>>> @@ -20259,40 +20369,50 @@ output_return_instruction (rtx operand, 
>>>> bool really_return, bool reverse,
>>>>          default:
>>>>            if (IS_CMSE_ENTRY (func_type))
>>>>              {
>>>> -             /* Check if we have to clear the 'GE bits' which is 
>>>> only used if
>>>> -                parallel add and subtraction instructions are 
>>>> available.  */
>>>> -             if (TARGET_INT_SIMD)
>>>> -               snprintf (instr, sizeof (instr),
>>>> -                         "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
>>>> -             else
>>>> -               snprintf (instr, sizeof (instr),
>>>> -                         "msr%s\tAPSR_nzcvq, %%|lr", conditional);
>>>> -
>>>> -             output_asm_insn (instr, & operand);
>>>> -             /* Do not clear FPSCR if targeting Armv8.1-M Mainline, 
>>>> VLDR takes
>>>> -                care of it.  */
>>>> -             if (TARGET_HARD_FLOAT && ! TARGET_HAVE_FPCXT_CMSE)
>>>> +             /* For Armv8.1-M, this is cleared as part of the CLRM 
>>>> instruction
>>>> +                emitted by cmse_nonsecure_entry_clear_before_return 
>>>> () and the
>>>> +                VSTR/VLDR instructions in the prologue and 
>>>> epilogue.  */
>>>> +             if (!TARGET_HAVE_FPCXT_CMSE)
>>>>                  {
>>>> -                 /* Clear the cumulative exception-status bits 
>>>> (0-4,7) and the
>>>> -                    condition code bits (28-31) of the FPSCR.  We 
>>>> need to
>>>> -                    remember to clear the first scratch register 
>>>> used (IP) and
>>>> -                    save and restore the second (r4).  */
>>>> -                 snprintf (instr, sizeof (instr), "push\t{%%|r4}");
>>>> -                 output_asm_insn (instr, & operand);
>>>> -                 snprintf (instr, sizeof (instr), "vmrs\t%%|ip, 
>>>> fpscr");
>>>> -                 output_asm_insn (instr, & operand);
>>>> -                 snprintf (instr, sizeof (instr), "movw\t%%|r4, 
>>>> #65376");
>>>> -                 output_asm_insn (instr, & operand);
>>>> -                 snprintf (instr, sizeof (instr), "movt\t%%|r4, 
>>>> #4095");
>>>> -                 output_asm_insn (instr, & operand);
>>>> -                 snprintf (instr, sizeof (instr), "and\t%%|ip, 
>>>> %%|r4");
>>>> -                 output_asm_insn (instr, & operand);
>>>> -                 snprintf (instr, sizeof (instr), "vmsr\tfpscr, 
>>>> %%|ip");
>>>> -                 output_asm_insn (instr, & operand);
>>>> -                 snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
>>>> -                 output_asm_insn (instr, & operand);
>>>> -                 snprintf (instr, sizeof (instr), "mov\t%%|ip, 
>>>> %%|lr");
>>>> +                 /* Check if we have to clear the 'GE bits' which 
>>>> is only used if
>>>> +                    parallel add and subtraction instructions are 
>>>> available.  */
>>>> +                 if (TARGET_INT_SIMD)
>>>> +                   snprintf (instr, sizeof (instr),
>>>> +                             "msr%s\tAPSR_nzcvqg, %%|lr", 
>>>> conditional);
>>>> +                 else
>>>> +                   snprintf (instr, sizeof (instr),
>>>> +                             "msr%s\tAPSR_nzcvq, %%|lr", conditional);
>>>> +
>>>>                    output_asm_insn (instr, & operand);
>>>> +                 /* Do not clear FPSCR if targeting Armv8.1-M 
>>>> Mainline, VLDR takes
>>>> +                    care of it.  */
>>>> +                 if (TARGET_HARD_FLOAT)
>>>> +                   {
>>>> +                     /* Clear the cumulative exception-status bits 
>>>> (0-4,7) and
>>>> +                        the condition code bits (28-31) of the 
>>>> FPSCR.  We need
>>>> +                        to remember to clear the first scratch 
>>>> register used
>>>> +                        (IP) and save and restore the second (r4).
>>>> +
>>>> +                        Important note: the length of the
>>>> +                        thumb2_cmse_entry_return insn pattern must 
>>>> account for
>>>> +                        the size of the below instructions. */
>>>> +                     snprintf (instr, sizeof (instr), 
>>>> "push\t{%%|r4}");
>>>> +                     output_asm_insn (instr, & operand);
>>>
>>>
>>> I know this is pre-existing in this function, but I think we should 
>>> just use output_asm_insn directly here:
>>> output_asm_insn ("push\t{%%|r4}", & operand);
>>>
>>> and avoid all the snprintfs.
>>>
>>>
>>>> +                     snprintf (instr, sizeof (instr), "vmrs\t%%|ip, 
>>>> fpscr");
>>>> +                     output_asm_insn (instr, & operand);
>>>> +                     snprintf (instr, sizeof (instr), "movw\t%%|r4, 
>>>> #65376");
>>>> +                     output_asm_insn (instr, & operand);
>>>> +                     snprintf (instr, sizeof (instr), "movt\t%%|r4, 
>>>> #4095");
>>>> +                     output_asm_insn (instr, & operand);
>>>> +                     snprintf (instr, sizeof (instr), "and\t%%|ip, 
>>>> %%|r4");
>>>> +                     output_asm_insn (instr, & operand);
>>>> +                     snprintf (instr, sizeof (instr), "vmsr\tfpscr, 
>>>> %%|ip");
>>>> +                     output_asm_insn (instr, & operand);
>>>> +                     snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
>>>> +                     output_asm_insn (instr, & operand);
>>>> +                     snprintf (instr, sizeof (instr), "mov\t%%|ip, 
>>>> %%|lr");
>>>> +                     output_asm_insn (instr, & operand);
>>>> +                   }
>>>>                  }
>>>>                snprintf (instr, sizeof (instr), "bxns\t%%|lr");
>>>>              }
>>>> @@ -24690,8 +24810,11 @@ thumb_exit (FILE *f, int 
>>>> reg_containing_return_addr)
>>>>
>>>>        if (IS_CMSE_ENTRY (arm_current_func_type ()))
>>>>          {
>>>> -         asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
>>>> -                      reg_containing_return_addr);
>>>> +         /* For Armv8.1-M, this is cleared as part of the CLRM 
>>>> instruction
>>>> +            emitted by cmse_nonsecure_entry_clear_before_return 
>>>> ().  */
>>>> +         if (!TARGET_HAVE_FPCXT_CMSE)
>>>> +           asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
>>>> +                        reg_containing_return_addr);
>>>>            asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
>>>>          }
>>>>        else
>>>> @@ -24931,11 +25054,14 @@ thumb_exit (FILE *f, int 
>>>> reg_containing_return_addr)
>>>>           address.  It may therefore contain information that we 
>>>> might not want
>>>>           to leak, hence it must be cleared.  The value in R0 will 
>>>> never be a
>>>>           secret at this point, so it is safe to use it, see the 
>>>> clearing code
>>>> -        in 'cmse_nonsecure_entry_clear_before_return'.  */
>>>> +        in cmse_nonsecure_entry_clear_before_return ().  */
>>>>        if (reg_containing_return_addr != LR_REGNUM)
>>>>          asm_fprintf (f, "\tmov\tlr, r0\n");
>>>>
>>>> -      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
>>>> reg_containing_return_addr);
>>>> +      /* For Armv8.1-M, this is cleared as part of the CLRM 
>>>> instruction emitted
>>>> +        by cmse_nonsecure_entry_clear_before_return ().  */
>>>> +      if (!TARGET_HAVE_FPCXT_CMSE)
>>>> +       asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
>>>> reg_containing_return_addr);
>>>>        asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
>>>>      }
>>>>    else
>>>> diff --git a/gcc/config/arm/predicates.md 
>>>> b/gcc/config/arm/predicates.md
>>>> index 
>>>> 8b36e7ee462235ad26e132f1ccf98d28c2487d67..e5c583ef3d167194e7a061d7c3e98d3b4bb5269c 
>>>> 100644
>>>> --- a/gcc/config/arm/predicates.md
>>>> +++ b/gcc/config/arm/predicates.md
>>>> @@ -510,6 +510,12 @@
>>>>              (match_test "satisfies_constraint_Dy (op)")
>>>>              (match_test "satisfies_constraint_G (op)"))))
>>>>
>>>> +(define_special_predicate "clear_multiple_operation"
>>>> +  (match_code "parallel")
>>>> +{
>>>> + return clear_operation_p (op);
>>>> +})
>>>> +
>>>>  (define_special_predicate "load_multiple_operation"
>>>>    (match_code "parallel")
>>>>  {
>>>> diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
>>>> index 
>>>> 6ccc875e2b4e7b8ce256e52da966dfe220c6f5d6..9994c0d59f741ef47d0ec43dd53a2324b031d048 
>>>> 100644
>>>> --- a/gcc/config/arm/thumb2.md
>>>> +++ b/gcc/config/arm/thumb2.md
>>>> @@ -1599,3 +1599,39 @@
>>>>        FAIL;
>>>>   }")
>>>>
>>>> +(define_insn "*clear_apsr"
>>>> +  [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)]
>>>> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
>>>> +  "clrm%?\\t{APSR}"
>>>> +  [(set_attr "predicable" "yes")]
>>>> +)
>>>
>>>
>>> Similar to earlier, if this clears the whole APSR then it should also 
>>> represent a clobber of the CC reg.
>>>
>>>
>>>> +
>>>> +;; The operands are validated through the clear_multiple_operation
>>>> +;; match_parallel predicate rather than through constraints so 
>>>> enable it only
>>>> +;; after reload.
>>>> +(define_insn "*clear_multiple"
>>>> +  [(match_parallel 0 "clear_multiple_operation"
>>>> +     [(set (match_operand:SI 1 "register_operand" "")
>>>> +          (const_int 0))])]
>>>> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && 
>>>> reload_completed"
>>>> +  {
>>>> +    char pattern[100];
>>>> +    int i, num_saves = XVECLEN (operands[0], 0);
>>>> +
>>>> +    strcpy (pattern, \"clrm%?\\t{\");
>>>> +    for (i = 0; i < num_saves; i++)
>>>> +      {
>>>> +       if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
>>>> +         strcat (pattern, \"APSR\");
>>>> +       else
>>>> +         strcat (pattern,
>>>> +                 reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, 
>>>> i), 0))]);
>>>> +       if (i < num_saves - 1)
>>>> +         strcat (pattern, \", %|\");
>>>> +      }
>>>> +    strcat (pattern, \"}\");
>>>> +    output_asm_insn (pattern, operands);
>>>> +    return \"\";
>>>> +  }
>>>> +  [(set_attr "predicable" "yes")]
>>>> +)
>>>> diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
>>>> index 
>>>> 324359be7127f04a80ebc0079ad0a9964dfd82a7..498bc0798dbaaa3ee73815ba27864ae92a2fd08e 
>>>> 100644
>>>> --- a/gcc/config/arm/unspecs.md
>>>> +++ b/gcc/config/arm/unspecs.md
>>>> @@ -174,6 +174,7 @@
>>>>    VUNSPEC_MRRC2                ; Represent the coprocessor mrrc2 
>>>> instruction.
>>>>    VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional 
>>>> speculation barrier.
>>>>    VUNSPEC_VSTR_VLDR    ; Represent the vstr/vldr instruction.
>>>> +  VUNSPEC_CLRM_APSR    ; Represent the clearing of APSR with clrm 
>>>> instruction.
>>>>  ])
>>>>
>>>>  ;; Enumerators for NEON unspecs.
>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>>>> index 
>>>> 6d611e130b6f3b544807b767927d99b89071343b..7036cb9508c27d56c4b2c01a81c44bf6f1f9c781 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>>>> @@ -36,6 +36,7 @@ main (void)
>>>>  /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
>>>>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>
>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>>>> index 
>>>> b7ec0a040319545b50590261278f1517bcb22796..50d4979470dd21738453e0d70c7a69ee0752ac41 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>>>> @@ -33,6 +33,7 @@ main (void)
>>>>  /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
>>>>  /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
>>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>
>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>>>> index 
>>>> 7b9c3f0fe061317f71d3122dea7a55ab5311f234..2b7507c900ab18705083ba1d86359e1ae36a50a2 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>>>> @@ -34,5 +34,6 @@ main (void)
>>>>  /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
>>>>  /* { dg-final { scan-assembler "movt\tr1, 63" } } */
>>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>>> index 
>>>> aa0ec8e0b0f0953a5a5cbc2db58413176c2505f3..35cab1f3233daac9fba50d25dac23364c798fb9c 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>>> @@ -105,8 +105,10 @@ qux (int_nsfunc_t * callback)
>>>>  /* { dg-final { scan-assembler "bic" } } */
>>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { 
>>>> target arm_cmse_clear_ok } } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>> target arm_cmse_clear_ok } } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
>>>> +/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
>>>> arm_cmse_clear_ok } } } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>
>>>>  int call_callback (void)
>>>>  {
>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>>> index 
>>>> df1ea52bec533c36a738d7d3b2b2ff749b0f3713..1f5af7c2dba7747f6058d12af8ef80b4dd1b1431 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>>> @@ -9,5 +9,6 @@ int foo (void)
>>>>    return bar ();
>>>>  }
>>>>
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>>  /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } 
>>>> } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>>> index 
>>>> 62c63b888ab49e99fba0a08b69941e73c9a8d33b..c52e1c14d9956743625e3b8a200e823f163924e3 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>>> @@ -12,5 +12,5 @@
>>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>>> index 
>>>> b718a70522b86e2bc58900681a781129543f8869..fdba955a32fc5ad492b74974185f98470bc49a7e 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>>> @@ -10,6 +10,5 @@
>>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>>> index 
>>>> 16536ab4f9ec5782463ab90f404a2e9f6f938850..85068ceaac6a5c0c60af4a54c0af0d20326fc18d 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>>> @@ -13,5 +13,5 @@
>>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>>> index 
>>>> 0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5..af69d38acf47d9d1d55480edba2b66f07e2d06ad 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>>> @@ -10,6 +10,5 @@
>>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>>> index 
>>>> 914ea39626f2f72eac8c9c1cb495b0855e58f5e1..62201595549f07b046c7c5972d612ab155c4c38c 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>>> @@ -13,5 +13,5 @@
>>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>>> index 
>>>> 32435d255805331c7c56a096675b7a2af3286e5e..287f0d6faad113fbc8c30051280668baa58ab130 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>>> @@ -7,7 +7,5 @@
>>>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>>> index 
>>>> eb655b5504e58dc842853c8cb874c5cef3b82aa6..7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>>> @@ -8,10 +8,7 @@
>>>>  /* Checks for saving and clearing prior to function call. */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>>>> index 
>>>> ab266af7092afbce868792446124c291188e8a90..638643d0a6772d43f440df3942c6c723f1eff3ef 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>>>> @@ -6,10 +6,6 @@
>>>>  #include "../../../cmse-5.x"
>>>>
>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>>> } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>>> @@ -26,7 +22,6 @@
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>> arm_dsp } } } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>> arm_dsp } } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" 
>>>> } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>>> index 
>>>> fd1a24b3258e8403394dac98ff7c4712b0eb7a1b..9ec14d1a707839e4858bac72bc292fd0984bf86c 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>>> @@ -8,10 +8,7 @@
>>>>  /* Checks for saving and clearing prior to function call. */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>>> index 
>>>> d8f9b7758d50f74f777fcda22f3f6714ff28bb96..d375879ed02483c05d7853c95f9b9e15383ff321 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>>> @@ -8,10 +8,7 @@
>>>>  /* Checks for saving and clearing prior to function call. */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>>> index 
>>>> 4878c6ef9157abff003780fbf6401db8eb3ef2f3..e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>>> @@ -8,10 +8,7 @@
>>>>  /* Checks for saving and clearing prior to function call. */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>>>> index 
>>>> 82aad2d13d6b170c92fd2c2345ab76f41e383013..7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>>>> @@ -6,10 +6,6 @@
>>>>  #include "../../../cmse-5.x"
>>>>
>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>>> } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>> @@ -19,7 +15,6 @@
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>> arm_dsp } } } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>> arm_dsp } } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" 
>>>> } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>>> index 
>>>> 8e054c2aeebac4bd3f164b00ad867bc2d72cb674..d998b43a148250a15eb4aae9fb0ef6e4bf51203b 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>>> @@ -8,10 +8,7 @@
>>>>  /* Checks for saving and clearing prior to function call. */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>>> index 
>>>> e74cea7697ba1c12ebeef21636d1b8fd60b42677..e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>>> @@ -8,10 +8,7 @@
>>>>  /* Checks for saving and clearing prior to function call. */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>>> index 
>>>> 4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d..d43a9f85a199ecdf7e018852b3af9b4cf36af81f 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>>> @@ -8,9 +8,9 @@
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>>
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>>>> index 
>>>> c684d79fae00feb8e15e9f142735f005473b6011..157bccb9ff3256056d496a0d0770374315b04d87 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>>>> @@ -5,13 +5,8 @@
>>>>  #include "../../../cmse-5.x"
>>>>
>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>>> } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tip, lr" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>> arm_dsp } } } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>> arm_dsp } } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>>> index 
>>>> 4cb6a54a0a5b02954519e64503d7c2c4c0e4750d..02e48157a2c61b0a8bee77e949944acc2a4bee37 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>>> @@ -7,10 +7,7 @@
>>>>  /* Checks for saving and clearing prior to function call. */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>>
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>>> index 
>>>> 4764b2fadfb38661764b909cdb2c9cd109e24df0..c7a22a2ba464dce26b289635dd8dcc8213ae33d8 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>>> @@ -9,8 +9,7 @@
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>>
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>>>> index 
>>>> 9b2e7565d24ff52138b0fb90a1e6268aa4c515a0..2522a17a6316d76a21d8d241d4c44cdddf1981e0 
>>>> 100644
>>>> --- 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>>>> +++ 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>>>> @@ -8,9 +8,6 @@
>>>>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>>> } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>>> @@ -27,7 +24,6 @@
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>> arm_dsp } } } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>> arm_dsp } } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>>> index 
>>>> 9e93d75c35de5e3dde1074fb99da94edc2648319..d34ca383236fdd31723966e6218ea918cf8c9122 
>>>> 100644
>>>> --- 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>>> +++ 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>>> @@ -8,10 +8,7 @@
>>>>  /* Checks for saving and clearing prior to function call. */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>>
>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>>> index 
>>>> 566889e66c8cea6ca32348f48742d2c325336995..ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250 
>>>> 100644
>>>> --- 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>>> +++ 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>>> @@ -10,8 +10,7 @@
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>
>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>>> index 
>>>> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..ff9a7dfa5e696e3a6c4132343d0ee94c3068c208 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>>> @@ -9,8 +9,9 @@
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" 
>>>> } } */
>>>> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>>> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>>>>
>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>>>> index 
>>>> 5af1fdb934ce5aa5afd8d096122b6e9b55591bd9..eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>>>> @@ -7,10 +7,6 @@
>>>>
>>>>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } 
>>>> } */
>>>> -/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>>>> @@ -19,7 +15,6 @@
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>>>>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>> arm_dsp } } } } */
>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>> arm_dsp } } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>>> index 
>>>> 1c38290e79d18a8f94e44b974c54220e553a9a49..03d36aa650986b6069e2fe1c1f3f98fa9664d88a 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>>> @@ -8,10 +8,7 @@
>>>>  /* Checks for saving and clearing prior to function call. */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
>>>>
>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>>> index 
>>>> 39c2e72f968ce9f30d36bd347544ca26b3dfad8a..ce45e10688f855ca7b2a63777d2b3d3418815589 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>>> @@ -10,8 +10,7 @@
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>
>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>>> index 
>>>> d51db020c7707fa714364b10dd3ec5896a9dad17..dbd1d34413ef36f2b03716c0d9cf46b024af0835 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>>> @@ -10,6 +10,5 @@
>>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>>> index 
>>>> 131afbbf4289b238438c53ab9ea55d13b8567513..3edc7f1e259779a24e722d67ed544c0a673090c7 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>>> @@ -14,5 +14,5 @@
>>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git 
>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>>>> index 
>>>> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..3a72406df2492206c2cb8ac7b63e4242ec0ba598 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>>>> @@ -9,8 +9,9 @@
>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
>>>> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" 
>>>> } } */
>>>> +/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>>> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>>>
>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c 
>>>> b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>>>> index 
>>>> 5f6891a26d9be6edbb81c6c9e71897d1b49c8c60..90fdac18e30424edca60b6f884227adbf716899d 
>>>> 100644
>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>>>> @@ -29,5 +29,6 @@ main (void)
>>>>  /* { dg-final { scan-assembler "movs\tr1, #255" } } */
>>>>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>> target arm_cmse_clear_ok } } } */
>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>
> 
> +;; The operands are validated through the clear_multiple_operation
> +;; match_parallel predicate rather than through constraints so enable 
> it only
> +;; after reload.
> +(define_insn "*clear_multiple"
> +  [(match_parallel 0 "clear_multiple_operation"
> +     [(set (match_operand:SI 1 "register_operand" "")
> +       (const_int 0))])]
> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && 
> reload_completed"
> +  {
> +    char pattern[100];
> +    int i, num_saves = XVECLEN (operands[0], 0);
> +
> +    strcpy (pattern, \"clrm%?\\t{\");
> +    for (i = 0; i < num_saves; i++)
> +      {
> +    if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
> +      {
> +        strcat (pattern, \"APSR\");
> +        // Skip clobber
> 
> 
> I don't think this comment is useful. If you want to keep it, convert it 
> to C-style /**/.
> 
> 
> Otherwise ok.
> Thanks!
> Kyrill
> 
> 

Ok, I've gotten rid of the comment.


Thanks,
Mihail
> 
> +        ++i;
> +      }
> +    else
> +      strcat (pattern,
> +          reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 0))]);
> +    if (i < num_saves - 1)
> +      strcat (pattern, \", %|\");
> +      }
> +    strcat (pattern, \"}\");
> +    output_asm_insn (pattern, operands);
> +    return \"\";
> +  }
> +  [(set_attr "predicable" "yes")]
> +)
> 

[-- Attachment #2: diff4.patch --]
[-- Type: text/x-patch, Size: 45804 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index c685bcbf99c81210a34192cc31db055fa7b2d605..1db1ff001a5b9d4d7796f0de9355d2b46030c96e 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -78,6 +78,7 @@ extern int thumb_legitimate_offset_p (machine_mode, HOST_WIDE_INT);
 extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
 extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
                                  bool, bool);
+extern bool clear_operation_p (rtx);
 extern int arm_const_double_rtx (rtx);
 extern int vfp3_const_double_rtx (rtx);
 extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx *, int *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 68c8779245e56be0c8e808a8c98d631eee3f325c..d10ff0736fed4baa92fab0ff978db62c05c6dc7f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -13634,6 +13634,70 @@ ldm_stm_operation_p (rtx op, bool load, machine_mode mode,
   return true;
 }
 
+/* Checks whether OP is a valid parallel pattern for a CLRM insn.  To be a
+   valid CLRM pattern, OP must have the following form:
+
+   [(set (reg:SI <N>) (const_int 0))
+    (set (reg:SI <M>) (const_int 0))
+    ...
+    (unspec_volatile [(const_int 0)]
+		     VUNSPEC_CLRM_APSR)
+    (clobber (reg:CC CC_REGNUM))
+   ]
+
+   Any number (including 0) of set expressions is valid, the volatile unspec is
+   optional.  All registers but SP and PC are allowed and registers must be in
+   strict increasing order.  */
+
+bool
+clear_operation_p (rtx op)
+{
+  HOST_WIDE_INT i;
+  unsigned regno, last_regno;
+  rtx elt, reg, zero;
+  machine_mode mode;
+  HOST_WIDE_INT count = XVECLEN (op, 0);
+
+  for (i = 0; i < count; i++)
+    {
+      elt = XVECEXP (op, 0, i);
+
+      if (GET_CODE (elt) == UNSPEC_VOLATILE)
+	{
+	  if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
+	      || XVECLEN (elt, 0) != 1
+	      || XVECEXP (elt, 0, 0) != CONST0_RTX (SImode)
+	      || i != count - 2)
+	    return false;
+
+	  continue;
+	}
+
+      if (GET_CODE (elt) == CLOBBER)
+	continue;
+
+      if (GET_CODE (elt) != SET)
+	return false;
+
+      reg = SET_DEST (elt);
+      regno = REGNO (reg);
+      mode = GET_MODE (reg);
+      zero = SET_SRC (elt);
+
+      if (!REG_P (reg)
+	  || GET_MODE (reg) != SImode
+	  || regno == SP_REGNUM
+	  || regno == PC_REGNUM
+	  || (i != 0 && regno <= last_regno)
+	  || zero != CONST0_RTX (SImode))
+	return false;
+
+      last_regno = REGNO (reg);
+    }
+
+  return true;
+}
+
 /* Return true iff it would be profitable to turn a sequence of NOPS loads
    or stores (depending on IS_STORE) into a load-multiple or store-multiple
    instruction.  ADD_OFFSET is nonzero if the base address register needs
@@ -17964,6 +18028,62 @@ cmse_clear_registers (sbitmap to_clear_bitmap, uint32_t *padding_bits_to_clear,
 
   /* Clear full registers.  */
 
+  if (TARGET_HAVE_FPCXT_CMSE)
+    {
+      rtvec vunspec_vec;
+      int i, j, k, nb_regs;
+      rtx use_seq, par, reg, set, vunspec;
+      int to_clear_bitmap_size = SBITMAP_SIZE (to_clear_bitmap);
+      auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
+      auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
+
+      /* Get set of core registers to clear.  */
+      bitmap_clear (core_regs_bitmap);
+      bitmap_set_range (core_regs_bitmap, R0_REGNUM,
+			IP_REGNUM - R0_REGNUM + 1);
+      bitmap_and (to_clear_core_bitmap, to_clear_bitmap,
+		  core_regs_bitmap);
+      gcc_assert (!bitmap_empty_p (to_clear_core_bitmap));
+
+      if (bitmap_empty_p (to_clear_core_bitmap))
+	return;
+
+      /* Create clrm RTX pattern.  */
+      nb_regs = bitmap_count_bits (to_clear_core_bitmap);
+      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 2));
+
+      /* Insert core register clearing RTX in the pattern.  */
+      start_sequence ();
+      for (j = 0, i = minregno; j < nb_regs; i++)
+	{
+	  if (!bitmap_bit_p (to_clear_core_bitmap, i))
+	    continue;
+
+	  reg = gen_rtx_REG (SImode, i);
+	  set = gen_rtx_SET (reg, const0_rtx);
+	  XVECEXP (par, 0, j++) = set;
+	  emit_use (reg);
+	}
+
+      /* Insert APSR register clearing RTX in the pattern
+       * along with clobbering CC.  */
+      vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
+      vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
+					 VUNSPEC_CLRM_APSR);
+
+      XVECEXP (par, 0, j++) = vunspec;
+
+      rtx ccreg = gen_rtx_REG (CCmode, CC_REGNUM);
+      rtx clobber = gen_rtx_CLOBBER (VOIDmode, ccreg);
+      XVECEXP (par, 0, j) = clobber;
+
+      use_seq = get_insns ();
+      end_sequence ();
+
+      emit_insn_after (use_seq, emit_insn (par));
+      minregno = FIRST_VFP_REGNUM;
+    }
+
   /* If not marked for clearing, clearing_reg already does not contain
      any secret.  */
   if (clearing_regno <= maxregno
@@ -20627,40 +20747,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
 	    {
-	      /* Check if we have to clear the 'GE bits' which is only used if
-		 parallel add and subtraction instructions are available.  */
-	      if (TARGET_INT_SIMD)
-		snprintf (instr, sizeof (instr),
-			  "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
-	      else
-		snprintf (instr, sizeof (instr),
-			  "msr%s\tAPSR_nzcvq, %%|lr", conditional);
-
-	      output_asm_insn (instr, & operand);
-	      /* Do not clear FPSCR if targeting Armv8.1-M Mainline, VLDR takes
-		 care of it.  */
-	      if (TARGET_HARD_FLOAT && ! TARGET_HAVE_FPCXT_CMSE)
+	      /* For Armv8.1-M, this is cleared as part of the CLRM instruction
+		 emitted by cmse_nonsecure_entry_clear_before_return () and the
+		 VSTR/VLDR instructions in the prologue and epilogue.  */
+	      if (!TARGET_HAVE_FPCXT_CMSE)
 		{
-		  /* Clear the cumulative exception-status bits (0-4,7) and the
-		     condition code bits (28-31) of the FPSCR.  We need to
-		     remember to clear the first scratch register used (IP) and
-		     save and restore the second (r4).  */
-		  snprintf (instr, sizeof (instr), "push\t{%%|r4}");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "vmrs\t%%|ip, fpscr");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "movw\t%%|r4, #65376");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "movt\t%%|r4, #4095");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "and\t%%|ip, %%|r4");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "vmsr\tfpscr, %%|ip");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
-		  output_asm_insn (instr, & operand);
-		  snprintf (instr, sizeof (instr), "mov\t%%|ip, %%|lr");
+		  /* Check if we have to clear the 'GE bits' which is only used if
+		     parallel add and subtraction instructions are available.  */
+		  if (TARGET_INT_SIMD)
+		    snprintf (instr, sizeof (instr),
+			      "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
+		  else
+		    snprintf (instr, sizeof (instr),
+			      "msr%s\tAPSR_nzcvq, %%|lr", conditional);
+
 		  output_asm_insn (instr, & operand);
+		  /* Do not clear FPSCR if targeting Armv8.1-M Mainline, VLDR takes
+		     care of it.  */
+		  if (TARGET_HARD_FLOAT)
+		    {
+		      /* Clear the cumulative exception-status bits (0-4,7) and
+			 the condition code bits (28-31) of the FPSCR.  We need
+			 to remember to clear the first scratch register used
+			 (IP) and save and restore the second (r4).
+
+			 Important note: the length of the
+			 thumb2_cmse_entry_return insn pattern must account for
+			 the size of the below instructions.  */
+		      output_asm_insn ("push\t{%|r4}", & operand);
+		      output_asm_insn ("vmrs\t%|ip, fpscr", & operand);
+		      output_asm_insn ("movw\t%|r4, #65376", & operand);
+		      output_asm_insn ("movt\t%|r4, #4095", & operand);
+		      output_asm_insn ("and\t%|ip, %|r4", & operand);
+		      output_asm_insn ("vmsr\tfpscr, %|ip", & operand);
+		      output_asm_insn ("pop\t{%|r4}", & operand);
+		      output_asm_insn ("mov\t%|ip, %|lr", & operand);
+		    }
 		}
 	      snprintf (instr, sizeof (instr), "bxns\t%%|lr");
 	    }
@@ -22643,6 +22765,9 @@ arm_expand_prologue (void)
       saved_regs += 4;
       insn = emit_insn (gen_push_fpsysreg_insn (stack_pointer_rtx,
 						GEN_INT (FPCXTNS_ENUM)));
+      rtx dwarf = gen_rtx_SET (stack_pointer_rtx,
+			  plus_constant (Pmode, stack_pointer_rtx, -4));
+      add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
@@ -25059,8 +25184,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
 	{
-	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
-		       reg_containing_return_addr);
+	  /* For Armv8.1-M, this is cleared as part of the CLRM instruction
+	     emitted by cmse_nonsecure_entry_clear_before_return ().  */
+	  if (!TARGET_HAVE_FPCXT_CMSE)
+	    asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+			 reg_containing_return_addr);
 	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
 	}
       else
@@ -25300,11 +25428,14 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
          address.  It may therefore contain information that we might not want
 	 to leak, hence it must be cleared.  The value in R0 will never be a
 	 secret at this point, so it is safe to use it, see the clearing code
-	 in 'cmse_nonsecure_entry_clear_before_return'.  */
+	 in cmse_nonsecure_entry_clear_before_return ().  */
       if (reg_containing_return_addr != LR_REGNUM)
 	asm_fprintf (f, "\tmov\tlr, r0\n");
 
-      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
+      /* For Armv8.1-M, this is cleared as part of the CLRM instruction emitted
+	 by cmse_nonsecure_entry_clear_before_return ().  */
+      if (!TARGET_HAVE_FPCXT_CMSE)
+	asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
       asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
     }
   else
@@ -26842,6 +26973,9 @@ arm_expand_epilogue (bool really_return)
 
 	  insn = emit_insn (gen_pop_fpsysreg_insn (stack_pointer_rtx,
 						   GEN_INT (FPCXTNS_ENUM)));
+	  rtx dwarf = gen_rtx_SET (stack_pointer_rtx,
+				  plus_constant (Pmode, stack_pointer_rtx, 4));
+	  add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
 	  RTX_FRAME_RELATED_P (insn) = 1;
 	}
       }
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index 267c446c03e8903c21a0d74e43ae589ffcf689f4..3668c45081f116d1648ba08bab87aed9eab971c3 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -537,6 +537,12 @@
 	    (match_test "satisfies_constraint_Dy (op)")
 	    (match_test "satisfies_constraint_G (op)"))))
 
+(define_special_predicate "clear_multiple_operation"
+  (match_code "parallel")
+{
+ return clear_operation_p (op);
+})
+
 (define_special_predicate "load_multiple_operation"
   (match_code "parallel")
 {
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index 7fce50b045b40f0d29ba792dce05e43072dad3b0..f55983b2f0786245ecd27bc7f8ec7b5fff8bc408 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1576,3 +1576,43 @@
       FAIL;
  }")
 
+(define_insn "*clear_apsr"
+  [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)
+  (clobber (reg:CC CC_REGNUM))]
+  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
+  "clrm%?\\t{APSR}"
+  [(set_attr "predicable" "yes")]
+)
+
+;; The operands are validated through the clear_multiple_operation
+;; match_parallel predicate rather than through constraints so enable it only
+;; after reload.
+(define_insn "*clear_multiple"
+  [(match_parallel 0 "clear_multiple_operation"
+     [(set (match_operand:SI 1 "register_operand" "")
+	   (const_int 0))])]
+  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && reload_completed"
+  {
+    char pattern[100];
+    int i, num_saves = XVECLEN (operands[0], 0);
+
+    strcpy (pattern, \"clrm%?\\t{\");
+    for (i = 0; i < num_saves; i++)
+      {
+	if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
+	  {
+	    strcat (pattern, \"APSR\");
+	    ++i;
+	  }
+	else
+	  strcat (pattern,
+		  reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 0))]);
+	if (i < num_saves - 1)
+	  strcat (pattern, \", %|\");
+      }
+    strcat (pattern, \"}\");
+    output_asm_insn (pattern, operands);
+    return \"\";
+  }
+  [(set_attr "predicable" "yes")]
+)
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 59d354e9a918187ab2f747d5e5f8f7edd9ad7082..4dcdcc6fc3fd3ea396e1d5479c8ce0b37db065f1 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -212,6 +212,7 @@
   VUNSPEC_MRRC2		; Represent the coprocessor mrrc2 instruction.
   VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional speculation barrier.
   VUNSPEC_VSTR_VLDR	; Represent the vstr/vldr instruction.
+  VUNSPEC_CLRM_APSR	; Represent the clearing of APSR with clrm instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
index 6d611e130b6f3b544807b767927d99b89071343b..7036cb9508c27d56c4b2c01a81c44bf6f1f9c781 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -36,6 +36,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
index b7ec0a040319545b50590261278f1517bcb22796..50d4979470dd21738453e0d70c7a69ee0752ac41 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -33,6 +33,7 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
 /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
index 7b9c3f0fe061317f71d3122dea7a55ab5311f234..2b7507c900ab18705083ba1d86359e1ae36a50a2 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -34,5 +34,6 @@ main (void)
 /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
 /* { dg-final { scan-assembler "movt\tr1, 63" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index aa0ec8e0b0f0953a5a5cbc2db58413176c2505f3..35cab1f3233daac9fba50d25dac23364c798fb9c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -105,8 +105,10 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "bic" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! arm_cmse_clear_ok } } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
 
 int call_callback (void)
 {
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
index df1ea52bec533c36a738d7d3b2b2ff749b0f3713..1f5af7c2dba7747f6058d12af8ef80b4dd1b1431 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -9,5 +9,6 @@ int foo (void)
   return bar ();
 }
 
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
index 62c63b888ab49e99fba0a08b69941e73c9a8d33b..c52e1c14d9956743625e3b8a200e823f163924e3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
@@ -12,5 +12,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
index b718a70522b86e2bc58900681a781129543f8869..fdba955a32fc5ad492b74974185f98470bc49a7e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
@@ -10,6 +10,5 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
index 16536ab4f9ec5782463ab90f404a2e9f6f938850..85068ceaac6a5c0c60af4a54c0af0d20326fc18d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
@@ -13,5 +13,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
index 0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5..af69d38acf47d9d1d55480edba2b66f07e2d06ad 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
@@ -10,6 +10,5 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
index 914ea39626f2f72eac8c9c1cb495b0855e58f5e1..62201595549f07b046c7c5972d612ab155c4c38c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
@@ -13,5 +13,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
index 32435d255805331c7c56a096675b7a2af3286e5e..287f0d6faad113fbc8c30051280668baa58ab130 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
@@ -7,7 +7,5 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index eb655b5504e58dc842853c8cb874c5cef3b82aa6..7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
index ab266af7092afbce868792446124c291188e8a90..638643d0a6772d43f440df3942c6c723f1eff3ef 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
@@ -6,10 +6,6 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
@@ -26,7 +22,6 @@
 /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index fd1a24b3258e8403394dac98ff7c4712b0eb7a1b..9ec14d1a707839e4858bac72bc292fd0984bf86c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index d8f9b7758d50f74f777fcda22f3f6714ff28bb96..d375879ed02483c05d7853c95f9b9e15383ff321 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 4878c6ef9157abff003780fbf6401db8eb3ef2f3..e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
index 82aad2d13d6b170c92fd2c2345ab76f41e383013..7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
@@ -6,10 +6,6 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
@@ -19,7 +15,6 @@
 /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index 8e054c2aeebac4bd3f164b00ad867bc2d72cb674..d998b43a148250a15eb4aae9fb0ef6e4bf51203b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index e74cea7697ba1c12ebeef21636d1b8fd60b42677..e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index 4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d..d43a9f85a199ecdf7e018852b3af9b4cf36af81f 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -8,9 +8,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
index c684d79fae00feb8e15e9f142735f005473b6011..157bccb9ff3256056d496a0d0770374315b04d87 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
@@ -5,13 +5,8 @@
 #include "../../../cmse-5.x"
 
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
-/* { dg-final { scan-assembler "mov\tip, lr" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index 4cb6a54a0a5b02954519e64503d7c2c4c0e4750d..02e48157a2c61b0a8bee77e949944acc2a4bee37 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -7,10 +7,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index 4764b2fadfb38661764b909cdb2c9cd109e24df0..c7a22a2ba464dce26b289635dd8dcc8213ae33d8 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -9,8 +9,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
index 9b2e7565d24ff52138b0fb90a1e6268aa4c515a0..2522a17a6316d76a21d8d241d4c44cdddf1981e0 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
@@ -8,9 +8,6 @@
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
@@ -27,7 +24,6 @@
 /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index 9e93d75c35de5e3dde1074fb99da94edc2648319..d34ca383236fdd31723966e6218ea918cf8c9122 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index 566889e66c8cea6ca32348f48742d2c325336995..ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -10,8 +10,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..ff9a7dfa5e696e3a6c4132343d0ee94c3068c208 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -9,8 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
-/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
index 5af1fdb934ce5aa5afd8d096122b6e9b55591bd9..eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
@@ -7,10 +7,6 @@
 
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" } } */
-/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
-/* { dg-final { scan-assembler "mov\tr1, lr" } } */
-/* { dg-final { scan-assembler "mov\tr2, lr" } } */
-/* { dg-final { scan-assembler "mov\tr3, lr" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
@@ -19,7 +15,6 @@
 /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
 /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! arm_dsp } } } } */
-/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target arm_dsp } } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } } */
 /* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 1c38290e79d18a8f94e44b974c54220e553a9a49..03d36aa650986b6069e2fe1c1f3f98fa9664d88a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -8,10 +8,7 @@
 /* Checks for saving and clearing prior to function call.  */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index 39c2e72f968ce9f30d36bd347544ca26b3dfad8a..ce45e10688f855ca7b2a63777d2b3d3418815589 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -10,8 +10,7 @@
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
index d51db020c7707fa714364b10dd3ec5896a9dad17..dbd1d34413ef36f2b03716c0d9cf46b024af0835 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
@@ -10,6 +10,5 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr2, r4" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
index 131afbbf4289b238438c53ab9ea55d13b8567513..3edc7f1e259779a24e722d67ed544c0a673090c7 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
@@ -14,5 +14,5 @@
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "mov\tr3, r4" } } */
+/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
index 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..3a72406df2492206c2cb8ac7b63e4242ec0ba598 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
@@ -9,8 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
-/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
-/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
+/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
 /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
index 5f6891a26d9be6edbb81c6c9e71897d1b49c8c60..90fdac18e30424edca60b6f884227adbf716899d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -29,5 +29,6 @@ main (void)
 /* { dg-final { scan-assembler "movs\tr1, #255" } } */
 /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
 /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
+/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "bxns" } } */

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall function
  2019-11-12 10:24   ` [PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall function Kyrill Tkachov
@ 2019-12-18 13:39     ` Mihail Ionescu
  0 siblings, 0 replies; 35+ messages in thread
From: Mihail Ionescu @ 2019-12-18 13:39 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 21792 bytes --]

Hi Kyrill,

On 11/12/2019 10:22 AM, Kyrill Tkachov wrote:
> Hi Mihail,
> 
> On 10/23/19 3:24 PM, Mihail Ionescu wrote:
>> [PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall 
>> function
>>
>> Hi,
>>
>> === Context ===
>>
>> This patch is part of a patch series to add support for Armv8.1-M
>> Mainline Security Extensions architecture. Its purpose is to generate
>> lazy store and load instruction inline when calling a function with the
>> cmse_nonsecure_call attribute with the soft or softfp floating-point
>> ABI.
>>
>> === Patch description ===
>>
>> This patch adds two new patterns for the VLSTM and VLLDM instructions.
>> cmse_nonsecure_call_inline_register_clear is then modified to
>> generate VLSTM and VLLDM respectively before and after calls to
>> functions with the cmse_nonsecure_call attribute in order to have lazy
>> saving, clearing and restoring of VFP registers. Since these
>> instructions do not do writeback of the base register, the stack is 
>> adjusted
>> prior the lazy store and after the lazy load with appropriate frame
>> debug notes to describe the effect on the CFA register.
>>
>> As with CLRM, VSCCLRM and VSTR/VLDR, the instruction is modeled as an
>> unspecified operation to the memory pointed to by the base register.
>>
>> ChangeLog entries are as follows:
>>
>> *** gcc/ChangeLog ***
>>
>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm.c (arm_add_cfa_adjust_cfa_note): Declare early.
>>         (cmse_nonsecure_call_inline_register_clear): Define new 
>> lazy_fpclear
>>         variable as true when floating-point ABI is not hard.  Replace
>>         check against TARGET_HARD_FLOAT_ABI by checks against 
>> lazy_fpclear.
>>         Generate VLSTM and VLLDM instruction respectively before and
>>         after a function call to cmse_nonsecure_call function.
>>         * config/arm/unspecs.md (VUNSPEC_VLSTM): Define unspec.
>>         (VUNSPEC_VLLDM): Likewise.
>>         * config/arm/vfp.md (lazy_store_multiple_insn): New define_insn.
>>         (lazy_load_multiple_insn): Likewise.
>>
>> *** gcc/testsuite/ChangeLog ***
>>
>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Add check 
>> for VLSTM and
>>         VLLDM.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: Likewise.
>>
>> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
>> regression.
>>
>> Is this ok for trunk?
>>
>> Best regards,
>>
>> Mihail
>>
>>
>> ###############     Attachment also inlined for ease of reply 
>> ###############
>>
>>
>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>> index 
>> bcc86d50a10f11d9672258442089a0aa5c450b2f..b10f996c023e830ca24ff83fcbab335caf85d4cb 
>> 100644
>> --- a/gcc/config/arm/arm.c
>> +++ b/gcc/config/arm/arm.c
>> @@ -186,6 +186,7 @@ static int arm_register_move_cost (machine_mode, 
>> reg_class_t, reg_class_t);
>>  static int arm_memory_move_cost (machine_mode, reg_class_t, bool);
>>  static void emit_constant_insn (rtx cond, rtx pattern);
>>  static rtx_insn *emit_set_insn (rtx, rtx);
>> +static void arm_add_cfa_adjust_cfa_note (rtx, int, rtx, rtx);
>>  static rtx emit_multi_reg_push (unsigned long, unsigned long);
>>  static void arm_emit_multi_reg_pop (unsigned long);
>>  static int vfp_emit_fstmd (int, int);
>> @@ -17830,6 +17831,9 @@ cmse_nonsecure_call_inline_register_clear (void)
>>        FOR_BB_INSNS (bb, insn)
>>          {
>>            bool clear_callee_saved = TARGET_HAVE_FPCTX_CMSE;
>> +         /* frame = VFP regs + FPSCR + VPR.  */
>> +         unsigned lazy_store_stack_frame_size =
>> +           (LAST_VFP_REGNUM - FIRST_VFP_REGNUM + 1 + 2) * 
>> UNITS_PER_WORD;
>>            unsigned long callee_saved_mask =
>>              ((1 << (LAST_HI_REGNUM + 1)) - 1)
>>              & ~((1 << (LAST_ARG_REGNUM + 1)) - 1);
>> @@ -17847,7 +17851,7 @@ cmse_nonsecure_call_inline_register_clear (void)
>>            CUMULATIVE_ARGS args_so_far_v;
>>            cumulative_args_t args_so_far;
>>            tree arg_type, fntype;
>> -         bool first_param = true;
>> +         bool first_param = true, lazy_fpclear = !TARGET_HARD_FLOAT_ABI;
>>            function_args_iterator args_iter;
>>            uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
>>
>> @@ -17881,7 +17885,7 @@ cmse_nonsecure_call_inline_register_clear (void)
>>               -mfloat-abi=hard.  For -mfloat-abi=softfp we will be 
>> using the
>>               lazy store and loads which clear both caller- and 
>> callee-saved
>>               registers.  */
>> -         if (TARGET_HARD_FLOAT_ABI)
>> +         if (!lazy_fpclear)
>>              {
>>                auto_sbitmap float_bitmap (maxregno + 1);
>>
>> @@ -17965,8 +17969,23 @@ cmse_nonsecure_call_inline_register_clear (void)
>>                   disabled for pop (see below).  */
>>                RTX_FRAME_RELATED_P (push_insn) = 0;
>>
>> +             /* Lazy store multiple.  */
>> +             if (lazy_fpclear)
>> +               {
>> +                 rtx imm;
>> +                 rtx_insn *add_insn;
>> +
>> +                 imm = gen_int_mode (- lazy_store_stack_frame_size, 
>> SImode);
>> +                 add_insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
>> + stack_pointer_rtx, imm));
>> +                 arm_add_cfa_adjust_cfa_note (add_insn,
>> +                                              - 
>> lazy_store_stack_frame_size,
>> + stack_pointer_rtx,
>> + stack_pointer_rtx);
>> +                 emit_insn (gen_lazy_store_multiple_insn 
>> (stack_pointer_rtx));
>> +               }
>>                /* Save VFP callee-saved registers.  */
>> -             if (TARGET_HARD_FLOAT_ABI)
>> +             else
>>                  {
>>                    vfp_emit_fstmd (D7_VFP_REGNUM + 1,
>>                                    (max_fp_regno - D7_VFP_REGNUM) / 2);
>> @@ -17992,8 +18011,21 @@ cmse_nonsecure_call_inline_register_clear (void)
>>
>>                start_sequence ();
>>
>> +             /* Lazy load multiple done as part of libcall in 
>> Armv8-M.  */
>> +             if (lazy_fpclear)
>> +               {
>> +                 rtx imm = gen_int_mode (lazy_store_stack_frame_size, 
>> SImode);
>> +                 emit_insn (gen_lazy_load_multiple_insn 
>> (stack_pointer_rtx));
>> +                 rtx_insn *add_insn =
>> +                   emit_insn (gen_addsi3 (stack_pointer_rtx,
>> + stack_pointer_rtx, imm));
>> +                 arm_add_cfa_adjust_cfa_note (add_insn,
>> + lazy_store_stack_frame_size,
>> + stack_pointer_rtx,
>> + stack_pointer_rtx);
>> +               }
>>                /* Restore VFP callee-saved registers.  */
>> -             if (TARGET_HARD_FLOAT_ABI)
>> +             else
>>                  {
>>                    int nb_callee_saved_vfp_regs =
>>                      (max_fp_regno - D7_VFP_REGNUM) / 2;
>> diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
>> index 
>> ad072705525cc3c4035a22b5f99546bcd0e79ec5..9c9a68ae4f0a3d45f4c730f274b85f0b1ff00348 
>> 100644
>> --- a/gcc/config/arm/unspecs.md
>> +++ b/gcc/config/arm/unspecs.md
>> @@ -177,6 +177,10 @@
>>    VUNSPEC_CLRM_APSR    ; Represent the clearing of APSR with clrm 
>> instruction.
>>    VUNSPEC_VSCCLRM_VPR  ; Represent the clearing of VPR with vscclrm
>>                          ; instruction.
>> +  VUNSPEC_VLSTM                ; Represent the lazy store multiple 
>> with vlstm
>> +                       ; instruction.
>> +  VUNSPEC_VLLDM                ; Represent the lazy load multiple 
>> with vlldm
>> +                       ; instruction.
>>  ])
>>
>>  ;; Enumerators for NEON unspecs.
>> diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
>> index 
>> 2bf928f32626ce2731ebdfedffbbf64d806eff53..d3807acdd4d3691da63dcc5d6b3d5d8aad4bfe0e 
>> 100644
>> --- a/gcc/config/arm/vfp.md
>> +++ b/gcc/config/arm/vfp.md
>> @@ -1677,6 +1677,30 @@
>>     (set_attr "type" "mov_reg")]
>>  )
>>
>> +(define_insn "lazy_store_multiple_insn"
>> +  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
>> +       (plus:SI (match_dup 0) (const_int -4)))
>> +   (unspec_volatile [(const_int 0)
>> +                    (mem:SI (plus:SI (match_dup 0) (const_int -4)))]
>> +                   VUNSPEC_VLSTM)]
>> +  "use_cmse && reload_completed"
>> +  "vlstm%?\\t%0"
>> +  [(set_attr "predicable" "yes")
>> +   (set_attr "type" "store_4")]
>> +)
>> +
>> +(define_insn "lazy_load_multiple_insn"
>> +  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
>> +       (plus:SI (match_dup 0) (const_int 4)))
>> +   (unspec_volatile:SI [(const_int 0)
>> +                       (mem:SI (match_dup 0))]
>> +                      VUNSPEC_VLLDM)]
>> +  "use_cmse && reload_completed"
>> +  "vlldm%?\\t%0"
>> +  [(set_attr "predicable" "yes")
>> +   (set_attr "type" "load_4")]
>> +)
>> +
> 
> Same question on the representation as for an earlier patch.
> 
> Why aren't we using one of the POST_INC addressing modes to represent this?
> 
> Patch looks good otherwise.
> 
> Thanks,
> 
> Kyrill
> 

The patterns are now updated to use post_{inc/dec}

Regards,
Mihail

> 
> 
>>  (define_insn_and_split "*cmpsf_split_vfp"
>>    [(set (reg:CCFP CC_REGNUM)
>>          (compare:CCFP (match_operand:SF 0 "s_register_operand"  "t")
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>> index 
>> 07a6719b4f1a260a3461f7408e278dd6e71f60d3..52d22427de79c6a76fbe32b8df7f76b4b286249c 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>> @@ -11,7 +11,9 @@
>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>>  /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
>> fp, ip, APSR\}" } } */
>> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>> index 
>> ca2961ac18ccacec6907b1d1d217c6c2e28072e7..40026d5ee1cc62b4acf48be9619ccd69ef4ead7b 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>> @@ -8,7 +8,9 @@
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>> index 
>> 7a1abb51fcf9a62a24583e792953845f21bbed49..6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>> @@ -10,7 +10,9 @@
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>>  /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>> r10, fp, ip, APSR\}" } } */
>> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>> index 
>> 90aadffb7aa14ceeea22232148c11e9543eee0e7..8d05576add940c277e5a13f7aab99e6807c1553d 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>> @@ -9,7 +9,9 @@
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>> index 
>> 28f2e86dfaa89902d1c04fc2890c5445b5bb0af5..1f0a14742781b7340685338901dbfab9b700b779 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>> @@ -11,7 +11,9 @@
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>>  /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>> r10, fp, ip, APSR\}" } } */
>> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>> index 
>> 15d3b682c798dd6635ed6b90d9aa8e705fefa265..842794181087ddbd5ce59680035a0cb61ce5682e 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>> @@ -12,7 +12,9 @@
>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>>  /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
>> fp, ip, APSR\}" } } */
>> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>> index 
>> 3d48859028ab8dd22d9ffed7c95ece59c2ed937e..38c9d5457034d2427413bcce7e7be6bad80f7a67 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>> @@ -9,7 +9,9 @@
>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>>  /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>> index 
>> 0e2dcae36927d2c7187ca2b60c935504268476bc..6a17bd322fcc4e7e00ea289ee7373db9d8c37a87 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>> @@ -11,7 +11,9 @@
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> +/* { dg-final { scan-assembler "vlstm\tsp" } } */
>>  /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>> r10, fp, ip, APSR\}" } } */
>> +/* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>>

[-- Attachment #2: diff8.patch --]
[-- Type: text/x-patch, Size: 12855 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 32f51626c71610799f0c422f206a7de18ddc249d..1169cba37fc7d76f84cb060f0d6d118fdeeaba18 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -187,6 +187,7 @@ static int arm_register_move_cost (machine_mode, reg_class_t, reg_class_t);
 static int arm_memory_move_cost (machine_mode, reg_class_t, bool);
 static void emit_constant_insn (rtx cond, rtx pattern);
 static rtx_insn *emit_set_insn (rtx, rtx);
+static void arm_add_cfa_adjust_cfa_note (rtx, int, rtx, rtx);
 static rtx emit_multi_reg_push (unsigned long, unsigned long);
 static void arm_emit_multi_reg_pop (unsigned long);
 static int vfp_emit_fstmd (int, int);
@@ -18208,6 +18209,9 @@ cmse_nonsecure_call_inline_register_clear (void)
       FOR_BB_INSNS (bb, insn)
 	{
 	  bool clear_callee_saved = TARGET_HAVE_FPCXT_CMSE;
+	  /* frame = VFP regs + FPSCR + VPR.  */
+	  unsigned lazy_store_stack_frame_size
+	    = (LAST_VFP_REGNUM - FIRST_VFP_REGNUM + 1 + 2) * UNITS_PER_WORD;
 	  unsigned long callee_saved_mask
 	    = ((1 << (LAST_HI_REGNUM + 1)) - 1)
 	    & ~((1 << (LAST_ARG_REGNUM + 1)) - 1);
@@ -18225,7 +18229,7 @@ cmse_nonsecure_call_inline_register_clear (void)
 	  CUMULATIVE_ARGS args_so_far_v;
 	  cumulative_args_t args_so_far;
 	  tree arg_type, fntype;
-	  bool first_param = true;
+	  bool first_param = true, lazy_fpclear = !TARGET_HARD_FLOAT_ABI;
 	  function_args_iterator args_iter;
 	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
 
@@ -18259,7 +18263,7 @@ cmse_nonsecure_call_inline_register_clear (void)
 	     -mfloat-abi=hard.  For -mfloat-abi=softfp we will be using the
 	     lazy store and loads which clear both caller- and callee-saved
 	     registers.  */
-	  if (TARGET_HARD_FLOAT_ABI)
+	  if (!lazy_fpclear)
 	    {
 	      auto_sbitmap float_bitmap (maxregno + 1);
 
@@ -18343,8 +18347,23 @@ cmse_nonsecure_call_inline_register_clear (void)
 		 disabled for pop (see below).  */
 	      RTX_FRAME_RELATED_P (push_insn) = 0;
 
+	      /* Lazy store multiple.  */
+	      if (lazy_fpclear)
+		{
+		  rtx imm;
+		  rtx_insn *add_insn;
+
+		  imm = gen_int_mode (- lazy_store_stack_frame_size, SImode);
+		  add_insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
+						    stack_pointer_rtx, imm));
+		  arm_add_cfa_adjust_cfa_note (add_insn,
+					       - lazy_store_stack_frame_size,
+					       stack_pointer_rtx,
+					       stack_pointer_rtx);
+		  emit_insn (gen_lazy_store_multiple_insn (stack_pointer_rtx));
+		}
 	      /* Save VFP callee-saved registers.  */
-	      if (TARGET_HARD_FLOAT_ABI)
+	      else
 		{
 		  vfp_emit_fstmd (D7_VFP_REGNUM + 1,
 				  (max_fp_regno - D7_VFP_REGNUM) / 2);
@@ -18370,8 +18389,21 @@ cmse_nonsecure_call_inline_register_clear (void)
 
 	      start_sequence ();
 
+	      /* Lazy load multiple done as part of libcall in Armv8-M.  */
+	      if (lazy_fpclear)
+		{
+		  rtx imm = gen_int_mode (lazy_store_stack_frame_size, SImode);
+		  emit_insn (gen_lazy_load_multiple_insn (stack_pointer_rtx));
+		  rtx_insn *add_insn =
+		    emit_insn (gen_addsi3 (stack_pointer_rtx,
+					   stack_pointer_rtx, imm));
+		  arm_add_cfa_adjust_cfa_note (add_insn,
+					       lazy_store_stack_frame_size,
+					       stack_pointer_rtx,
+					       stack_pointer_rtx);
+		}
 	      /* Restore VFP callee-saved registers.  */
-	      if (TARGET_HARD_FLOAT_ABI)
+	      else
 		{
 		  int nb_callee_saved_vfp_regs =
 		    (max_fp_regno - D7_VFP_REGNUM) / 2;
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 335b2a6d4a2cdc8bca807b5bf3e623d7a165922a..430d03d319ec1515d2408cdc904d52890238ba92 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -215,6 +215,10 @@
   VUNSPEC_CLRM_APSR	; Represent the clearing of APSR with clrm instruction.
   VUNSPEC_VSCCLRM_VPR	; Represent the clearing of VPR with vscclrm
 			; instruction.
+  VUNSPEC_VLSTM		; Represent the lazy store multiple with vlstm
+			; instruction.
+  VUNSPEC_VLLDM		; Represent the lazy load multiple with vlldm
+			; instruction.
 ])
 
 ;; Enumerators for NEON unspecs.
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index a2d8b80374f7198e00a05d35b31d4946c5f1491f..c91e750a687652d103f9952312d3625ca4e1c977 100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -1673,6 +1673,30 @@
    (set_attr "type" "mov_reg")]
 )
 
+(define_insn "lazy_store_multiple_insn"
+  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
+	(post_dec:SI (match_dup 0)))
+   (unspec_volatile [(const_int 0)
+		     (mem:SI (post_dec:SI (match_dup 0)))]
+		    VUNSPEC_VLSTM)]
+  "use_cmse && reload_completed"
+  "vlstm%?\\t%0"
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "store_4")]
+)
+
+(define_insn "lazy_load_multiple_insn"
+  [(set (match_operand:SI 0 "s_register_operand" "+&rk")
+	(post_inc:SI (match_dup 0)))
+   (unspec_volatile:SI [(const_int 0)
+			(mem:SI (match_dup 0))]
+		       VUNSPEC_VLLDM)]
+  "use_cmse && reload_completed"
+  "vlldm%?\\t%0"
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "load_4")]
+)
+
 (define_insn_and_split "*cmpsf_split_vfp"
   [(set (reg:CCFP CC_REGNUM)
 	(compare:CCFP (match_operand:SF 0 "s_register_operand"  "t")
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index 07a6719b4f1a260a3461f7408e278dd6e71f60d3..52d22427de79c6a76fbe32b8df7f76b4b286249c 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index ca2961ac18ccacec6907b1d1d217c6c2e28072e7..40026d5ee1cc62b4acf48be9619ccd69ef4ead7b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -8,7 +8,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index 7a1abb51fcf9a62a24583e792953845f21bbed49..6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -10,7 +10,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index 90aadffb7aa14ceeea22232148c11e9543eee0e7..8d05576add940c277e5a13f7aab99e6807c1553d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -9,7 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index 28f2e86dfaa89902d1c04fc2890c5445b5bb0af5..1f0a14742781b7340685338901dbfab9b700b779 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index 15d3b682c798dd6635ed6b90d9aa8e705fefa265..842794181087ddbd5ce59680035a0cb61ce5682e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -12,7 +12,9 @@
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 3d48859028ab8dd22d9ffed7c95ece59c2ed937e..38c9d5457034d2427413bcce7e7be6bad80f7a67 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -9,7 +9,9 @@
 /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index 0e2dcae36927d2c7187ca2b60c935504268476bc..6a17bd322fcc4e7e00ea289ee7373db9d8c37a87 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -11,7 +11,9 @@
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
+/* { dg-final { scan-assembler "vlstm\tsp" } } */
 /* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 9/10] Call nscall function with blxns
  2019-11-12 10:25   ` [PATCH, GCC/ARM, 9/10] Call nscall function with blxns Kyrill Tkachov
@ 2019-12-18 13:52     ` Mihail Ionescu
  2019-12-18 17:00       ` Kyrill Tkachov
  0 siblings, 1 reply; 35+ messages in thread
From: Mihail Ionescu @ 2019-12-18 13:52 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 64859 bytes --]

Hi,

On 11/12/2019 10:23 AM, Kyrill Tkachov wrote:
> 
> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>> [PATCH, GCC/ARM, 9/10] Call nscall function with blxns
>>
>> Hi,
>>
>> === Context ===
>>
>> This patch is part of a patch series to add support for Armv8.1-M
>> Mainline Security Extensions architecture. Its purpose is to call
>> functions with the cmse_nonsecure_call attribute directly using blxns
>> with no undue restriction on the register used for that.
>>
>> === Patch description ===
>>
>> This change to use BLXNS to call a nonsecure function from secure
>> directly (not using a libcall) is made in 2 steps:
>> - change nonsecure_call patterns to use blxns instead of calling
>>   __gnu_cmse_nonsecure_call
>> - loosen requirement for function address to allow any register when
>>   doing BLXNS.
>>
>> The former is a straightforward check over whether instructions added in
>> Armv8.1-M Mainline are available while the latter consist in making the
>> nonsecure call pattern accept any register by using match_operand and
>> changing the nonsecure_call_internal expander to no force r4 when
>> targeting Armv8.1-M Mainline.
>>
>> The tricky bit is actually in the test update, specifically how to check
>> that register lists for CLRM have all registers except for the one
>> holding parameters (already done) and the one holding the address used
>> by BLXNS. This is achieved with 3 scan-assembler directives.
>>
>> 1) The first one lists all registers that can appear in CLRM but make
>>    each of them optional.
>>    Property guaranteed: no wrong register is cleared and none appears
>>    twice in the register list.
>> 2) The second directive check that the CLRM is made of a fixed number
>>    of the right registers to be cleared. The number used is the number
>>    of registers that could contain a secret minus one (used to hold the
>>    address of the function to call.
>>    Property guaranteed: register list has the right number of registers
>>    Cumulated property guaranteed: only registers with a potential secret
>>    are cleared and they are all listed but ont
>> 3) The last directive checks that we cannot find a CLRM with a register
>>    in it that also appears in BLXNS. This is check via the use of a
>>    back-reference on any of the allowed register in CLRM, the
>>    back-reference enforcing that whatever register match in CLRM must be
>>    the same in the BLXNS.
>>    Property guaranteed: register used for BLXNS is different from
>>    registers cleared in CLRM.
>>
>> Some more care needs to happen for the gcc.target/arm/cmse/cmse-1.c
>> testcase due to there being two CLRM generated. To ensure the third
>> directive match the right CLRM to the BLXNS, a negative lookahead is
>> used between the CLRM register list and the BLXNS. The way negative
>> lookahead work is by matching the *position* where a given regular
>> expression does not match. In this case, since it comes after the CLRM
>> register list it is requesting that what comes after the register list
>> does not have a CLRM again followed by BLXNS. This guarantees that the
>> .*blxns after only matches a blxns without another CLRM before.
>>
>> ChangeLog entries are as follows:
>>
>> *** gcc/ChangeLog ***
>>
>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm.md (nonsecure_call_internal): Do not force 
>> memory
>>         address in r4 when targeting Armv8.1-M Mainline.
>>         (nonsecure_call_value_internal): Likewise.
>>         * config/arm/thumb2.md (nonsecure_call_reg_thumb2): Make 
>> memory address
>>         a register match_operand again.  Emit BLXNS when targeting
>>         Armv8.1-M Mainline.
>>         (nonsecure_call_value_reg_thumb2): Likewise.
>>
>> *** gcc/testsuite/ChangeLog ***
>>
>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/cmse-1.c: Add check for BLXNS when 
>> instructions
>>         introduced in Armv8.1-M Mainline Security Extensions are 
>> available and
>>         restrict checks for libcall to __gnu_cmse_nonsecure_call to 
>> Armv8-M
>>         targets only.  Adapt CLRM check to verify register used for 
>> BLXNS is
>>         not in the CLRM register list.
>>         * gcc.target/arm/cmse/cmse-14.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise and 
>> adapt
>>         check for LSB clearing bit to be using the same register as 
>> BLXNS when
>>         targeting Armv8.1-M Mainline.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: 
>> Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
>>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.
>>         * gcc.target/arm/cmse/cmse-15.c: Count BLXNS when targeting 
>> Armv8.1-M
>>         Mainline and restrict libcall count to Armv8-M.
>>
>> Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; 
>> testsuite shows no
>> regression.
>>
>> Is this ok for trunk?
>>
> Ok.
> 
> Thanks,
> 
> Kyrill
> 
> 


I found a small issue with this one. The constraint for the first 
operand of nonsecure_call_reg_thumb2 was wrong as it allowed it to pick 
and overwrite the ip register which can hold the address for the non 
secure call. The constraint has now been changed to pick one of the low 
registers.


Regards,
Mihail

>> Best regards,
>>
>> Mihail
>>
>>
>> ###############     Attachment also inlined for ease of reply 
>> ###############
>>
>>
>> diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
>> index 
>> d607f88cb05ffa9cd8a47b8c8e0c53ea3a5ca411..b7af3c060427d972e3cd1c7a8055aec20335c02b 
>> 100644
>> --- a/gcc/config/arm/arm.md
>> +++ b/gcc/config/arm/arm.md
>> @@ -7561,12 +7561,15 @@
>>    "use_cmse"
>>    "
>>    {
>> -    rtx tmp;
>> -    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
>> +    if (!TARGET_HAVE_FPCTX_CMSE)
>> +      {
>> +       rtx tmp =
>> +         copy_to_suggested_reg (XEXP (operands[0], 0),
>>                                   gen_rtx_REG (SImode, R4_REGNUM),
>>                                   SImode);
>>
>> -    operands[0] = replace_equiv_address (operands[0], tmp);
>> +       operands[0] = replace_equiv_address (operands[0], tmp);
>> +      }
>>    }")
>>
>>  (define_insn "*call_reg_armv5"
>> @@ -7669,12 +7672,15 @@
>>    "use_cmse"
>>    "
>>    {
>> -    rtx tmp;
>> -    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
>> +    if (!TARGET_HAVE_FPCTX_CMSE)
>> +      {
>> +       rtx tmp =
>> +         copy_to_suggested_reg (XEXP (operands[1], 0),
>>                                   gen_rtx_REG (SImode, R4_REGNUM),
>>                                   SImode);
>>
>> -    operands[1] = replace_equiv_address (operands[1], tmp);
>> +       operands[1] = replace_equiv_address (operands[1], tmp);
>> +      }
>>    }")
>>
>>  (define_insn "*call_value_reg_armv5"
>> diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
>> index 
>> 19d25cfe9b97b9428e3a6daebbf8dfb5648f29ef..964b3e2afcd524bb342373b400e35d0a72c4bd7f 
>> 100644
>> --- a/gcc/config/arm/thumb2.md
>> +++ b/gcc/config/arm/thumb2.md
>> @@ -560,13 +560,18 @@
>>  )
>>
>>  (define_insn "*nonsecure_call_reg_thumb2"
>> -  [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
>> +  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" 
>> "r"))]
>>                      UNSPEC_NONSECURE_MEM)
>> -        (match_operand 0 "" ""))
>> -   (use (match_operand 1 "" ""))
>> +        (match_operand 1 "" ""))
>> +   (use (match_operand 2 "" ""))
>>     (clobber (reg:SI LR_REGNUM))]
>>    "TARGET_THUMB2 && use_cmse"
>> -  "bl\\t__gnu_cmse_nonsecure_call"
>> +  {
>> +    if (TARGET_HAVE_FPCTX_CMSE)
>> +      return "blxns\\t%0";
>> +    else
>> +      return "bl\\t__gnu_cmse_nonsecure_call";
>> +  }
>>    [(set_attr "length" "4")
>>     (set_attr "type" "call")]
>>  )
>> @@ -585,13 +590,18 @@
>>  (define_insn "*nonsecure_call_value_reg_thumb2"
>>    [(set (match_operand 0 "" "")
>>          (call
>> -        (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
>> +        (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" 
>> "l*r"))]
>>                      UNSPEC_NONSECURE_MEM)
>> -        (match_operand 1 "" "")))
>> -   (use (match_operand 2 "" ""))
>> +        (match_operand 2 "" "")))
>> +   (use (match_operand 3 "" ""))
>>     (clobber (reg:SI LR_REGNUM))]
>>    "TARGET_THUMB2 && use_cmse"
>> -  "bl\t__gnu_cmse_nonsecure_call"
>> +  {
>> +    if (TARGET_HAVE_FPCTX_CMSE)
>> +      return "blxns\\t%1";
>> +    else
>> +      return "bl\\t__gnu_cmse_nonsecure_call";
>> +  }
>>    [(set_attr "length" "4")
>>     (set_attr "type" "call")]
>>  )
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>> index 
>> 9f36fa3b1d8b86b4e1827909fca4fee181ba1c61..ddfcfacab5f601a729319a9d2dab03e61ee56bca 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>> @@ -110,7 +110,13 @@ qux (int_nsfunc_t * callback)
>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
>> arm_cmse_clear_ok } } } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" { target arm_cmse_clear_ok } } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" { target arm_cmse_clear_ok } } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" { target arm_cmse_clear_ok } } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}(?!.*clrm.*blxns).*blxns\t\\1" 
>> { target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" { target arm_cmse_clear_ok } } } */
>>
>>  int call_callback (void)
>> @@ -120,4 +126,5 @@ int call_callback (void)
>>    else
>>      return default_callback ();
>>  }
>> -/* { dg-final { scan-assembler-times 
>> "bl\\s+__gnu_cmse_nonsecure_call" 1 } } */
>> +/* { dg-final { scan-assembler-times 
>> "bl\\s+__gnu_cmse_nonsecure_call" 1 { target { ! arm_cmse_clear_ok } } 
>> } } */
>> +/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } } 
>> } */
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>> index 
>> 6d39afab44329e78a8ff2f693fd94fe6a501af5a..5ab97856066e14c0005b56210e62f2b7a59fd911 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>> @@ -10,7 +10,15 @@ int foo (void)
>>  }
>>
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" { target arm_cmse_clear_ok } } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" { target arm_cmse_clear_ok } } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" { target arm_cmse_clear_ok } } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" { 
>> target arm_cmse_clear_ok } } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" { target arm_cmse_clear_ok } } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> -/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
>> +/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" { 
>> target { ! arm_cmse_clear_ok } } } } */
>> +/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" { 
>> target { ! arm_cmse_clear_ok } } } } */
>> +/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } } 
>> } */
>> +/* { dg-final { scan-assembler-not 
>> "^(.*\\s)?bl?(?!xns)\[^\\s]*\\s+bar" { target arm_cmse_clear_ok } } } */
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
>> index 
>> 4e9ace1f3f33b8a8653797e29ca62eb3dd7ae918..0e37b50e004d74dc81f5a8bdc0c9ba21ceaca67d 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
>> @@ -69,4 +69,9 @@ int secure5 (void)
>>  {
>>    return (*s_bar2) ();
>>  }
>> -/* { dg-final { scan-assembler-times 
>> "bl\\s+__gnu_cmse_nonsecure_call" 6 } } */
>> +
>> +/* ARMv8-M expectation.  */
>> +/* { dg-final { scan-assembler-times 
>> "bl\\s+__gnu_cmse_nonsecure_call" 6 { target { ! arm_cmse_clear_ok } } 
>> } } */
>> +
>> +/* ARMv8.1-M expectation.  */
>> +/* { dg-final { scan-assembler-times "blxns" 6 { target 
>> arm_cmse_clear_ok } } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>> index 
>> d4caf513ed2153370369bddbfcf6d2568d9f2f1e..ff34edb21c36c9f114aa934fa86ea962d932f273 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>> @@ -10,9 +10,16 @@
>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>  /* { dg-final { scan-assembler "mov\tip, #3" } } */
>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
>> fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
>> ){9}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>> index 
>> 2b7655a2c9971fb0aad4e6c8a1fee72e21028fad..4d1407aba4418006463fdca59cbe90e768e78391 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>> @@ -8,9 +8,16 @@
>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>  /* { dg-final { scan-assembler "movw\tip, #2047" } } */
>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>> r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>> ){10}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>> index 
>> 1a62076df9d6831d06f5ac6bdcb7deed0ecd23f8..9b1227adfdc03457266573447c7996245a114110 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>> @@ -11,9 +11,16 @@
>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>  /* { dg-final { scan-assembler "mov\tip, #255" } } */
>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
>> fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
>> ){9}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>> index 
>> 1319ac9766bcd330f6d8f0f7754a64a1dcc105b1..aec958fc9b9d125c54022911ee34affa9dd81797 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>> @@ -8,9 +8,16 @@
>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>  /* { dg-final { scan-assembler "movw\tip, #2047" } } */
>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>> r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>> ){10}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>> index 
>> 9bb60175529d77a3b1868f62a5a4d5355f00b76b..ae039e292d55423b1dc1b19551278418224bbe5e 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>> @@ -11,9 +11,16 @@
>>  /* { dg-final { scan-assembler "movw\tip, #65535" } } */
>>  /* { dg-final { scan-assembler "movt\tip, 31" } } */
>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
>> fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
>> ){9}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>> index 
>> 11ca78bfdaf1ebe09f9699c278dc3db4fd20768c..f455f8cf19b1d8f32bd6ca208d33c144da644c29 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>> @@ -5,9 +5,16 @@
>>
>>  /* { dg-final { scan-assembler "movw\tip, #1799" } } */
>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[1-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[1-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, r5, r6, r7, r8, 
>> r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r2, )?(r3, )?(r4, 
>> )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[1-9\]|r10|fp|ip), 
>> ){11}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[1-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
>> index 
>> 2f14c52715e0ad6e6ab69b01713ee13985a22653..3e76364c40452a7946e3b97e2321fd6e6d204355 
>> 100644
>> --- 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
>> +++ 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
>> @@ -15,9 +15,16 @@
>>  /* { dg-final { scan-assembler "movw\tip, #65535" } } */
>>  /* { dg-final { scan-assembler "movt\tip, 31" } } */
>>  /* { dg-final { scan-assembler "and\tr3, r3, ip" } } */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[4-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[4-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r5, r6, r7, r8, r9, r10, fp, 
>> ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r4, )?(r5, )?(r6, )?(r7, 
>> )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[4-9\]|r10|fp|ip), 
>> ){8}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>> index 
>> e759db24fac27be2de664ad4faced7bb5d3be84a..0c49277389271321c7fd7faa6ae6aaee2c299def 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>> @@ -6,11 +6,18 @@
>>  #include "../../../cmse-13.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>> d13, d14, d15\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
>> @@ -20,4 +27,4 @@
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>> index 
>> 9df7b5de3ad64e719fc97d7a67a4893398e87b32..3c66b0a8c6f1c7be6c8cf77b2c71916a08c7b357 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>> @@ -6,14 +6,21 @@
>>  #include "../../../cmse-7.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>> d13, d14, d15\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
>>  /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>> index 
>> b36ff73cb9b46d4d3a91f854c022787dc000d9c3..7d456c39705b15fa5b55270ac6b4ed57f5c7e465 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>> @@ -6,11 +6,18 @@
>>  #include "../../../cmse-8.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>> d13, d14, d15\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
>> @@ -18,4 +25,4 @@
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>> index 
>> 72493f032355828bdf48b84dc98d8102becd1b36..ab95c83a1167aff9fd4c0e24fe5580895cfbf0bb 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>> @@ -6,11 +6,18 @@
>>  #include "../../../cmse-13.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>> d13, d14, d15\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
>> @@ -22,4 +29,4 @@
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>> index 
>> 112ed78d6f172be31d4a4f06840d32a90cdf3dd4..cf58d547972e21e0816a1bdf74968d0b50d2bd08 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>> @@ -6,14 +6,21 @@
>>  #include "../../../cmse-7.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>> d13, d14, d15\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
>>  /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>> index 
>> f48e8a0a020cebed8c9fa124d352f047442979d6..1854d03d0814c90f8014a28fb1c81c6866f0071d 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>> @@ -6,15 +6,22 @@
>>  #include "../../../cmse-8.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>> d13, d14, d15\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>  /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
>>  /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>> index 
>> 52d22427de79c6a76fbe32b8df7f76b4b286249c..1b207c394081e6ec9bf569961a4a059d5b47fe20 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>> @@ -5,18 +5,25 @@
>>  #include "../../../cmse-13.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
>> fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, 
>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), 
>> ){9}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>> index 
>> 40026d5ee1cc62b4acf48be9619ccd69ef4ead7b..3ec639480868944ed29065936c1fab10aa9e0fed 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>> @@ -5,15 +5,22 @@
>>  #include "../../../cmse-7.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>> index 
>> 6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4..5c1d245d4aa966812e52f327c7ceba5dabba2e18 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>> @@ -5,17 +5,24 @@
>>  #include "../../../cmse-8.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>> r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>> ){10}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>> index 
>> 8d05576add940c277e5a13f7aab99e6807c1553d..3228692c2686fcae8e1369f984aaa6c375ad6418 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>> @@ -6,13 +6,20 @@
>>  #include "../../../cmse-7.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>> index 
>> 1f0a14742781b7340685338901dbfab9b700b779..1c60d97dabd99136533a61fef5ae099eae4bbc93 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>> @@ -6,15 +6,22 @@
>>  #include "../../../cmse-8.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>> r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>> ){10}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>> index 
>> 842794181087ddbd5ce59680035a0cb61ce5682e..c366f6ae4ccc65d943dbbf045925ca9c6e8921ca 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>> @@ -6,16 +6,23 @@
>>  #include "../../../cmse-13.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, 
>> fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, 
>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), 
>> ){9}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>> index 
>> 38c9d5457034d2427413bcce7e7be6bad80f7a67..186a4480f4e816bdb2413ecbc690470e1c2480e6 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>> @@ -6,13 +6,20 @@
>>  #include "../../../cmse-7.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>> r8, r9, r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>> )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>> ){12}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>> index 
>> 6a17bd322fcc4e7e00ea289ee7373db9d8c37a87..f0f74f06bbd1eed2f71b46bc8947c99ce1de0765 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>> @@ -6,15 +6,22 @@
>>  #include "../../../cmse-8.x"
>>
>>  /* Checks for saving and clearing prior to function call. */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>> r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>> ){10}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>>
>>  /* Now we check that we use the correct intrinsic to call. */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>> index 
>> 43e58ebde56ceb229edca2db25b720c42207c100..4d58eed1ac21e32dfa893397736be45129af53b8 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>> @@ -8,9 +8,16 @@
>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>  /* { dg-final { scan-assembler "movw\tip, #511" } } */
>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>> r10, fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>> ){10}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c 
>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>> index 
>> 6adf8fae5c3a56a6e50278919a2edbd2fda58f42..95de458b50172f6e84ffc2625fc35eca8f65108a 
>> 100644
>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>> @@ -12,9 +12,16 @@
>>  /* { dg-final { scan-assembler "movw\tip, #65535" } } */
>>  /* { dg-final { scan-assembler "movt\tip, 31" } } */
>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>> +/* Shift on the same register as blxns.  */
>> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
>> #1.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, 
>> fp, ip, APSR\}" } } */
>> +/* Check the right registers are cleared and none appears twice.  */
>> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>> +/* Check that the right number of registers is cleared and thus only one
>> +   register is missing.  */
>> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
>> ){9}APSR\}" } } */
>> +/* Check that no cleared register is used for blxns.  */
>> +/* { dg-final { scan-assembler-not 
>> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>> fp\}" } } */
>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>> +/* { dg-final { scan-assembler "blxns" } } */
>>

[-- Attachment #2: diff9.patch --]
[-- Type: text/x-patch, Size: 52893 bytes --]

diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 4f035cbfddd574c86cd907b579ddaf93be179943..d3ac2ff54b62206be3c70461b98c5e122ff3b340 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -7984,12 +7984,15 @@
   "use_cmse"
   "
   {
-    rtx tmp;
-    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+    if (!TARGET_HAVE_FPCXT_CMSE)
+      {
+	rtx tmp =
+	  copy_to_suggested_reg (XEXP (operands[0], 0),
 				 gen_rtx_REG (SImode, R4_REGNUM),
 				 SImode);
 
-    operands[0] = replace_equiv_address (operands[0], tmp);
+	operands[0] = replace_equiv_address (operands[0], tmp);
+      }
   }")
 
 (define_insn "*call_reg_armv5"
@@ -8092,12 +8095,15 @@
   "use_cmse"
   "
   {
-    rtx tmp;
-    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+    if (!TARGET_HAVE_FPCXT_CMSE)
+      {
+	rtx tmp =
+	  copy_to_suggested_reg (XEXP (operands[1], 0),
 				 gen_rtx_REG (SImode, R4_REGNUM),
 				 SImode);
 
-    operands[1] = replace_equiv_address (operands[1], tmp);
+	operands[1] = replace_equiv_address (operands[1], tmp);
+      }
   }")
 
 (define_insn "*call_value_reg_armv5"
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index f55983b2f0786245ecd27bc7f8ec7b5fff8bc408..8c08629a9e5e0621073132dc0e41a788b3581273 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -537,13 +537,18 @@
 )
 
 (define_insn "*nonsecure_call_reg_thumb2"
-  [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "l*r"))]
 		    UNSPEC_NONSECURE_MEM)
-	 (match_operand 0 "" ""))
-   (use (match_operand 1 "" ""))
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_THUMB2 && use_cmse"
-  "bl\\t__gnu_cmse_nonsecure_call"
+  {
+    if (TARGET_HAVE_FPCXT_CMSE)
+      return "blxns\\t%0";
+    else
+      return "bl\\t__gnu_cmse_nonsecure_call";
+  }
   [(set_attr "length" "4")
    (set_attr "type" "call")]
 )
@@ -562,13 +567,18 @@
 (define_insn "*nonsecure_call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call
-	 (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
 		    UNSPEC_NONSECURE_MEM)
-	 (match_operand 1 "" "")))
-   (use (match_operand 2 "" ""))
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_THUMB2 && use_cmse"
-  "bl\t__gnu_cmse_nonsecure_call"
+  {
+    if (TARGET_HAVE_FPCXT_CMSE)
+      return "blxns\\t%1";
+    else
+      return "bl\\t__gnu_cmse_nonsecure_call";
+  }
   [(set_attr "length" "4")
    (set_attr "type" "call")]
 )
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index 9f36fa3b1d8b86b4e1827909fca4fee181ba1c61..ddfcfacab5f601a729319a9d2dab03e61ee56bca 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -110,7 +110,13 @@ qux (int_nsfunc_t * callback)
 /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! arm_cmse_clear_ok } } } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}(?!.*clrm.*blxns).*blxns\t\\1" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
 
 int call_callback (void)
@@ -120,4 +126,5 @@ int call_callback (void)
   else
     return default_callback ();
 }
-/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 1 } } */
+/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 1 { target { ! arm_cmse_clear_ok } } } } */
+/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
index 6d39afab44329e78a8ff2f693fd94fe6a501af5a..5ab97856066e14c0005b56210e62f2b7a59fd911 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -10,7 +10,15 @@ int foo (void)
 }
 
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" { target arm_cmse_clear_ok } } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" { target arm_cmse_clear_ok } } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" { target arm_cmse_clear_ok } } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
-/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" { target { ! arm_cmse_clear_ok } } } } */
+/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" { target { ! arm_cmse_clear_ok } } } } */
+/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } } } */
+/* { dg-final { scan-assembler-not "^(.*\\s)?bl?(?!xns)\[^\\s]*\\s+bar" { target arm_cmse_clear_ok } } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
index 4e9ace1f3f33b8a8653797e29ca62eb3dd7ae918..0e37b50e004d74dc81f5a8bdc0c9ba21ceaca67d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
@@ -69,4 +69,9 @@ int secure5 (void)
 {
   return (*s_bar2) ();
 }
-/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 6 } } */
+
+/* ARMv8-M expectation.  */
+/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 6 { target { ! arm_cmse_clear_ok } } } } */
+
+/* ARMv8.1-M expectation.  */
+/* { dg-final { scan-assembler-times "blxns" 6 { target arm_cmse_clear_ok } } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
index d4caf513ed2153370369bddbfcf6d2568d9f2f1e..ff34edb21c36c9f114aa934fa86ea962d932f273 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
@@ -10,9 +10,16 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "mov\tip, #3" } } */
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
index 2b7655a2c9971fb0aad4e6c8a1fee72e21028fad..4d1407aba4418006463fdca59cbe90e768e78391 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
@@ -8,9 +8,16 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "movw\tip, #2047" } } */
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
index 1a62076df9d6831d06f5ac6bdcb7deed0ecd23f8..9b1227adfdc03457266573447c7996245a114110 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
@@ -11,9 +11,16 @@
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
 /* { dg-final { scan-assembler "mov\tip, #255" } } */
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
index 1319ac9766bcd330f6d8f0f7754a64a1dcc105b1..aec958fc9b9d125c54022911ee34affa9dd81797 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
@@ -8,9 +8,16 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "movw\tip, #2047" } } */
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
index 9bb60175529d77a3b1868f62a5a4d5355f00b76b..ae039e292d55423b1dc1b19551278418224bbe5e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
@@ -11,9 +11,16 @@
 /* { dg-final { scan-assembler "movw\tip, #65535" } } */
 /* { dg-final { scan-assembler "movt\tip, 31" } } */
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
index 11ca78bfdaf1ebe09f9699c278dc3db4fd20768c..f455f8cf19b1d8f32bd6ca208d33c144da644c29 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
@@ -5,9 +5,16 @@
 
 /* { dg-final { scan-assembler "movw\tip, #1799" } } */
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[1-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[1-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[1-9\]|r10|fp|ip), ){11}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[1-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
index 2f14c52715e0ad6e6ab69b01713ee13985a22653..3e76364c40452a7946e3b97e2321fd6e6d204355 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
@@ -15,9 +15,16 @@
 /* { dg-final { scan-assembler "movw\tip, #65535" } } */
 /* { dg-final { scan-assembler "movt\tip, 31" } } */
 /* { dg-final { scan-assembler "and\tr3, r3, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[4-9\]|r10|fp|ip), ){8}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
index e759db24fac27be2de664ad4faced7bb5d3be84a..0c49277389271321c7fd7faa6ae6aaee2c299def 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
@@ -6,11 +6,18 @@
 #include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
@@ -20,4 +27,4 @@
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
index 9df7b5de3ad64e719fc97d7a67a4893398e87b32..3c66b0a8c6f1c7be6c8cf77b2c71916a08c7b357 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
@@ -6,14 +6,21 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
 /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
index b36ff73cb9b46d4d3a91f854c022787dc000d9c3..7d456c39705b15fa5b55270ac6b4ed57f5c7e465 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
@@ -6,11 +6,18 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
@@ -18,4 +25,4 @@
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
index 72493f032355828bdf48b84dc98d8102becd1b36..ab95c83a1167aff9fd4c0e24fe5580895cfbf0bb 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
@@ -6,11 +6,18 @@
 #include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
@@ -22,4 +29,4 @@
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
index 112ed78d6f172be31d4a4f06840d32a90cdf3dd4..cf58d547972e21e0816a1bdf74968d0b50d2bd08 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
@@ -6,14 +6,21 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
 /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
index f48e8a0a020cebed8c9fa124d352f047442979d6..1854d03d0814c90f8014a28fb1c81c6866f0071d 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
@@ -6,15 +6,22 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, d13, d14, d15\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
 /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
 /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
index 52d22427de79c6a76fbe32b8df7f76b4b286249c..1b207c394081e6ec9bf569961a4a059d5b47fe20 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
@@ -5,18 +5,25 @@
 #include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
index 40026d5ee1cc62b4acf48be9619ccd69ef4ead7b..3ec639480868944ed29065936c1fab10aa9e0fed 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
@@ -5,15 +5,22 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
index 6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4..5c1d245d4aa966812e52f327c7ceba5dabba2e18 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
@@ -5,17 +5,24 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler-not "vmov" } } */
 /* { dg-final { scan-assembler-not "vmsr" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
index 8d05576add940c277e5a13f7aab99e6807c1553d..3228692c2686fcae8e1369f984aaa6c375ad6418 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
@@ -6,13 +6,20 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
index 1f0a14742781b7340685338901dbfab9b700b779..1c60d97dabd99136533a61fef5ae099eae4bbc93 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
@@ -6,15 +6,22 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
index 842794181087ddbd5ce59680035a0cb61ce5682e..c366f6ae4ccc65d943dbbf045925ca9c6e8921ca 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
@@ -6,16 +6,23 @@
 #include "../../../cmse-13.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
index 38c9d5457034d2427413bcce7e7be6bad80f7a67..186a4480f4e816bdb2413ecbc690470e1c2480e6 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
@@ -6,13 +6,20 @@
 #include "../../../cmse-7.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), ){12}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
index 6a17bd322fcc4e7e00ea289ee7373db9d8c37a87..f0f74f06bbd1eed2f71b46bc8947c99ce1de0765 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
@@ -6,15 +6,22 @@
 #include "../../../cmse-8.x"
 
 /* Checks for saving and clearing prior to function call.  */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
 /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 /* { dg-final { scan-assembler "vlstm\tsp" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "vlldm\tsp" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
 
 /* Now we check that we use the correct intrinsic to call.  */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
index 43e58ebde56ceb229edca2db25b720c42207c100..4d58eed1ac21e32dfa893397736be45129af53b8 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
@@ -8,9 +8,16 @@
 /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
 /* { dg-final { scan-assembler "movw\tip, #511" } } */
 /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), ){10}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
index 6adf8fae5c3a56a6e50278919a2edbd2fda58f42..95de458b50172f6e84ffc2625fc35eca8f65108a 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
@@ -12,9 +12,16 @@
 /* { dg-final { scan-assembler "movw\tip, #65535" } } */
 /* { dg-final { scan-assembler "movt\tip, 31" } } */
 /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
-/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
-/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* Shift on the same register as blxns.  */
+/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
+/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, #1.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, r10, fp, ip, APSR\}" } } */
+/* Check the right registers are cleared and none appears twice.  */
+/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
+/* Check that the right number of registers is cleared and thus only one
+   register is missing.  */
+/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), ){9}APSR\}" } } */
+/* Check that no cleared register is used for blxns.  */
+/* { dg-final { scan-assembler-not "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
 /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, fp\}" } } */
-/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler "blxns" } } */

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 9/10] Call nscall function with blxns
  2019-12-18 13:52     ` Mihail Ionescu
@ 2019-12-18 17:00       ` Kyrill Tkachov
  0 siblings, 0 replies; 35+ messages in thread
From: Kyrill Tkachov @ 2019-12-18 17:00 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw


On 12/18/19 1:38 PM, Mihail Ionescu wrote:
> Hi,
>
> On 11/12/2019 10:23 AM, Kyrill Tkachov wrote:
>>
>> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>>> [PATCH, GCC/ARM, 9/10] Call nscall function with blxns
>>>
>>> Hi,
>>>
>>> === Context ===
>>>
>>> This patch is part of a patch series to add support for Armv8.1-M
>>> Mainline Security Extensions architecture. Its purpose is to call
>>> functions with the cmse_nonsecure_call attribute directly using blxns
>>> with no undue restriction on the register used for that.
>>>
>>> === Patch description ===
>>>
>>> This change to use BLXNS to call a nonsecure function from secure
>>> directly (not using a libcall) is made in 2 steps:
>>> - change nonsecure_call patterns to use blxns instead of calling
>>>   __gnu_cmse_nonsecure_call
>>> - loosen requirement for function address to allow any register when
>>>   doing BLXNS.
>>>
>>> The former is a straightforward check over whether instructions 
>>> added in
>>> Armv8.1-M Mainline are available while the latter consist in making the
>>> nonsecure call pattern accept any register by using match_operand and
>>> changing the nonsecure_call_internal expander to no force r4 when
>>> targeting Armv8.1-M Mainline.
>>>
>>> The tricky bit is actually in the test update, specifically how to 
>>> check
>>> that register lists for CLRM have all registers except for the one
>>> holding parameters (already done) and the one holding the address used
>>> by BLXNS. This is achieved with 3 scan-assembler directives.
>>>
>>> 1) The first one lists all registers that can appear in CLRM but make
>>>    each of them optional.
>>>    Property guaranteed: no wrong register is cleared and none appears
>>>    twice in the register list.
>>> 2) The second directive check that the CLRM is made of a fixed number
>>>    of the right registers to be cleared. The number used is the number
>>>    of registers that could contain a secret minus one (used to hold the
>>>    address of the function to call.
>>>    Property guaranteed: register list has the right number of registers
>>>    Cumulated property guaranteed: only registers with a potential 
>>> secret
>>>    are cleared and they are all listed but ont
>>> 3) The last directive checks that we cannot find a CLRM with a register
>>>    in it that also appears in BLXNS. This is check via the use of a
>>>    back-reference on any of the allowed register in CLRM, the
>>>    back-reference enforcing that whatever register match in CLRM 
>>> must be
>>>    the same in the BLXNS.
>>>    Property guaranteed: register used for BLXNS is different from
>>>    registers cleared in CLRM.
>>>
>>> Some more care needs to happen for the gcc.target/arm/cmse/cmse-1.c
>>> testcase due to there being two CLRM generated. To ensure the third
>>> directive match the right CLRM to the BLXNS, a negative lookahead is
>>> used between the CLRM register list and the BLXNS. The way negative
>>> lookahead work is by matching the *position* where a given regular
>>> expression does not match. In this case, since it comes after the CLRM
>>> register list it is requesting that what comes after the register list
>>> does not have a CLRM again followed by BLXNS. This guarantees that the
>>> .*blxns after only matches a blxns without another CLRM before.
>>>
>>> ChangeLog entries are as follows:
>>>
>>> *** gcc/ChangeLog ***
>>>
>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>
>>>         * config/arm/arm.md (nonsecure_call_internal): Do not force 
>>> memory
>>>         address in r4 when targeting Armv8.1-M Mainline.
>>>         (nonsecure_call_value_internal): Likewise.
>>>         * config/arm/thumb2.md (nonsecure_call_reg_thumb2): Make 
>>> memory address
>>>         a register match_operand again.  Emit BLXNS when targeting
>>>         Armv8.1-M Mainline.
>>>         (nonsecure_call_value_reg_thumb2): Likewise.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>>
>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>
>>>         * gcc.target/arm/cmse/cmse-1.c: Add check for BLXNS when 
>>> instructions
>>>         introduced in Armv8.1-M Mainline Security Extensions are 
>>> available and
>>>         restrict checks for libcall to __gnu_cmse_nonsecure_call to 
>>> Armv8-M
>>>         targets only.  Adapt CLRM check to verify register used for 
>>> BLXNS is
>>>         not in the CLRM register list.
>>>         * gcc.target/arm/cmse/cmse-14.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise 
>>> and adapt
>>>         check for LSB clearing bit to be using the same register as 
>>> BLXNS when
>>>         targeting Armv8.1-M Mainline.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c: 
>>> Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: 
>>> Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: 
>>> Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: 
>>> Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
>>>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.
>>>         * gcc.target/arm/cmse/cmse-15.c: Count BLXNS when targeting 
>>> Armv8.1-M
>>>         Mainline and restrict libcall count to Armv8-M.
>>>
>>> Testing: bootstrapped on arm-linux-gnueabihf and arm-none-eabi; 
>>> testsuite shows no
>>> regression.
>>>
>>> Is this ok for trunk?
>>>
>> Ok.
>>
>> Thanks,
>>
>> Kyrill
>>
>>
>
>
> I found a small issue with this one. The constraint for the first 
> operand of nonsecure_call_reg_thumb2 was wrong as it allowed it to 
> pick and overwrite the ip register which can hold the address for the 
> non secure call. The constraint has now been changed to pick one of 
> the low registers.


Ok.

Thanks,

Kyrill


>
>
> Regards,
> Mihail
>
>>> Best regards,
>>>
>>> Mihail
>>>
>>>
>>> ###############     Attachment also inlined for ease of reply 
>>> ###############
>>>
>>>
>>> diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
>>> index 
>>> d607f88cb05ffa9cd8a47b8c8e0c53ea3a5ca411..b7af3c060427d972e3cd1c7a8055aec20335c02b 
>>> 100644
>>> --- a/gcc/config/arm/arm.md
>>> +++ b/gcc/config/arm/arm.md
>>> @@ -7561,12 +7561,15 @@
>>>    "use_cmse"
>>>    "
>>>    {
>>> -    rtx tmp;
>>> -    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
>>> +    if (!TARGET_HAVE_FPCTX_CMSE)
>>> +      {
>>> +       rtx tmp =
>>> +         copy_to_suggested_reg (XEXP (operands[0], 0),
>>>                                   gen_rtx_REG (SImode, R4_REGNUM),
>>>                                   SImode);
>>>
>>> -    operands[0] = replace_equiv_address (operands[0], tmp);
>>> +       operands[0] = replace_equiv_address (operands[0], tmp);
>>> +      }
>>>    }")
>>>
>>>  (define_insn "*call_reg_armv5"
>>> @@ -7669,12 +7672,15 @@
>>>    "use_cmse"
>>>    "
>>>    {
>>> -    rtx tmp;
>>> -    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
>>> +    if (!TARGET_HAVE_FPCTX_CMSE)
>>> +      {
>>> +       rtx tmp =
>>> +         copy_to_suggested_reg (XEXP (operands[1], 0),
>>>                                   gen_rtx_REG (SImode, R4_REGNUM),
>>>                                   SImode);
>>>
>>> -    operands[1] = replace_equiv_address (operands[1], tmp);
>>> +       operands[1] = replace_equiv_address (operands[1], tmp);
>>> +      }
>>>    }")
>>>
>>>  (define_insn "*call_value_reg_armv5"
>>> diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
>>> index 
>>> 19d25cfe9b97b9428e3a6daebbf8dfb5648f29ef..964b3e2afcd524bb342373b400e35d0a72c4bd7f 
>>> 100644
>>> --- a/gcc/config/arm/thumb2.md
>>> +++ b/gcc/config/arm/thumb2.md
>>> @@ -560,13 +560,18 @@
>>>  )
>>>
>>>  (define_insn "*nonsecure_call_reg_thumb2"
>>> -  [(call (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
>>> +  [(call (unspec:SI [(mem:SI (match_operand:SI 0 
>>> "s_register_operand" "r"))]
>>>                      UNSPEC_NONSECURE_MEM)
>>> -        (match_operand 0 "" ""))
>>> -   (use (match_operand 1 "" ""))
>>> +        (match_operand 1 "" ""))
>>> +   (use (match_operand 2 "" ""))
>>>     (clobber (reg:SI LR_REGNUM))]
>>>    "TARGET_THUMB2 && use_cmse"
>>> -  "bl\\t__gnu_cmse_nonsecure_call"
>>> +  {
>>> +    if (TARGET_HAVE_FPCTX_CMSE)
>>> +      return "blxns\\t%0";
>>> +    else
>>> +      return "bl\\t__gnu_cmse_nonsecure_call";
>>> +  }
>>>    [(set_attr "length" "4")
>>>     (set_attr "type" "call")]
>>>  )
>>> @@ -585,13 +590,18 @@
>>>  (define_insn "*nonsecure_call_value_reg_thumb2"
>>>    [(set (match_operand 0 "" "")
>>>          (call
>>> -        (unspec:SI [(mem:SI (reg:SI R4_REGNUM))]
>>> +        (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" 
>>> "l*r"))]
>>>                      UNSPEC_NONSECURE_MEM)
>>> -        (match_operand 1 "" "")))
>>> -   (use (match_operand 2 "" ""))
>>> +        (match_operand 2 "" "")))
>>> +   (use (match_operand 3 "" ""))
>>>     (clobber (reg:SI LR_REGNUM))]
>>>    "TARGET_THUMB2 && use_cmse"
>>> -  "bl\t__gnu_cmse_nonsecure_call"
>>> +  {
>>> +    if (TARGET_HAVE_FPCTX_CMSE)
>>> +      return "blxns\\t%1";
>>> +    else
>>> +      return "bl\\t__gnu_cmse_nonsecure_call";
>>> +  }
>>>    [(set_attr "length" "4")
>>>     (set_attr "type" "call")]
>>>  )
>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>> index 
>>> 9f36fa3b1d8b86b4e1827909fca4fee181ba1c61..ddfcfacab5f601a729319a9d2dab03e61ee56bca 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>> @@ -110,7 +110,13 @@ qux (int_nsfunc_t * callback)
>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
>>> arm_cmse_clear_ok } } } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" { target arm_cmse_clear_ok } } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" { target arm_cmse_clear_ok } } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" { target arm_cmse_clear_ok } } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}(?!.*clrm.*blxns).*blxns\t\\1" 
>>> { target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" { target arm_cmse_clear_ok } } } */
>>>
>>>  int call_callback (void)
>>> @@ -120,4 +126,5 @@ int call_callback (void)
>>>    else
>>>      return default_callback ();
>>>  }
>>> -/* { dg-final { scan-assembler-times 
>>> "bl\\s+__gnu_cmse_nonsecure_call" 1 } } */
>>> +/* { dg-final { scan-assembler-times 
>>> "bl\\s+__gnu_cmse_nonsecure_call" 1 { target { ! arm_cmse_clear_ok } 
>>> } } } */
>>> +/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } 
>>> } } */
>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>> index 
>>> 6d39afab44329e78a8ff2f693fd94fe6a501af5a..5ab97856066e14c0005b56210e62f2b7a59fd911 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>> @@ -10,7 +10,15 @@ int foo (void)
>>>  }
>>>
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" { target arm_cmse_clear_ok } } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" { target arm_cmse_clear_ok } } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" { target arm_cmse_clear_ok } } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" { target arm_cmse_clear_ok } } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" { 
>>> target arm_cmse_clear_ok } } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" { target arm_cmse_clear_ok } } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> -/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" } 
>>> } */
>>> +/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" { 
>>> target { ! arm_cmse_clear_ok } } } } */
>>> +/* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" { 
>>> target { ! arm_cmse_clear_ok } } } } */
>>> +/* { dg-final { scan-assembler "blxns" { target arm_cmse_clear_ok } 
>>> } } */
>>> +/* { dg-final { scan-assembler-not 
>>> "^(.*\\s)?bl?(?!xns)\[^\\s]*\\s+bar" { target arm_cmse_clear_ok } } 
>>> } */
>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
>>> index 
>>> 4e9ace1f3f33b8a8653797e29ca62eb3dd7ae918..0e37b50e004d74dc81f5a8bdc0c9ba21ceaca67d 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
>>> @@ -69,4 +69,9 @@ int secure5 (void)
>>>  {
>>>    return (*s_bar2) ();
>>>  }
>>> -/* { dg-final { scan-assembler-times 
>>> "bl\\s+__gnu_cmse_nonsecure_call" 6 } } */
>>> +
>>> +/* ARMv8-M expectation.  */
>>> +/* { dg-final { scan-assembler-times 
>>> "bl\\s+__gnu_cmse_nonsecure_call" 6 { target { ! arm_cmse_clear_ok } 
>>> } } } */
>>> +
>>> +/* ARMv8.1-M expectation.  */
>>> +/* { dg-final { scan-assembler-times "blxns" 6 { target 
>>> arm_cmse_clear_ok } } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>> index 
>>> d4caf513ed2153370369bddbfcf6d2568d9f2f1e..ff34edb21c36c9f114aa934fa86ea962d932f273 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>> @@ -10,9 +10,16 @@
>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>  /* { dg-final { scan-assembler "mov\tip, #3" } } */
>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
>>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
>>> ){9}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>> index 
>>> 2b7655a2c9971fb0aad4e6c8a1fee72e21028fad..4d1407aba4418006463fdca59cbe90e768e78391 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>> @@ -8,9 +8,16 @@
>>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>>  /* { dg-final { scan-assembler "movw\tip, #2047" } } */
>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>>> ){10}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>> index 
>>> 1a62076df9d6831d06f5ac6bdcb7deed0ecd23f8..9b1227adfdc03457266573447c7996245a114110 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>> @@ -11,9 +11,16 @@
>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>  /* { dg-final { scan-assembler "mov\tip, #255" } } */
>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
>>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
>>> ){9}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>> index 
>>> 1319ac9766bcd330f6d8f0f7754a64a1dcc105b1..aec958fc9b9d125c54022911ee34affa9dd81797 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>> @@ -8,9 +8,16 @@
>>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>>  /* { dg-final { scan-assembler "movw\tip, #2047" } } */
>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>>> ){10}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>> index 
>>> 9bb60175529d77a3b1868f62a5a4d5355f00b76b..ae039e292d55423b1dc1b19551278418224bbe5e 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>> @@ -11,9 +11,16 @@
>>>  /* { dg-final { scan-assembler "movw\tip, #65535" } } */
>>>  /* { dg-final { scan-assembler "movt\tip, 31" } } */
>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
>>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
>>> ){9}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>> index 
>>> 11ca78bfdaf1ebe09f9699c278dc3db4fd20768c..f455f8cf19b1d8f32bd6ca208d33c144da644c29 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>> @@ -5,9 +5,16 @@
>>>
>>>  /* { dg-final { scan-assembler "movw\tip, #1799" } } */
>>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[1-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[1-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, r5, r6, r7, r8, 
>>> r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r2, )?(r3, )?(r4, 
>>> )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } 
>>> } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[1-9\]|r10|fp|ip), 
>>> ){11}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[1-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
>>> index 
>>> 2f14c52715e0ad6e6ab69b01713ee13985a22653..3e76364c40452a7946e3b97e2321fd6e6d204355 
>>> 100644
>>> --- 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
>>> +++ 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-and-union.c
>>> @@ -15,9 +15,16 @@
>>>  /* { dg-final { scan-assembler "movw\tip, #65535" } } */
>>>  /* { dg-final { scan-assembler "movt\tip, 31" } } */
>>>  /* { dg-final { scan-assembler "and\tr3, r3, ip" } } */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[4-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[4-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r5, r6, r7, r8, r9, r10, 
>>> fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r4, )?(r5, )?(r6, )?(r7, 
>>> )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[4-9\]|r10|fp|ip), 
>>> ){8}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>> index 
>>> e759db24fac27be2de664ad4faced7bb5d3be84a..0c49277389271321c7fd7faa6ae6aaee2c299def 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>> @@ -6,11 +6,18 @@
>>>  #include "../../../cmse-13.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>>> d13, d14, d15\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts3, #1\.0" } } */
>>> @@ -20,4 +27,4 @@
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>> index 
>>> 9df7b5de3ad64e719fc97d7a67a4893398e87b32..3c66b0a8c6f1c7be6c8cf77b2c71916a08c7b357 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>> @@ -6,14 +6,21 @@
>>>  #include "../../../cmse-7.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>>> d13, d14, d15\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
>>>  /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>> index 
>>> b36ff73cb9b46d4d3a91f854c022787dc000d9c3..7d456c39705b15fa5b55270ac6b4ed57f5c7e465 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>> @@ -6,11 +6,18 @@
>>>  #include "../../../cmse-8.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>>> d13, d14, d15\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
>>> @@ -18,4 +25,4 @@
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>> index 
>>> 72493f032355828bdf48b84dc98d8102becd1b36..ab95c83a1167aff9fd4c0e24fe5580895cfbf0bb 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>> @@ -6,11 +6,18 @@
>>>  #include "../../../cmse-13.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>>> d13, d14, d15\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f64\td1, #1\.0" } } */
>>> @@ -22,4 +29,4 @@
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>> index 
>>> 112ed78d6f172be31d4a4f06840d32a90cdf3dd4..cf58d547972e21e0816a1bdf74968d0b50d2bd08 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>> @@ -6,14 +6,21 @@
>>>  #include "../../../cmse-7.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>>> d13, d14, d15\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "vscclrm\t\{s0-s31, VPR\}" } } */
>>>  /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>> index 
>>> f48e8a0a020cebed8c9fa124d352f047442979d6..1854d03d0814c90f8014a28fb1c81c6866f0071d 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>> @@ -6,15 +6,22 @@
>>>  #include "../../../cmse-8.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vpush.64\t\{d8, d9, d10, d11, d12, 
>>> d13, d14, d15\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>>  /* { dg-final { scan-assembler "vscclrm\t\{s2-s31, VPR\}" } } */
>>>  /* { dg-final { scan-assembler "vldm\tsp!, \{d8-d15\}" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>> index 
>>> 52d22427de79c6a76fbe32b8df7f76b4b286249c..1b207c394081e6ec9bf569961a4a059d5b47fe20 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>> @@ -5,18 +5,25 @@
>>>  #include "../../../cmse-13.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, 
>>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), 
>>> ){9}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } 
>>> } */
>>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>> index 
>>> 40026d5ee1cc62b4acf48be9619ccd69ef4ead7b..3ec639480868944ed29065936c1fab10aa9e0fed 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>> @@ -5,15 +5,22 @@
>>>  #include "../../../cmse-7.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>> index 
>>> 6edc1f6ed7e6bc27024056375db4a2d30c3ea3c4..5c1d245d4aa966812e52f327c7ceba5dabba2e18 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>> @@ -5,17 +5,24 @@
>>>  #include "../../../cmse-8.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>>> ){10}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>> index 
>>> 8d05576add940c277e5a13f7aab99e6807c1553d..3228692c2686fcae8e1369f984aaa6c375ad6418 
>>> 100644
>>> --- 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>> +++ 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>> @@ -6,13 +6,20 @@
>>>  #include "../../../cmse-7.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>> index 
>>> 1f0a14742781b7340685338901dbfab9b700b779..1c60d97dabd99136533a61fef5ae099eae4bbc93 
>>> 100644
>>> --- 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>> +++ 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>> @@ -6,15 +6,22 @@
>>>  #include "../../../cmse-8.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>>> ){10}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>> index 
>>> 842794181087ddbd5ce59680035a0cb61ce5682e..c366f6ae4ccc65d943dbbf045925ca9c6e8921ca 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>> @@ -6,16 +6,23 @@
>>>  #include "../../../cmse-13.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[1,4-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[1,4-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r1, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r1, )?(r4, )?(r5, )?(r6, 
>>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[1,4-9\]|r10|fp|ip), 
>>> ){9}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[1,4-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } 
>>> } */
>>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>> index 
>>> 38c9d5457034d2427413bcce7e7be6bad80f7a67..186a4480f4e816bdb2413ecbc690470e1c2480e6 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>> @@ -6,13 +6,20 @@
>>>  #include "../../../cmse-7.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[0-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, r5, r6, r7, 
>>> r8, r9, r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r0, )?(r1, )?(r2, )?(r3, 
>>> )?(r4, )?(r5, )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, 
>>> )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[0-9\]|r10|fp|ip), 
>>> ){12}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[0-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>> index 
>>> 6a17bd322fcc4e7e00ea289ee7373db9d8c37a87..f0f74f06bbd1eed2f71b46bc8947c99ce1de0765 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>> @@ -6,15 +6,22 @@
>>>  #include "../../../cmse-8.x"
>>>
>>>  /* Checks for saving and clearing prior to function call. */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>>  /* { dg-final { scan-assembler "vlstm\tsp" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>>> ){10}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "vlldm\tsp" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>>
>>>  /* Now we check that we use the correct intrinsic to call. */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>> index 
>>> 43e58ebde56ceb229edca2db25b720c42207c100..4d58eed1ac21e32dfa893397736be45129af53b8 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>> @@ -8,9 +8,16 @@
>>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>>  /* { dg-final { scan-assembler "movw\tip, #511" } } */
>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[2-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r2, r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r2, )?(r3, )?(r4, )?(r5, 
>>> )?(r6, )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[2-9\]|r10|fp|ip), 
>>> ){10}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[2-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>> diff --git 
>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c 
>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>> index 
>>> 6adf8fae5c3a56a6e50278919a2edbd2fda58f42..95de458b50172f6e84ffc2625fc35eca8f65108a 
>>> 100644
>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>> @@ -12,9 +12,16 @@
>>>  /* { dg-final { scan-assembler "movw\tip, #65535" } } */
>>>  /* { dg-final { scan-assembler "movt\tip, 31" } } */
>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>> -/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>> -/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>> +/* Shift on the same register as blxns.  */
>>> +/* { dg-final { scan-assembler "lsrs\t(r\[3-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>> +/* { dg-final { scan-assembler "lsls\t(r\[3-9\]|r10|fp|ip), \\1, 
>>> #1.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6, r7, r8, r9, 
>>> r10, fp\}" } } */
>>> -/* { dg-final { scan-assembler "clrm\t\{r3, r5, r6, r7, r8, r9, 
>>> r10, fp, ip, APSR\}" } } */
>>> +/* Check the right registers are cleared and none appears twice.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{(r3, )?(r4, )?(r5, )?(r6, 
>>> )?(r7, )?(r8, )?(r9, )?(r10, )?(fp, )?(ip, )?APSR\}" } } */
>>> +/* Check that the right number of registers is cleared and thus 
>>> only one
>>> +   register is missing.  */
>>> +/* { dg-final { scan-assembler "clrm\t\{((r\[3-9\]|r10|fp|ip), 
>>> ){9}APSR\}" } } */
>>> +/* Check that no cleared register is used for blxns.  */
>>> +/* { dg-final { scan-assembler-not 
>>> "clrm\t\{\[^\}\]\+(r\[3-9\]|r10|fp|ip),\[^\}\]\+\}.*blxns\t\\1" } } */
>>>  /* { dg-final { scan-assembler "pop\t\{r4, r5, r6, r7, r8, r9, r10, 
>>> fp\}" } } */
>>> -/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
>>> +/* { dg-final { scan-assembler "blxns" } } */
>>>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
  2019-12-18 13:29         ` Mihail Ionescu
@ 2020-01-13 17:30           ` Kyrill Tkachov
  2020-01-17 21:06             ` [PATCH] arm: fix rtl checking bootstrap (PR target/93312) Jakub Jelinek
  0 siblings, 1 reply; 35+ messages in thread
From: Kyrill Tkachov @ 2020-01-13 17:30 UTC (permalink / raw)
  To: Mihail Ionescu, gcc-patches; +Cc: Richard Earnshaw


On 12/18/19 1:26 PM, Mihail Ionescu wrote:
> Hi Kyrill,
>
> On 12/17/2019 10:26 AM, Kyrill Tkachov wrote:
>> Hi Mihail,
>>
>> On 12/16/19 6:29 PM, Mihail Ionescu wrote:
>>> Hi Kyrill,
>>>
>>> On 11/12/2019 09:55 AM, Kyrill Tkachov wrote:
>>>> Hi Mihail,
>>>>
>>>> On 10/23/19 10:26 AM, Mihail Ionescu wrote:
>>>>> [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM
>>>>>
>>>>> Hi,
>>>>>
>>>>> === Context ===
>>>>>
>>>>> This patch is part of a patch series to add support for Armv8.1-M
>>>>> Mainline Security Extensions architecture. Its purpose is to improve
>>>>> code density of functions with the cmse_nonsecure_entry attribute and
>>>>> when calling function with the cmse_nonsecure_call attribute by using
>>>>> CLRM to do all the general purpose registers clearing as well as
>>>>> clearing the APSR register.
>>>>>
>>>>> === Patch description ===
>>>>>
>>>>> This patch adds a new pattern for the CLRM instruction and guards the
>>>>> current clearing code in output_return_instruction() and thumb_exit()
>>>>> on Armv8.1-M Mainline instructions not being present.
>>>>> cmse_clear_registers () is then modified to use the new CLRM 
>>>>> instruction
>>>>> when targeting Armv8.1-M Mainline while keeping Armv8-M register
>>>>> clearing code for VFP registers.
>>>>>
>>>>> For the CLRM instruction, which does not mandated APSR in the 
>>>>> register
>>>>> list, checking whether it is the right volatile unspec or a clearing
>>>>> register is done in clear_operation_p.
>>>>>
>>>>> Note that load/store multiple were deemed sufficiently different in
>>>>> terms of RTX structure compared to the CLRM pattern for a different
>>>>> function to be used to validate the match_parallel.
>>>>>
>>>>> ChangeLog entries are as follows:
>>>>>
>>>>> *** gcc/ChangeLog ***
>>>>>
>>>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>
>>>>>         * config/arm/arm-protos.h (clear_operation_p): Declare.
>>>>>         * config/arm/arm.c (clear_operation_p): New function.
>>>>>         (cmse_clear_registers): Generate clear_multiple 
>>>>> instruction pattern if
>>>>>         targeting Armv8.1-M Mainline or successor.
>>>>>         (output_return_instruction): Only output APSR register 
>>>>> clearing if
>>>>>         Armv8.1-M Mainline instructions not available.
>>>>>         (thumb_exit): Likewise.
>>>>>         * config/arm/predicates.md (clear_multiple_operation): New 
>>>>> predicate.
>>>>>         * config/arm/thumb2.md (clear_apsr): New define_insn.
>>>>>         (clear_multiple): Likewise.
>>>>>         * config/arm/unspecs.md (VUNSPEC_CLRM_APSR): New volatile 
>>>>> unspec.
>>>>>
>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>
>>>>> 2019-10-23  Mihail-Calin Ionescu <mihail.ionescu@arm.com>
>>>>> 2019-10-23  Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>
>>>>>         * gcc.target/arm/cmse/bitfield-1.c: Add check for CLRM.
>>>>>         * gcc.target/arm/cmse/bitfield-2.c: Likewise.
>>>>>         * gcc.target/arm/cmse/bitfield-3.c: Likewise.
>>>>>         * gcc.target/arm/cmse/struct-1.c: Likewise.
>>>>>         * gcc.target/arm/cmse/cmse-14.c: Likewise.
>>>>>         * gcc.target/arm/cmse/cmse-1.c: Likewise. Restrict checks 
>>>>> for Armv8-M
>>>>>         GPR clearing when CLRM is not available.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c: likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c: likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c: likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c: 
>>>>> Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/union-1.c: Likewise.
>>>>>         * gcc.target/arm/cmse/mainline/8_1m/union-2.c: Likewise.
>>>>>
>>>>> Testing: bootstrapped on arm-linux-gnueabihf and testsuite shows no
>>>>> regression.
>>>>>
>>>>> Is this ok for trunk?
>>>>>
>>>>> Best regards,
>>>>>
>>>>> Mihail
>>>>>
>>>>>
>>>>> ###############     Attachment also inlined for ease of reply 
>>>>> ###############
>>>>>
>>>>>
>>>>> diff --git a/gcc/config/arm/arm-protos.h 
>>>>> b/gcc/config/arm/arm-protos.h
>>>>> index 
>>>>> f995974f9bb89ab3c7ff0888c394b0dfaf7da60c..1a948d2c97526ad7e67e8d4a610ac74cfdb13882 
>>>>> 100644
>>>>> --- a/gcc/config/arm/arm-protos.h
>>>>> +++ b/gcc/config/arm/arm-protos.h
>>>>> @@ -77,6 +77,7 @@ extern int thumb_legitimate_offset_p 
>>>>> (machine_mode, HOST_WIDE_INT);
>>>>>  extern int thumb1_legitimate_address_p (machine_mode, rtx, int);
>>>>>  extern bool ldm_stm_operation_p (rtx, bool, machine_mode mode,
>>>>>                                   bool, bool);
>>>>> +extern bool clear_operation_p (rtx);
>>>>>  extern int arm_const_double_rtx (rtx);
>>>>>  extern int vfp3_const_double_rtx (rtx);
>>>>>  extern int neon_immediate_valid_for_move (rtx, machine_mode, rtx 
>>>>> *, int *);
>>>>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>>>> index 
>>>>> d485e80096c9d2eef2172d211a0a5ab63cdbb3c7..3a373cea33c3d0b966cbe700d26f66fe069e1efb 
>>>>> 100644
>>>>> --- a/gcc/config/arm/arm.c
>>>>> +++ b/gcc/config/arm/arm.c
>>>>> @@ -13499,6 +13499,66 @@ ldm_stm_operation_p (rtx op, bool load, 
>>>>> machine_mode mode,
>>>>>    return true;
>>>>>  }
>>>>>
>>>>> +/* Checks whether OP is a valid parallel pattern for a CLRM insn. 
>>>>> To be a
>>>>> +   valid CLRM pattern, OP must have the following form:
>>>>> +
>>>>> +   [(set (reg:SI <N>) (const_int 0))
>>>>> +    (set (reg:SI <M>) (const_int 0))
>>>>> +    ...
>>>>> +    (unspec_volatile [(const_int 0)]
>>>>> +                    VUNSPEC_CLRM_APSR)
>>>>> +   ]
>>>>
>>>>
>>>> If this clears the whole APSR than it also clobbers the condition 
>>>> flags, right?
>>>>
>>>> Then it should also have a  (clobber (reg:CC CC_REGNUM)) in there.
>>>> Yes -- it should also clobber the condition flags, thanks for catching 
>>> this. I've updated the patch to include the CC clobbering.
>>>
>>> Regards,
>>> Mihail
>>>>
>>>>> +
>>>>> +   Any number (including 0) of set expressions is valid, the 
>>>>> volatile unspec is
>>>>> +   optional.  All registers but SP and PC are allowed and 
>>>>> registers must be in
>>>>> +   strict increasing order.  */
>>>>> +
>>>>> +bool
>>>>> +clear_operation_p (rtx op)
>>>>> +{
>>>>> +  HOST_WIDE_INT i;
>>>>> +  unsigned regno, last_regno;
>>>>> +  rtx elt, reg, zero;
>>>>> +  machine_mode mode;
>>>>> +  HOST_WIDE_INT count = XVECLEN (op, 0);
>>>>> +
>>>>> +  for (i = 0; i < count; i++)
>>>>> +    {
>>>>> +      elt = XVECEXP (op, 0, i);
>>>>> +
>>>>> +      if (GET_CODE (elt) == UNSPEC_VOLATILE)
>>>>> +       {
>>>>> +         if (XINT (elt, 1) != VUNSPEC_CLRM_APSR
>>>>> +             || XVECLEN (elt, 0) != 1
>>>>> +             || XVECEXP (elt, 0, 0) != CONST0_RTX (SImode)
>>>>> +             || i != count - 1)
>>>>> +           return false;
>>>>> +
>>>>> +         continue;
>>>>> +       }
>>>>> +
>>>>> +      if (GET_CODE (elt) != SET)
>>>>> +       return false;
>>>>> +
>>>>> +      reg = SET_DEST (elt);
>>>>> +      regno = REGNO (reg);
>>>>> +      mode = GET_MODE (reg);
>>>>> +      zero = SET_SRC (elt);
>>>>> +
>>>>> +      if (!REG_P (reg)
>>>>> +         || GET_MODE (reg) != SImode
>>>>> +         || regno == SP_REGNUM
>>>>> +         || regno == PC_REGNUM
>>>>> +         || (i != 0 && regno <= last_regno)
>>>>> +         || zero != CONST0_RTX (SImode))
>>>>> +       return false;
>>>>> +
>>>>> +      last_regno = REGNO (reg);
>>>>> +    }
>>>>> +
>>>>> +  return true;
>>>>> +}
>>>>> +
>>>>>  /* Return true iff it would be profitable to turn a sequence of 
>>>>> NOPS loads
>>>>>     or stores (depending on IS_STORE) into a load-multiple or 
>>>>> store-multiple
>>>>>     instruction.  ADD_OFFSET is nonzero if the base address 
>>>>> register needs
>>>>> @@ -17596,6 +17656,56 @@ cmse_clear_registers (sbitmap 
>>>>> to_clear_bitmap, uint32_t *padding_bits_to_clear,
>>>>>
>>>>>    /* Clear full registers.  */
>>>>>
>>>>> +  if (TARGET_HAVE_FPCXT_CMSE)
>>>>> +    {
>>>>> +      rtvec vunspec_vec;
>>>>> +      int i, j, k, nb_regs;
>>>>> +      rtx use_seq, par, reg, set, vunspec;
>>>>> +      int to_clear_bitmap_size = SBITMAP_SIZE (to_clear_bitmap);
>>>>> +      auto_sbitmap core_regs_bitmap (to_clear_bitmap_size);
>>>>> +      auto_sbitmap to_clear_core_bitmap (to_clear_bitmap_size);
>>>>> +
>>>>> +      /* Get set of core registers to clear.  */
>>>>> +      bitmap_clear (core_regs_bitmap);
>>>>> +      bitmap_set_range (core_regs_bitmap, R0_REGNUM,
>>>>> +                       IP_REGNUM - R0_REGNUM + 1);
>>>>> +      bitmap_and (to_clear_core_bitmap, to_clear_bitmap,
>>>>> +                 core_regs_bitmap);
>>>>> +      gcc_assert (!bitmap_empty_p (to_clear_core_bitmap));
>>>>> +
>>>>> +      if (bitmap_empty_p (to_clear_core_bitmap))
>>>>> +       return;
>>>>> +
>>>>> +      /* Create clrm RTX pattern.  */
>>>>> +      nb_regs = bitmap_count_bits (to_clear_core_bitmap);
>>>>> +      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nb_regs + 1));
>>>>> +
>>>>> +      /* Insert core register clearing RTX in the pattern. */
>>>>> +      start_sequence ();
>>>>> +      for (j = 0, i = minregno; j < nb_regs; i++)
>>>>> +       {
>>>>> +         if (!bitmap_bit_p (to_clear_core_bitmap, i))
>>>>> +           continue;
>>>>> +
>>>>> +         reg = gen_rtx_REG (SImode, i);
>>>>> +         set = gen_rtx_SET (reg, const0_rtx);
>>>>> +         XVECEXP (par, 0, j++) = set;
>>>>> +         emit_use (reg);
>>>>> +       }
>>>>> +
>>>>> +      /* Insert APSR register clearing RTX in the pattern. */
>>>>> +      vunspec_vec = gen_rtvec (1, gen_int_mode (0, SImode));
>>>>> +      vunspec = gen_rtx_UNSPEC_VOLATILE (SImode, vunspec_vec,
>>>>> + VUNSPEC_CLRM_APSR);
>>>>> +      XVECEXP (par, 0, j) = vunspec;
>>>>> +
>>>>> +      use_seq = get_insns ();
>>>>> +      end_sequence ();
>>>>> +
>>>>> +      emit_insn_after (use_seq, emit_insn (par));
>>>>> +      minregno = FIRST_VFP_REGNUM;
>>>>> +    }
>>>>> +
>>>>>    /* If not marked for clearing, clearing_reg already does not 
>>>>> contain
>>>>>       any secret.  */
>>>>>    if (clearing_regno <= maxregno
>>>>> @@ -20259,40 +20369,50 @@ output_return_instruction (rtx operand, 
>>>>> bool really_return, bool reverse,
>>>>>          default:
>>>>>            if (IS_CMSE_ENTRY (func_type))
>>>>>              {
>>>>> -             /* Check if we have to clear the 'GE bits' which is 
>>>>> only used if
>>>>> -                parallel add and subtraction instructions are 
>>>>> available.  */
>>>>> -             if (TARGET_INT_SIMD)
>>>>> -               snprintf (instr, sizeof (instr),
>>>>> -                         "msr%s\tAPSR_nzcvqg, %%|lr", conditional);
>>>>> -             else
>>>>> -               snprintf (instr, sizeof (instr),
>>>>> -                         "msr%s\tAPSR_nzcvq, %%|lr", conditional);
>>>>> -
>>>>> -             output_asm_insn (instr, & operand);
>>>>> -             /* Do not clear FPSCR if targeting Armv8.1-M 
>>>>> Mainline, VLDR takes
>>>>> -                care of it.  */
>>>>> -             if (TARGET_HARD_FLOAT && ! TARGET_HAVE_FPCXT_CMSE)
>>>>> +             /* For Armv8.1-M, this is cleared as part of the 
>>>>> CLRM instruction
>>>>> +                emitted by 
>>>>> cmse_nonsecure_entry_clear_before_return () and the
>>>>> +                VSTR/VLDR instructions in the prologue and 
>>>>> epilogue.  */
>>>>> +             if (!TARGET_HAVE_FPCXT_CMSE)
>>>>>                  {
>>>>> -                 /* Clear the cumulative exception-status bits 
>>>>> (0-4,7) and the
>>>>> -                    condition code bits (28-31) of the FPSCR.  We 
>>>>> need to
>>>>> -                    remember to clear the first scratch register 
>>>>> used (IP) and
>>>>> -                    save and restore the second (r4).  */
>>>>> -                 snprintf (instr, sizeof (instr), "push\t{%%|r4}");
>>>>> -                 output_asm_insn (instr, & operand);
>>>>> -                 snprintf (instr, sizeof (instr), "vmrs\t%%|ip, 
>>>>> fpscr");
>>>>> -                 output_asm_insn (instr, & operand);
>>>>> -                 snprintf (instr, sizeof (instr), "movw\t%%|r4, 
>>>>> #65376");
>>>>> -                 output_asm_insn (instr, & operand);
>>>>> -                 snprintf (instr, sizeof (instr), "movt\t%%|r4, 
>>>>> #4095");
>>>>> -                 output_asm_insn (instr, & operand);
>>>>> -                 snprintf (instr, sizeof (instr), "and\t%%|ip, 
>>>>> %%|r4");
>>>>> -                 output_asm_insn (instr, & operand);
>>>>> -                 snprintf (instr, sizeof (instr), "vmsr\tfpscr, 
>>>>> %%|ip");
>>>>> -                 output_asm_insn (instr, & operand);
>>>>> -                 snprintf (instr, sizeof (instr), "pop\t{%%|r4}");
>>>>> -                 output_asm_insn (instr, & operand);
>>>>> -                 snprintf (instr, sizeof (instr), "mov\t%%|ip, 
>>>>> %%|lr");
>>>>> +                 /* Check if we have to clear the 'GE bits' which 
>>>>> is only used if
>>>>> +                    parallel add and subtraction instructions are 
>>>>> available.  */
>>>>> +                 if (TARGET_INT_SIMD)
>>>>> +                   snprintf (instr, sizeof (instr),
>>>>> +                             "msr%s\tAPSR_nzcvqg, %%|lr", 
>>>>> conditional);
>>>>> +                 else
>>>>> +                   snprintf (instr, sizeof (instr),
>>>>> +                             "msr%s\tAPSR_nzcvq, %%|lr", 
>>>>> conditional);
>>>>> +
>>>>>                    output_asm_insn (instr, & operand);
>>>>> +                 /* Do not clear FPSCR if targeting Armv8.1-M 
>>>>> Mainline, VLDR takes
>>>>> +                    care of it.  */
>>>>> +                 if (TARGET_HARD_FLOAT)
>>>>> +                   {
>>>>> +                     /* Clear the cumulative exception-status 
>>>>> bits (0-4,7) and
>>>>> +                        the condition code bits (28-31) of the 
>>>>> FPSCR.  We need
>>>>> +                        to remember to clear the first scratch 
>>>>> register used
>>>>> +                        (IP) and save and restore the second (r4).
>>>>> +
>>>>> +                        Important note: the length of the
>>>>> +                        thumb2_cmse_entry_return insn pattern 
>>>>> must account for
>>>>> +                        the size of the below instructions. */
>>>>> +                     snprintf (instr, sizeof (instr), 
>>>>> "push\t{%%|r4}");
>>>>> +                     output_asm_insn (instr, & operand);
>>>>
>>>>
>>>> I know this is pre-existing in this function, but I think we should 
>>>> just use output_asm_insn directly here:
>>>> output_asm_insn ("push\t{%%|r4}", & operand);
>>>>
>>>> and avoid all the snprintfs.
>>>>
>>>>
>>>>> +                     snprintf (instr, sizeof (instr), 
>>>>> "vmrs\t%%|ip, fpscr");
>>>>> +                     output_asm_insn (instr, & operand);
>>>>> +                     snprintf (instr, sizeof (instr), 
>>>>> "movw\t%%|r4, #65376");
>>>>> +                     output_asm_insn (instr, & operand);
>>>>> +                     snprintf (instr, sizeof (instr), 
>>>>> "movt\t%%|r4, #4095");
>>>>> +                     output_asm_insn (instr, & operand);
>>>>> +                     snprintf (instr, sizeof (instr), 
>>>>> "and\t%%|ip, %%|r4");
>>>>> +                     output_asm_insn (instr, & operand);
>>>>> +                     snprintf (instr, sizeof (instr), 
>>>>> "vmsr\tfpscr, %%|ip");
>>>>> +                     output_asm_insn (instr, & operand);
>>>>> +                     snprintf (instr, sizeof (instr), 
>>>>> "pop\t{%%|r4}");
>>>>> +                     output_asm_insn (instr, & operand);
>>>>> +                     snprintf (instr, sizeof (instr), 
>>>>> "mov\t%%|ip, %%|lr");
>>>>> +                     output_asm_insn (instr, & operand);
>>>>> +                   }
>>>>>                  }
>>>>>                snprintf (instr, sizeof (instr), "bxns\t%%|lr");
>>>>>              }
>>>>> @@ -24690,8 +24810,11 @@ thumb_exit (FILE *f, int 
>>>>> reg_containing_return_addr)
>>>>>
>>>>>        if (IS_CMSE_ENTRY (arm_current_func_type ()))
>>>>>          {
>>>>> -         asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
>>>>> -                      reg_containing_return_addr);
>>>>> +         /* For Armv8.1-M, this is cleared as part of the CLRM 
>>>>> instruction
>>>>> +            emitted by cmse_nonsecure_entry_clear_before_return 
>>>>> ().  */
>>>>> +         if (!TARGET_HAVE_FPCXT_CMSE)
>>>>> +           asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
>>>>> +                        reg_containing_return_addr);
>>>>>            asm_fprintf (f, "\tbxns\t%r\n", 
>>>>> reg_containing_return_addr);
>>>>>          }
>>>>>        else
>>>>> @@ -24931,11 +25054,14 @@ thumb_exit (FILE *f, int 
>>>>> reg_containing_return_addr)
>>>>>           address.  It may therefore contain information that we 
>>>>> might not want
>>>>>           to leak, hence it must be cleared.  The value in R0 will 
>>>>> never be a
>>>>>           secret at this point, so it is safe to use it, see the 
>>>>> clearing code
>>>>> -        in 'cmse_nonsecure_entry_clear_before_return'. */
>>>>> +        in cmse_nonsecure_entry_clear_before_return (). */
>>>>>        if (reg_containing_return_addr != LR_REGNUM)
>>>>>          asm_fprintf (f, "\tmov\tlr, r0\n");
>>>>>
>>>>> -      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
>>>>> reg_containing_return_addr);
>>>>> +      /* For Armv8.1-M, this is cleared as part of the CLRM 
>>>>> instruction emitted
>>>>> +        by cmse_nonsecure_entry_clear_before_return (). */
>>>>> +      if (!TARGET_HAVE_FPCXT_CMSE)
>>>>> +       asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", 
>>>>> reg_containing_return_addr);
>>>>>        asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
>>>>>      }
>>>>>    else
>>>>> diff --git a/gcc/config/arm/predicates.md 
>>>>> b/gcc/config/arm/predicates.md
>>>>> index 
>>>>> 8b36e7ee462235ad26e132f1ccf98d28c2487d67..e5c583ef3d167194e7a061d7c3e98d3b4bb5269c 
>>>>> 100644
>>>>> --- a/gcc/config/arm/predicates.md
>>>>> +++ b/gcc/config/arm/predicates.md
>>>>> @@ -510,6 +510,12 @@
>>>>>              (match_test "satisfies_constraint_Dy (op)")
>>>>>              (match_test "satisfies_constraint_G (op)"))))
>>>>>
>>>>> +(define_special_predicate "clear_multiple_operation"
>>>>> +  (match_code "parallel")
>>>>> +{
>>>>> + return clear_operation_p (op);
>>>>> +})
>>>>> +
>>>>>  (define_special_predicate "load_multiple_operation"
>>>>>    (match_code "parallel")
>>>>>  {
>>>>> diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
>>>>> index 
>>>>> 6ccc875e2b4e7b8ce256e52da966dfe220c6f5d6..9994c0d59f741ef47d0ec43dd53a2324b031d048 
>>>>> 100644
>>>>> --- a/gcc/config/arm/thumb2.md
>>>>> +++ b/gcc/config/arm/thumb2.md
>>>>> @@ -1599,3 +1599,39 @@
>>>>>        FAIL;
>>>>>   }")
>>>>>
>>>>> +(define_insn "*clear_apsr"
>>>>> +  [(unspec_volatile:SI [(const_int 0)] VUNSPEC_CLRM_APSR)]
>>>>> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse"
>>>>> +  "clrm%?\\t{APSR}"
>>>>> +  [(set_attr "predicable" "yes")]
>>>>> +)
>>>>
>>>>
>>>> Similar to earlier, if this clears the whole APSR then it should 
>>>> also represent a clobber of the CC reg.
>>>>
>>>>
>>>>> +
>>>>> +;; The operands are validated through the clear_multiple_operation
>>>>> +;; match_parallel predicate rather than through constraints so 
>>>>> enable it only
>>>>> +;; after reload.
>>>>> +(define_insn "*clear_multiple"
>>>>> +  [(match_parallel 0 "clear_multiple_operation"
>>>>> +     [(set (match_operand:SI 1 "register_operand" "")
>>>>> +          (const_int 0))])]
>>>>> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && 
>>>>> reload_completed"
>>>>> +  {
>>>>> +    char pattern[100];
>>>>> +    int i, num_saves = XVECLEN (operands[0], 0);
>>>>> +
>>>>> +    strcpy (pattern, \"clrm%?\\t{\");
>>>>> +    for (i = 0; i < num_saves; i++)
>>>>> +      {
>>>>> +       if (GET_CODE (XVECEXP (operands[0], 0, i)) == 
>>>>> UNSPEC_VOLATILE)
>>>>> +         strcat (pattern, \"APSR\");
>>>>> +       else
>>>>> +         strcat (pattern,
>>>>> +                 reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, 
>>>>> i), 0))]);
>>>>> +       if (i < num_saves - 1)
>>>>> +         strcat (pattern, \", %|\");
>>>>> +      }
>>>>> +    strcat (pattern, \"}\");
>>>>> +    output_asm_insn (pattern, operands);
>>>>> +    return \"\";
>>>>> +  }
>>>>> +  [(set_attr "predicable" "yes")]
>>>>> +)
>>>>> diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
>>>>> index 
>>>>> 324359be7127f04a80ebc0079ad0a9964dfd82a7..498bc0798dbaaa3ee73815ba27864ae92a2fd08e 
>>>>> 100644
>>>>> --- a/gcc/config/arm/unspecs.md
>>>>> +++ b/gcc/config/arm/unspecs.md
>>>>> @@ -174,6 +174,7 @@
>>>>>    VUNSPEC_MRRC2                ; Represent the coprocessor mrrc2 
>>>>> instruction.
>>>>>    VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional 
>>>>> speculation barrier.
>>>>>    VUNSPEC_VSTR_VLDR    ; Represent the vstr/vldr instruction.
>>>>> +  VUNSPEC_CLRM_APSR    ; Represent the clearing of APSR with clrm 
>>>>> instruction.
>>>>>  ])
>>>>>
>>>>>  ;; Enumerators for NEON unspecs.
>>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>>>>> index 
>>>>> 6d611e130b6f3b544807b767927d99b89071343b..7036cb9508c27d56c4b2c01a81c44bf6f1f9c781 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
>>>>> @@ -36,6 +36,7 @@ main (void)
>>>>>  /* { dg-final { scan-assembler "movw\tr1, #1855" } } */
>>>>>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>>>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>>
>>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>>>>> index 
>>>>> b7ec0a040319545b50590261278f1517bcb22796..50d4979470dd21738453e0d70c7a69ee0752ac41 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
>>>>> @@ -33,6 +33,7 @@ main (void)
>>>>>  /* { dg-final { scan-assembler "movw\tr1, #1919" } } */
>>>>>  /* { dg-final { scan-assembler "movt\tr1, 2047" } } */
>>>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>>
>>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>>>>> index 
>>>>> 7b9c3f0fe061317f71d3122dea7a55ab5311f234..2b7507c900ab18705083ba1d86359e1ae36a50a2 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
>>>>> @@ -34,5 +34,6 @@ main (void)
>>>>>  /* { dg-final { scan-assembler "movw\tr1, #65535" } } */
>>>>>  /* { dg-final { scan-assembler "movt\tr1, 63" } } */
>>>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>>>> index 
>>>>> aa0ec8e0b0f0953a5a5cbc2db58413176c2505f3..35cab1f3233daac9fba50d25dac23364c798fb9c 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
>>>>> @@ -105,8 +105,10 @@ qux (int_nsfunc_t * callback)
>>>>>  /* { dg-final { scan-assembler "bic" } } */
>>>>>  /* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
>>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" 
>>>>> { target arm_cmse_clear_ok } } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
>>>>> +/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" { target { ! 
>>>>> arm_cmse_clear_ok } } } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>
>>>>>  int call_callback (void)
>>>>>  {
>>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>>>> index 
>>>>> df1ea52bec533c36a738d7d3b2b2ff749b0f3713..1f5af7c2dba7747f6058d12af8ef80b4dd1b1431 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
>>>>> @@ -9,5 +9,6 @@ int foo (void)
>>>>>    return bar ();
>>>>>  }
>>>>>
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler-not "^(.*\\s)?bl?\[^\\s]*\\s+bar" 
>>>>> } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>>>> index 
>>>>> 62c63b888ab49e99fba0a08b69941e73c9a8d33b..c52e1c14d9956743625e3b8a200e823f163924e3 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-4.c
>>>>> @@ -12,5 +12,5 @@
>>>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>>>> index 
>>>>> b718a70522b86e2bc58900681a781129543f8869..fdba955a32fc5ad492b74974185f98470bc49a7e 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-5.c
>>>>> @@ -10,6 +10,5 @@
>>>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>>>> index 
>>>>> 16536ab4f9ec5782463ab90f404a2e9f6f938850..85068ceaac6a5c0c60af4a54c0af0d20326fc18d 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-6.c
>>>>> @@ -13,5 +13,5 @@
>>>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>>>> index 
>>>>> 0b3cc1e2b2b26e185a9d5d4855d3bea8c70289b5..af69d38acf47d9d1d55480edba2b66f07e2d06ad 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-7.c
>>>>> @@ -10,6 +10,5 @@
>>>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>>>> index 
>>>>> 914ea39626f2f72eac8c9c1cb495b0855e58f5e1..62201595549f07b046c7c5972d612ab155c4c38c 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-8.c
>>>>> @@ -13,5 +13,5 @@
>>>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>>>> index 
>>>>> 32435d255805331c7c56a096675b7a2af3286e5e..287f0d6faad113fbc8c30051280668baa58ab130 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/bitfield-9.c
>>>>> @@ -7,7 +7,5 @@
>>>>>  /* { dg-final { scan-assembler "and\tr0, r0, ip" } } */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>>>> index 
>>>>> eb655b5504e58dc842853c8cb874c5cef3b82aa6..7b2df1faff5ea6ce6e7a58a37cd23eaf9616ee97 
>>>>> 100644
>>>>> --- 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>>>> +++ 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-13.c
>>>>> @@ -8,10 +8,7 @@
>>>>>  /* Checks for saving and clearing prior to function call. */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts2, #1\.0" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>>>>> index 
>>>>> ab266af7092afbce868792446124c291188e8a90..638643d0a6772d43f440df3942c6c723f1eff3ef 
>>>>> 100644
>>>>> --- 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>>>>> +++ 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-5.c
>>>>> @@ -6,10 +6,6 @@
>>>>>  #include "../../../cmse-5.x"
>>>>>
>>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" 
>>>>> } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>>>> @@ -26,7 +22,6 @@
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>>> arm_dsp } } } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>>> arm_dsp } } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, 
>>>>> APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>>>> index 
>>>>> fd1a24b3258e8403394dac98ff7c4712b0eb7a1b..9ec14d1a707839e4858bac72bc292fd0984bf86c 
>>>>> 100644
>>>>> --- 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>>>> +++ 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-7.c
>>>>> @@ -8,10 +8,7 @@
>>>>>  /* Checks for saving and clearing prior to function call. */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>>>> index 
>>>>> d8f9b7758d50f74f777fcda22f3f6714ff28bb96..d375879ed02483c05d7853c95f9b9e15383ff321 
>>>>> 100644
>>>>> --- 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>>>> +++ 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard-sp/cmse-8.c
>>>>> @@ -8,10 +8,7 @@
>>>>>  /* Checks for saving and clearing prior to function call. */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>>>> index 
>>>>> 4878c6ef9157abff003780fbf6401db8eb3ef2f3..e5cb0fabd4ce20ef8e57f25778b81a3ed3908af0 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-13.c
>>>>> @@ -8,10 +8,7 @@
>>>>>  /* Checks for saving and clearing prior to function call. */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>>>>> index 
>>>>> 82aad2d13d6b170c92fd2c2345ab76f41e383013..7e3b7609dfa5c8c1df77e413fa1bb85aa80ea9f6 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-5.c
>>>>> @@ -6,10 +6,6 @@
>>>>>  #include "../../../cmse-5.x"
>>>>>
>>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" 
>>>>> } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmov\.f32\ts0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>>> @@ -19,7 +15,6 @@
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>>> arm_dsp } } } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>>> arm_dsp } } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, ip, 
>>>>> APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>>>> index 
>>>>> 8e054c2aeebac4bd3f164b00ad867bc2d72cb674..d998b43a148250a15eb4aae9fb0ef6e4bf51203b 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-7.c
>>>>> @@ -8,10 +8,7 @@
>>>>>  /* Checks for saving and clearing prior to function call. */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>>>> index 
>>>>> e74cea7697ba1c12ebeef21636d1b8fd60b42677..e416bef2cb9fabd9cb33e3c1c87057ebdd3d6daf 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/hard/cmse-8.c
>>>>> @@ -8,10 +8,7 @@
>>>>>  /* Checks for saving and clearing prior to function call. */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler-not "vmov\.f64\td0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>>>> index 
>>>>> 4c4a0c956fa574f8fa25e4222ce9274bfbc5e32d..d43a9f85a199ecdf7e018852b3af9b4cf36af81f 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-13.c
>>>>> @@ -8,9 +8,9 @@
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>>>
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>>>>> index 
>>>>> c684d79fae00feb8e15e9f142735f005473b6011..157bccb9ff3256056d496a0d0770374315b04d87 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-5.c
>>>>> @@ -5,13 +5,8 @@
>>>>>  #include "../../../cmse-5.x"
>>>>>
>>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" 
>>>>> } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tip, lr" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>>> arm_dsp } } } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>>> arm_dsp } } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>>>> index 
>>>>> 4cb6a54a0a5b02954519e64503d7c2c4c0e4750d..02e48157a2c61b0a8bee77e949944acc2a4bee37 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-7.c
>>>>> @@ -7,10 +7,7 @@
>>>>>  /* Checks for saving and clearing prior to function call. */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>>>
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>>>> index 
>>>>> 4764b2fadfb38661764b909cdb2c9cd109e24df0..c7a22a2ba464dce26b289635dd8dcc8213ae33d8 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/soft/cmse-8.c
>>>>> @@ -9,8 +9,7 @@
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmov" } } */
>>>>>  /* { dg-final { scan-assembler-not "vmsr" } } */
>>>>>
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>>>>> index 
>>>>> 9b2e7565d24ff52138b0fb90a1e6268aa4c515a0..2522a17a6316d76a21d8d241d4c44cdddf1981e0 
>>>>> 100644
>>>>> --- 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>>>>> +++ 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-5.c
>>>>> @@ -8,9 +8,6 @@
>>>>>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" 
>>>>> } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts2, #1\.0" } } */
>>>>> @@ -27,7 +24,6 @@
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts13, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts14, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f32\ts15, #1\.0" } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>>> arm_dsp } } } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>>> arm_dsp } } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>>>> index 
>>>>> 9e93d75c35de5e3dde1074fb99da94edc2648319..d34ca383236fdd31723966e6218ea918cf8c9122 
>>>>> 100644
>>>>> --- 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>>>> +++ 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-7.c
>>>>> @@ -8,10 +8,7 @@
>>>>>  /* Checks for saving and clearing prior to function call. */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } 
>>>>> } */
>>>>>
>>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>>>> index 
>>>>> 566889e66c8cea6ca32348f48742d2c325336995..ff8e9816cff1569bbfc1c5213c1f8ed2e49ba250 
>>>>> 100644
>>>>> --- 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>>>> +++ 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp-sp/cmse-8.c
>>>>> @@ -10,8 +10,7 @@
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>>
>>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>>>> index 
>>>>> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..ff9a7dfa5e696e3a6c4132343d0ee94c3068c208 
>>>>> 100644
>>>>> --- 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>>>> +++ 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-13.c
>>>>> @@ -9,8 +9,9 @@
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, 
>>>>> r4" } } */
>>>>> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>>>> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, APSR\}" } } */
>>>>>
>>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>>>>> index 
>>>>> 5af1fdb934ce5aa5afd8d096122b6e9b55591bd9..eb7561f2a2629f3c153afe3a1a5c58d8abb9d07b 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-5.c
>>>>> @@ -7,10 +7,6 @@
>>>>>
>>>>>  /* { dg-final { scan-assembler "__acle_se_foo:" } } */
>>>>>  /* { dg-final { scan-assembler "vstr\tFPCXTNS, \\\[sp, #-4\\\]!" 
>>>>> } } */
>>>>> -/* { dg-final { scan-assembler-not "mov\tr0, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, lr" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, lr" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td0, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td1, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td2, #1\.0" } } */
>>>>> @@ -19,7 +15,6 @@
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td5, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td6, #1\.0" } } */
>>>>>  /* { dg-final { scan-assembler "vmov\.f64\td7, #1\.0" } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvq, lr" { target { ! 
>>>>> arm_dsp } } } } */
>>>>> -/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target 
>>>>> arm_dsp } } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" } 
>>>>> } */
>>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>>>> index 
>>>>> 1c38290e79d18a8f94e44b974c54220e553a9a49..03d36aa650986b6069e2fe1c1f3f98fa9664d88a 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-7.c
>>>>> @@ -8,10 +8,7 @@
>>>>>  /* Checks for saving and clearing prior to function call. */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r0, r1, r2, r3, APSR\}" } 
>>>>> } */
>>>>>
>>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>>>> index 
>>>>> 39c2e72f968ce9f30d36bd347544ca26b3dfad8a..ce45e10688f855ca7b2a63777d2b3d3418815589 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/softfp/cmse-8.c
>>>>> @@ -10,8 +10,7 @@
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>>
>>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>>>> index 
>>>>> d51db020c7707fa714364b10dd3ec5896a9dad17..dbd1d34413ef36f2b03716c0d9cf46b024af0835 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-1.c
>>>>> @@ -10,6 +10,5 @@
>>>>>  /* { dg-final { scan-assembler "and\tr1, r1, ip" } } */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr2, r4" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r2, r3, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>>>> index 
>>>>> 131afbbf4289b238438c53ab9ea55d13b8567513..3edc7f1e259779a24e722d67ed544c0a673090c7 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8_1m/union-2.c
>>>>> @@ -14,5 +14,5 @@
>>>>>  /* { dg-final { scan-assembler "and\tr2, r2, ip" } } */
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>> -/* { dg-final { scan-assembler "mov\tr3, r4" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r3, APSR\}" } } */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git 
>>>>> a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>>>>> index 
>>>>> 0ee28de4123c5e09df7c5d1046e0bd555af6f0fa..3a72406df2492206c2cb8ac7b63e4242ec0ba598 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/8m/softfp/cmse-13.c
>>>>> @@ -9,8 +9,9 @@
>>>>>  /* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
>>>>>  /* { dg-final { scan-assembler-not "mov\tr0, r4" } } */
>>>>> -/* { dg-final { scan-assembler "\n\tmov\tr1, r4" } } */
>>>>> -/* { dg-final { scan-assembler-not "\n\tmov\tr2, r4\n\tmov\tr3, 
>>>>> r4" } } */
>>>>> +/* { dg-final { scan-assembler "mov\tr1, r4" } } */
>>>>> +/* { dg-final { scan-assembler-not "mov\tr2, r4" } } */
>>>>> +/* { dg-final { scan-assembler-not "mov\tr3, r4" } } */
>>>>>
>>>>>  /* Now we check that we use the correct intrinsic to call. */
>>>>>  /* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } 
>>>>> } */
>>>>> diff --git a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c 
>>>>> b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>>>>> index 
>>>>> 5f6891a26d9be6edbb81c6c9e71897d1b49c8c60..90fdac18e30424edca60b6f884227adbf716899d 
>>>>> 100644
>>>>> --- a/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>>>>> +++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
>>>>> @@ -29,5 +29,6 @@ main (void)
>>>>>  /* { dg-final { scan-assembler "movs\tr1, #255" } } */
>>>>>  /* { dg-final { scan-assembler "movt\tr1, 65535" } } */
>>>>>  /* { dg-final { scan-assembler "ands\tr0(, r0)?, r1" } } */
>>>>> +/* { dg-final { scan-assembler "clrm\t\{r1, r2, r3, ip, APSR\}" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "vldr\tFPCXTNS, \\\[sp\\\], #4" { 
>>>>> target arm_cmse_clear_ok } } } */
>>>>>  /* { dg-final { scan-assembler "bxns" } } */
>>>>>
>>
>> +;; The operands are validated through the clear_multiple_operation
>> +;; match_parallel predicate rather than through constraints so 
>> enable it only
>> +;; after reload.
>> +(define_insn "*clear_multiple"
>> +  [(match_parallel 0 "clear_multiple_operation"
>> +     [(set (match_operand:SI 1 "register_operand" "")
>> +       (const_int 0))])]
>> +  "TARGET_THUMB2 && TARGET_HAVE_FPCXT_CMSE && use_cmse && 
>> reload_completed"
>> +  {
>> +    char pattern[100];
>> +    int i, num_saves = XVECLEN (operands[0], 0);
>> +
>> +    strcpy (pattern, \"clrm%?\\t{\");
>> +    for (i = 0; i < num_saves; i++)
>> +      {
>> +    if (GET_CODE (XVECEXP (operands[0], 0, i)) == UNSPEC_VOLATILE)
>> +      {
>> +        strcat (pattern, \"APSR\");
>> +        // Skip clobber
>>
>>
>> I don't think this comment is useful. If you want to keep it, convert 
>> it to C-style /**/.
>>
>>
>> Otherwise ok.
>> Thanks!
>> Kyrill
>>
>>
>
> Ok, I've gotten rid of the comment.
>

This is ok.

Thanks,

Kyrill


>
> Thanks,
> Mihail
>>
>> +        ++i;
>> +      }
>> +    else
>> +      strcat (pattern,
>> +          reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 0))]);
>> +    if (i < num_saves - 1)
>> +      strcat (pattern, \", %|\");
>> +      }
>> +    strcat (pattern, \"}\");
>> +    output_asm_insn (pattern, operands);
>> +    return \"\";
>> +  }
>> +  [(set_attr "predicable" "yes")]
>> +)
>>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH] arm: fix rtl checking bootstrap (PR target/93312)
  2020-01-13 17:30           ` Kyrill Tkachov
@ 2020-01-17 21:06             ` Jakub Jelinek
  2020-01-18  1:42               ` Jeff Law
  0 siblings, 1 reply; 35+ messages in thread
From: Jakub Jelinek @ 2020-01-17 21:06 UTC (permalink / raw)
  To: Kyrill Tkachov; +Cc: Mihail Ionescu, gcc-patches, Richard Earnshaw

Hi!

As reported in PR93312, the:
> > > > > >         * config/arm/arm.c (clear_operation_p): New function.
change broke RTL checking bootstrap.

On the testcase from the PR (which is distilled from libgcc2.c, so I think
we don't need to add it into testsuite) we ICE because SET_DEST (elt) is
not a REG, but SUBREG.  The code uses REGNO on it, which is invalid, but
only stores it into a variable, then performs REG_P (reg) check,
determines it is not a REG and bails early.

The following patch just moves the regno variable initialization after that
check, it isn't used in between.  And, as a small optimization, because
reg doesn't change, doesn't use REGNO (reg) a second time to set last_regno.

Ok for trunk if it passes bootstrap/regtest?

2020-01-17  Jakub Jelinek  <jakub@redhat.com>

	PR target/93312
	* config/arm/arm.c (clear_operation_p): Don't use REGNO until
	after checking the argument is a REG.  Don't use REGNO (reg)
	again to set last_regno, reuse regno variable instead.

--- gcc/config/arm/arm.c.jj	2020-01-17 09:31:28.594195284 +0100
+++ gcc/config/arm/arm.c	2020-01-17 19:30:47.747756756 +0100
@@ -13779,7 +13779,6 @@ clear_operation_p (rtx op, bool vfp)
 	return false;
 
       reg = SET_DEST (elt);
-      regno = REGNO (reg);
       zero = SET_SRC (elt);
 
       if (!REG_P (reg)
@@ -13787,6 +13786,8 @@ clear_operation_p (rtx op, bool vfp)
 	  || zero != CONST0_RTX (SImode))
 	return false;
 
+      regno = REGNO (reg);
+
       if (vfp)
 	{
 	  if (i != 1 && regno != last_regno + 1)
@@ -13800,7 +13801,7 @@ clear_operation_p (rtx op, bool vfp)
 	    return false;
 	}
 
-      last_regno = REGNO (reg);
+      last_regno = regno;
     }
 
   return true;


	Jakub

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] arm: fix rtl checking bootstrap (PR target/93312)
  2020-01-17 21:06             ` [PATCH] arm: fix rtl checking bootstrap (PR target/93312) Jakub Jelinek
@ 2020-01-18  1:42               ` Jeff Law
  0 siblings, 0 replies; 35+ messages in thread
From: Jeff Law @ 2020-01-18  1:42 UTC (permalink / raw)
  To: Jakub Jelinek, Kyrill Tkachov
  Cc: Mihail Ionescu, gcc-patches, Richard Earnshaw

On Fri, 2020-01-17 at 20:15 +0100, Jakub Jelinek wrote:
> Hi!
> 
> As reported in PR93312, the:
> > > > > > >         * config/arm/arm.c (clear_operation_p): New function.
> change broke RTL checking bootstrap.
> 
> On the testcase from the PR (which is distilled from libgcc2.c, so I think
> we don't need to add it into testsuite) we ICE because SET_DEST (elt) is
> not a REG, but SUBREG.  The code uses REGNO on it, which is invalid, but
> only stores it into a variable, then performs REG_P (reg) check,
> determines it is not a REG and bails early.
> 
> The following patch just moves the regno variable initialization after that
> check, it isn't used in between.  And, as a small optimization, because
> reg doesn't change, doesn't use REGNO (reg) a second time to set last_regno.
> 
> Ok for trunk if it passes bootstrap/regtest?
> 
> 2020-01-17  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR target/93312
> 	* config/arm/arm.c (clear_operation_p): Don't use REGNO until
> 	after checking the argument is a REG.  Don't use REGNO (reg)
> 	again to set last_regno, reuse regno variable instead.
OK
jeff
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2020-01-18  0:08 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-23 14:31 [PATCH, GCC/ARM, 0/10] Add support for Armv8.1-M Mainline Security Extension Mihail Ionescu
2019-10-23 14:31 ` [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions Mihail Ionescu
2019-10-23 14:31 ` [PATCH, GCC/ARM, 1/10] Fix -mcmse check in libgcc Mihail Ionescu
2019-10-23 14:31 ` [PATCH, GCC/ARM, 5/10] Clear VFP registers with VSCCLRM Mihail Ionescu
2019-10-23 14:31 ` [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM Mihail Ionescu
2019-10-23 14:31 ` [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline Mihail Ionescu
2019-10-23 14:33 ` [PATCH, GCC/ARM, 6/10] Clear GPRs inline when calling nscall function Mihail Ionescu
2019-10-23 14:34 ` [PATCH, GCC/ARM, 9/10] Call nscall function with blxns Mihail Ionescu
2019-10-23 14:34 ` [PATCH, GCC/ARM, 7/10] Clear all VFP regs inline in hardfloat nscall functions Mihail Ionescu
2019-10-23 14:34 ` [PATCH, GCC/ARM, 10/10] Enable -mcmse Mihail Ionescu
2019-10-23 15:07 ` [PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall function Mihail Ionescu
     [not found] ` <27d47273-6c06-450c-81a3-cee0c7355577@VE1EUR03FT028.eop-EUR03.prod.protection.outlook.com>
2019-11-04 16:44   ` [PATCH, GCC/ARM, 1/10] Fix -mcmse check in libgcc Kyrill Tkachov
     [not found] ` <b3358cc4-8ee5-4039-891d-229a653270cb@VE1EUR03FT005.eop-EUR03.prod.protection.outlook.com>
2019-11-04 16:49   ` [PATCH, GCC/ARM, 2/10] Add command line support for Armv8.1-M Mainline Kyrill Tkachov
2019-11-06 15:59     ` Kyrill Tkachov
2019-12-16 18:29       ` Mihail Ionescu
2019-12-17 10:24         ` Kyrill Tkachov
     [not found] ` <38378aaf-a33f-40b1-8595-b65b16f74363@AM5EUR03FT051.eop-EUR03.prod.protection.outlook.com>
2019-11-06 16:12   ` [PATCH, GCC/ARM, 3/10] Save/restore FPCXTNS in nsentry functions Kyrill Tkachov
2019-12-16 18:30     ` Mihail Ionescu
2019-12-17 10:26       ` Kyrill Tkachov
     [not found] ` <58a87082-6686-466f-84ed-1a8da281ecbb@DB5EUR03FT053.eop-EUR03.prod.protection.outlook.com>
2019-11-12  9:56   ` [PATCH, GCC/ARM, 4/10] Clear GPR with CLRM Kyrill Tkachov
2019-12-16 19:16     ` Mihail Ionescu
2019-12-17 10:27       ` Kyrill Tkachov
2019-12-18 13:29         ` Mihail Ionescu
2020-01-13 17:30           ` Kyrill Tkachov
2020-01-17 21:06             ` [PATCH] arm: fix rtl checking bootstrap (PR target/93312) Jakub Jelinek
2020-01-18  1:42               ` Jeff Law
     [not found] ` <b15c924d-b109-4221-aded-5d859a1c48c6@AM5EUR03FT012.eop-EUR03.prod.protection.outlook.com>
2019-11-12 10:13   ` [PATCH, GCC/ARM, 5/10] Clear VFP registers with VSCCLRM Kyrill Tkachov
     [not found] ` <67d2e066-3981-4959-b56d-05d59d8afa12@VE1EUR03FT030.eop-EUR03.prod.protection.outlook.com>
2019-11-12 10:19   ` [PATCH, GCC/ARM, 6/10] Clear GPRs inline when calling nscall function Kyrill Tkachov
     [not found] ` <6f7c01d4-0459-41c8-bd16-928eb034c1be@VE1EUR03FT044.eop-EUR03.prod.protection.outlook.com>
2019-11-12 10:22   ` [PATCH, GCC/ARM, 7/10] Clear all VFP regs inline in hardfloat nscall functions Kyrill Tkachov
     [not found] ` <ad64c6ab-11ff-4aad-942e-04e0f6d1d705@VE1EUR03FT027.eop-EUR03.prod.protection.outlook.com>
2019-11-12 10:24   ` [PATCH, GCC/ARM, 8/10] Do lazy store & load inline when calling nscall function Kyrill Tkachov
2019-12-18 13:39     ` Mihail Ionescu
     [not found] ` <c58f33d1-930f-4d24-9564-26b812bd8b07@VE1EUR03FT028.eop-EUR03.prod.protection.outlook.com>
2019-11-12 10:25   ` [PATCH, GCC/ARM, 9/10] Call nscall function with blxns Kyrill Tkachov
2019-12-18 13:52     ` Mihail Ionescu
2019-12-18 17:00       ` Kyrill Tkachov
     [not found] ` <e5be4cd4-6c85-48ba-809a-ee489e9da01a@AM5EUR03FT012.eop-EUR03.prod.protection.outlook.com>
2019-11-12 10:31   ` [PATCH, GCC/ARM, 10/10] Enable -mcmse Kyrill Tkachov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).