public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions
@ 2016-07-25 13:17 Andre Vieira (lists)
  2016-07-25 13:20 ` [PATCH 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics Andre Vieira (lists)
                   ` (7 more replies)
  0 siblings, 8 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-07-25 13:17 UTC (permalink / raw)
  To: GCC Patches

[PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions

Hello,

This is a respin of a previous patch series for ARMv8-M Security
Extensions. In this version I have removed one patch, rebased the rest
and changed some of them.

This patch series aims at implementing support for ARMv8-M's Security
Extensions. You can find the specification of ARMV8-M Security
Extensions in: ARM®v8-M Security Extensions: Requirements on Development
Tools
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

We currently:
- do not support passing arguments or returning on the stack for
cmse_nonsecure_{call,entry} functions,
- only test Security Extensions for -mfpu=fpv5-d16 and fpv5-sp-d16 and
only support single and double precision FPU's with d16.

Bootstrapped and tested on arm-none-linux-gnueabihf and tested on
arm-none-eabi with ARMv8-M Baseline and Mainline targets.

Andre Vieira (7):
 Add support for ARMv8-M's Security Extensions flag and intrinsics
 Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
 ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and
bxns return
 ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
 Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
 ARMv8-M Security Extension's cmse_nonsecure_call: use
__gnu_cmse_nonsecure_call
 Added support for ARMV8-M Security Extension cmse_nonsecure_caller
intrinsic

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

* [PATCH 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics
  2016-07-25 13:17 [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Andre Vieira (lists)
@ 2016-07-25 13:20 ` Andre Vieira (lists)
  2016-08-24 11:00   ` [PATCHv2 " Andre Vieira (lists)
  2016-07-25 13:21 ` [PATCH 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute Andre Vieira (lists)
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-07-25 13:20 UTC (permalink / raw)
  To: gcc-patches

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

This patch adds the support of the '-mcmse' option to enable ARMv8-M's
Security Extensions and supports the following intrinsics:
cmse_TT
cmse_TT_fptr
cmse_TTT
cmse_TTT_fptr
cmse_TTA
cmse_TTA_fptr
cmse_TTAT
cmse_TTAT_fptr
cmse_check_address_range
cmse_check_pointed_object
cmse_is_nsfptr
cmse_nsfptr_create

It also defines the mandatory cmse_address_info struct and the
__ARM_FEATURE_CMSE macro.
See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
Extensions: Requirements on Development Tools
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

*** gcc/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config.gcc (extra_headers): Added arm_cmse.h.
        * config/arm/arm-arches.def (ARM_ARCH):
        (armv8-m): Add FL2_CMSE.
        (armv8-m.main): Likewise.
        (armv8-m.main+dsp): Likewise.
        * config/arm/arm-c.c
        (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
        * config/arm/arm-protos.h
        (arm_is_constant_pool_ref): Define FL2_CMSE.
        * config/arm.c (arm_arch_cmse): New.
        (arm_option_override): New error for unsupported cmse target.
        * config/arm/arm.h (arm_arch_cmse): New.
        * config/arm/arm.opt (mcmse): New.
        * doc/invoke.texi (ARM Options): Add -mcmse.
        * config/arm/arm_cmse.h: New file.

*** libgcc/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/cmse.c: Likewise.
        * config/arm/t-arm (HAVE_CMSE): New.

*** gcc/testsuite/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse.exp: New.
        * gcc.target/arm/cmse/cmse-1.c: New.
        * gcc.target/arm/cmse/cmse-12.c: New.
        * lib/target-supports.exp
        (check_effective_target_arm_cmse_ok): New.

[-- Attachment #2: diff --]
[-- Type: text/plain, Size: 22961 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 1f75f17877334c2bb61cd16b69539ec7514db8ae..8555bbf19d81b517493c86b38aff31a633ac50eb 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -320,7 +320,7 @@ arc*-*-*)
 arm*-*-*)
 	cpu_type=arm
 	extra_objs="arm-builtins.o aarch-common.o"
-	extra_headers="mmintrin.h arm_neon.h arm_acle.h"
+	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_cmse.h"
 	target_type_format_char='%'
 	c_target_objs="arm-c.o"
 	cxx_target_objs="arm-c.o"
diff --git a/gcc/config/arm/arm-arches.def b/gcc/config/arm/arm-arches.def
index be46521c9eaea54f9ad78a92874567589289dbdf..0e523959551cc3b1da31411ccdd1105b830db845 100644
--- a/gcc/config/arm/arm-arches.def
+++ b/gcc/config/arm/arm-arches.def
@@ -63,11 +63,11 @@ ARM_ARCH("armv8.1-a+crc",cortexa53, 8A,
 	  ARM_FSET_MAKE (FL_CO_PROC | FL_CRC32 | FL_FOR_ARCH8A,
 			 FL2_FOR_ARCH8_1A))
 ARM_ARCH("armv8-m.base", cortexm0, 8M_BASE,
-	 ARM_FSET_MAKE_CPU1 (			      FL_FOR_ARCH8M_BASE))
+	 ARM_FSET_MAKE (			  FL_FOR_ARCH8M_BASE, FL2_CMSE))
 ARM_ARCH("armv8-m.main", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC |	      FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC |		  FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("armv8-m.main+dsp", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("iwmmxt",  iwmmxt,     5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT))
 ARM_ARCH("iwmmxt2", iwmmxt2,    5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT | FL_IWMMXT2))
 
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index b98470fff45b20a5398c2534bc3bb3edfb7bfd01..ad2fb09d1f9ca14300c6283f3831a527db656267 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -76,6 +76,14 @@ arm_cpu_builtins (struct cpp_reader* pfile)
 
   def_or_undef_macro (pfile, "__ARM_32BIT_STATE", TARGET_32BIT);
 
+  if (arm_arch8 && !arm_arch_notm)
+    {
+      if (arm_arch_cmse && use_cmse)
+	builtin_define_with_int_value ("__ARM_FEATURE_CMSE", 3);
+      else
+	builtin_define ("__ARM_FEATURE_CMSE");
+    }
+
   if (TARGET_ARM_FEATURE_LDREX)
     builtin_define_with_int_value ("__ARM_FEATURE_LDREX",
 				   TARGET_ARM_FEATURE_LDREX);
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 49c3a92dba80db32b698a0b44ad72d56111c1358..0754fb7252a8b86ffacc0cee4598686752af6e56 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -391,6 +391,7 @@ extern bool arm_is_constant_pool_ref (rtx);
 #define FL_ARCH6KZ    (1 << 31)       /* ARMv6KZ architecture.  */
 
 #define FL2_ARCH8_1   (1 << 0)	      /* Architecture 8.1.  */
+#define FL2_CMSE      (1 << 1)	      /* ARMv8-M Security Extensions.  */
 
 /* Flags that only effect tuning, not available instructions.  */
 #define FL_TUNE		(FL_WBUF | FL_VFPV2 | FL_STRONG | FL_LDSCHED \
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 317885cf7197b6755c4d9b5717afe61662626786..e3697bbcb425999db31ac2b4f47e14bb3f2ffa89 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -509,6 +509,9 @@ extern bool arm_disable_literal_pool;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 extern int arm_arch_crc;
 
+/* Nonzero if chip supports the ARMv8-M Security Extensions.  */
+extern int arm_arch_cmse;
+
 #ifndef TARGET_DEFAULT
 #define TARGET_DEFAULT  (MASK_APCS_FRAME)
 #endif
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 195de4822c8f26acbd67e08604719365b3d68534..9903d9cd8c5ff68a2318a643bdf31cf48016eba4 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -889,6 +889,9 @@ int arm_condexec_masklen = 0;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 int arm_arch_crc = 0;
 
+/* Nonzero if chip supports the ARMv8-M security extensions.  */
+int arm_arch_cmse = 0;
+
 /* Nonzero if the core has a very small, high-latency, multiply unit.  */
 int arm_m_profile_small_mul = 0;
 
@@ -3232,6 +3235,7 @@ arm_option_override (void)
   arm_arch_no_volatile_ce = ARM_FSET_HAS_CPU1 (insn_flags, FL_NO_VOLATILE_CE);
   arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0;
   arm_arch_crc = ARM_FSET_HAS_CPU1 (insn_flags, FL_CRC32);
+  arm_arch_cmse = ARM_FSET_HAS_CPU2 (insn_flags, FL2_CMSE);
   arm_m_profile_small_mul = ARM_FSET_HAS_CPU1 (insn_flags, FL_SMALLMUL);
 
   /* V5 code we generate is completely interworking capable, so we turn off
@@ -3494,6 +3498,9 @@ arm_option_override (void)
   if (target_slow_flash_data)
     arm_disable_literal_pool = true;
 
+  if (use_cmse && !arm_arch_cmse)
+    error ("target CPU does not support ARMv8-M Security Extensions");
+
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index 0ebe0174390167b79a64583c35a3f8fb018f6538..cb956632e23f4464c26f180d633b20091f212a37 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -109,6 +109,10 @@ mfloat-abi=
 Target RejectNegative Joined Enum(float_abi_type) Var(arm_float_abi) Init(TARGET_DEFAULT_FLOAT_ABI)
 Specify if floating point hardware should be used.
 
+mcmse
+Target RejectNegative Var(use_cmse)
+Specify that the compiler should target secure code as per ARMv8-M Security Extensions.
+
 Enum
 Name(float_abi_type) Type(enum float_abi_type)
 Known floating-point ABIs (for use with the -mfloat-abi= option):
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
new file mode 100644
index 0000000000000000000000000000000000000000..c9afdcbf48160a963fc254795543a1d9e981a215
--- /dev/null
+++ b/gcc/config/arm/arm_cmse.h
@@ -0,0 +1,192 @@
+/* ARMv8-M Secure Extensions intrinsics include file.
+
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef _GCC_ARM_CMSE_H
+#define _GCC_ARM_CMSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __ARM_BIG_ENDIAN
+
+typedef union {
+  struct cmse_address_info {
+#if __ARM_FEATURE_CMSE & 2
+    unsigned idau_region:8;
+    unsigned idau_region_valid:1;
+    unsigned secure:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned nonsecure_read_ok:1;
+#else
+    unsigned :12;
+#endif
+    unsigned readwrite_ok:1;
+    unsigned read_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region:8;
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#else
+
+typedef union {
+  struct cmse_address_info {
+    unsigned mpu_region:8;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned read_ok:1;
+    unsigned readwrite_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned nonsecure_read_ok:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned secure:1;
+    unsigned idau_region_valid:1;
+    unsigned idau_region:8;
+#else
+    unsigned :12;
+#endif
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#endif /* __ARM_BIG_ENDIAN */
+
+#define cmse_TT_fptr(p) (cmse_TT_fptr_generic ((__cmse_fptr)(p)))
+
+typedef void (*__cmse_fptr)(void);
+
+#define __CMSE_TT_ASM(flags) \
+{ \
+  cmse_address_info_t __result; \
+   __asm__ ("tt" # flags " %0,%1" \
+	   : "=r"(__result) \
+	   : "r"(__p) \
+	   : "memory"); \
+  return __result; \
+}
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT_fptr_generic (__cmse_fptr __p)
+__CMSE_TT_ASM ()
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT (void *__p)
+__CMSE_TT_ASM ()
+
+#define cmse_TTT_fptr(p) (cmse_TTT_fptr_generic ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT_fptr_generic (__cmse_fptr __p)
+__CMSE_TT_ASM (t)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT (void *__p)
+__CMSE_TT_ASM (t)
+
+#if __ARM_FEATURE_CMSE & 2
+
+#define cmse_TTA_fptr(p) (cmse_TTA_fptr_generic ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA_fptr_generic (__cmse_fptr __p)
+__CMSE_TT_ASM (a)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA (void *__p)
+__CMSE_TT_ASM (a)
+
+#define cmse_TTAT_fptr(p) (cmse_TTAT_fptr_generic ((__cmse_fptr)(p)))
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT_fptr_generic (__cmse_fptr __p)
+__CMSE_TT_ASM (at)
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT (void *__p)
+__CMSE_TT_ASM (at)
+
+#define CMSE_AU_NONSECURE	2
+#define CMSE_MPU_NONSECURE	16
+#define CMSE_NONSECURE		18
+
+#endif /* __ARM_FEATURE_CMSE & 2 */
+
+#define CMSE_MPU_UNPRIV		4
+#define CMSE_MPU_READWRITE	1
+#define CMSE_MPU_READ		8
+
+__extension__ void *
+cmse_check_address_range (void *, size_t, int);
+
+#define cmse_check_pointed_object(p, f) \
+  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
+
+#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
+
+#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
+
+#endif /* __ARM_FEATURE_CMSE & 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GCC_ARM_CMSE_H */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 5b9e6174cfa5bcfa3a58055c7610725d9ed3de2d..d8949fd54541fe5695841aa078fd078e2742ddfe 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -11567,6 +11567,7 @@ instructions, but allow the compiler to schedule those calls.
 * ARM iWMMXt Built-in Functions::
 * ARM C Language Extensions (ACLE)::
 * ARM Floating Point Status and Control Intrinsics::
+* ARM ARMv8-M Security Extensions::
 * AVR Built-in Functions::
 * Blackfin Built-in Functions::
 * FR-V Built-in Functions::
@@ -12412,6 +12413,14 @@ unsigned int __builtin_arm_get_fpscr ()
 void __builtin_arm_set_fpscr (unsigned int)
 @end smallexample
 
+@node ARM ARMv8-M Security Extensions
+@subsection ARM ARMv8-M Security Extensions
+
+GCC implements the ARMv8-M Security Extensions as described in the ARMv8-M
+Security Extensions: Requiremenets on Development Tools Engineering
+Specification, which can be found at
+@uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
+
 @node AVR Built-in Functions
 @subsection AVR Built-in Functions
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9a4db388a3b3dc644b0c555f1a1121cef14ef2df..539dba0cce0c531bc1ccd4f5fa9562f1e20694e5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -639,7 +639,8 @@ Objective-C and Objective-C++ Dialects}.
 -mneon-for-64bits @gol
 -mslow-flash-data @gol
 -masm-syntax-unified @gol
--mrestrict-it}
+-mrestrict-it @gol
+-mcmse}
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol
@@ -14527,6 +14528,12 @@ Print CPU tuning information as comment in assembler file.  This is
 an option used only for regression testing of the compiler and not
 intended for ordinary use in compiling code.  This option is disabled
 by default.
+
+@item -mcmse
+@opindex mcmse
+Generate secure code as per the "ARMv8-M Security Extensions: Requirements on
+Development Tools Engineering Specification", which can be found on
+@url{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 @end table
 
 @node AVR Options
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..d5b9a2d9d59569de170da814ae660e9fb2b943e7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mcmse -fdump-rtl-expand" }  */
+
+#include <arm_cmse.h>
+
+extern int a;
+extern int bar (void);
+
+int foo (char * p)
+{
+  cmse_address_info_t cait;
+
+  cait = cmse_TT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTA (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTA_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTAT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTAT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char), 0);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_READWRITE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV | CMSE_MPU_READ);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_AU_NONSECURE
+					 | CMSE_MPU_NONSECURE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  p = (char *) cmse_check_pointed_object (p, CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  return a;
+}
+/* { dg-final { scan-assembler-times "\ttt " 2 } } */
+/* { dg-final { scan-assembler-times "ttt " 2 } } */
+/* { dg-final { scan-assembler-times "tta " 2 } } */
+/* { dg-final { scan-assembler-times "ttat " 2 } } */
+/* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
+/* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
new file mode 100644
index 0000000000000000000000000000000000000000..87a2f1363a4e4bd817503e79e504980210e722c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+#include <arm_cmse.h>
+
+char *
+foo (char * p)
+{
+  if (!cmse_is_nsfptr (p))
+    return cmse_nsfptr_create (p);
+}
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler-not "cmse_is_nsfptr" } } */
+/* { dg-final { scan-assembler-not "cmse_nsfptr_create" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
new file mode 100644
index 0000000000000000000000000000000000000000..f797dba1901720e04249d61078c1cbf2a3e436a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -0,0 +1,50 @@
+#   Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite for ARMv8-M Security Extensions using the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Exit immediately if the target does not support -mcmse.
+if ![check_effective_target_arm_cmse_ok] then {
+    return
+}
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+set saved-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default "assemble"
+
+set saved-lto_torture_options ${LTO_TORTURE_OPTIONS}
+set LTO_TORTURE_OPTIONS ""
+
+# These are for both baseline and mainline.
+gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
+	"" $DEFAULT_CFLAGS
+
+set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index b9909ada734c08a46af886b5190be9ea92fd98e5..051a9d68a5db7f9417486bec9b8f3ad3812bae79 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -3519,6 +3519,19 @@ proc check_effective_target_arm_thumb1_cbz_ok {} {
     }
 }
 
+# Return 1 if this is an ARM target where ARMv8-M Security Extensions is
+# available.
+
+proc check_effective_target_arm_cmse_ok {} {
+    return [check_no_compiler_messages arm_cmse object {
+	int
+	foo (void)
+	{
+	  asm ("bxns r0");
+	}
+    } "-mcmse"];
+}
+
 # Return 1 if this compilation turns on string_ops_prefer_neon on.
 
 proc check_effective_target_arm_tune_string_ops_prefer_neon { } {
diff --git a/libgcc/config/arm/cmse.c b/libgcc/config/arm/cmse.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe3a22967c8536f2a8c05b58627f964d3fb1d345
--- /dev/null
+++ b/libgcc/config/arm/cmse.c
@@ -0,0 +1,108 @@
+/* ARMv8-M Security Extensions routines.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <arm_cmse.h>
+
+/* ARM intrinsic function to perform a permission check on a given
+   address range.  See ACLE changes for ARMv8-M.  */
+
+void *
+cmse_check_address_range (void *p, size_t size, int flags)
+{
+  cmse_address_info_t permb, perme;
+  char *pb = (char *) p, *pe;
+
+  /* Check if the range wraps around.  */
+  if (UINTPTR_MAX - (uintptr_t) p < size)
+    return NULL;
+
+  /* Check if an unknown flag is present.  */
+  int known = CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE | CMSE_MPU_READ;
+  int known_secure_level = CMSE_MPU_UNPRIV;
+#if __ARM_FEATURE_CMSE & 2
+  known |= CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE;
+  known_secure_level |= CMSE_MPU_NONSECURE;
+#endif
+  if (flags & (~known))
+    return NULL;
+
+  /* Execute the right variant of the TT instructions.  */
+  pe = pb + size - 1;
+  const int singleCheck = (((uintptr_t) pb ^ (uintptr_t) pe) < 32);
+  switch (flags & known_secure_level)
+    {
+    case 0:
+      permb = cmse_TT (pb);
+      perme = singleCheck ? permb : cmse_TT (pe);
+      break;
+    case CMSE_MPU_UNPRIV:
+      permb = cmse_TTT (pb);
+      perme = singleCheck ? permb : cmse_TTT (pe);
+      break;
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_NONSECURE:
+      permb = cmse_TTA (pb);
+      perme = singleCheck ? permb : cmse_TTA (pe);
+      break;
+    case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+      permb = cmse_TTAT (pb);
+      perme = singleCheck ? permb : cmse_TTAT (pe);
+      break;
+#endif
+    default:
+      /* Invalid flag, eg.  CMSE_MPU_NONSECURE specified but
+	 __ARM_FEATURE_CMSE & 2 == 0.  */
+      return NULL;
+    }
+
+  /* Check that the range does not cross MPU, SAU, or IDAU boundaries.  */
+  if (permb.value != perme.value)
+    return NULL;
+
+  /* Check the permissions on the range.  */
+  switch (flags & (~known_secure_level))
+    {
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+    case		 CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_readwrite_ok	? p : NULL;
+    case CMSE_MPU_READ | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_read_ok	? p : NULL;
+    case CMSE_AU_NONSECURE:
+      return permb.flags.secure			? NULL : p;
+#endif
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE:
+    case		 CMSE_MPU_READWRITE:
+      return permb.flags.readwrite_ok		? p : NULL;
+    case CMSE_MPU_READ:
+      return permb.flags.read_ok		? p : NULL;
+    default:
+      return NULL;
+    }
+}
+
+
+#endif /* __ARM_FEATURE_CMSE & 1.  */
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 4e17e99b4a53bbafc0f1f8dddd02000f0e8f4f48..5618143bfd0f02b170db3f9e4c0a15cecb403cec 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -1,3 +1,15 @@
 LIB1ASMSRC = arm/lib1funcs.S
 LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
 	_thumb1_case_uhi _thumb1_case_si
+
+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),)
+CMSE_OPTS:=-mcmse
+endif
+
+ifdef HAVE_CMSE
+libgcc-objects += cmse.o cmse_nonsecure_call.o
+
+cmse.o: $(srcdir)/config/arm/cmse.c
+	$(gcc_compile) -c $(CMSE_OPTS) $<
+endif

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

* [PATCH 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
  2016-07-25 13:17 [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Andre Vieira (lists)
  2016-07-25 13:20 ` [PATCH 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics Andre Vieira (lists)
@ 2016-07-25 13:21 ` Andre Vieira (lists)
  2016-08-24 11:01   ` [PATCHv2 " Andre Vieira (lists)
  2016-07-25 13:23 ` [PATCH 3/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return Andre Vieira (lists)
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-07-25 13:21 UTC (permalink / raw)
  To: gcc-patches

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

This patch adds support for the ARMv8-M Security Extensions
'cmse_nonsecure_entry' attribute. In this patch we implement the
attribute handling and diagnosis around the attribute. See Section 5.4
of ARM®v8-M Security Extensions
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

*** gcc/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
        (arm_attribute_table): Added cmse_nonsecure_entry
        (arm_compute_func_type): Handle cmse_nonsecure_entry.
        (cmse_func_args_or_return_in_stack): New.
        (arm_handle_cmse_nonsecure_entry): New.
        * config/arm/arm.h (ARM_FT_CMSE_ENTRY): New macro define.
        (IS_CMSE_ENTRY): Likewise.

*** gcc/testsuite/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse-3.c: New.

[-- Attachment #2: diff2 --]
[-- Type: text/plain, Size: 7315 bytes --]

diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index e3697bbcb425999db31ac2b4f47e14bb3f2ffa89..5307ec8f904230db5ea44150ef471d928926ab6d 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -1373,6 +1373,7 @@ enum reg_class
 #define ARM_FT_VOLATILE		(1 << 4) /* Does not return.  */
 #define ARM_FT_NESTED		(1 << 5) /* Embedded inside another func.  */
 #define ARM_FT_STACKALIGN	(1 << 6) /* Called with misaligned stack.  */
+#define ARM_FT_CMSE_ENTRY	(1 << 7) /* ARMv8-M non-secure entry function.  */
 
 /* Some macros to test these flags.  */
 #define ARM_FUNC_TYPE(t)	(t & ARM_FT_TYPE_MASK)
@@ -1381,6 +1382,7 @@ enum reg_class
 #define IS_NAKED(t)        	(t & ARM_FT_NAKED)
 #define IS_NESTED(t)       	(t & ARM_FT_NESTED)
 #define IS_STACKALIGN(t)       	(t & ARM_FT_STACKALIGN)
+#define IS_CMSE_ENTRY(t)	(t & ARM_FT_CMSE_ENTRY)
 
 
 /* Structure used to hold the function stack frame layout.  Offsets are
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9903d9cd8c5ff68a2318a643bdf31cf48016eba4..11417ab3c2f7101866ee5d6b100913480e5c336e 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -134,6 +134,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
+static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -343,6 +344,9 @@ static const struct attribute_spec arm_attribute_table[] =
   { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute,
     false },
 #endif
+  /* ARMv8-M Security Extensions support.  */
+  { "cmse_nonsecure_entry", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_entry, false },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -3633,6 +3637,9 @@ arm_compute_func_type (void)
   else
     type |= arm_isr_value (TREE_VALUE (a));
 
+  if (lookup_attribute ("cmse_nonsecure_entry", attr))
+    type |= ARM_FT_CMSE_ENTRY;
+
   return type;
 }
 
@@ -6634,6 +6641,110 @@ arm_handle_notshared_attribute (tree *node,
 }
 #endif
 
+/* This function returns true if a function with declaration FNDECL, name
+   NAME and type FNTYPE uses the stack to pass arguments or return variables
+   and false otherwise.  This is used for functions with the attributes
+   'cmse_nonsecure_call' or 'cmse_nonsecure_entry' and this function will issue
+   diagnostic messages if the stack is used.  */
+
+static bool
+cmse_func_args_or_return_in_stack (tree fndecl, tree name, tree fntype)
+{
+  function_args_iterator args_iter;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
+  bool first_param = true;
+  tree arg_type, prev_arg_type = NULL_TREE, ret_type;
+
+  /* Error out if any argument is passed on the stack.  */
+  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX, fndecl);
+  args_so_far = pack_cumulative_args (&args_so_far_v);
+  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+    {
+      rtx arg_rtx;
+      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+      prev_arg_type = arg_type;
+      if (VOID_TYPE_P (arg_type))
+	continue;
+
+      if (!first_param)
+	arm_function_arg_advance (args_so_far, arg_mode, arg_type, true);
+      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type, true);
+      if (!arg_rtx
+	  || arm_arg_partial_bytes (args_so_far, arg_mode, arg_type, true))
+	{
+	  error ("%qE attribute not available to functions with arguments "
+		 "passed on the stack", name);
+	  return true;
+	}
+      first_param = false;
+    }
+
+  /* Error out for variadic functions since we cannot control how many
+     arguments will be passed and thus stack could be used.  stdarg_p () is not
+     used for the checking to avoid browsing arguments twice.  */
+  if (prev_arg_type != NULL_TREE && !VOID_TYPE_P (prev_arg_type))
+    {
+      error ("%qE attribute not available to functions with variable number "
+	     "of arguments", name);
+      return true;
+    }
+
+  /* Error out if return value is passed on the stack.  */
+  ret_type = TREE_TYPE (fntype);
+  if (arm_return_in_memory (ret_type, fntype))
+    {
+      error ("%qE attribute not available to functions that return value on "
+	     "the stack", name);
+      return true;
+    }
+  return false;
+}
+
+/* Called upon detection of the use of the cmse_nonsecure_entry attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function declaration tree or otherwise issue a warning.  */
+
+static tree
+arm_handle_cmse_nonsecure_entry (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree fndecl;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Ignore attribute for function types.  */
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+	       name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  fndecl = *node;
+
+  /* Warn for static linkage functions.  */
+  if (!TREE_PUBLIC (fndecl))
+    {
+      warning (OPT_Wattributes, "%qE attribute has no effect on functions "
+	       "with static linkage", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (fndecl, name,
+						TREE_TYPE (fndecl));
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c2920e1dc310106d83203eb51e1a68a275d0152
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+struct span2 {
+  float a, b, c, d;
+};
+
+union test_union
+{
+  long long a;
+  int b;
+  struct span2 c;
+} test_union;
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (long long a, int b, long long c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+bar (long long a, int b, struct span c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+baz (int a, ...) {} /* { dg-error "not available to functions with variable number of arguments" } */
+
+struct span __attribute__ ((cmse_nonsecure_entry))
+qux (void) { /* { dg-error "not available to functions that return value on the stack" } */
+  struct span ret = {0, 0};
+  return ret;
+}
+
+void __attribute__ ((cmse_nonsecure_entry))
+norf (struct span2 a) {}
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */

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

* [PATCH 3/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return
  2016-07-25 13:17 [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Andre Vieira (lists)
  2016-07-25 13:20 ` [PATCH 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics Andre Vieira (lists)
  2016-07-25 13:21 ` [PATCH 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute Andre Vieira (lists)
@ 2016-07-25 13:23 ` Andre Vieira (lists)
  2016-10-25 16:29   ` Andre Vieira (lists)
  2016-07-25 13:24 ` [PATCH 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers Andre Vieira (lists)
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-07-25 13:23 UTC (permalink / raw)
  To: gcc-patches

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

This patch extends support for the ARMv8-M Security Extensions
'cmse_nonsecure_entry' attribute in two ways:

1) Generate two labels for the function, the regular function name and
one with the function's name appended to '__acle_se_', this will trigger
the linker to create a secure gateway veneer for this entry function.
2) Return from cmse_nonsecure_entry marked functions using bxns.

See Section 5.4 of ARM®v8-M Security Extensions
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).


*** gcc/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (use_return_insn): Change to return with  bxns
        when cmse_nonsecure_entry.
        (output_return_instruction): Likewise.
        (arm_output_function_prologue): Likewise.
        (thumb_pop): Likewise.
        (thumb_exit): Likewise.
        (arm_function_ok_for_sibcall): Disable sibcall for entry functions.
        (arm_asm_declare_function_name): New.
        * config/arm/arm-protos.h (arm_asm_declare_function_name): New.
        * config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
        use arm_asm_declare_function_name.

*** gcc/testsuite/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse-2.c: New.
        * gcc.target/arm/cmse/cmse-4.c: New.

[-- Attachment #2: diff3 --]
[-- Type: text/plain, Size: 10608 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 0754fb7252a8b86ffacc0cee4598686752af6e56..1d2e35b52f631570450b6c8eaf077e18e9b99203 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -31,6 +31,7 @@ extern int arm_volatile_func (void);
 extern void arm_expand_prologue (void);
 extern void arm_expand_epilogue (bool);
 extern void arm_declare_function_name (FILE *, const char *, tree);
+extern void arm_asm_declare_function_name (FILE *, const char *, tree);
 extern void thumb2_expand_return (bool);
 extern const char *arm_strip_name_encoding (const char *);
 extern void arm_asm_output_labelref (FILE *, const char *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 11417ab3c2f7101866ee5d6b100913480e5c336e..9fba371768b1eba3a11dc8aa5d6acf8cc30f464d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3866,6 +3866,11 @@ use_return_insn (int iscond, rtx sibling)
 	return 0;
     }
 
+  /* 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))
+    return 0;
+
   /* If there are saved registers but the LR isn't saved, then we need
      two instructions for the return.  */
   if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
@@ -6903,6 +6908,11 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
   if (IS_INTERRUPT (func_type))
     return false;
 
+  /* ARMv8-M non-secure entry functions need to return with bxns which is only
+     generated for entry functions themselves.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    return false;
+
   if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
     {
       /* Check that the return value locations are the same.  For
@@ -19739,6 +19749,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	 (e.g. interworking) then we can load the return address
 	 directly into the PC.  Otherwise we must load it into LR.  */
       if (really_return
+	  && !IS_CMSE_ENTRY (func_type)
 	  && (IS_INTERRUPT (func_type) || !TARGET_INTERWORK))
 	return_reg = reg_names[PC_REGNUM];
       else
@@ -19879,8 +19890,10 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	  break;
 
 	default:
+	  if (IS_CMSE_ENTRY (func_type))
+	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
 	  /* Use bx if it's available.  */
-	  if (arm_arch5 || arm_arch4t)
+	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
 	  else
 	    sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
@@ -19893,6 +19906,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
   return "";
 }
 
+/* Output in FILE asm statements needed to declare the NAME of the function
+   defined by its DECL node.  */
+
+void
+arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
+{
+  size_t cmse_name_len;
+  char *cmse_name = 0;
+  char cmse_prefix[] = "__acle_se_";
+
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_entry",
+				    DECL_ATTRIBUTES (decl)))
+    {
+      cmse_name_len = sizeof (cmse_prefix) + strlen (name);
+      cmse_name = XALLOCAVEC (char, cmse_name_len);
+      snprintf (cmse_name, cmse_name_len, "%s%s", cmse_prefix, name);
+      targetm.asm_out.globalize_label (file, cmse_name);
+    }
+
+  if (cmse_name)
+    {
+      ARM_DECLARE_FUNCTION_NAME (file, cmse_name, decl);
+      ASM_OUTPUT_TYPE_DIRECTIVE (file, cmse_name, "function");
+    }
+
+  ARM_DECLARE_FUNCTION_NAME (file, name, decl);
+  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
+  ASM_OUTPUT_LABEL (file, name);
+
+  if (cmse_name)
+    ASM_OUTPUT_LABEL (file, cmse_name);
+
+  ARM_OUTPUT_FN_UNWIND (file, TRUE);
+}
+
 /* Write the function name into the code section, directly preceding
    the function prologue.
 
@@ -19942,10 +19991,6 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
 {
   unsigned long func_type;
 
-  /* ??? Do we want to print some of the below anyway?  */
-  if (TARGET_THUMB1)
-    return;
-
   /* Sanity check.  */
   gcc_assert (!arm_ccfsm_state && !arm_target_insn);
 
@@ -19980,6 +20025,8 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
     asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
   if (IS_STACKALIGN (func_type))
     asm_fprintf (f, "\t%@ Stack Align: May be called with mis-aligned SP.\n");
+  if (IS_CMSE_ENTRY (func_type))
+    asm_fprintf (f, "\t%@ Non-secure entry function: called from non-secure code.\n");
 
   asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
 	       crtl->args.size,
@@ -24033,8 +24080,8 @@ thumb_pop (FILE *f, unsigned long mask)
   if (mask & (1 << PC_REGNUM))
     {
       /* Catch popping the PC.  */
-      if (TARGET_INTERWORK || TARGET_BACKTRACE
-	  || crtl->calls_eh_return)
+      if (TARGET_INTERWORK || TARGET_BACKTRACE || crtl->calls_eh_return
+	  || IS_CMSE_ENTRY (arm_current_func_type ()))
 	{
 	  /* The PC is never poped directly, instead
 	     it is popped into r3 and then BX is used.  */
@@ -24095,7 +24142,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
       if (crtl->calls_eh_return)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
-      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+      else
+	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
     }
   /* Otherwise if we are not supporting interworking and we have not created
@@ -24104,7 +24154,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
   else if (!TARGET_INTERWORK
 	   && !TARGET_BACKTRACE
 	   && !is_called_in_ARM_mode (current_function_decl)
-	   && !crtl->calls_eh_return)
+	   && !crtl->calls_eh_return
+	   && !IS_CMSE_ENTRY (arm_current_func_type ()))
     {
       asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
       return;
@@ -24327,7 +24378,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
     asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
   /* Return to caller.  */
-  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+  else
+    asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
 \f
 /* Scan INSN just before assembler is output for it.
@@ -25208,6 +25262,12 @@ thumb2_expand_return (bool simple_return)
 
   if (!simple_return && saved_regs_mask)
     {
+      /* TODO: Verify that this path is never taken for cmse_nonsecure_entry
+	 functions or adapt code to handle according to ACLE.  This path should
+	 not be reachable for cmse_nonsecure_entry functions though we prefer
+	 to guard it for now to ensure that future code changes do not silently
+	 change this behavior.  */
+      gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
       if (num_regs == 1)
         {
           rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
@@ -25625,6 +25685,7 @@ arm_expand_epilogue (bool really_return)
 
       if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
           && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
+	  && !IS_CMSE_ENTRY (func_type)
           && !IS_STACKALIGN (func_type)
           && really_return
           && crtl->args.pretend_args_size == 0
diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h
index 246de5492665ba2a0292736a9c53fbaaef184d72..fd8fc1cb0e6aa2212774068513233d6e818eeec8 100644
--- a/gcc/config/arm/elf.h
+++ b/gcc/config/arm/elf.h
@@ -75,16 +75,7 @@
 
 /* We might need a ARM specific header to function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_NAME
-#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)		\
-  do								\
-    {								\
-      ARM_DECLARE_FUNCTION_NAME (FILE, NAME, DECL);		\
-      ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");	\
-      ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));		\
-      ASM_OUTPUT_LABEL(FILE, NAME);				\
-      ARM_OUTPUT_FN_UNWIND (FILE, TRUE);			\
-    }								\
-  while (0)
+#define ASM_DECLARE_FUNCTION_NAME arm_asm_declare_function_name
 
 /* We might need an ARM specific trailer for function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_SIZE
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a91ac39ee37ef20495e047b402d3f5edc60a613
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+void
+foo (void) {}
+
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f930ab04a1097c64097a4e003296bbe85733319
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+
+extern int qux (void);
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (void) {}
+
+static void __attribute__ ((cmse_nonsecure_entry))
+bar (void) {} /* { dg-warning "has no effect on functions with static linkage" } */
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return qux ();
+}
+
+/* { dg-final { scan-assembler-times "bxns" 2 } } */
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..65200bcf29b219706911bbb799c847aefc92cb1c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
+
+
+int __attribute__ ((cmse_nonsecure_entry))
+foo (int a)
+{
+  return a + 1;
+}
+
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */

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

* [PATCH 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-07-25 13:17 [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Andre Vieira (lists)
                   ` (2 preceding siblings ...)
  2016-07-25 13:23 ` [PATCH 3/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return Andre Vieira (lists)
@ 2016-07-25 13:24 ` Andre Vieira (lists)
  2016-08-24 11:01   ` [PATCHv2 " Andre Vieira (lists)
  2016-07-25 13:25 ` [PATCH 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute Andre Vieira (lists)
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-07-25 13:24 UTC (permalink / raw)
  To: gcc-patches

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

This patch extends support for the ARMv8-M Security Extensions
'cmse_nonsecure_entry' attribute to safeguard against leak of
information through unbanked registers.

When returning from a nonsecure entry function we clear all caller-saved
registers that are not used to pass return values, by writing either the
LR, in case of general purpose registers, or the value 0, in case of FP
registers. We use the LR to write to APSR and FPSCR too. We currently do
not support entry functions that pass arguments or return variables on
the stack and we diagnose this. This patch relies on the existing code
to make sure callee-saved registers used in cmse_nonsecure_entry
functions are saved and restored thus retaining their nonsecure mode
value, this should be happening already as it is required by AAPCS.

This patch also clears padding bits for cmse_nonsecure_entry functions
with struct and union return types. For unions a bit is only considered
a padding bit if it is an unused bit in every field of that union. The
function that calculates these is used in a later patch to do the same
for arguments of cmse_nonsecure_call's.

*** gcc/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (output_return_instruction): Clear
        registers.
        (thumb2_expand_return): Likewise.
        (thumb1_expand_epilogue): Likewise.
        (thumb_exit): Likewise.
        (arm_expand_epilogue): Likewise.
        (cmse_nonsecure_entry_clear_before_return): New.
        (comp_not_to_clear_mask_str_un): New.
        (compute_not_to_clear_mask): New.
        * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
        * config/arm/thumb2.md (*thumb2_return): Likewise.

*** gcc/testsuite/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
        * gcc.target/arm/cmse/struct-1.c: New.
        * gcc.target/arm/cmse/bitfield-1.c: New.
        * gcc.target/arm/cmse/bitfield-2.c: New.
        * gcc.target/arm/cmse/bitfield-3.c: New.
        * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
cleared.
        * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.

[-- Attachment #2: diff4 --]
[-- Type: text/plain, Size: 36278 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9fba371768b1eba3a11dc8aa5d6acf8cc30f464d..81a9d9a6fb29d0956a661734d60dd2e44cb554b8 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17473,6 +17473,279 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
   return;
 }
 
+/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for structs
+   and unions in the context of ARMv8-M Security Extensions.  It is used as a
+   helper function for both 'cmse_nonsecure_call' and 'cmse_nonsecure_entry'
+   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to either one
+   or four masks, depending on whether it is being computed for a
+   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
+   respectively.  The tree for the type of the argument or a field within an
+   argument is passed in ARG_TYPE, the current register this argument or field
+   starts in is kept in the pointer REGNO and updated accordingly, the bit this
+   argument or field starts at is passed in STARTING_BIT and the last used bit
+   is kept in LAST_USED_BIT which is also updated accordingly.  */
+
+static unsigned HOST_WIDE_INT
+comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
+			       uint32_t * padding_bits_to_clear,
+			       unsigned starting_bit, int * last_used_bit)
+
+{
+  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
+
+  if (TREE_CODE (arg_type) == RECORD_TYPE)
+    {
+      unsigned current_bit = starting_bit;
+      tree field;
+      long int offset, size;
+
+
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  /* The offset within a structure is always an offset from
+	     the start of that structure.  Make sure we take that into the
+	     calculation of the register based offset that we use here.  */
+	  offset = starting_bit;
+	  offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
+	  offset %= 32;
+
+	  /* This is the actual size of the field, for bitfields this is the
+	     bitfield width and not the container size.  */
+	  size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+
+	  if (*last_used_bit != offset)
+	    {
+	      if (offset < *last_used_bit)
+		{
+		  /* This field's offset is before the 'last_used_bit', that
+		     means this field goes on the next register.  So we need to
+		     pad the rest of the current register and increase the
+		     register number.  */
+		  uint32_t mask;
+		  mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
+		  mask++;
+
+		  *(padding_bits_to_clear + *regno) |= mask;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      else
+		{
+		  /* Otherwise we pad the bits between the last field's end and
+		     the start of the new field.  */
+		  uint32_t mask;
+
+		  mask = UINT32_MAX >> (32 - offset);
+		  mask -= ((uint32_t) 1 << *last_used_bit) - 1;
+		  *(padding_bits_to_clear + *regno) |= mask;
+		}
+	      current_bit = offset;
+	    }
+
+	  /* Calculate further padding bits for inner structs/unions too.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	    {
+	      *last_used_bit = current_bit;
+	      not_to_clear_reg_mask
+		|= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
+						  padding_bits_to_clear, offset,
+						  last_used_bit);
+	    }
+	  else
+	    {
+	      /* Update 'current_bit' with this field's size.  If the
+		 'current_bit' lies in a subsequent register, update 'regno' and
+		 reset 'current_bit' to point to the current bit in that new
+		 register.  */
+	      current_bit += size;
+	      while (current_bit >= 32)
+		{
+		  current_bit-=32;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      *last_used_bit = current_bit;
+	    }
+
+	  field = TREE_CHAIN (field);
+	}
+      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+    }
+  else if (TREE_CODE (arg_type) == UNION_TYPE)
+    {
+      tree field, field_t;
+      int i, regno_t, field_size;
+      int max_reg = -1;
+      int max_bit = -1;
+      uint32_t mask;
+      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
+	= {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
+
+      /* To compute the padding bits in a union we only consider bits as
+	 padding bits if they are always either a padding bit or fall outside a
+	 fields size for all fields in the union.  */
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
+	    = {0U, 0U, 0U, 0U};
+	  int last_used_bit_t = *last_used_bit;
+	  regno_t = *regno;
+	  field_t = TREE_TYPE (field);
+
+	  /* If the field's type is either a record or a union make sure to
+	     compute their padding bits too.  */
+	  if (RECORD_OR_UNION_TYPE_P (field_t))
+	    not_to_clear_reg_mask
+	      |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
+						&padding_bits_to_clear_t[0],
+						starting_bit, &last_used_bit_t);
+	  else
+	    {
+	      field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+	      regno_t = (field_size / 32) + *regno;
+	      last_used_bit_t = (starting_bit + field_size) % 32;
+	    }
+
+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;
+
+	  /* Update the maximum size of the fields in terms of registers used
+	     ('max_reg') and the 'last_used_bit' in said register.  */
+	  if (max_reg < regno_t)
+	    {
+	      max_reg = regno_t;
+	      max_bit = last_used_bit_t;
+	    }
+	  else if (max_reg == regno_t && max_bit < last_used_bit_t)
+	    max_bit = last_used_bit_t;
+
+	  field = TREE_CHAIN (field);
+	}
+
+      /* Update the current padding_bits_to_clear using the intersection of the
+	 padding bits of all the fields.  */
+      for (i=*regno; i < max_reg; i++)
+	padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+
+      /* Do not keep trailing padding bits, we do not know yet whether this
+	 is the end of the argument.  */
+      mask = ((uint32_t) 1 << max_bit) - 1;
+      padding_bits_to_clear[max_reg]
+	|= padding_bits_to_clear_res[max_reg] & mask;
+
+      *regno = max_reg;
+      *last_used_bit = max_bit;
+    }
+  else
+    /* This function should only be used for structs and unions.  */
+    gcc_unreachable ();
+
+  return not_to_clear_reg_mask;
+}
+
+/* In the context of ARMv8-M Security Extensions, this function is used for both
+   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to compute what
+   registers are used when returning or passing arguments, which is then
+   returned as a mask.  It will also compute a mask to indicate padding/unused
+   bits for each of these registers, and passes this through the
+   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is passed in
+   ARG_TYPE, the rtl representation of the argument is passed in ARG_RTX and
+   the starting register used to pass this argument or return value is passed
+   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to compute these
+   for struct and union types.  */
+
+static unsigned HOST_WIDE_INT
+compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
+			     uint32_t * padding_bits_to_clear)
+
+{
+  int last_used_bit = 0;
+  unsigned HOST_WIDE_INT not_to_clear_mask;
+
+  if (RECORD_OR_UNION_TYPE_P (arg_type))
+    {
+      not_to_clear_mask
+	= comp_not_to_clear_mask_str_un (arg_type, &regno,
+					 padding_bits_to_clear, 0,
+					 &last_used_bit);
+
+
+      /* If the 'last_used_bit' is not zero, that means we are still using a
+	 part of the last 'regno'.  In such cases we must clear the trailing
+	 bits.  Otherwise we are not using regno and we should mark it as to
+	 clear.  */
+      if (last_used_bit != 0)
+	*(padding_bits_to_clear + regno)
+	  |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;
+      else
+	not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
+    }
+  else
+    {
+      not_to_clear_mask = 0;
+      /* We are not dealing with structs nor unions.  So these arguments may be
+	 passed in floating point registers too.  In some cases a BLKmode is
+	 used when returning or passing arguments in multiple VFP registers.  */
+      if (GET_MODE (arg_rtx) == BLKmode)
+	{
+	  int i, arg_regs;
+	  rtx reg;
+
+	  /* This should really only occur when dealing with the hard-float
+	     ABI.  */
+	  gcc_assert (TARGET_HARD_FLOAT_ABI && TARGET_VFP);
+
+	  for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
+	    {
+	      reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
+	      gcc_assert (REG_P (reg));
+
+	      not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
+
+	      /* If we are dealing with DF mode, make sure we don't
+		 clear either of the registers it addresses.  */
+	      arg_regs = ARM_NUM_REGS (GET_MODE (reg));
+	      if (arg_regs > 1)
+		{
+		  unsigned HOST_WIDE_INT mask;
+		  mask = HOST_WIDE_INT_1U << (REGNO (reg) + arg_regs);
+		  mask -= HOST_WIDE_INT_1U << REGNO (reg);
+		  not_to_clear_mask |= mask;
+		}
+	    }
+	}
+      else
+	{
+	  /* Otherwise we can rely on the MODE to determine how many registers
+	     are being used by this argument.  */
+	  int arg_regs = ARM_NUM_REGS (GET_MODE (arg_rtx));
+	  not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	  if (arg_regs > 1)
+	    {
+	      unsigned HOST_WIDE_INT
+	      mask = HOST_WIDE_INT_1U << (REGNO (arg_rtx) + arg_regs);
+	      mask -= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	      not_to_clear_mask |= mask;
+	    }
+	}
+    }
+
+  return not_to_clear_mask;
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -19891,7 +20164,25 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
-	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    {
+	      /* 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);
+	      if (TARGET_HARD_FLOAT && TARGET_VFP)
+		{
+		  snprintf (instr, sizeof (instr), "vmsr%s\tfpscr, %%|lr",
+			    conditional);
+		  output_asm_insn (instr, & operand);
+		}
+	      snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    }
 	  /* Use bx if it's available.  */
 	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
@@ -24143,7 +24434,20 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
-	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	{
+	  /* 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)
+	    asm_fprintf (f, "\tmsr\tAPSR_nzcvqg, %r\n",
+			 reg_containing_return_addr);
+	  else
+	    asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+			 reg_containing_return_addr);
+
+	  if (TARGET_HARD_FLOAT && TARGET_VFP)
+	    asm_fprintf (f, "\tvmsr\tfpscr, %r\n", reg_containing_return_addr);
+	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	}
       else
 	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
@@ -24379,7 +24683,20 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
   /* Return to caller.  */
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
-    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    {
+      /* 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)
+	asm_fprintf (f, "\tmsr\tAPSR_nzcvqg, %r\n",
+		     reg_containing_return_addr);
+      else
+	asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+		     reg_containing_return_addr);
+
+      if (TARGET_HARD_FLOAT && TARGET_VFP)
+	asm_fprintf (f, "\tvmsr\tfpscr, %r\n", reg_containing_return_addr);
+      asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    }
   else
     asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
@@ -25241,6 +25558,119 @@ thumb1_expand_prologue (void)
     cfun->machine->lr_save_eliminated = 0;
 }
 
+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask;
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask |= (1ULL << IP_REGNUM);
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check TARGET_VFP to make sure these are present.  */
+  if (TARGET_HARD_FLOAT && TARGET_VFP)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask |= float_mask;
+      maxregno = LAST_VFP_REGNUM;
+    }
+
+  /* If the user has defined registers to be caller saved, these are no longer
+     restored by the function before returning and must thus be cleared for
+     security purposes.  */
+  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+    {
+      /* We do not touch registers that can be used to pass arguments as per
+	 the AAPCS, since these should never be made callee-saved by user
+	 options.  */
+      if (regno >= FIRST_VFP_REGNUM && regno <= D7_VFP_REGNUM)
+	continue;
+      if (regno >= IP_REGNUM && regno <= PC_REGNUM)
+	continue;
+      if (call_used_regs[regno])
+	to_clear_mask |= (1ULL << regno);
+    }
+
+  /* Make sure we do not clear the registers used to return the result in.  */
+  result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+  if (!VOID_TYPE_P (result_type))
+    {
+      result_rtl = arm_function_value (result_type, current_function_decl, 0);
+
+      /* No need to check that we return in registers, because we don't
+	 support returning on stack yet.  */
+      to_clear_mask
+	&= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
+				       padding_bits_to_clear_ptr);
+    }
+
+  if (padding_bits_to_clear != 0)
+    {
+      rtx reg_rtx;
+      /* Padding bits to clear is not 0 so we know we are dealing with
+	 returning a composite type, which only uses r0.  Let's make sure that
+	 r1-r3 is cleared too, we will use r1 as a scratch register.  */
+      gcc_assert ((to_clear_mask & 0xe) == 0xe);
+
+      reg_rtx = gen_rtx_REG (SImode, 1);
+
+      /* Fill the lower half of the negated padding_bits_to_clear.  */
+      emit_move_insn (reg_rtx,
+		      GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
+
+      /* Also fill the top half of the negated padding_bits_to_clear.  */
+      if (((~padding_bits_to_clear) >> 16) > 0)
+	emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
+						      GEN_INT (16),
+						      GEN_INT (16)),
+				GEN_INT ((~padding_bits_to_clear) >> 16)));
+
+      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, 0),
+			   gen_rtx_REG (SImode, 0),
+			   reg_rtx));
+    }
+
+  for (regno = 0; regno <= maxregno; regno++)
+    {
+      if (!(to_clear_mask & (1ULL << regno)))
+	continue;
+
+      if (IS_VFP_REGNUM (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)
+	      && to_clear_mask & (1ULL << (regno + 1)))
+	    {
+	      emit_move_insn (gen_rtx_REG (DFmode, regno++),
+			      CONST1_RTX (DFmode));
+	      emit_use (gen_rtx_REG (DFmode, 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 (SImode, regno),
+			  gen_rtx_REG (SImode, LR_REGNUM));
+	  emit_use (gen_rtx_REG (SImode, regno));
+	}
+    }
+}
+
 /* Generate pattern *pop_multiple_with_stack_update_and_return if single
    POP instruction can be generated.  LR should be replaced by PC.  All
    the checks required are already done by  USE_RETURN_INSN ().  Hence,
@@ -25290,6 +25720,8 @@ thumb2_expand_return (bool simple_return)
     }
   else
     {
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	cmse_nonsecure_entry_clear_before_return ();
       emit_jump_insn (simple_return_rtx);
     }
 }
@@ -25348,6 +25780,10 @@ thumb1_expand_epilogue (void)
 
   if (! df_regs_ever_live_p (LR_REGNUM))
     emit_use (gen_rtx_REG (SImode, LR_REGNUM));
+
+  /* Clear all caller-saved regs that are not used to return.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    cmse_nonsecure_entry_clear_before_return ();
 }
 
 /* Epilogue code for APCS frame.  */
@@ -25782,6 +26218,14 @@ 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 (!really_return)
     return;
 
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index cd98de7dcb40de483a9f93c0674bd216f4b0c56a..c3d4b4e71193ce347f1e8a931b66705619d9b0c5 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1843,8 +1843,15 @@
   "*
     return thumb1_unexpanded_epilogue ();
   "
-  ; Length is absolute worst case
-  [(set_attr "length" "44")
+  ; Length is absolute worst case, when using CMSE and if this is an entry
+  ; function an extra 4 (MSR) to 8 (VMSR) bytes might be added.
+  [(set (attr "length")
+	(if_then_else
+	 (match_test "IS_CMSE_ENTRY (arm_current_func_type ())")
+	 (if_then_else (match_test "TARGET_HARD_FLOAT && TARGET_VFP")
+	  (const_int 52)
+	  (const_int 48))
+	 (const_int 44)))
    (set_attr "type" "block")
    ;; We don't clobber the conditions, but the potential length of this
    ;; operation is sufficient to make conditionalizing the sequence
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index ab08288413c3e64911e8d7a8199b9809e0282d8e..3227c4226738a23b56a59cdf7a0052111317678c 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1118,7 +1118,15 @@
   "TARGET_THUMB2"
   "* return output_return_instruction (const_true_rtx, true, false, true);"
   [(set_attr "type" "branch")
-   (set_attr "length" "4")]
+  ; If this is a return from a cmse_nonsecure_entry function then code will be
+  ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+  ; we adapt the length accordingly.
+   (set (attr "length")
+    (if_then_else (match_test "IS_CMSE_ENTRY (arm_current_func_type ())")
+     (if_then_else (match_test "TARGET_HARD_FLOAT && TARGET_VFP")
+      (const_int 12)
+      (const_int 8))
+     (const_int 4)))]
 )
 
 (define_insn_and_split "thumb2_eh_return"
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c6354c7a8cfead895e6c62d61c3f2a2bca1a1f2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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 "msr\tAPSR_nzcvq, r1" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..fccc51d5c82f7955ee4cb8256c1dd38f9ff2670d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned short  a : 6;
+  unsigned char	  b : 3;
+  unsigned char	  c;
+  unsigned short  d : 8;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 63u;
+  t.b = 7u;
+  t.c = 255u;
+  t.d = 255u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 63u
+      || t.b != 7u
+      || t.c != 255u
+      || t.d != 255u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6aee3c4c022d50baec8ab16443130897540e703
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a : 7;
+  signed char b : 3;
+  short	      c : 11;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -64;
+  t.b = -4 ;
+  t.c = -1024;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -64
+      || t.b != -4
+      || t.c != -1024)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..285a2b92f64c1913ef585b8daa4d27c6da0a3d2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a;
+  signed char b : 2;
+  short		: 1;
+  signed char c : 3;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -32768;
+  t.b = -2;
+  t.c = -4;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -32768
+      || t.b != -2
+      || t.c != -4)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index f797dba1901720e04249d61078c1cbf2a3e436a9..38f18414c2fefec56161e6ac3f7291b03a3b29a3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -43,6 +43,26 @@ set LTO_TORTURE_OPTIONS ""
 gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
 	"" $DEFAULT_CFLAGS
 
+if {[check_effective_target_arm_arch_v8m_base_ok]} then {
+    # Baseline only
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/baseline/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
+if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    # Mainline -mfloat-abi=soft
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
+	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
 set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
 set dg-do-what-default ${saved-dg-do-what-default}
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..f18c8fc98fb95618ab9ddafba0f0b7f0ccef2839
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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 "mov\tip, 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..a1199dca8ca7a49c6f764e2007b575ace40414e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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 "mov\tip, 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7229ea8eb2da1da264f58f8518daf303d1bdeda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..c22775ace8361729c36130422475522fbaca05b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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 "mov\tip, 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..28b05c391081bd42407b4e56a1e84daa549fa06e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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 "mov\tip, 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { 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
new file mode 100644
index 0000000000000000000000000000000000000000..2d366a944df692f29ab44e3ee4d33c777b126223
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 255u;
+  t.b = 32767u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 255u || t.b != 32767u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
+

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

* [PATCH 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
  2016-07-25 13:17 [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Andre Vieira (lists)
                   ` (3 preceding siblings ...)
  2016-07-25 13:24 ` [PATCH 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers Andre Vieira (lists)
@ 2016-07-25 13:25 ` Andre Vieira (lists)
  2016-08-24 11:01   ` [PATCHv2 " Andre Vieira (lists)
  2016-07-25 13:26 ` [PATCH 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call Andre Vieira (lists)
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-07-25 13:25 UTC (permalink / raw)
  To: gcc-patches

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

This patch adds support for the ARMv8-M Security Extensions
'cmse_nonsecure_call' attribute. This attribute may only be used for
function types and when used in combination with the '-mcmse'
compilation flag. See Section 5.5 of ARM®v8-M Security Extensions
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

We currently do not support cmse_nonsecure_call functions that pass
arguments or return variables on the stack and we diagnose this.

*** gcc/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (gimplify.h): New include.
        (arm_handle_cmse_nonsecure_call): New.
        (arm_attribute_table): Added cmse_nonsecure_call.

*** gcc/testsuite/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse-3.c: Add tests.
        * gcc.target/arm/cmse/cmse-4.c: Add tests.

[-- Attachment #2: diff5 --]
[-- Type: text/plain, Size: 6284 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 81a9d9a6fb29d0956a661734d60dd2e44cb554b8..128baae92e4b65507eb18b679874b1ad24ca7c4a 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -61,6 +61,7 @@
 #include "builtins.h"
 #include "tm-constrs.h"
 #include "rtl-iter.h"
+#include "gimplify.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -135,6 +136,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
 static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
+static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -347,6 +349,8 @@ static const struct attribute_spec arm_attribute_table[] =
   /* ARMv8-M Security Extensions support.  */
   { "cmse_nonsecure_entry", 0, 0, true, false, false,
     arm_handle_cmse_nonsecure_entry, false },
+  { "cmse_nonsecure_call", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_call, false },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -6750,6 +6754,78 @@ arm_handle_cmse_nonsecure_entry (tree *node, tree name,
   return NULL_TREE;
 }
 
+
+/* Called upon detection of the use of the cmse_nonsecure_call attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function type tree or otherwise issue a diagnostic.  The
+   reason we check this at declaration time is to only allow the use of the
+   attribute with declarations of function pointers and not function
+   declarations.  This function checks NODE is of the expected type and issues
+   diagnostics otherwise using NAME.  If it is not of the expected type
+   *NO_ADD_ATTRS will be set to true.  */
+
+static tree
+arm_handle_cmse_nonsecure_call (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree decl = NULL_TREE;
+  tree type, fntype, main_variant;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == TYPE_DECL)
+    {
+      decl = *node;
+      type = TREE_TYPE (decl);
+    }
+
+  if (!decl
+      || (!(TREE_CODE (type) == POINTER_TYPE
+	    && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+	  && TREE_CODE (type) != FUNCTION_TYPE))
+    {
+	warning (OPT_Wattributes, "%qE attribute only applies to base type of a "
+		 "function pointer", name);
+	*no_add_attrs = true;
+	return NULL_TREE;
+    }
+
+  /* type is either a function pointer, when the attribute is used on a function
+   * pointer, or a function type when used in a typedef.  */
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    fntype = type;
+  else
+    fntype = TREE_TYPE (type);
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (NULL, name, fntype);
+
+  if (*no_add_attrs)
+    return NULL_TREE;
+
+  /* Prevent trees being shared among function types with and without
+     cmse_nonsecure_call attribute.  Do however make sure they keep the same
+     main_variant, this is required for correct DIE output.  */
+  main_variant = TYPE_MAIN_VARIANT (fntype);
+  fntype = build_distinct_type_copy (fntype);
+  TYPE_MAIN_VARIANT (fntype) = main_variant;
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    TREE_TYPE (decl) = fntype;
+  else
+    TREE_TYPE (type) = fntype;
+
+  /* Construct a type attribute and add it to the function type.  */
+  tree attrs = tree_cons (get_identifier ("cmse_nonsecure_call"), NULL_TREE,
+			  TYPE_ATTRIBUTES (fntype));
+  TYPE_ATTRIBUTES (fntype) = attrs;
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
index 2c2920e1dc310106d83203eb51e1a68a275d0152..7f92a4c28b3333e4c8fdc256211f3ed74a383cd4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -35,3 +35,11 @@ norf (struct span2 a) {}
 
 void __attribute__ ((cmse_nonsecure_entry))
 foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) bar2 (long long a, int b, long long c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) baz2 (long long a, int b, struct span c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef struct span __attribute__ ((cmse_nonsecure_call)) qux2 (void); /* { dg-error "not available to functions that return value on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) norf2 (int a, ...); /* { dg-error "not available to functions with variable number of arguments" } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
index 6f930ab04a1097c64097a4e003296bbe85733319..d0999a4181ac022b115ae20cf3e1c8bf78f6becf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -19,9 +19,16 @@ baz (void)
   return qux ();
 }
 
+void __attribute__ ((cmse_nonsecure_call))
+quux (void) {} /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
+int __attribute__ ((cmse_nonsecure_call)) norf; /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
 /* { dg-final { scan-assembler-times "bxns" 2 } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
 /* { dg-final { scan-assembler "baz:" } } */
 /* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_quux:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_norf:" } } */

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

* [PATCH 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-07-25 13:17 [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Andre Vieira (lists)
                   ` (4 preceding siblings ...)
  2016-07-25 13:25 ` [PATCH 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute Andre Vieira (lists)
@ 2016-07-25 13:26 ` Andre Vieira (lists)
  2016-08-24 11:02   ` [PATCHv2 " Andre Vieira (lists)
  2016-07-25 13:29 ` [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic Andre Vieira (lists)
  2016-08-08  4:20 ` [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Sandra Loosemore
  7 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-07-25 13:26 UTC (permalink / raw)
  To: gcc-patches

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

This patch extends support for the ARMv8-M Security Extensions
'cmse_nonsecure_call' to use a new library function
'__gnu_cmse_nonsecure_call'. This library function is responsible for
(without using r0-r3 or d0-d7):
1) saving and clearing all callee-saved registers using the secure stack
2) clearing the LSB of the address passed in r4 and using blxns to
'jump' to it
3) clearing ASPR, including the 'ge bits' if DSP is enabled
4) clearing FPSCR if using non-soft float-abi
5) restoring callee-saved registers.

The decisions whether to include DSP 'ge bits' clearing and floating
point registers (single/double precision) all depends on the multilib used.

See Section 5.5 of ARM®v8-M Security Extensions
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

*** gcc/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (detect_cmse_nonsecure_call): New.
        (cmse_nonsecure_call_clear_caller_saved): New.
        (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
        * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
        * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
        (call_value): Likewise.
        (nonsecure_call_internal): New.
        (nonsecure_call_value_internal): New.
        * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
        (*nonsecure_call_value_reg_thumb1_v5): New.
        * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
        (*nonsecure_call_value_reg_thumb2): New.
        * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.

*** libgcc/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/cmse_nonsecure_call.S: New.
	* config/arm/t-arm: Compile cmse_nonsecure_call.S


*** gcc/testsuite/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
        * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
        * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
        * gcc.target/arm/cmse/baseline/cmse-11.c: New.
	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
        * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
        * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.


[-- Attachment #2: diff6 --]
[-- Type: text/plain, Size: 81710 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 1d2e35b52f631570450b6c8eaf077e18e9b99203..e7e223f7a932163cba8beeb76c10b4c90eae9234 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -133,6 +133,7 @@ extern int arm_const_double_inline_cost (rtx);
 extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
+bool detect_cmse_nonsecure_call (tree);
 extern const char *output_call (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 128baae92e4b65507eb18b679874b1ad24ca7c4a..fd0bc10083026ce544bf56244ce0eb740295e5d3 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17822,6 +17822,197 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Saves callee saved registers, clears callee saved registers and caller saved
+   registers not used to pass arguments before a cmse_nonsecure_call.  And
+   restores the callee saved registers after.  */
+
+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  uint64_t to_clear_mask, float_mask;
+	  rtx_insn *seq;
+	  rtx pat, call, unspec, reg, cleared_reg, tmp;
+	  unsigned int regno, maxregno;
+	  rtx address;
+	  CUMULATIVE_ARGS args_so_far_v;
+	  cumulative_args_t args_so_far;
+	  tree arg_type, fntype;
+	  bool using_r4, first_param = true;
+	  function_args_iterator args_iter;
+	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
+	  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
+
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  if (!CALL_P (insn))
+	    continue;
+
+	  pat = PATTERN (insn);
+	  gcc_assert (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 0);
+	  call = XVECEXP (pat, 0, 0);
+
+	  /* Get the real call RTX if the insn sets a value, ie. returns.  */
+	  if (GET_CODE (call) == SET)
+	      call = SET_SRC (call);
+
+	  /* Check if it is a cmse_nonsecure_call.  */
+	  unspec = XEXP (call, 0);
+	  if (GET_CODE (unspec) != UNSPEC
+	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
+	    continue;
+
+	  /* Determine the caller-saved registers we need to clear.  */
+	  to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
+	  maxregno = NUM_ARG_REGS - 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
+	     lazy store and loads which clear both caller- and callee-saved
+	     registers.  */
+	  if (TARGET_HARD_FLOAT_ABI && TARGET_VFP)
+	    {
+	      float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
+	      float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
+	      to_clear_mask |= float_mask;
+	      maxregno = D7_VFP_REGNUM;
+	    }
+
+	  /* Make sure the register used to hold the function address is not
+	     cleared.  */
+	  address = RTVEC_ELT (XVEC (unspec, 0), 0);
+	  gcc_assert (MEM_P (address));
+	  gcc_assert (REG_P (XEXP (address, 0)));
+	  to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+
+	  /* Set basic block of call insn so that df rescan is performed on
+	     insns inserted here.  */
+	  set_block_for_insn (insn, bb);
+	  df_set_flags (DF_DEFER_INSN_RESCAN);
+	  start_sequence ();
+
+	  /* Make sure the scheduler doesn't schedule other insns beyond
+	     here.  */
+	  emit_insn (gen_blockage ());
+
+	  /* Walk through all arguments and clear registers appropriately.
+	  */
+	  fntype = TREE_TYPE (MEM_EXPR (address));
+	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
+				    NULL_TREE);
+	  args_so_far = pack_cumulative_args (&args_so_far_v);
+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask &=
+		~compute_not_to_clear_mask (arg_type, arg_rtx,
+					      REGNO (arg_rtx),
+					      padding_bits_to_clear_ptr);
+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = 0; regno < NUM_ARG_REGS; regno++)
+	    {
+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = 0; regno <= maxregno; regno++)
+	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST1_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST1_RTX (SFmode));
+		}
+	      else
+		emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+	    }
+
+	  seq = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (seq, insn);
+
+	}
+    }
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -18122,6 +18313,8 @@ arm_reorg (void)
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
+  if (use_cmse)
+    cmse_nonsecure_call_clear_caller_saved ();
   if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
@@ -18494,6 +18687,23 @@ vfp_emit_fstmd (int base_reg, int count)
   return count * 8;
 }
 
+/* Returns true if -mcmse has been passed and the function pointed to by 'addr'
+   has the cmse_nonsecure_call attribute and returns false otherwise.  */
+
+bool
+detect_cmse_nonsecure_call (tree addr)
+{
+  if (!addr)
+    return FALSE;
+
+  tree fntype = TREE_TYPE (addr);
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_call",
+				    TYPE_ATTRIBUTES (fntype)))
+    return TRUE;
+  return FALSE;
+}
+
+
 /* Emit a call instruction with pattern PAT.  ADDR is the address of
    the call target.  */
 
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 820471556efbac6b35d46a03fb763cbd30bea30f..3e0d5097938871b1219ed2c426271be55a004950 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -7640,6 +7640,7 @@
   "
   {
     rtx callee, pat;
+    tree addr = MEM_EXPR (operands[0]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[2] == NULL_RTX)
@@ -7654,8 +7655,17 @@
 	: !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_internal (operands[0], operands[1], operands[2]);
-    arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_internal (operands[0], operands[1],
+					   operands[2]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_internal (operands[0], operands[1], operands[2]);
+	arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+      }
     DONE;
   }"
 )
@@ -7666,6 +7676,24 @@
 	      (use (match_operand 2 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_internal"
+  [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand" "")]
+			       UNSPEC_NONSECURE_MEM)
+		    (match_operand 1 "general_operand" ""))
+	      (use (match_operand 2 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[0] = replace_equiv_address (operands[0], tmp);
+  }")
+
 (define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
@@ -7701,6 +7729,7 @@
   "
   {
     rtx pat, callee;
+    tree addr = MEM_EXPR (operands[1]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
@@ -7715,9 +7744,18 @@
 	: !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_value_internal (operands[0], operands[1],
-				   operands[2], operands[3]);
-    arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_value_internal (operands[0], operands[1],
+						 operands[2], operands[3]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_value_internal (operands[0], operands[1],
+				       operands[2], operands[3]);
+	arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+      }
     DONE;
   }"
 )
@@ -7729,6 +7767,25 @@
 	      (use (match_operand 3 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_value_internal"
+  [(parallel [(set (match_operand       0 "" "")
+		   (call (unspec:SI [(match_operand 1 "memory_operand" "")]
+				    UNSPEC_NONSECURE_MEM)
+			 (match_operand 2 "general_operand" "")))
+	      (use (match_operand 3 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[1] = replace_equiv_address (operands[1], tmp);
+  }")
+
 (define_insn "*call_value_reg_armv5"
   [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index c3d4b4e71193ce347f1e8a931b66705619d9b0c5..643b0ec35b260d49ffba3df5fd94b33c17ad85c3 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1705,6 +1705,19 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb1_v5"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_reg_thumb1"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
 	 (match_operand 1 "" ""))
@@ -1737,6 +1750,21 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb1_v5"
+  [(set (match_operand 0 "" "")
+	(call (unspec:SI
+	       [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+	       UNSPEC_NONSECURE_MEM)
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB1 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb1"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index 3227c4226738a23b56a59cdf7a0052111317678c..5ea64174cf1c6965ad8e0cc43d62e881158d6d02 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -581,6 +581,19 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
@@ -592,6 +605,21 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+	(call
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "register_operand" "l*r"))]
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 5744c62cf5ab3b3711fef2b442c62cd3eadf0793..c2f5e5b52cd84380c009af4077bd6effda923701 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -84,6 +84,8 @@
   UNSPEC_VRINTA         ; Represent a float to integral float rounding
                         ; towards nearest, ties away from zero.
   UNSPEC_PROBE_STACK    ; Probe stack memory reference
+  UNSPEC_NONSECURE_MEM	; Represent non-secure memory in ARMv8-M with
+			; security extension
 ])
 
 (define_c_enum "unspec" [
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6c1386c06edbdb58e76fa5e612c918010c507f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51ce2d42c051aeda8b06ad97086f2563a5fc47d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e9104b546a7693fcb2399622e828b1197eac1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 1023" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "movt\tr4, 32767" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d8941bbfeebd59744c43f10c842816b36ec9915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ffbb718d34d5bb8f10e1f3c0505c7dc393c670c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a6141829237823b8734de045a590a1917fa60b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #1799" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..642f4e0346b5186c78645780b45fe9c838848d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #7939" } } */
+/* { dg-final { scan-assembler "movt\tr4, 15" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, 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/baseline/cmse-11.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
new file mode 100644
index 0000000000000000000000000000000000000000..3007409ad88b9d2312ece4d55f3695787a1aa566
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+
+int
+foo (int a)
+{
+  return bar (bar (a + 1));
+}
+
+/* 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 "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\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/baseline/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2b931be5912b421f8427535ded3298883bec639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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 "movs\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmovs\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmovs\tr2, r4\n\tmovs\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/baseline/cmse-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..95da045690ae170a101949134482e821f27fe3aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* Remember dont clear r0 and r1, because we are passing the double parameter
+ * for bar in them.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, 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/baseline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff18e839b02c19c2c77769b18ef5ee1cfacf0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8063" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2e024b7f0776381f511077af91bd1ee5632ff12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
index 65200bcf29b219706911bbb799c847aefc92cb1c..79ddc7cb1fe1724b82ae028c2ddf91321e855811 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -2,11 +2,19 @@
 /* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
 
 
+void __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+typedef void __attribute__ ((cmse_nonsecure_call)) baz (int);
+
 int __attribute__ ((cmse_nonsecure_entry))
-foo (int a)
+foo (int a, baz b)
 {
+  bar (a);
+  b (a);
   return a + 1;
 }
 
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler-not "blxns" } } */
+/* { dg-final { scan-assembler-not "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 38f18414c2fefec56161e6ac3f7291b03a3b29a3..66a8b7da005f7dfeffbded61b02fd6a7473a1dcf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -50,6 +50,8 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
+	    "" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
 	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b1396d52e742a1710ed5ad33fbeb559d866f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d029044aa9aa1d412c28ee5d18a8e3d0be36546
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..005515ab9cb85c201a2a8b2f6417d73ceeacbc60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dd218e62fdee2a6af819079ba1ea1909185d076
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { 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/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..c833bcb0ae978572fad46780bc180f61ccb14345
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cdb8c44b19c811f3a7b4fbce102a6c768f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e139ba61af57f06cff5a9d121c97bbf41e170bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { 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/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..285fa854b3d61c4d856e9be863ee73a87f1b11a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f56aaf2a97e740a77473cab245614b6fa696c04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..749f8a7278cb4ea9fd4462887ce7f37b57f83248
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad5068aac263f1c2edb17b8707fc9d1c0af6959
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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\.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/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..b18259eaef6da1933ef2d58d63b97d4bb4e450f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..182ddf9540374f30ae3694259f1edb62161455e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd262c89085eb0dc8737ad7955c3a12531492b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..e33568400ef830abaa019b5c2727a9f3b5d5704b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..024a12e0a414730eb1cbebfca8574d548238ab28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb195eb58d59fe9ea5ed74af79646199c61bcdae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..22ed3f8af882f96da49919c60fc6f4cd74dfc54b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634065e7cb64a5069cbb3c9be4b8cf9177f5e29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..04f8466cc112c03ee5a05e6e5223d2c66a033bbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffe94de85417b81f9dcb366eb1b40dc1661c91b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc846cd7a51303ec00f8f512a54cd697fbd0682
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d0f136ef171111c1cca6cd24c4f46b9fcb7fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/libgcc/config/arm/cmse_nonsecure_call.S b/libgcc/config/arm/cmse_nonsecure_call.S
new file mode 100644
index 0000000000000000000000000000000000000000..bddbfe714da81291f7bde4d4a8f7da4350149b85
--- /dev/null
+++ b/libgcc/config/arm/cmse_nonsecure_call.S
@@ -0,0 +1,136 @@
+/* CMSE wrapper function used to save, clear and restore callee saved registers
+   for cmse_nonsecure_call's.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+.syntax unified
+.thumb
+.global __gnu_cmse_nonsecure_call
+__gnu_cmse_nonsecure_call:
+#if defined(__ARM_ARCH_8M_MAIN__)
+push	    {r5-r11,lr}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+
+/* Save and clear callee-saved registers only if we are dealing with hard float
+   ABI.  The unused caller-saved registers have already been cleared by GCC
+   generated code.  */
+#ifdef __ARM_PCS_VFP
+vpush.f64   {d8-d15}
+#if __ARM_FP & 0x04
+vmov.f32    s16, #1.00000
+vmov.f32    s17, #1.00000
+vmov.f32    s18, #1.00000
+vmov.f32    s19, #1.00000
+vmov.f32    s20, #1.00000
+vmov.f32    s21, #1.00000
+vmov.f32    s22, #1.00000
+vmov.f32    s23, #1.00000
+vmov.f32    s24, #1.00000
+vmov.f32    s25, #1.00000
+vmov.f32    s26, #1.00000
+vmov.f32    s27, #1.00000
+vmov.f32    s28, #1.00000
+vmov.f32    s29, #1.00000
+vmov.f32    s30, #1.00000
+vmov.f32    s31, #1.00000
+#elif __ARM_FP & 0x08
+vmov.f64    d8, #1.00000
+vmov.f64    d9, #1.00000
+vmov.f64    d10, #1.00000
+vmov.f64    d11, #1.00000
+vmov.f64    d12, #1.00000
+vmov.f64    d13, #1.00000
+vmov.f64    d14, #1.00000
+vmov.f64    d15, #1.00000
+#else
+#error "Half precision implementation not supported."
+#endif
+vmsr	    fpscr, r4
+
+/* We are not dealing with hard float ABI, so we can safely use the vlstm and
+   vlldm instructions without needing to preserve the registers used for
+   argument passing.  */
+#else
+sub	    sp, sp, #0x88 /* Reserve stack space to save all floating point
+			     registers, including FPSCR.  */
+vlstm	    sp		  /* Lazy store and clearance of d0-d16 and FPSCR.  */
+#endif /* __ARM_PCS_VFP */
+
+/* Make sure to clear the 'GE' bits of the APSR register if 32-bit SIMD
+   instructions are available.  */
+#if defined(__ARM_FEATURE_SIMD32)
+msr	    APSR_nzcvqg, r4
+#else
+msr	    APSR_nzcvq, r4
+#endif
+
+blxns	    r4
+
+#ifdef __ARM_PCS_VFP
+vpop.f64    {d8-d15}
+#else
+vlldm	    sp		  /* Lazy restore of d0-d16 and FPSCR.  */
+add	    sp, sp, #0x88 /* Free space used to save floating point registers.  */
+#endif /* __ARM_PCS_VFP */
+
+pop	    {r5-r11}
+
+#elif defined (__ARM_ARCH_8M_BASE__)
+push	    {r5-r7}
+mov	    r5, r8
+mov	    r6, r9
+mov	    r7, r10
+push	    {r5-r7}
+mov	    r5, r11
+mov	    r6, lr
+push	    {r5,r6}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+msr	    APSR_nzcvq, r4
+blxns	    r4
+pop	    {r5, r6}
+mov	    lr, r6
+mov	    r11, r5
+pop	    {r5-r7}
+mov	    r10, r7
+mov	    r9, r6
+mov	    r8, r5
+pop	    {r5-r7}
+blx	    lr
+
+#else
+#error "This should only be used for armv8-m base- and mainline."
+#endif
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 5618143bfd0f02b170db3f9e4c0a15cecb403cec..9e85ac06b146feaa14ab83374a0156737b870310 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -12,4 +12,6 @@ libgcc-objects += cmse.o cmse_nonsecure_call.o
 
 cmse.o: $(srcdir)/config/arm/cmse.c
 	$(gcc_compile) -c $(CMSE_OPTS) $<
+cmse_nonsecure_call.o: $(srcdir)/config/arm/cmse_nonsecure_call.S
+		       $(gcc_compile) -c $<
 endif

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

* [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic
  2016-07-25 13:17 [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Andre Vieira (lists)
                   ` (5 preceding siblings ...)
  2016-07-25 13:26 ` [PATCH 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call Andre Vieira (lists)
@ 2016-07-25 13:29 ` Andre Vieira (lists)
  2016-08-24 11:02   ` Andre Vieira (lists)
  2016-08-08  4:20 ` [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Sandra Loosemore
  7 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-07-25 13:29 UTC (permalink / raw)
  To: gcc-patches

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

This patch adds support ARMv8-M's Security Extension's
cmse_nonsecure_caller intrinsic. This intrinsic is used to check whether
an entry function was called from a non-secure state.
See Section 5.4.3 of ARM®v8-M Security Extensions: Requirements on
Development Tools
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html)
for further details.

The FIXME in config/arm/arm_cmse.h is for a diagnostic message that is
suggested in the ARMv8-M Security Extensions document mentioned above,
to diagnose the use of the cmse_nonsecure_caller intrinsic outside of
functions with the 'cmse_nonsecure_entry' attribute.  Checking whether
the intrinsic is called from within such functions can easily be done
inside 'arm_expand_builtin'. However, making the warning point to the
right location is more complicated.  The ARMv8-M Security Extensions
specification does mention that such a diagnostic might become
mandatory, so I might have to pick this up later, otherwise it is left
as a potential extra feature.


*** gcc/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm-builtins.c (arm_builtins): Define
        ARM_BUILTIN_CMSE_NONSECURE_CALLER.
        (bdesc_2arg): Add line for cmse_nonsecure_caller.
        (arm_expand_builtin): Handle cmse_nonsecure_caller.
        * config/arm/arm_cmse.h (cmse_nonsecure_caller): New.

*** gcc/testsuite/ChangeLog ***
2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse-1.c: Add test for
        cmse_nonsecure_caller.

[-- Attachment #2: diff7 --]
[-- Type: text/plain, Size: 3897 bytes --]

diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index 68b2839879f78e8d819444fbc11d2a91f8d6279a..2589ec2d1233f3daff94a1d35ebf63c8a9b93ecf 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -515,6 +515,8 @@ enum arm_builtins
   ARM_BUILTIN_GET_FPSCR,
   ARM_BUILTIN_SET_FPSCR,
 
+  ARM_BUILTIN_CMSE_NONSECURE_CALLER,
+
 #undef CRYPTO1
 #undef CRYPTO2
 #undef CRYPTO3
@@ -1789,6 +1791,17 @@ arm_init_builtins (void)
 	= add_builtin_function ("__builtin_arm_stfscr", ftype_set_fpscr,
 				ARM_BUILTIN_SET_FPSCR, BUILT_IN_MD, NULL, NULL_TREE);
     }
+
+  if (arm_arch_cmse)
+    {
+      tree ftype_cmse_nonsecure_caller
+	= build_function_type_list (unsigned_type_node, NULL);
+      arm_builtin_decls[ARM_BUILTIN_CMSE_NONSECURE_CALLER]
+	= add_builtin_function ("__builtin_arm_cmse_nonsecure_caller",
+				ftype_cmse_nonsecure_caller,
+				ARM_BUILTIN_CMSE_NONSECURE_CALLER, BUILT_IN_MD,
+				NULL, NULL_TREE);
+    }
 }
 
 /* Return the ARM builtin for CODE.  */
@@ -2368,6 +2381,12 @@ arm_expand_builtin (tree exp,
       emit_insn (pat);
       return target;
 
+    case ARM_BUILTIN_CMSE_NONSECURE_CALLER:
+      target = gen_reg_rtx (SImode);
+      op0 = arm_return_addr (0, NULL_RTX);
+      emit_insn (gen_addsi3 (target, op0, const1_rtx));
+      return target;
+
     case ARM_BUILTIN_TEXTRMSB:
     case ARM_BUILTIN_TEXTRMUB:
     case ARM_BUILTIN_TEXTRMSH:
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
index c9afdcbf48160a963fc254795543a1d9e981a215..989d09f9d08268224e745da5a2e0aa85916cd3a9 100644
--- a/gcc/config/arm/arm_cmse.h
+++ b/gcc/config/arm/arm_cmse.h
@@ -163,6 +163,13 @@ __attribute__ ((__always_inline__))
 cmse_TTAT (void *__p)
 __CMSE_TT_ASM (at)
 
+/* FIXME: diagnose use outside cmse_nonsecure_entry functions.  */
+__extension__ static __inline int __attribute__ ((__always_inline__))
+cmse_nonsecure_caller (void)
+{
+  return __builtin_arm_cmse_nonsecure_caller ();
+}
+
 #define CMSE_AU_NONSECURE	2
 #define CMSE_MPU_NONSECURE	16
 #define CMSE_NONSECURE		18
@@ -177,7 +184,7 @@ __extension__ void *
 cmse_check_address_range (void *, size_t, int);
 
 #define cmse_check_pointed_object(p, f) \
-  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
+      ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
 
 #define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index d5b9a2d9d59569de170da814ae660e9fb2b943e7..ddcf12a30a6c1806969d239c448da81ccf49532e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -65,3 +65,32 @@ int foo (char * p)
 /* { dg-final { scan-assembler-times "ttat " 2 } } */
 /* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
 /* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
+
+typedef int (*int_ret_funcptr_t) (void);
+typedef int __attribute__ ((cmse_nonsecure_call)) (*int_ret_nsfuncptr_t) (void);
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return cmse_nonsecure_caller ();
+}
+
+int __attribute__ ((cmse_nonsecure_entry))
+qux (int_ret_funcptr_t int_ret_funcptr)
+{
+  int_ret_nsfuncptr_t int_ret_nsfunc_ptr;
+
+  if (cmse_is_nsfptr (int_ret_funcptr))
+    {
+      int_ret_nsfunc_ptr = cmse_nsfptr_create (int_ret_funcptr);
+      return int_ret_nsfunc_ptr ();
+    }
+  return 0;
+}
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "\tcmse_nonsecure_caller" } } */
+/* { dg-final { scan-rtl-dump "and.*reg.*const_int 1" expand } } */
+/* { dg-final { scan-assembler "bic" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */

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

* Re: [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions
  2016-07-25 13:17 [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Andre Vieira (lists)
                   ` (6 preceding siblings ...)
  2016-07-25 13:29 ` [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic Andre Vieira (lists)
@ 2016-08-08  4:20 ` Sandra Loosemore
  2016-08-09 12:01   ` Andre Vieira (lists)
  7 siblings, 1 reply; 72+ messages in thread
From: Sandra Loosemore @ 2016-08-08  4:20 UTC (permalink / raw)
  To: Andre Vieira (lists), GCC Patches

On 07/25/2016 07:17 AM, Andre Vieira (lists) wrote:
> [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions
>
> Hello,
>
> This is a respin of a previous patch series for ARMv8-M Security
> Extensions. In this version I have removed one patch, rebased the rest
> and changed some of them.
>
> This patch series aims at implementing support for ARMv8-M's Security
> Extensions. You can find the specification of ARMV8-M Security
> Extensions in: ARM®v8-M Security Extensions: Requirements on Development
> Tools
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>
> We currently:
> - do not support passing arguments or returning on the stack for
> cmse_nonsecure_{call,entry} functions,
> - only test Security Extensions for -mfpu=fpv5-d16 and fpv5-sp-d16 and
> only support single and double precision FPU's with d16.
>
> Bootstrapped and tested on arm-none-linux-gnueabihf and tested on
> arm-none-eabi with ARMv8-M Baseline and Mainline targets.
>
> Andre Vieira (7):
>   Add support for ARMv8-M's Security Extensions flag and intrinsics
>   Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
>   ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and
> bxns return
>   ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
>   Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
>   ARMv8-M Security Extension's cmse_nonsecure_call: use
> __gnu_cmse_nonsecure_call
>   Added support for ARMV8-M Security Extension cmse_nonsecure_caller
> intrinsic

I didn't see any documentation here for the new attributes and built-in 
function.

-Sandra

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

* Re: [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions
  2016-08-08  4:20 ` [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Sandra Loosemore
@ 2016-08-09 12:01   ` Andre Vieira (lists)
  2016-08-09 16:47     ` Sandra Loosemore
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-08-09 12:01 UTC (permalink / raw)
  To: gcc-patches, sandra

On 08/08/16 05:19, Sandra Loosemore wrote:
> On 07/25/2016 07:17 AM, Andre Vieira (lists) wrote:
>> [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions
>>
>> Hello,
>>
>> This is a respin of a previous patch series for ARMv8-M Security
>> Extensions. In this version I have removed one patch, rebased the rest
>> and changed some of them.
>>
>> This patch series aims at implementing support for ARMv8-M's Security
>> Extensions. You can find the specification of ARMV8-M Security
>> Extensions in: ARM®v8-M Security Extensions: Requirements on Development
>> Tools
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> We currently:
>> - do not support passing arguments or returning on the stack for
>> cmse_nonsecure_{call,entry} functions,
>> - only test Security Extensions for -mfpu=fpv5-d16 and fpv5-sp-d16 and
>> only support single and double precision FPU's with d16.
>>
>> Bootstrapped and tested on arm-none-linux-gnueabihf and tested on
>> arm-none-eabi with ARMv8-M Baseline and Mainline targets.
>>
>> Andre Vieira (7):
>>   Add support for ARMv8-M's Security Extensions flag and intrinsics
>>   Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
>>   ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and
>> bxns return
>>   ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
>>   Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
>>   ARMv8-M Security Extension's cmse_nonsecure_call: use
>> __gnu_cmse_nonsecure_call
>>   Added support for ARMV8-M Security Extension cmse_nonsecure_caller
>> intrinsic
> 
> I didn't see any documentation here for the new attributes and built-in
> function.
> 
> -Sandra
> 

Hi Sandra,

The documentation is in the ARMV8-M Security Extensions in: ARM®v8-M
Security Extensions: Requirements on Development Tools document I linked
in the email above and subsequent emails
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

Also per patch I refer to the relevant sections. So for instance in
PATCH 3/7 refers to Section 5.4, which describes Entry functions and
mentions the cmse_nonsecure_entry attribute. Whereas PATCH 7/7 refers to
Section 5.4.3 of the same document which describes the
cmse_nonsecure_caller intrinsic which that patch implements.

Is there a specific intrinsic/attribute you are missing?

Cheers,
Andre

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

* Re: [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions
  2016-08-09 12:01   ` Andre Vieira (lists)
@ 2016-08-09 16:47     ` Sandra Loosemore
  2016-08-10  8:09       ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Sandra Loosemore @ 2016-08-09 16:47 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

On 08/09/2016 06:01 AM, Andre Vieira (lists) wrote:
> [snip]
>
> The documentation is in the ARMV8-M Security Extensions in: ARM®v8-M
> Security Extensions: Requirements on Development Tools document I linked
> in the email above and subsequent emails
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>
> Also per patch I refer to the relevant sections. So for instance in
> PATCH 3/7 refers to Section 5.4, which describes Entry functions and
> mentions the cmse_nonsecure_entry attribute. Whereas PATCH 7/7 refers to
> Section 5.4.3 of the same document which describes the
> cmse_nonsecure_caller intrinsic which that patch implements.
>
> Is there a specific intrinsic/attribute you are missing?

You need to at least add entries to the relevant sections in extend.texi 
for the new target-specific intrinsic and attributes.  The documentation 
there doesn't need to be terribly detailed (one sentence and a link to 
the external document is probably all you need), but it's important that 
these things be listed in GCC's supported extensions so that users know 
they can use them and so that people who see them in code written by 
other people can find out what they mean.

-Sandra

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

* Re: [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions
  2016-08-09 16:47     ` Sandra Loosemore
@ 2016-08-10  8:09       ` Andre Vieira (lists)
  2016-08-24 11:02         ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-08-10  8:09 UTC (permalink / raw)
  To: Sandra Loosemore, gcc-patches

On 09/08/16 17:47, Sandra Loosemore wrote:
> On 08/09/2016 06:01 AM, Andre Vieira (lists) wrote:
>> [snip]
>>
>> The documentation is in the ARMV8-M Security Extensions in: ARM®v8-M
>> Security Extensions: Requirements on Development Tools document I linked
>> in the email above and subsequent emails
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> Also per patch I refer to the relevant sections. So for instance in
>> PATCH 3/7 refers to Section 5.4, which describes Entry functions and
>> mentions the cmse_nonsecure_entry attribute. Whereas PATCH 7/7 refers to
>> Section 5.4.3 of the same document which describes the
>> cmse_nonsecure_caller intrinsic which that patch implements.
>>
>> Is there a specific intrinsic/attribute you are missing?
> 
> You need to at least add entries to the relevant sections in extend.texi
> for the new target-specific intrinsic and attributes.  The documentation
> there doesn't need to be terribly detailed (one sentence and a link to
> the external document is probably all you need), but it's important that
> these things be listed in GCC's supported extensions so that users know
> they can use them and so that people who see them in code written by
> other people can find out what they mean.
> 
> -Sandra
> 


I see, I did add a new entry to extend.texi for ARMv8-M Security
Extensions. I will also mention all intrinsics and attributes there.

Thank you.

Andre

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

* [PATCHv2 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics
  2016-07-25 13:20 ` [PATCH 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics Andre Vieira (lists)
@ 2016-08-24 11:00   ` Andre Vieira (lists)
  2016-10-25 16:26     ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-08-24 11:00 UTC (permalink / raw)
  To: gcc-patches

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

On 25/07/16 14:19, Andre Vieira (lists) wrote:
> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
> Security Extensions and supports the following intrinsics:
> cmse_TT
> cmse_TT_fptr
> cmse_TTT
> cmse_TTT_fptr
> cmse_TTA
> cmse_TTA_fptr
> cmse_TTAT
> cmse_TTAT_fptr
> cmse_check_address_range
> cmse_check_pointed_object
> cmse_is_nsfptr
> cmse_nsfptr_create
> 
> It also defines the mandatory cmse_address_info struct and the
> __ARM_FEATURE_CMSE macro.
> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
> Extensions: Requirements on Development Tools
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
> 
> *** gcc/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config.gcc (extra_headers): Added arm_cmse.h.
>         * config/arm/arm-arches.def (ARM_ARCH):
>         (armv8-m): Add FL2_CMSE.
>         (armv8-m.main): Likewise.
>         (armv8-m.main+dsp): Likewise.
>         * config/arm/arm-c.c
>         (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>         * config/arm/arm-protos.h
>         (arm_is_constant_pool_ref): Define FL2_CMSE.
>         * config/arm.c (arm_arch_cmse): New.
>         (arm_option_override): New error for unsupported cmse target.
>         * config/arm/arm.h (arm_arch_cmse): New.
>         * config/arm/arm.opt (mcmse): New.
>         * doc/invoke.texi (ARM Options): Add -mcmse.
>         * config/arm/arm_cmse.h: New file.
> 
> *** libgcc/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/cmse.c: Likewise.
>         * config/arm/t-arm (HAVE_CMSE): New.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse.exp: New.
>         * gcc.target/arm/cmse/cmse-1.c: New.
>         * gcc.target/arm/cmse/cmse-12.c: New.
>         * lib/target-supports.exp
>         (check_effective_target_arm_cmse_ok): New.
> 

Added more documentation as requested.

This patch adds the support of the '-mcmse' option to enable ARMv8-M's
Security Extensions and supports the following intrinsics:
cmse_TT
cmse_TT_fptr
cmse_TTT
cmse_TTT_fptr
cmse_TTA
cmse_TTA_fptr
cmse_TTAT
cmse_TTAT_fptr
cmse_check_address_range
cmse_check_pointed_object
cmse_is_nsfptr
cmse_nsfptr_create

It also defines the mandatory cmse_address_info struct and the
__ARM_FEATURE_CMSE macro.
See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
Extensions: Requirements on Development Tools
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

*** gcc/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config.gcc (extra_headers): Added arm_cmse.h.
        * config/arm/arm-arches.def (ARM_ARCH):
        (armv8-m): Add FL2_CMSE.
        (armv8-m.main): Likewise.
        (armv8-m.main+dsp): Likewise.
        * config/arm/arm-c.c
        (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
        * config/arm/arm-protos.h
        (arm_is_constant_pool_ref): Define FL2_CMSE.
        * config/arm.c (arm_arch_cmse): New.
        (arm_option_override): New error for unsupported cmse target.
        * config/arm/arm.h (arm_arch_cmse): New.
        * config/arm/arm.opt (mcmse): New.
        * doc/invoke.texi (ARM Options): Add -mcmse.
        * doc/extend.texi (ARM ARMv8-M Security Extensions): Add section.
        * config/arm/arm_cmse.h: New file.

*** libgcc/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>
        * config/arm/cmse.c: Likewise.
        * config/arm/t-arm (HAVE_CMSE): New.


*** gcc/testsuite/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse.exp: New.
        * gcc.target/arm/cmse/cmse-1.c: New.
        * gcc.target/arm/cmse/cmse-12.c: New.
        * lib/target-supports.exp
        (check_effective_target_arm_cmse_ok): New.

[-- Attachment #2: diff --]
[-- Type: text/plain, Size: 23529 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 1f75f17877334c2bb61cd16b69539ec7514db8ae..8555bbf19d81b517493c86b38aff31a633ac50eb 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -320,7 +320,7 @@ arc*-*-*)
 arm*-*-*)
 	cpu_type=arm
 	extra_objs="arm-builtins.o aarch-common.o"
-	extra_headers="mmintrin.h arm_neon.h arm_acle.h"
+	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_cmse.h"
 	target_type_format_char='%'
 	c_target_objs="arm-c.o"
 	cxx_target_objs="arm-c.o"
diff --git a/gcc/config/arm/arm-arches.def b/gcc/config/arm/arm-arches.def
index be46521c9eaea54f9ad78a92874567589289dbdf..0e523959551cc3b1da31411ccdd1105b830db845 100644
--- a/gcc/config/arm/arm-arches.def
+++ b/gcc/config/arm/arm-arches.def
@@ -63,11 +63,11 @@ ARM_ARCH("armv8.1-a+crc",cortexa53, 8A,
 	  ARM_FSET_MAKE (FL_CO_PROC | FL_CRC32 | FL_FOR_ARCH8A,
 			 FL2_FOR_ARCH8_1A))
 ARM_ARCH("armv8-m.base", cortexm0, 8M_BASE,
-	 ARM_FSET_MAKE_CPU1 (			      FL_FOR_ARCH8M_BASE))
+	 ARM_FSET_MAKE (			  FL_FOR_ARCH8M_BASE, FL2_CMSE))
 ARM_ARCH("armv8-m.main", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC |	      FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC |		  FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("armv8-m.main+dsp", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("iwmmxt",  iwmmxt,     5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT))
 ARM_ARCH("iwmmxt2", iwmmxt2,    5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT | FL_IWMMXT2))
 
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index b98470fff45b20a5398c2534bc3bb3edfb7bfd01..ad2fb09d1f9ca14300c6283f3831a527db656267 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -76,6 +76,14 @@ arm_cpu_builtins (struct cpp_reader* pfile)
 
   def_or_undef_macro (pfile, "__ARM_32BIT_STATE", TARGET_32BIT);
 
+  if (arm_arch8 && !arm_arch_notm)
+    {
+      if (arm_arch_cmse && use_cmse)
+	builtin_define_with_int_value ("__ARM_FEATURE_CMSE", 3);
+      else
+	builtin_define ("__ARM_FEATURE_CMSE");
+    }
+
   if (TARGET_ARM_FEATURE_LDREX)
     builtin_define_with_int_value ("__ARM_FEATURE_LDREX",
 				   TARGET_ARM_FEATURE_LDREX);
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 49c3a92dba80db32b698a0b44ad72d56111c1358..0754fb7252a8b86ffacc0cee4598686752af6e56 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -391,6 +391,7 @@ extern bool arm_is_constant_pool_ref (rtx);
 #define FL_ARCH6KZ    (1 << 31)       /* ARMv6KZ architecture.  */
 
 #define FL2_ARCH8_1   (1 << 0)	      /* Architecture 8.1.  */
+#define FL2_CMSE      (1 << 1)	      /* ARMv8-M Security Extensions.  */
 
 /* Flags that only effect tuning, not available instructions.  */
 #define FL_TUNE		(FL_WBUF | FL_VFPV2 | FL_STRONG | FL_LDSCHED \
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 317885cf7197b6755c4d9b5717afe61662626786..e3697bbcb425999db31ac2b4f47e14bb3f2ffa89 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -509,6 +509,9 @@ extern bool arm_disable_literal_pool;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 extern int arm_arch_crc;
 
+/* Nonzero if chip supports the ARMv8-M Security Extensions.  */
+extern int arm_arch_cmse;
+
 #ifndef TARGET_DEFAULT
 #define TARGET_DEFAULT  (MASK_APCS_FRAME)
 #endif
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 195de4822c8f26acbd67e08604719365b3d68534..9903d9cd8c5ff68a2318a643bdf31cf48016eba4 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -889,6 +889,9 @@ int arm_condexec_masklen = 0;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 int arm_arch_crc = 0;
 
+/* Nonzero if chip supports the ARMv8-M security extensions.  */
+int arm_arch_cmse = 0;
+
 /* Nonzero if the core has a very small, high-latency, multiply unit.  */
 int arm_m_profile_small_mul = 0;
 
@@ -3232,6 +3235,7 @@ arm_option_override (void)
   arm_arch_no_volatile_ce = ARM_FSET_HAS_CPU1 (insn_flags, FL_NO_VOLATILE_CE);
   arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0;
   arm_arch_crc = ARM_FSET_HAS_CPU1 (insn_flags, FL_CRC32);
+  arm_arch_cmse = ARM_FSET_HAS_CPU2 (insn_flags, FL2_CMSE);
   arm_m_profile_small_mul = ARM_FSET_HAS_CPU1 (insn_flags, FL_SMALLMUL);
 
   /* V5 code we generate is completely interworking capable, so we turn off
@@ -3494,6 +3498,9 @@ arm_option_override (void)
   if (target_slow_flash_data)
     arm_disable_literal_pool = true;
 
+  if (use_cmse && !arm_arch_cmse)
+    error ("target CPU does not support ARMv8-M Security Extensions");
+
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index 0ebe0174390167b79a64583c35a3f8fb018f6538..cb956632e23f4464c26f180d633b20091f212a37 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -109,6 +109,10 @@ mfloat-abi=
 Target RejectNegative Joined Enum(float_abi_type) Var(arm_float_abi) Init(TARGET_DEFAULT_FLOAT_ABI)
 Specify if floating point hardware should be used.
 
+mcmse
+Target RejectNegative Var(use_cmse)
+Specify that the compiler should target secure code as per ARMv8-M Security Extensions.
+
 Enum
 Name(float_abi_type) Type(enum float_abi_type)
 Known floating-point ABIs (for use with the -mfloat-abi= option):
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
new file mode 100644
index 0000000000000000000000000000000000000000..b4232937c6ae04754a6bbc513b143672a4be5530
--- /dev/null
+++ b/gcc/config/arm/arm_cmse.h
@@ -0,0 +1,192 @@
+/* ARMv8-M Secure Extensions intrinsics include file.
+
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef _GCC_ARM_CMSE_H
+#define _GCC_ARM_CMSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __ARM_BIG_ENDIAN
+
+typedef union {
+  struct cmse_address_info {
+#if __ARM_FEATURE_CMSE & 2
+    unsigned idau_region:8;
+    unsigned idau_region_valid:1;
+    unsigned secure:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned nonsecure_read_ok:1;
+#else
+    unsigned :12;
+#endif
+    unsigned readwrite_ok:1;
+    unsigned read_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region:8;
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#else
+
+typedef union {
+  struct cmse_address_info {
+    unsigned mpu_region:8;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned read_ok:1;
+    unsigned readwrite_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned nonsecure_read_ok:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned secure:1;
+    unsigned idau_region_valid:1;
+    unsigned idau_region:8;
+#else
+    unsigned :12;
+#endif
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#endif /* __ARM_BIG_ENDIAN */
+
+#define cmse_TT_fptr(p) (__cmse_TT_fptr ((__cmse_fptr)(p)))
+
+typedef void (*__cmse_fptr)(void);
+
+#define __CMSE_TT_ASM(flags) \
+{ \
+  cmse_address_info_t __result; \
+   __asm__ ("tt" # flags " %0,%1" \
+	   : "=r"(__result) \
+	   : "r"(__p) \
+	   : "memory"); \
+  return __result; \
+}
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM ()
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT (void *__p)
+__CMSE_TT_ASM ()
+
+#define cmse_TTT_fptr(p) (__cmse_TTT_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TTT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (t)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT (void *__p)
+__CMSE_TT_ASM (t)
+
+#if __ARM_FEATURE_CMSE & 2
+
+#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TTA_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (a)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA (void *__p)
+__CMSE_TT_ASM (a)
+
+#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+__cmse_TTAT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (at)
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT (void *__p)
+__CMSE_TT_ASM (at)
+
+#define CMSE_AU_NONSECURE	2
+#define CMSE_MPU_NONSECURE	16
+#define CMSE_NONSECURE		18
+
+#endif /* __ARM_FEATURE_CMSE & 2 */
+
+#define CMSE_MPU_UNPRIV		4
+#define CMSE_MPU_READWRITE	1
+#define CMSE_MPU_READ		8
+
+__extension__ void *
+cmse_check_address_range (void *, size_t, int);
+
+#define cmse_check_pointed_object(p, f) \
+  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
+
+#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
+
+#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
+
+#endif /* __ARM_FEATURE_CMSE & 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GCC_ARM_CMSE_H */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 5b9e6174cfa5bcfa3a58055c7610725d9ed3de2d..85efef29b99c26350a67079c0fbcae02b036ac20 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -11567,6 +11567,7 @@ instructions, but allow the compiler to schedule those calls.
 * ARM iWMMXt Built-in Functions::
 * ARM C Language Extensions (ACLE)::
 * ARM Floating Point Status and Control Intrinsics::
+* ARM ARMv8-M Security Extensions::
 * AVR Built-in Functions::
 * Blackfin Built-in Functions::
 * FR-V Built-in Functions::
@@ -12412,6 +12413,31 @@ unsigned int __builtin_arm_get_fpscr ()
 void __builtin_arm_set_fpscr (unsigned int)
 @end smallexample
 
+@node ARM ARMv8-M Security Extensions
+@subsection ARM ARMv8-M Security Extensions
+
+GCC implements the ARMv8-M Security Extensions as described in the ARMv8-M
+Security Extensions: Requiremenets on Development Tools Engineering
+Specification, which can be found at
+@uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
+
+As part of the Security Extensions GCC implements the intrinsics below.  FPTR
+is used here to mean any function pointer type.
+
+@smallexample
+cmse_address_info_t cmse_TT (void *)
+cmse_address_info_t cmse_TT_fptr (FPTR)
+cmse_address_info_t cmse_TTT (void *)
+cmse_address_info_t cmse_TTT_fptr (FPTR)
+cmse_address_info_t cmse_TTA (void *)
+cmse_address_info_t cmse_TTA_fptr (FPTR)
+cmse_address_info_t cmse_TTAT (void *)
+cmse_address_info_t cmse_TTAT_fptr (FPTR)
+void * cmse_check_address_range (void *, size_t, int)
+typeof(p) cmse_nsfptr_create (FPTR p)
+intptr_t cmse_is_nsfptr (FPTR)
+@end smallexample
+
 @node AVR Built-in Functions
 @subsection AVR Built-in Functions
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9a4db388a3b3dc644b0c555f1a1121cef14ef2df..539dba0cce0c531bc1ccd4f5fa9562f1e20694e5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -639,7 +639,8 @@ Objective-C and Objective-C++ Dialects}.
 -mneon-for-64bits @gol
 -mslow-flash-data @gol
 -masm-syntax-unified @gol
--mrestrict-it}
+-mrestrict-it @gol
+-mcmse}
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol
@@ -14527,6 +14528,12 @@ Print CPU tuning information as comment in assembler file.  This is
 an option used only for regression testing of the compiler and not
 intended for ordinary use in compiling code.  This option is disabled
 by default.
+
+@item -mcmse
+@opindex mcmse
+Generate secure code as per the "ARMv8-M Security Extensions: Requirements on
+Development Tools Engineering Specification", which can be found on
+@url{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 @end table
 
 @node AVR Options
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..d5b9a2d9d59569de170da814ae660e9fb2b943e7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mcmse -fdump-rtl-expand" }  */
+
+#include <arm_cmse.h>
+
+extern int a;
+extern int bar (void);
+
+int foo (char * p)
+{
+  cmse_address_info_t cait;
+
+  cait = cmse_TT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTA (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTA_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTAT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTAT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char), 0);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_READWRITE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV | CMSE_MPU_READ);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_AU_NONSECURE
+					 | CMSE_MPU_NONSECURE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  p = (char *) cmse_check_pointed_object (p, CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  return a;
+}
+/* { dg-final { scan-assembler-times "\ttt " 2 } } */
+/* { dg-final { scan-assembler-times "ttt " 2 } } */
+/* { dg-final { scan-assembler-times "tta " 2 } } */
+/* { dg-final { scan-assembler-times "ttat " 2 } } */
+/* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
+/* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
new file mode 100644
index 0000000000000000000000000000000000000000..87a2f1363a4e4bd817503e79e504980210e722c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+#include <arm_cmse.h>
+
+char *
+foo (char * p)
+{
+  if (!cmse_is_nsfptr (p))
+    return cmse_nsfptr_create (p);
+}
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler-not "cmse_is_nsfptr" } } */
+/* { dg-final { scan-assembler-not "cmse_nsfptr_create" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
new file mode 100644
index 0000000000000000000000000000000000000000..f797dba1901720e04249d61078c1cbf2a3e436a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -0,0 +1,50 @@
+#   Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite for ARMv8-M Security Extensions using the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Exit immediately if the target does not support -mcmse.
+if ![check_effective_target_arm_cmse_ok] then {
+    return
+}
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+set saved-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default "assemble"
+
+set saved-lto_torture_options ${LTO_TORTURE_OPTIONS}
+set LTO_TORTURE_OPTIONS ""
+
+# These are for both baseline and mainline.
+gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
+	"" $DEFAULT_CFLAGS
+
+set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index b9909ada734c08a46af886b5190be9ea92fd98e5..051a9d68a5db7f9417486bec9b8f3ad3812bae79 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -3519,6 +3519,19 @@ proc check_effective_target_arm_thumb1_cbz_ok {} {
     }
 }
 
+# Return 1 if this is an ARM target where ARMv8-M Security Extensions is
+# available.
+
+proc check_effective_target_arm_cmse_ok {} {
+    return [check_no_compiler_messages arm_cmse object {
+	int
+	foo (void)
+	{
+	  asm ("bxns r0");
+	}
+    } "-mcmse"];
+}
+
 # Return 1 if this compilation turns on string_ops_prefer_neon on.
 
 proc check_effective_target_arm_tune_string_ops_prefer_neon { } {
diff --git a/libgcc/config/arm/cmse.c b/libgcc/config/arm/cmse.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe3a22967c8536f2a8c05b58627f964d3fb1d345
--- /dev/null
+++ b/libgcc/config/arm/cmse.c
@@ -0,0 +1,108 @@
+/* ARMv8-M Security Extensions routines.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <arm_cmse.h>
+
+/* ARM intrinsic function to perform a permission check on a given
+   address range.  See ACLE changes for ARMv8-M.  */
+
+void *
+cmse_check_address_range (void *p, size_t size, int flags)
+{
+  cmse_address_info_t permb, perme;
+  char *pb = (char *) p, *pe;
+
+  /* Check if the range wraps around.  */
+  if (UINTPTR_MAX - (uintptr_t) p < size)
+    return NULL;
+
+  /* Check if an unknown flag is present.  */
+  int known = CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE | CMSE_MPU_READ;
+  int known_secure_level = CMSE_MPU_UNPRIV;
+#if __ARM_FEATURE_CMSE & 2
+  known |= CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE;
+  known_secure_level |= CMSE_MPU_NONSECURE;
+#endif
+  if (flags & (~known))
+    return NULL;
+
+  /* Execute the right variant of the TT instructions.  */
+  pe = pb + size - 1;
+  const int singleCheck = (((uintptr_t) pb ^ (uintptr_t) pe) < 32);
+  switch (flags & known_secure_level)
+    {
+    case 0:
+      permb = cmse_TT (pb);
+      perme = singleCheck ? permb : cmse_TT (pe);
+      break;
+    case CMSE_MPU_UNPRIV:
+      permb = cmse_TTT (pb);
+      perme = singleCheck ? permb : cmse_TTT (pe);
+      break;
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_NONSECURE:
+      permb = cmse_TTA (pb);
+      perme = singleCheck ? permb : cmse_TTA (pe);
+      break;
+    case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+      permb = cmse_TTAT (pb);
+      perme = singleCheck ? permb : cmse_TTAT (pe);
+      break;
+#endif
+    default:
+      /* Invalid flag, eg.  CMSE_MPU_NONSECURE specified but
+	 __ARM_FEATURE_CMSE & 2 == 0.  */
+      return NULL;
+    }
+
+  /* Check that the range does not cross MPU, SAU, or IDAU boundaries.  */
+  if (permb.value != perme.value)
+    return NULL;
+
+  /* Check the permissions on the range.  */
+  switch (flags & (~known_secure_level))
+    {
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+    case		 CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_readwrite_ok	? p : NULL;
+    case CMSE_MPU_READ | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_read_ok	? p : NULL;
+    case CMSE_AU_NONSECURE:
+      return permb.flags.secure			? NULL : p;
+#endif
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE:
+    case		 CMSE_MPU_READWRITE:
+      return permb.flags.readwrite_ok		? p : NULL;
+    case CMSE_MPU_READ:
+      return permb.flags.read_ok		? p : NULL;
+    default:
+      return NULL;
+    }
+}
+
+
+#endif /* __ARM_FEATURE_CMSE & 1.  */
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 4e17e99b4a53bbafc0f1f8dddd02000f0e8f4f48..5618143bfd0f02b170db3f9e4c0a15cecb403cec 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -1,3 +1,15 @@
 LIB1ASMSRC = arm/lib1funcs.S
 LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
 	_thumb1_case_uhi _thumb1_case_si
+
+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),)
+CMSE_OPTS:=-mcmse
+endif
+
+ifdef HAVE_CMSE
+libgcc-objects += cmse.o cmse_nonsecure_call.o
+
+cmse.o: $(srcdir)/config/arm/cmse.c
+	$(gcc_compile) -c $(CMSE_OPTS) $<
+endif

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

* [PATCHv2 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
  2016-07-25 13:21 ` [PATCH 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute Andre Vieira (lists)
@ 2016-08-24 11:01   ` Andre Vieira (lists)
  2016-10-25 16:28     ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-08-24 11:01 UTC (permalink / raw)
  To: gcc-patches

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

On 25/07/16 14:21, Andre Vieira (lists) wrote:
> This patch adds support for the ARMv8-M Security Extensions
> 'cmse_nonsecure_entry' attribute. In this patch we implement the
> attribute handling and diagnosis around the attribute. See Section 5.4
> of ARM®v8-M Security Extensions
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
> 
> *** gcc/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
>         (arm_attribute_table): Added cmse_nonsecure_entry
>         (arm_compute_func_type): Handle cmse_nonsecure_entry.
>         (cmse_func_args_or_return_in_stack): New.
>         (arm_handle_cmse_nonsecure_entry): New.
>         * config/arm/arm.h (ARM_FT_CMSE_ENTRY): New macro define.
>         (IS_CMSE_ENTRY): Likewise.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse-3.c: New.
>

Added more documentation as requested.

----

This patch adds support for the ARMv8-M Security Extensions
'cmse_nonsecure_entry' attribute. In this patch we implement the
attribute handling and diagnosis around the attribute. See Section 5.4
of ARM®v8-M Security Extensions
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

*** gcc/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
        (arm_attribute_table): Added cmse_nonsecure_entry
        (arm_compute_func_type): Handle cmse_nonsecure_entry.
        (cmse_func_args_or_return_in_stack): New.
        (arm_handle_cmse_nonsecure_entry): New.
        * config/arm/arm.h (ARM_FT_CMSE_ENTRY): New macro define.
        (IS_CMSE_ENTRY): Likewise.
        * doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.

*** gcc/testsuite/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse-3.c: New.

[-- Attachment #2: diff2 --]
[-- Type: text/plain, Size: 8021 bytes --]

diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index e3697bbcb425999db31ac2b4f47e14bb3f2ffa89..5307ec8f904230db5ea44150ef471d928926ab6d 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -1373,6 +1373,7 @@ enum reg_class
 #define ARM_FT_VOLATILE		(1 << 4) /* Does not return.  */
 #define ARM_FT_NESTED		(1 << 5) /* Embedded inside another func.  */
 #define ARM_FT_STACKALIGN	(1 << 6) /* Called with misaligned stack.  */
+#define ARM_FT_CMSE_ENTRY	(1 << 7) /* ARMv8-M non-secure entry function.  */
 
 /* Some macros to test these flags.  */
 #define ARM_FUNC_TYPE(t)	(t & ARM_FT_TYPE_MASK)
@@ -1381,6 +1382,7 @@ enum reg_class
 #define IS_NAKED(t)        	(t & ARM_FT_NAKED)
 #define IS_NESTED(t)       	(t & ARM_FT_NESTED)
 #define IS_STACKALIGN(t)       	(t & ARM_FT_STACKALIGN)
+#define IS_CMSE_ENTRY(t)	(t & ARM_FT_CMSE_ENTRY)
 
 
 /* Structure used to hold the function stack frame layout.  Offsets are
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9903d9cd8c5ff68a2318a643bdf31cf48016eba4..11417ab3c2f7101866ee5d6b100913480e5c336e 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -134,6 +134,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
+static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -343,6 +344,9 @@ static const struct attribute_spec arm_attribute_table[] =
   { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute,
     false },
 #endif
+  /* ARMv8-M Security Extensions support.  */
+  { "cmse_nonsecure_entry", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_entry, false },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -3633,6 +3637,9 @@ arm_compute_func_type (void)
   else
     type |= arm_isr_value (TREE_VALUE (a));
 
+  if (lookup_attribute ("cmse_nonsecure_entry", attr))
+    type |= ARM_FT_CMSE_ENTRY;
+
   return type;
 }
 
@@ -6634,6 +6641,110 @@ arm_handle_notshared_attribute (tree *node,
 }
 #endif
 
+/* This function returns true if a function with declaration FNDECL, name
+   NAME and type FNTYPE uses the stack to pass arguments or return variables
+   and false otherwise.  This is used for functions with the attributes
+   'cmse_nonsecure_call' or 'cmse_nonsecure_entry' and this function will issue
+   diagnostic messages if the stack is used.  */
+
+static bool
+cmse_func_args_or_return_in_stack (tree fndecl, tree name, tree fntype)
+{
+  function_args_iterator args_iter;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
+  bool first_param = true;
+  tree arg_type, prev_arg_type = NULL_TREE, ret_type;
+
+  /* Error out if any argument is passed on the stack.  */
+  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX, fndecl);
+  args_so_far = pack_cumulative_args (&args_so_far_v);
+  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+    {
+      rtx arg_rtx;
+      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+      prev_arg_type = arg_type;
+      if (VOID_TYPE_P (arg_type))
+	continue;
+
+      if (!first_param)
+	arm_function_arg_advance (args_so_far, arg_mode, arg_type, true);
+      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type, true);
+      if (!arg_rtx
+	  || arm_arg_partial_bytes (args_so_far, arg_mode, arg_type, true))
+	{
+	  error ("%qE attribute not available to functions with arguments "
+		 "passed on the stack", name);
+	  return true;
+	}
+      first_param = false;
+    }
+
+  /* Error out for variadic functions since we cannot control how many
+     arguments will be passed and thus stack could be used.  stdarg_p () is not
+     used for the checking to avoid browsing arguments twice.  */
+  if (prev_arg_type != NULL_TREE && !VOID_TYPE_P (prev_arg_type))
+    {
+      error ("%qE attribute not available to functions with variable number "
+	     "of arguments", name);
+      return true;
+    }
+
+  /* Error out if return value is passed on the stack.  */
+  ret_type = TREE_TYPE (fntype);
+  if (arm_return_in_memory (ret_type, fntype))
+    {
+      error ("%qE attribute not available to functions that return value on "
+	     "the stack", name);
+      return true;
+    }
+  return false;
+}
+
+/* Called upon detection of the use of the cmse_nonsecure_entry attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function declaration tree or otherwise issue a warning.  */
+
+static tree
+arm_handle_cmse_nonsecure_entry (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree fndecl;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Ignore attribute for function types.  */
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+	       name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  fndecl = *node;
+
+  /* Warn for static linkage functions.  */
+  if (!TREE_PUBLIC (fndecl))
+    {
+      warning (OPT_Wattributes, "%qE attribute has no effect on functions "
+	       "with static linkage", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (fndecl, name,
+						TREE_TYPE (fndecl));
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 85efef29b99c26350a67079c0fbcae02b036ac20..1531ed66bdd0b51c268c2a666c2e078b4f0d7ea6 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12421,6 +12421,9 @@ Security Extensions: Requiremenets on Development Tools Engineering
 Specification, which can be found at
 @uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 
+As part of the Security Extensions GCC implements a new function attribute
+@code{cmse_nonsecure_entry}.
+
 As part of the Security Extensions GCC implements the intrinsics below.  FPTR
 is used here to mean any function pointer type.
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c2920e1dc310106d83203eb51e1a68a275d0152
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+struct span2 {
+  float a, b, c, d;
+};
+
+union test_union
+{
+  long long a;
+  int b;
+  struct span2 c;
+} test_union;
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (long long a, int b, long long c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+bar (long long a, int b, struct span c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+baz (int a, ...) {} /* { dg-error "not available to functions with variable number of arguments" } */
+
+struct span __attribute__ ((cmse_nonsecure_entry))
+qux (void) { /* { dg-error "not available to functions that return value on the stack" } */
+  struct span ret = {0, 0};
+  return ret;
+}
+
+void __attribute__ ((cmse_nonsecure_entry))
+norf (struct span2 a) {}
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */

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

* [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-07-25 13:24 ` [PATCH 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers Andre Vieira (lists)
@ 2016-08-24 11:01   ` Andre Vieira (lists)
  2016-10-25 16:29     ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-08-24 11:01 UTC (permalink / raw)
  To: gcc-patches

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

On 25/07/16 14:23, Andre Vieira (lists) wrote:
> This patch extends support for the ARMv8-M Security Extensions
> 'cmse_nonsecure_entry' attribute to safeguard against leak of
> information through unbanked registers.
> 
> When returning from a nonsecure entry function we clear all caller-saved
> registers that are not used to pass return values, by writing either the
> LR, in case of general purpose registers, or the value 0, in case of FP
> registers. We use the LR to write to APSR and FPSCR too. We currently do
> not support entry functions that pass arguments or return variables on
> the stack and we diagnose this. This patch relies on the existing code
> to make sure callee-saved registers used in cmse_nonsecure_entry
> functions are saved and restored thus retaining their nonsecure mode
> value, this should be happening already as it is required by AAPCS.
> 
> This patch also clears padding bits for cmse_nonsecure_entry functions
> with struct and union return types. For unions a bit is only considered
> a padding bit if it is an unused bit in every field of that union. The
> function that calculates these is used in a later patch to do the same
> for arguments of cmse_nonsecure_call's.
> 
> *** gcc/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (output_return_instruction): Clear
>         registers.
>         (thumb2_expand_return): Likewise.
>         (thumb1_expand_epilogue): Likewise.
>         (thumb_exit): Likewise.
>         (arm_expand_epilogue): Likewise.
>         (cmse_nonsecure_entry_clear_before_return): New.
>         (comp_not_to_clear_mask_str_un): New.
>         (compute_not_to_clear_mask): New.
>         * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
>         * config/arm/thumb2.md (*thumb2_return): Likewise.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
>         * gcc.target/arm/cmse/struct-1.c: New.
>         * gcc.target/arm/cmse/bitfield-1.c: New.
>         * gcc.target/arm/cmse/bitfield-2.c: New.
>         * gcc.target/arm/cmse/bitfield-3.c: New.
>         * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
> cleared.
>         * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>         * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>         * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
> 

Updated this patch to correctly clear only the cumulative
exception-status (0-4,7) and the condition code bits (28-31) of the
FPSCR. I also adapted the code to be handle the bigger floating point
register files.

----

This patch extends support for the ARMv8-M Security Extensions
'cmse_nonsecure_entry' attribute to safeguard against leak of
information through unbanked registers.

When returning from a nonsecure entry function we clear all caller-saved
registers that are not used to pass return values, by writing either the
LR, in case of general purpose registers, or the value 0, in case of FP
registers. We use the LR to write to APSR. For FPSCR we clear only the
cumulative exception-status (0-4, 7) and the condition code bits
(28-31). We currently do not support entry functions that pass arguments
or return variables on the stack and we diagnose this. This patch relies
on the existing code to make sure callee-saved registers used in
cmse_nonsecure_entry functions are saved and restored thus retaining
their nonsecure mode value, this should be happening already as it is
required by AAPCS.

This patch also clears padding bits for cmse_nonsecure_entry functions
with struct and union return types. For unions a bit is only considered
a padding bit if it is an unused bit in every field of that union. The
function that calculates these is used in a later patch to do the same
for arguments of cmse_nonsecure_call's.

*** gcc/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (output_return_instruction): Clear
        registers.
        (thumb2_expand_return): Likewise.
        (thumb1_expand_epilogue): Likewise.
        (thumb_exit): Likewise.
        (arm_expand_epilogue): Likewise.
        (cmse_nonsecure_entry_clear_before_return): New.
        (comp_not_to_clear_mask_str_un): New.
        (compute_not_to_clear_mask): New.
        * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
        * config/arm/thumb2.md (*thumb2_return): Duplicate pattern for
        cmse_nonsecure_entry functions.

*** gcc/testsuite/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
        * gcc.target/arm/cmse/struct-1.c: New.
        * gcc.target/arm/cmse/bitfield-1.c: New.
        * gcc.target/arm/cmse/bitfield-2.c: New.
        * gcc.target/arm/cmse/bitfield-3.c: New.
        * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
cleared.
        * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.

[-- Attachment #2: diff4 --]
[-- Type: text/plain, Size: 39184 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9fba371768b1eba3a11dc8aa5d6acf8cc30f464d..680b648a218d166d49e89be78ee30397dac7e87f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17473,6 +17473,279 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
   return;
 }
 
+/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for structs
+   and unions in the context of ARMv8-M Security Extensions.  It is used as a
+   helper function for both 'cmse_nonsecure_call' and 'cmse_nonsecure_entry'
+   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to either one
+   or four masks, depending on whether it is being computed for a
+   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
+   respectively.  The tree for the type of the argument or a field within an
+   argument is passed in ARG_TYPE, the current register this argument or field
+   starts in is kept in the pointer REGNO and updated accordingly, the bit this
+   argument or field starts at is passed in STARTING_BIT and the last used bit
+   is kept in LAST_USED_BIT which is also updated accordingly.  */
+
+static unsigned HOST_WIDE_INT
+comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
+			       uint32_t * padding_bits_to_clear,
+			       unsigned starting_bit, int * last_used_bit)
+
+{
+  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
+
+  if (TREE_CODE (arg_type) == RECORD_TYPE)
+    {
+      unsigned current_bit = starting_bit;
+      tree field;
+      long int offset, size;
+
+
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  /* The offset within a structure is always an offset from
+	     the start of that structure.  Make sure we take that into the
+	     calculation of the register based offset that we use here.  */
+	  offset = starting_bit;
+	  offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
+	  offset %= 32;
+
+	  /* This is the actual size of the field, for bitfields this is the
+	     bitfield width and not the container size.  */
+	  size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+
+	  if (*last_used_bit != offset)
+	    {
+	      if (offset < *last_used_bit)
+		{
+		  /* This field's offset is before the 'last_used_bit', that
+		     means this field goes on the next register.  So we need to
+		     pad the rest of the current register and increase the
+		     register number.  */
+		  uint32_t mask;
+		  mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
+		  mask++;
+
+		  *(padding_bits_to_clear + *regno) |= mask;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      else
+		{
+		  /* Otherwise we pad the bits between the last field's end and
+		     the start of the new field.  */
+		  uint32_t mask;
+
+		  mask = UINT32_MAX >> (32 - offset);
+		  mask -= ((uint32_t) 1 << *last_used_bit) - 1;
+		  *(padding_bits_to_clear + *regno) |= mask;
+		}
+	      current_bit = offset;
+	    }
+
+	  /* Calculate further padding bits for inner structs/unions too.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	    {
+	      *last_used_bit = current_bit;
+	      not_to_clear_reg_mask
+		|= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
+						  padding_bits_to_clear, offset,
+						  last_used_bit);
+	    }
+	  else
+	    {
+	      /* Update 'current_bit' with this field's size.  If the
+		 'current_bit' lies in a subsequent register, update 'regno' and
+		 reset 'current_bit' to point to the current bit in that new
+		 register.  */
+	      current_bit += size;
+	      while (current_bit >= 32)
+		{
+		  current_bit-=32;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      *last_used_bit = current_bit;
+	    }
+
+	  field = TREE_CHAIN (field);
+	}
+      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+    }
+  else if (TREE_CODE (arg_type) == UNION_TYPE)
+    {
+      tree field, field_t;
+      int i, regno_t, field_size;
+      int max_reg = -1;
+      int max_bit = -1;
+      uint32_t mask;
+      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
+	= {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
+
+      /* To compute the padding bits in a union we only consider bits as
+	 padding bits if they are always either a padding bit or fall outside a
+	 fields size for all fields in the union.  */
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
+	    = {0U, 0U, 0U, 0U};
+	  int last_used_bit_t = *last_used_bit;
+	  regno_t = *regno;
+	  field_t = TREE_TYPE (field);
+
+	  /* If the field's type is either a record or a union make sure to
+	     compute their padding bits too.  */
+	  if (RECORD_OR_UNION_TYPE_P (field_t))
+	    not_to_clear_reg_mask
+	      |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
+						&padding_bits_to_clear_t[0],
+						starting_bit, &last_used_bit_t);
+	  else
+	    {
+	      field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+	      regno_t = (field_size / 32) + *regno;
+	      last_used_bit_t = (starting_bit + field_size) % 32;
+	    }
+
+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;
+
+	  /* Update the maximum size of the fields in terms of registers used
+	     ('max_reg') and the 'last_used_bit' in said register.  */
+	  if (max_reg < regno_t)
+	    {
+	      max_reg = regno_t;
+	      max_bit = last_used_bit_t;
+	    }
+	  else if (max_reg == regno_t && max_bit < last_used_bit_t)
+	    max_bit = last_used_bit_t;
+
+	  field = TREE_CHAIN (field);
+	}
+
+      /* Update the current padding_bits_to_clear using the intersection of the
+	 padding bits of all the fields.  */
+      for (i=*regno; i < max_reg; i++)
+	padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+
+      /* Do not keep trailing padding bits, we do not know yet whether this
+	 is the end of the argument.  */
+      mask = ((uint32_t) 1 << max_bit) - 1;
+      padding_bits_to_clear[max_reg]
+	|= padding_bits_to_clear_res[max_reg] & mask;
+
+      *regno = max_reg;
+      *last_used_bit = max_bit;
+    }
+  else
+    /* This function should only be used for structs and unions.  */
+    gcc_unreachable ();
+
+  return not_to_clear_reg_mask;
+}
+
+/* In the context of ARMv8-M Security Extensions, this function is used for both
+   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to compute what
+   registers are used when returning or passing arguments, which is then
+   returned as a mask.  It will also compute a mask to indicate padding/unused
+   bits for each of these registers, and passes this through the
+   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is passed in
+   ARG_TYPE, the rtl representation of the argument is passed in ARG_RTX and
+   the starting register used to pass this argument or return value is passed
+   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to compute these
+   for struct and union types.  */
+
+static unsigned HOST_WIDE_INT
+compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
+			     uint32_t * padding_bits_to_clear)
+
+{
+  int last_used_bit = 0;
+  unsigned HOST_WIDE_INT not_to_clear_mask;
+
+  if (RECORD_OR_UNION_TYPE_P (arg_type))
+    {
+      not_to_clear_mask
+	= comp_not_to_clear_mask_str_un (arg_type, &regno,
+					 padding_bits_to_clear, 0,
+					 &last_used_bit);
+
+
+      /* If the 'last_used_bit' is not zero, that means we are still using a
+	 part of the last 'regno'.  In such cases we must clear the trailing
+	 bits.  Otherwise we are not using regno and we should mark it as to
+	 clear.  */
+      if (last_used_bit != 0)
+	*(padding_bits_to_clear + regno)
+	  |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;
+      else
+	not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
+    }
+  else
+    {
+      not_to_clear_mask = 0;
+      /* We are not dealing with structs nor unions.  So these arguments may be
+	 passed in floating point registers too.  In some cases a BLKmode is
+	 used when returning or passing arguments in multiple VFP registers.  */
+      if (GET_MODE (arg_rtx) == BLKmode)
+	{
+	  int i, arg_regs;
+	  rtx reg;
+
+	  /* This should really only occur when dealing with the hard-float
+	     ABI.  */
+	  gcc_assert (TARGET_HARD_FLOAT_ABI && TARGET_VFP);
+
+	  for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
+	    {
+	      reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
+	      gcc_assert (REG_P (reg));
+
+	      not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
+
+	      /* If we are dealing with DF mode, make sure we don't
+		 clear either of the registers it addresses.  */
+	      arg_regs = ARM_NUM_REGS (GET_MODE (reg));
+	      if (arg_regs > 1)
+		{
+		  unsigned HOST_WIDE_INT mask;
+		  mask = HOST_WIDE_INT_1U << (REGNO (reg) + arg_regs);
+		  mask -= HOST_WIDE_INT_1U << REGNO (reg);
+		  not_to_clear_mask |= mask;
+		}
+	    }
+	}
+      else
+	{
+	  /* Otherwise we can rely on the MODE to determine how many registers
+	     are being used by this argument.  */
+	  int arg_regs = ARM_NUM_REGS (GET_MODE (arg_rtx));
+	  not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	  if (arg_regs > 1)
+	    {
+	      unsigned HOST_WIDE_INT
+	      mask = HOST_WIDE_INT_1U << (REGNO (arg_rtx) + arg_regs);
+	      mask -= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	      not_to_clear_mask |= mask;
+	    }
+	}
+    }
+
+  return not_to_clear_mask;
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -19891,7 +20164,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
-	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    {
+	      /* 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);
+	      if (TARGET_HARD_FLOAT && TARGET_VFP)
+		{
+		  /* 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");
+		  output_asm_insn (instr, & operand);
+		}
+	      snprintf (instr, sizeof (instr), "bxns\t%%|lr");
+	    }
 	  /* Use bx if it's available.  */
 	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
@@ -24143,7 +24451,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
-	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	{
+	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+		       reg_containing_return_addr);
+	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	}
       else
 	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
@@ -24379,7 +24691,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
   /* Return to caller.  */
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
-    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    {
+      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
+      asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    }
   else
     asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
@@ -25241,6 +25556,133 @@ thumb1_expand_prologue (void)
     cfun->machine->lr_save_eliminated = 0;
 }
 
+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check TARGET_VFP to make sure these are present.  */
+  if (TARGET_HARD_FLOAT && TARGET_VFP)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      maxregno = LAST_VFP_REGNUM;
+
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask[0] |= float_mask;
+
+      float_mask = (1ULL << (maxregno - 63)) - 1;
+      to_clear_mask[1] = float_mask;
+
+      /* Make sure we dont clear the two scratch registers used to clear the
+	 relevant FPSCR bits in output_return_instruction.  We have only
+	 implemented the clearing of FP registers for Thumb-2, so we assert
+	 here that VFP was not enabled for Thumb-1 ARMv8-M targets.  */
+      gcc_assert (arm_arch_thumb2);
+      emit_use (gen_rtx_REG (SImode, IP_REGNUM));
+      to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+      emit_use (gen_rtx_REG (SImode, 4));
+      to_clear_mask[0] &= ~(1ULL << 4);
+    }
+
+  /* If the user has defined registers to be caller saved, these are no longer
+     restored by the function before returning and must thus be cleared for
+     security purposes.  */
+  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+    {
+      /* We do not touch registers that can be used to pass arguments as per
+	 the AAPCS, since these should never be made callee-saved by user
+	 options.  */
+      if (regno >= FIRST_VFP_REGNUM && regno <= D7_VFP_REGNUM)
+	continue;
+      if (regno >= IP_REGNUM && regno <= PC_REGNUM)
+	continue;
+      if (call_used_regs[regno])
+	to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+    }
+
+  /* Make sure we do not clear the registers used to return the result in.  */
+  result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+  if (!VOID_TYPE_P (result_type))
+    {
+      result_rtl = arm_function_value (result_type, current_function_decl, 0);
+
+      /* No need to check that we return in registers, because we don't
+	 support returning on stack yet.  */
+      to_clear_mask[0]
+	&= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
+				       padding_bits_to_clear_ptr);
+    }
+
+  if (padding_bits_to_clear != 0)
+    {
+      rtx reg_rtx;
+      /* Padding bits to clear is not 0 so we know we are dealing with
+	 returning a composite type, which only uses r0.  Let's make sure that
+	 r1-r3 is cleared too, we will use r1 as a scratch register.  */
+      gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
+
+      reg_rtx = gen_rtx_REG (SImode, 1);
+
+      /* Fill the lower half of the negated padding_bits_to_clear.  */
+      emit_move_insn (reg_rtx,
+		      GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
+
+      /* Also fill the top half of the negated padding_bits_to_clear.  */
+      if (((~padding_bits_to_clear) >> 16) > 0)
+	emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
+						      GEN_INT (16),
+						      GEN_INT (16)),
+				GEN_INT ((~padding_bits_to_clear) >> 16)));
+
+      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, 0),
+			   gen_rtx_REG (SImode, 0),
+			   reg_rtx));
+    }
+
+  for (regno = 0; regno <= maxregno; regno++)
+    {
+      if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
+	continue;
+
+      if (IS_VFP_REGNUM (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)
+	      && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 1)))
+	    {
+	      emit_move_insn (gen_rtx_REG (DFmode, regno++),
+			      CONST1_RTX (DFmode));
+	      emit_use (gen_rtx_REG (DFmode, 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 (SImode, regno),
+			  gen_rtx_REG (SImode, LR_REGNUM));
+	  emit_use (gen_rtx_REG (SImode, regno));
+	}
+    }
+}
+
 /* Generate pattern *pop_multiple_with_stack_update_and_return if single
    POP instruction can be generated.  LR should be replaced by PC.  All
    the checks required are already done by  USE_RETURN_INSN ().  Hence,
@@ -25290,6 +25732,8 @@ thumb2_expand_return (bool simple_return)
     }
   else
     {
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	cmse_nonsecure_entry_clear_before_return ();
       emit_jump_insn (simple_return_rtx);
     }
 }
@@ -25348,6 +25792,10 @@ thumb1_expand_epilogue (void)
 
   if (! df_regs_ever_live_p (LR_REGNUM))
     emit_use (gen_rtx_REG (SImode, LR_REGNUM));
+
+  /* Clear all caller-saved regs that are not used to return.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    cmse_nonsecure_entry_clear_before_return ();
 }
 
 /* Epilogue code for APCS frame.  */
@@ -25782,6 +26230,14 @@ 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 (!really_return)
     return;
 
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index cd98de7dcb40de483a9f93c0674bd216f4b0c56a..433fc79ae5810a4d3eb45d1ba80872a39e157e14 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1843,8 +1843,13 @@
   "*
     return thumb1_unexpanded_epilogue ();
   "
-  ; Length is absolute worst case
-  [(set_attr "length" "44")
+  ; Length is absolute worst case, when using CMSE and if this is an entry
+  ; function an extra 4 (MSR) bytes will be added.
+  [(set (attr "length")
+	(if_then_else
+	 (match_test "IS_CMSE_ENTRY (arm_current_func_type ())")
+	 (const_int 48)
+	 (const_int 44)))
    (set_attr "type" "block")
    ;; We don't clobber the conditions, but the potential length of this
    ;; operation is sufficient to make conditionalizing the sequence
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index ab08288413c3e64911e8d7a8199b9809e0282d8e..11dcb715262a853f3f25e38ecda4075edea9caf5 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1115,12 +1115,31 @@
 
 (define_insn "*thumb2_return"
   [(simple_return)]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
   "* return output_return_instruction (const_true_rtx, true, false, true);"
   [(set_attr "type" "branch")
    (set_attr "length" "4")]
 )
 
+(define_insn "*thumb2_return"
+  [(simple_return)]
+  "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
+  "* return output_return_instruction (const_true_rtx, true, false, true);"
+  [(set_attr "type" "branch")
+   ; This is a return from a cmse_nonsecure_entry function so code will be
+   ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+   ; we adapt the length accordingly.
+   (set (attr "length")
+     (if_then_else (match_test "TARGET_HARD_FLOAT && TARGET_VFP")
+      (const_int 12)
+      (const_int 8)))
+   ; We do not support predicate execution of returns from cmse_nonsecure_entry
+   ; functions because we need to clear the APSR.  Since predicable has to be
+   ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
+   ; functions.
+   (set_attr "predicable" "no")]
+)
+
 (define_insn_and_split "thumb2_eh_return"
   [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
 		    VUNSPEC_EH_RETURN)
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c6354c7a8cfead895e6c62d61c3f2a2bca1a1f2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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 "msr\tAPSR_nzcvq, r1" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..fccc51d5c82f7955ee4cb8256c1dd38f9ff2670d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned short  a : 6;
+  unsigned char	  b : 3;
+  unsigned char	  c;
+  unsigned short  d : 8;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 63u;
+  t.b = 7u;
+  t.c = 255u;
+  t.d = 255u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 63u
+      || t.b != 7u
+      || t.c != 255u
+      || t.d != 255u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6aee3c4c022d50baec8ab16443130897540e703
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a : 7;
+  signed char b : 3;
+  short	      c : 11;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -64;
+  t.b = -4 ;
+  t.c = -1024;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -64
+      || t.b != -4
+      || t.c != -1024)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..285a2b92f64c1913ef585b8daa4d27c6da0a3d2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a;
+  signed char b : 2;
+  short		: 1;
+  signed char c : 3;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -32768;
+  t.b = -2;
+  t.c = -4;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -32768
+      || t.b != -2
+      || t.c != -4)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index f797dba1901720e04249d61078c1cbf2a3e436a9..38f18414c2fefec56161e6ac3f7291b03a3b29a3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -43,6 +43,26 @@ set LTO_TORTURE_OPTIONS ""
 gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
 	"" $DEFAULT_CFLAGS
 
+if {[check_effective_target_arm_arch_v8m_base_ok]} then {
+    # Baseline only
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/baseline/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
+if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    # Mainline -mfloat-abi=soft
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
+	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
 set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
 set dg-do-what-default ${saved-dg-do-what-default}
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..88dec2762812614ee986ee1a023c0acce8f94c91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..29f60baf5212f9fa2e4436fe40c6abe4ac671254
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7229ea8eb2da1da264f58f8518daf303d1bdeda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..7734d77dc3812e6a158ea1f6b067930846fffccb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..6addaa1a4eda8e2930d5fe72c94697bcf6e604e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { 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
new file mode 100644
index 0000000000000000000000000000000000000000..2d366a944df692f29ab44e3ee4d33c777b126223
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 255u;
+  t.b = 32767u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 255u || t.b != 32767u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
+

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

* [PATCHv2 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
  2016-07-25 13:25 ` [PATCH 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute Andre Vieira (lists)
@ 2016-08-24 11:01   ` Andre Vieira (lists)
  2016-10-25 16:29     ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-08-24 11:01 UTC (permalink / raw)
  To: gcc-patches

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

On 25/07/16 14:25, Andre Vieira (lists) wrote:
> This patch adds support for the ARMv8-M Security Extensions
> 'cmse_nonsecure_call' attribute. This attribute may only be used for
> function types and when used in combination with the '-mcmse'
> compilation flag. See Section 5.5 of ARM®v8-M Security Extensions
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
> 
> We currently do not support cmse_nonsecure_call functions that pass
> arguments or return variables on the stack and we diagnose this.
> 
> *** gcc/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (gimplify.h): New include.
>         (arm_handle_cmse_nonsecure_call): New.
>         (arm_attribute_table): Added cmse_nonsecure_call.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse-3.c: Add tests.
>         * gcc.target/arm/cmse/cmse-4.c: Add tests.
> 

Added more documentation as requested.

---

This patch adds support for the ARMv8-M Security Extensions
'cmse_nonsecure_call' attribute. This attribute may only be used for
function types and when used in combination with the '-mcmse'
compilation flag. See Section 5.5 of ARM®v8-M Security Extensions
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

We currently do not support cmse_nonsecure_call functions that pass
arguments or return variables on the stack and we diagnose this.

*** gcc/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (gimplify.h): New include.
        (arm_handle_cmse_nonsecure_call): New.
        (arm_attribute_table): Added cmse_nonsecure_call.
        * doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.

*** gcc/testsuite/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse-3.c: Add tests.
        * gcc.target/arm/cmse/cmse-4.c: Add tests.

[-- Attachment #2: diff5 --]
[-- Type: text/plain, Size: 7129 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 680b648a218d166d49e89be78ee30397dac7e87f..647e41677834573db1b921d3e8445145767779c4 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -61,6 +61,7 @@
 #include "builtins.h"
 #include "tm-constrs.h"
 #include "rtl-iter.h"
+#include "gimplify.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -135,6 +136,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
 static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
+static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -347,6 +349,8 @@ static const struct attribute_spec arm_attribute_table[] =
   /* ARMv8-M Security Extensions support.  */
   { "cmse_nonsecure_entry", 0, 0, true, false, false,
     arm_handle_cmse_nonsecure_entry, false },
+  { "cmse_nonsecure_call", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_call, false },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -6750,6 +6754,78 @@ arm_handle_cmse_nonsecure_entry (tree *node, tree name,
   return NULL_TREE;
 }
 
+
+/* Called upon detection of the use of the cmse_nonsecure_call attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function type tree or otherwise issue a diagnostic.  The
+   reason we check this at declaration time is to only allow the use of the
+   attribute with declarations of function pointers and not function
+   declarations.  This function checks NODE is of the expected type and issues
+   diagnostics otherwise using NAME.  If it is not of the expected type
+   *NO_ADD_ATTRS will be set to true.  */
+
+static tree
+arm_handle_cmse_nonsecure_call (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree decl = NULL_TREE;
+  tree type, fntype, main_variant;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == TYPE_DECL)
+    {
+      decl = *node;
+      type = TREE_TYPE (decl);
+    }
+
+  if (!decl
+      || (!(TREE_CODE (type) == POINTER_TYPE
+	    && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+	  && TREE_CODE (type) != FUNCTION_TYPE))
+    {
+	warning (OPT_Wattributes, "%qE attribute only applies to base type of a "
+		 "function pointer", name);
+	*no_add_attrs = true;
+	return NULL_TREE;
+    }
+
+  /* type is either a function pointer, when the attribute is used on a function
+   * pointer, or a function type when used in a typedef.  */
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    fntype = type;
+  else
+    fntype = TREE_TYPE (type);
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (NULL, name, fntype);
+
+  if (*no_add_attrs)
+    return NULL_TREE;
+
+  /* Prevent trees being shared among function types with and without
+     cmse_nonsecure_call attribute.  Do however make sure they keep the same
+     main_variant, this is required for correct DIE output.  */
+  main_variant = TYPE_MAIN_VARIANT (fntype);
+  fntype = build_distinct_type_copy (fntype);
+  TYPE_MAIN_VARIANT (fntype) = main_variant;
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    TREE_TYPE (decl) = fntype;
+  else
+    TREE_TYPE (type) = fntype;
+
+  /* Construct a type attribute and add it to the function type.  */
+  tree attrs = tree_cons (get_identifier ("cmse_nonsecure_call"), NULL_TREE,
+			  TYPE_ATTRIBUTES (fntype));
+  TYPE_ATTRIBUTES (fntype) = attrs;
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 1531ed66bdd0b51c268c2a666c2e078b4f0d7ea6..f1e6a20583f9b16d5a670144a162203a12b239bd 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12421,8 +12421,8 @@ Security Extensions: Requiremenets on Development Tools Engineering
 Specification, which can be found at
 @uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 
-As part of the Security Extensions GCC implements a new function attribute
-@code{cmse_nonsecure_entry}.
+As part of the Security Extensions GCC implements two new function attributes:
+@code{cmse_nonsecure_entry} and @code{cmse_nonsecure_call}.
 
 As part of the Security Extensions GCC implements the intrinsics below.  FPTR
 is used here to mean any function pointer type.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
index 2c2920e1dc310106d83203eb51e1a68a275d0152..7f92a4c28b3333e4c8fdc256211f3ed74a383cd4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -35,3 +35,11 @@ norf (struct span2 a) {}
 
 void __attribute__ ((cmse_nonsecure_entry))
 foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) bar2 (long long a, int b, long long c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) baz2 (long long a, int b, struct span c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef struct span __attribute__ ((cmse_nonsecure_call)) qux2 (void); /* { dg-error "not available to functions that return value on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) norf2 (int a, ...); /* { dg-error "not available to functions with variable number of arguments" } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
index 6f930ab04a1097c64097a4e003296bbe85733319..d0999a4181ac022b115ae20cf3e1c8bf78f6becf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -19,9 +19,16 @@ baz (void)
   return qux ();
 }
 
+void __attribute__ ((cmse_nonsecure_call))
+quux (void) {} /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
+int __attribute__ ((cmse_nonsecure_call)) norf; /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
 /* { dg-final { scan-assembler-times "bxns" 2 } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
 /* { dg-final { scan-assembler "baz:" } } */
 /* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_quux:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_norf:" } } */

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

* [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-07-25 13:26 ` [PATCH 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call Andre Vieira (lists)
@ 2016-08-24 11:02   ` Andre Vieira (lists)
  2016-10-25 16:30     ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-08-24 11:02 UTC (permalink / raw)
  To: gcc-patches

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

On 25/07/16 14:26, Andre Vieira (lists) wrote:
> This patch extends support for the ARMv8-M Security Extensions
> 'cmse_nonsecure_call' to use a new library function
> '__gnu_cmse_nonsecure_call'. This library function is responsible for
> (without using r0-r3 or d0-d7):
> 1) saving and clearing all callee-saved registers using the secure stack
> 2) clearing the LSB of the address passed in r4 and using blxns to
> 'jump' to it
> 3) clearing ASPR, including the 'ge bits' if DSP is enabled
> 4) clearing FPSCR if using non-soft float-abi
> 5) restoring callee-saved registers.
> 
> The decisions whether to include DSP 'ge bits' clearing and floating
> point registers (single/double precision) all depends on the multilib used.
> 
> See Section 5.5 of ARM®v8-M Security Extensions
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
> 
> *** gcc/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>         (cmse_nonsecure_call_clear_caller_saved): New.
>         (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>         * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>         * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>         (call_value): Likewise.
>         (nonsecure_call_internal): New.
>         (nonsecure_call_value_internal): New.
>         * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>         (*nonsecure_call_value_reg_thumb1_v5): New.
>         * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>         (*nonsecure_call_value_reg_thumb2): New.
>         * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
> 
> *** libgcc/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/cmse_nonsecure_call.S: New.
> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
> 
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>         * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>         * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>         * gcc.target/arm/cmse/baseline/cmse-11.c: New.
> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
> 

Updated this patch to correctly clear only the cumulative
exception-status (0-4,7) and the condition code bits (28-31) of the FPSCR.

----

This patch extends support for the ARMv8-M Security Extensions
'cmse_nonsecure_call' to use a new library function
'__gnu_cmse_nonsecure_call'. This library function is responsible for
(without using r0-r3 or d0-d7):
1) saving and clearing all callee-saved registers using the secure stack
2) clearing the LSB of the address passed in r4 and using blxns to
'jump' to it
3) clearing ASPR, including the 'ge bits' if DSP is enabled
4) clearing the cumulative exception-status (0-4, 7) and the condition
bits (28-31) of the FPSCR if using non-soft float-abi
5) restoring callee-saved registers.

The decisions whether to include DSP 'ge bits' clearing and floating
point registers (single/double precision) all depends on the multilib used.

See Section 5.5 of ARM®v8-M Security Extensions
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).

*** gcc/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (detect_cmse_nonsecure_call): New.
        (cmse_nonsecure_call_clear_caller_saved): New.
        (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
        * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
        * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
        (call_value): Likewise.
        (nonsecure_call_internal): New.
        (nonsecure_call_value_internal): New.
        * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
        (*nonsecure_call_value_reg_thumb1_v5): New.
        * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
        (*nonsecure_call_value_reg_thumb2): New.
        * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.

*** libgcc/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/cmse_nonsecure_call.S: New.
	* config/arm/t-arm: Compile cmse_nonsecure_call.S


*** gcc/testsuite/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
        * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
        * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
        * gcc.target/arm/cmse/baseline/cmse-11.c: New.
	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
        * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
        * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.

[-- Attachment #2: diff6 --]
[-- Type: text/plain, Size: 81901 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 1d2e35b52f631570450b6c8eaf077e18e9b99203..e7e223f7a932163cba8beeb76c10b4c90eae9234 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -133,6 +133,7 @@ extern int arm_const_double_inline_cost (rtx);
 extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
+bool detect_cmse_nonsecure_call (tree);
 extern const char *output_call (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 647e41677834573db1b921d3e8445145767779c4..7c7220bf0cd83d72ccd20974b6a957929883f809 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17822,6 +17822,197 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Saves callee saved registers, clears callee saved registers and caller saved
+   registers not used to pass arguments before a cmse_nonsecure_call.  And
+   restores the callee saved registers after.  */
+
+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  uint64_t to_clear_mask, float_mask;
+	  rtx_insn *seq;
+	  rtx pat, call, unspec, reg, cleared_reg, tmp;
+	  unsigned int regno, maxregno;
+	  rtx address;
+	  CUMULATIVE_ARGS args_so_far_v;
+	  cumulative_args_t args_so_far;
+	  tree arg_type, fntype;
+	  bool using_r4, first_param = true;
+	  function_args_iterator args_iter;
+	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
+	  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
+
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  if (!CALL_P (insn))
+	    continue;
+
+	  pat = PATTERN (insn);
+	  gcc_assert (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 0);
+	  call = XVECEXP (pat, 0, 0);
+
+	  /* Get the real call RTX if the insn sets a value, ie. returns.  */
+	  if (GET_CODE (call) == SET)
+	      call = SET_SRC (call);
+
+	  /* Check if it is a cmse_nonsecure_call.  */
+	  unspec = XEXP (call, 0);
+	  if (GET_CODE (unspec) != UNSPEC
+	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
+	    continue;
+
+	  /* Determine the caller-saved registers we need to clear.  */
+	  to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
+	  maxregno = NUM_ARG_REGS - 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
+	     lazy store and loads which clear both caller- and callee-saved
+	     registers.  */
+	  if (TARGET_HARD_FLOAT_ABI && TARGET_VFP)
+	    {
+	      float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
+	      float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
+	      to_clear_mask |= float_mask;
+	      maxregno = D7_VFP_REGNUM;
+	    }
+
+	  /* Make sure the register used to hold the function address is not
+	     cleared.  */
+	  address = RTVEC_ELT (XVEC (unspec, 0), 0);
+	  gcc_assert (MEM_P (address));
+	  gcc_assert (REG_P (XEXP (address, 0)));
+	  to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+
+	  /* Set basic block of call insn so that df rescan is performed on
+	     insns inserted here.  */
+	  set_block_for_insn (insn, bb);
+	  df_set_flags (DF_DEFER_INSN_RESCAN);
+	  start_sequence ();
+
+	  /* Make sure the scheduler doesn't schedule other insns beyond
+	     here.  */
+	  emit_insn (gen_blockage ());
+
+	  /* Walk through all arguments and clear registers appropriately.
+	  */
+	  fntype = TREE_TYPE (MEM_EXPR (address));
+	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
+				    NULL_TREE);
+	  args_so_far = pack_cumulative_args (&args_so_far_v);
+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask &=
+		~compute_not_to_clear_mask (arg_type, arg_rtx,
+					      REGNO (arg_rtx),
+					      padding_bits_to_clear_ptr);
+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = 0; regno < NUM_ARG_REGS; regno++)
+	    {
+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = 0; regno <= maxregno; regno++)
+	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST1_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST1_RTX (SFmode));
+		}
+	      else
+		emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+	    }
+
+	  seq = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (seq, insn);
+
+	}
+    }
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -18122,6 +18313,8 @@ arm_reorg (void)
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
+  if (use_cmse)
+    cmse_nonsecure_call_clear_caller_saved ();
   if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
@@ -18494,6 +18687,23 @@ vfp_emit_fstmd (int base_reg, int count)
   return count * 8;
 }
 
+/* Returns true if -mcmse has been passed and the function pointed to by 'addr'
+   has the cmse_nonsecure_call attribute and returns false otherwise.  */
+
+bool
+detect_cmse_nonsecure_call (tree addr)
+{
+  if (!addr)
+    return FALSE;
+
+  tree fntype = TREE_TYPE (addr);
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_call",
+				    TYPE_ATTRIBUTES (fntype)))
+    return TRUE;
+  return FALSE;
+}
+
+
 /* Emit a call instruction with pattern PAT.  ADDR is the address of
    the call target.  */
 
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 820471556efbac6b35d46a03fb763cbd30bea30f..3e0d5097938871b1219ed2c426271be55a004950 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -7640,6 +7640,7 @@
   "
   {
     rtx callee, pat;
+    tree addr = MEM_EXPR (operands[0]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[2] == NULL_RTX)
@@ -7654,8 +7655,17 @@
 	: !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_internal (operands[0], operands[1], operands[2]);
-    arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_internal (operands[0], operands[1],
+					   operands[2]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_internal (operands[0], operands[1], operands[2]);
+	arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+      }
     DONE;
   }"
 )
@@ -7666,6 +7676,24 @@
 	      (use (match_operand 2 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_internal"
+  [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand" "")]
+			       UNSPEC_NONSECURE_MEM)
+		    (match_operand 1 "general_operand" ""))
+	      (use (match_operand 2 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[0] = replace_equiv_address (operands[0], tmp);
+  }")
+
 (define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
@@ -7701,6 +7729,7 @@
   "
   {
     rtx pat, callee;
+    tree addr = MEM_EXPR (operands[1]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
@@ -7715,9 +7744,18 @@
 	: !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_value_internal (operands[0], operands[1],
-				   operands[2], operands[3]);
-    arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_value_internal (operands[0], operands[1],
+						 operands[2], operands[3]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_value_internal (operands[0], operands[1],
+				       operands[2], operands[3]);
+	arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+      }
     DONE;
   }"
 )
@@ -7729,6 +7767,25 @@
 	      (use (match_operand 3 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_value_internal"
+  [(parallel [(set (match_operand       0 "" "")
+		   (call (unspec:SI [(match_operand 1 "memory_operand" "")]
+				    UNSPEC_NONSECURE_MEM)
+			 (match_operand 2 "general_operand" "")))
+	      (use (match_operand 3 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[1] = replace_equiv_address (operands[1], tmp);
+  }")
+
 (define_insn "*call_value_reg_armv5"
   [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 433fc79ae5810a4d3eb45d1ba80872a39e157e14..63a400fbfd8015cbd5a70252e24beacde4a5354d 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1705,6 +1705,19 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb1_v5"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_reg_thumb1"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
 	 (match_operand 1 "" ""))
@@ -1737,6 +1750,21 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb1_v5"
+  [(set (match_operand 0 "" "")
+	(call (unspec:SI
+	       [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+	       UNSPEC_NONSECURE_MEM)
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB1 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb1"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index 98b29121e98f036d29f83f5c78ef9c0cc78f630d..3f8d5fc141077e1f55a585ba95b997fa8e6faa0f 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -581,6 +581,19 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
@@ -592,6 +605,21 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+	(call
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "register_operand" "l*r"))]
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 5744c62cf5ab3b3711fef2b442c62cd3eadf0793..c2f5e5b52cd84380c009af4077bd6effda923701 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -84,6 +84,8 @@
   UNSPEC_VRINTA         ; Represent a float to integral float rounding
                         ; towards nearest, ties away from zero.
   UNSPEC_PROBE_STACK    ; Probe stack memory reference
+  UNSPEC_NONSECURE_MEM	; Represent non-secure memory in ARMv8-M with
+			; security extension
 ])
 
 (define_c_enum "unspec" [
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6c1386c06edbdb58e76fa5e612c918010c507f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51ce2d42c051aeda8b06ad97086f2563a5fc47d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e9104b546a7693fcb2399622e828b1197eac1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 1023" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "movt\tr4, 32767" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d8941bbfeebd59744c43f10c842816b36ec9915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ffbb718d34d5bb8f10e1f3c0505c7dc393c670c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a6141829237823b8734de045a590a1917fa60b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #1799" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..642f4e0346b5186c78645780b45fe9c838848d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #7939" } } */
+/* { dg-final { scan-assembler "movt\tr4, 15" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, 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/baseline/cmse-11.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
new file mode 100644
index 0000000000000000000000000000000000000000..3007409ad88b9d2312ece4d55f3695787a1aa566
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+
+int
+foo (int a)
+{
+  return bar (bar (a + 1));
+}
+
+/* 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 "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\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/baseline/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2b931be5912b421f8427535ded3298883bec639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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 "movs\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmovs\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmovs\tr2, r4\n\tmovs\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/baseline/cmse-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..95da045690ae170a101949134482e821f27fe3aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* Remember dont clear r0 and r1, because we are passing the double parameter
+ * for bar in them.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, 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/baseline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff18e839b02c19c2c77769b18ef5ee1cfacf0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8063" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2e024b7f0776381f511077af91bd1ee5632ff12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
index 65200bcf29b219706911bbb799c847aefc92cb1c..79ddc7cb1fe1724b82ae028c2ddf91321e855811 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -2,11 +2,19 @@
 /* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
 
 
+void __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+typedef void __attribute__ ((cmse_nonsecure_call)) baz (int);
+
 int __attribute__ ((cmse_nonsecure_entry))
-foo (int a)
+foo (int a, baz b)
 {
+  bar (a);
+  b (a);
   return a + 1;
 }
 
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler-not "blxns" } } */
+/* { dg-final { scan-assembler-not "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 38f18414c2fefec56161e6ac3f7291b03a3b29a3..66a8b7da005f7dfeffbded61b02fd6a7473a1dcf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -50,6 +50,8 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
+	    "" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
 	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b1396d52e742a1710ed5ad33fbeb559d866f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d029044aa9aa1d412c28ee5d18a8e3d0be36546
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..005515ab9cb85c201a2a8b2f6417d73ceeacbc60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dd218e62fdee2a6af819079ba1ea1909185d076
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { 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/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..c833bcb0ae978572fad46780bc180f61ccb14345
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cdb8c44b19c811f3a7b4fbce102a6c768f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e139ba61af57f06cff5a9d121c97bbf41e170bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { 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/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..285fa854b3d61c4d856e9be863ee73a87f1b11a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f56aaf2a97e740a77473cab245614b6fa696c04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..749f8a7278cb4ea9fd4462887ce7f37b57f83248
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad5068aac263f1c2edb17b8707fc9d1c0af6959
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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\.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/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..b18259eaef6da1933ef2d58d63b97d4bb4e450f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..182ddf9540374f30ae3694259f1edb62161455e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd262c89085eb0dc8737ad7955c3a12531492b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..e33568400ef830abaa019b5c2727a9f3b5d5704b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..024a12e0a414730eb1cbebfca8574d548238ab28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb195eb58d59fe9ea5ed74af79646199c61bcdae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..22ed3f8af882f96da49919c60fc6f4cd74dfc54b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634065e7cb64a5069cbb3c9be4b8cf9177f5e29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..04f8466cc112c03ee5a05e6e5223d2c66a033bbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffe94de85417b81f9dcb366eb1b40dc1661c91b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc846cd7a51303ec00f8f512a54cd697fbd0682
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d0f136ef171111c1cca6cd24c4f46b9fcb7fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/libgcc/config/arm/cmse_nonsecure_call.S b/libgcc/config/arm/cmse_nonsecure_call.S
new file mode 100644
index 0000000000000000000000000000000000000000..2944858d5e896dd8cabee3eae2558799776d9016
--- /dev/null
+++ b/libgcc/config/arm/cmse_nonsecure_call.S
@@ -0,0 +1,142 @@
+/* CMSE wrapper function used to save, clear and restore callee saved registers
+   for cmse_nonsecure_call's.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+.syntax unified
+.thumb
+.global __gnu_cmse_nonsecure_call
+__gnu_cmse_nonsecure_call:
+#if defined(__ARM_ARCH_8M_MAIN__)
+push	    {r5-r11,lr}
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+
+/* Save and clear callee-saved registers only if we are dealing with hard float
+   ABI.  The unused caller-saved registers have already been cleared by GCC
+   generated code.  */
+#ifdef __ARM_PCS_VFP
+vpush.f64   {d8-d15}
+#if __ARM_FP & 0x04
+vmov.f32    s16, #1.00000
+vmov.f32    s17, #1.00000
+vmov.f32    s18, #1.00000
+vmov.f32    s19, #1.00000
+vmov.f32    s20, #1.00000
+vmov.f32    s21, #1.00000
+vmov.f32    s22, #1.00000
+vmov.f32    s23, #1.00000
+vmov.f32    s24, #1.00000
+vmov.f32    s25, #1.00000
+vmov.f32    s26, #1.00000
+vmov.f32    s27, #1.00000
+vmov.f32    s28, #1.00000
+vmov.f32    s29, #1.00000
+vmov.f32    s30, #1.00000
+vmov.f32    s31, #1.00000
+#elif __ARM_FP & 0x08
+vmov.f64    d8, #1.00000
+vmov.f64    d9, #1.00000
+vmov.f64    d10, #1.00000
+vmov.f64    d11, #1.00000
+vmov.f64    d12, #1.00000
+vmov.f64    d13, #1.00000
+vmov.f64    d14, #1.00000
+vmov.f64    d15, #1.00000
+#else
+#error "Half precision implementation not supported."
+#endif
+/* Clear the cumulative exception-status bits (0-4,7) and the
+   condition code bits (28-31) of the FPSCR.  */
+vmrs	    r5, fpscr
+movw	    r6, #65376
+movt	    r6, #4095
+ands	    r5, r6
+vmsr	    fpscr, r5
+
+/* We are not dealing with hard float ABI, so we can safely use the vlstm and
+   vlldm instructions without needing to preserve the registers used for
+   argument passing.  */
+#else
+sub	    sp, sp, #0x88 /* Reserve stack space to save all floating point
+			     registers, including FPSCR.  */
+vlstm	    sp		  /* Lazy store and clearance of d0-d16 and FPSCR.  */
+#endif /* __ARM_PCS_VFP */
+
+/* Make sure to clear the 'GE' bits of the APSR register if 32-bit SIMD
+   instructions are available.  */
+#if defined(__ARM_FEATURE_SIMD32)
+msr	    APSR_nzcvqg, r4
+#else
+msr	    APSR_nzcvq, r4
+#endif
+
+mov	    r5, r4
+mov	    r6, r4
+blxns	    r4
+
+#ifdef __ARM_PCS_VFP
+vpop.f64    {d8-d15}
+#else
+vlldm	    sp		  /* Lazy restore of d0-d16 and FPSCR.  */
+add	    sp, sp, #0x88 /* Free space used to save floating point registers.  */
+#endif /* __ARM_PCS_VFP */
+
+pop	    {r5-r11}
+
+#elif defined (__ARM_ARCH_8M_BASE__)
+push	    {r5-r7}
+mov	    r5, r8
+mov	    r6, r9
+mov	    r7, r10
+push	    {r5-r7}
+mov	    r5, r11
+mov	    r6, lr
+push	    {r5,r6}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+msr	    APSR_nzcvq, r4
+blxns	    r4
+pop	    {r5, r6}
+mov	    lr, r6
+mov	    r11, r5
+pop	    {r5-r7}
+mov	    r10, r7
+mov	    r9, r6
+mov	    r8, r5
+pop	    {r5-r7}
+blx	    lr
+
+#else
+#error "This should only be used for armv8-m base- and mainline."
+#endif
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 5618143bfd0f02b170db3f9e4c0a15cecb403cec..9e85ac06b146feaa14ab83374a0156737b870310 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -12,4 +12,6 @@ libgcc-objects += cmse.o cmse_nonsecure_call.o
 
 cmse.o: $(srcdir)/config/arm/cmse.c
 	$(gcc_compile) -c $(CMSE_OPTS) $<
+cmse_nonsecure_call.o: $(srcdir)/config/arm/cmse_nonsecure_call.S
+		       $(gcc_compile) -c $<
 endif

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

* Re: [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions
  2016-08-10  8:09       ` Andre Vieira (lists)
@ 2016-08-24 11:02         ` Andre Vieira (lists)
  2016-10-24 16:14           ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-08-24 11:02 UTC (permalink / raw)
  To: gcc-patches

On 10/08/16 09:08, Andre Vieira (lists) wrote:
> On 09/08/16 17:47, Sandra Loosemore wrote:
>> On 08/09/2016 06:01 AM, Andre Vieira (lists) wrote:
>>> [snip]
>>>
>>> The documentation is in the ARMV8-M Security Extensions in: ARM®v8-M
>>> Security Extensions: Requirements on Development Tools document I linked
>>> in the email above and subsequent emails
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>
>>> Also per patch I refer to the relevant sections. So for instance in
>>> PATCH 3/7 refers to Section 5.4, which describes Entry functions and
>>> mentions the cmse_nonsecure_entry attribute. Whereas PATCH 7/7 refers to
>>> Section 5.4.3 of the same document which describes the
>>> cmse_nonsecure_caller intrinsic which that patch implements.
>>>
>>> Is there a specific intrinsic/attribute you are missing?
>>
>> You need to at least add entries to the relevant sections in extend.texi
>> for the new target-specific intrinsic and attributes.  The documentation
>> there doesn't need to be terribly detailed (one sentence and a link to
>> the external document is probably all you need), but it's important that
>> these things be listed in GCC's supported extensions so that users know
>> they can use them and so that people who see them in code written by
>> other people can find out what they mean.
>>
>> -Sandra
>>
> 
> 
> I see, I did add a new entry to extend.texi for ARMv8-M Security
> Extensions. I will also mention all intrinsics and attributes there.
> 
> Thank you.
> 
> Andre
> 

I updated the patch series with more documentation in extend.texi and I
also fixed an issue with the clearing of FPSCR.

Cheers,
Andre

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

* Re: [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic
  2016-07-25 13:29 ` [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic Andre Vieira (lists)
@ 2016-08-24 11:02   ` Andre Vieira (lists)
  2016-10-25 16:30     ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-08-24 11:02 UTC (permalink / raw)
  To: gcc-patches

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

On 25/07/16 14:28, Andre Vieira (lists) wrote:
> This patch adds support ARMv8-M's Security Extension's
> cmse_nonsecure_caller intrinsic. This intrinsic is used to check whether
> an entry function was called from a non-secure state.
> See Section 5.4.3 of ARM®v8-M Security Extensions: Requirements on
> Development Tools
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html)
> for further details.
> 
> The FIXME in config/arm/arm_cmse.h is for a diagnostic message that is
> suggested in the ARMv8-M Security Extensions document mentioned above,
> to diagnose the use of the cmse_nonsecure_caller intrinsic outside of
> functions with the 'cmse_nonsecure_entry' attribute.  Checking whether
> the intrinsic is called from within such functions can easily be done
> inside 'arm_expand_builtin'. However, making the warning point to the
> right location is more complicated.  The ARMv8-M Security Extensions
> specification does mention that such a diagnostic might become
> mandatory, so I might have to pick this up later, otherwise it is left
> as a potential extra feature.
> 
> 
> *** gcc/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm-builtins.c (arm_builtins): Define
>         ARM_BUILTIN_CMSE_NONSECURE_CALLER.
>         (bdesc_2arg): Add line for cmse_nonsecure_caller.
>         (arm_expand_builtin): Handle cmse_nonsecure_caller.
>         * config/arm/arm_cmse.h (cmse_nonsecure_caller): New.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse-1.c: Add test for
>         cmse_nonsecure_caller.
> 
Added more documentation as requested.

---

This patch adds support ARMv8-M's Security Extension's
cmse_nonsecure_caller intrinsic. This intrinsic is used to check whether
an entry function was called from a non-secure state.
See Section 5.4.3 of ARM®v8-M Security Extensions: Requirements on
Development Tools
(http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html)
for further details.

The FIXME in config/arm/arm_cmse.h is for a diagnostic message that is
suggested in the ARMv8-M Security Extensions document mentioned above,
to diagnose the use of the cmse_nonsecure_caller intrinsic outside of
functions with the 'cmse_nonsecure_entry' attribute.  Checking whether
the intrinsic is called from within such functions can easily be done
inside 'arm_expand_builtin'. However, making the warning point to the
right location is more complicated.  The ARMv8-M Security Extensions
specification does mention that such a diagnostic might become
mandatory, so I might have to pick this up later, otherwise it is left
as a potential extra feature.


*** gcc/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm-builtins.c (arm_builtins): Define
        ARM_BUILTIN_CMSE_NONSECURE_CALLER.
        (bdesc_2arg): Add line for cmse_nonsecure_caller.
        (arm_expand_builtin): Handle cmse_nonsecure_caller.
        * config/arm/arm_cmse.h (cmse_nonsecure_caller): New.
        * doc/extend.texi (ARM ARMv8-M Security Extensions): New intrinsic.

*** gcc/testsuite/ChangeLog ***
2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse-1.c: Add test for
        cmse_nonsecure_caller.

[-- Attachment #2: diff7 --]
[-- Type: text/plain, Size: 4022 bytes --]

diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index 68b2839879f78e8d819444fbc11d2a91f8d6279a..2589ec2d1233f3daff94a1d35ebf63c8a9b93ecf 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -515,6 +515,8 @@ enum arm_builtins
   ARM_BUILTIN_GET_FPSCR,
   ARM_BUILTIN_SET_FPSCR,
 
+  ARM_BUILTIN_CMSE_NONSECURE_CALLER,
+
 #undef CRYPTO1
 #undef CRYPTO2
 #undef CRYPTO3
@@ -1789,6 +1791,17 @@ arm_init_builtins (void)
 	= add_builtin_function ("__builtin_arm_stfscr", ftype_set_fpscr,
 				ARM_BUILTIN_SET_FPSCR, BUILT_IN_MD, NULL, NULL_TREE);
     }
+
+  if (arm_arch_cmse)
+    {
+      tree ftype_cmse_nonsecure_caller
+	= build_function_type_list (unsigned_type_node, NULL);
+      arm_builtin_decls[ARM_BUILTIN_CMSE_NONSECURE_CALLER]
+	= add_builtin_function ("__builtin_arm_cmse_nonsecure_caller",
+				ftype_cmse_nonsecure_caller,
+				ARM_BUILTIN_CMSE_NONSECURE_CALLER, BUILT_IN_MD,
+				NULL, NULL_TREE);
+    }
 }
 
 /* Return the ARM builtin for CODE.  */
@@ -2368,6 +2381,12 @@ arm_expand_builtin (tree exp,
       emit_insn (pat);
       return target;
 
+    case ARM_BUILTIN_CMSE_NONSECURE_CALLER:
+      target = gen_reg_rtx (SImode);
+      op0 = arm_return_addr (0, NULL_RTX);
+      emit_insn (gen_addsi3 (target, op0, const1_rtx));
+      return target;
+
     case ARM_BUILTIN_TEXTRMSB:
     case ARM_BUILTIN_TEXTRMUB:
     case ARM_BUILTIN_TEXTRMSH:
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
index b4232937c6ae04754a6bbc513b143672a4be5530..d3f529cce90b8a7ecf8132ad40843270e0b229d2 100644
--- a/gcc/config/arm/arm_cmse.h
+++ b/gcc/config/arm/arm_cmse.h
@@ -163,6 +163,13 @@ __attribute__ ((__always_inline__))
 cmse_TTAT (void *__p)
 __CMSE_TT_ASM (at)
 
+/* FIXME: diagnose use outside cmse_nonsecure_entry functions.  */
+__extension__ static __inline int __attribute__ ((__always_inline__))
+cmse_nonsecure_caller (void)
+{
+  return __builtin_arm_cmse_nonsecure_caller ();
+}
+
 #define CMSE_AU_NONSECURE	2
 #define CMSE_MPU_NONSECURE	16
 #define CMSE_NONSECURE		18
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index f1e6a20583f9b16d5a670144a162203a12b239bd..1ec69b088f5dc1def9525450c5513354048e90dd 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12439,6 +12439,7 @@ cmse_address_info_t cmse_TTAT_fptr (FPTR)
 void * cmse_check_address_range (void *, size_t, int)
 typeof(p) cmse_nsfptr_create (FPTR p)
 intptr_t cmse_is_nsfptr (FPTR)
+int cmse_nonsecure_caller (void)
 @end smallexample
 
 @node AVR Built-in Functions
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index d5b9a2d9d59569de170da814ae660e9fb2b943e7..ddcf12a30a6c1806969d239c448da81ccf49532e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -65,3 +65,32 @@ int foo (char * p)
 /* { dg-final { scan-assembler-times "ttat " 2 } } */
 /* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
 /* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
+
+typedef int (*int_ret_funcptr_t) (void);
+typedef int __attribute__ ((cmse_nonsecure_call)) (*int_ret_nsfuncptr_t) (void);
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return cmse_nonsecure_caller ();
+}
+
+int __attribute__ ((cmse_nonsecure_entry))
+qux (int_ret_funcptr_t int_ret_funcptr)
+{
+  int_ret_nsfuncptr_t int_ret_nsfunc_ptr;
+
+  if (cmse_is_nsfptr (int_ret_funcptr))
+    {
+      int_ret_nsfunc_ptr = cmse_nsfptr_create (int_ret_funcptr);
+      return int_ret_nsfunc_ptr ();
+    }
+  return 0;
+}
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "\tcmse_nonsecure_caller" } } */
+/* { dg-final { scan-rtl-dump "and.*reg.*const_int 1" expand } } */
+/* { dg-final { scan-assembler "bic" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */

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

* Re: [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions
  2016-08-24 11:02         ` Andre Vieira (lists)
@ 2016-10-24 16:14           ` Kyrill Tkachov
  0 siblings, 0 replies; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-24 16:14 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

Hi Andre,

On 24/08/16 12:02, Andre Vieira (lists) wrote:
> On 10/08/16 09:08, Andre Vieira (lists) wrote:
>> On 09/08/16 17:47, Sandra Loosemore wrote:
>>> On 08/09/2016 06:01 AM, Andre Vieira (lists) wrote:
>>>> [snip]
>>>>
>>>> The documentation is in the ARMV8-M Security Extensions in: ARM®v8-M
>>>> Security Extensions: Requirements on Development Tools document I linked
>>>> in the email above and subsequent emails
>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>
>>>> Also per patch I refer to the relevant sections. So for instance in
>>>> PATCH 3/7 refers to Section 5.4, which describes Entry functions and
>>>> mentions the cmse_nonsecure_entry attribute. Whereas PATCH 7/7 refers to
>>>> Section 5.4.3 of the same document which describes the
>>>> cmse_nonsecure_caller intrinsic which that patch implements.
>>>>
>>>> Is there a specific intrinsic/attribute you are missing?
>>> You need to at least add entries to the relevant sections in extend.texi
>>> for the new target-specific intrinsic and attributes.  The documentation
>>> there doesn't need to be terribly detailed (one sentence and a link to
>>> the external document is probably all you need), but it's important that
>>> these things be listed in GCC's supported extensions so that users know
>>> they can use them and so that people who see them in code written by
>>> other people can find out what they mean.
>>>
>>> -Sandra
>>>
>>
>> I see, I did add a new entry to extend.texi for ARMv8-M Security
>> Extensions. I will also mention all intrinsics and attributes there.
>>
>> Thank you.
>>
>> Andre
>>
> I updated the patch series with more documentation in extend.texi and I
> also fixed an issue with the clearing of FPSCR.

Can you please rebase the patches on latest trunk and resend them?
I could not apply the first patch with patch -p1 on today's trunk...
I'll try to get to them this week, sorry for the delay.

Thanks,
Kyrill

> Cheers,
> Andre
>

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

* Re: [PATCHv2 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics
  2016-08-24 11:00   ` [PATCHv2 " Andre Vieira (lists)
@ 2016-10-25 16:26     ` Andre Vieira (lists)
  2016-10-26  9:13       ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-25 16:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 24/08/16 12:00, Andre Vieira (lists) wrote:
> On 25/07/16 14:19, Andre Vieira (lists) wrote:
>> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
>> Security Extensions and supports the following intrinsics:
>> cmse_TT
>> cmse_TT_fptr
>> cmse_TTT
>> cmse_TTT_fptr
>> cmse_TTA
>> cmse_TTA_fptr
>> cmse_TTAT
>> cmse_TTAT_fptr
>> cmse_check_address_range
>> cmse_check_pointed_object
>> cmse_is_nsfptr
>> cmse_nsfptr_create
>>
>> It also defines the mandatory cmse_address_info struct and the
>> __ARM_FEATURE_CMSE macro.
>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>> Extensions: Requirements on Development Tools
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> *** gcc/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config.gcc (extra_headers): Added arm_cmse.h.
>>         * config/arm/arm-arches.def (ARM_ARCH):
>>         (armv8-m): Add FL2_CMSE.
>>         (armv8-m.main): Likewise.
>>         (armv8-m.main+dsp): Likewise.
>>         * config/arm/arm-c.c
>>         (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>         * config/arm/arm-protos.h
>>         (arm_is_constant_pool_ref): Define FL2_CMSE.
>>         * config/arm.c (arm_arch_cmse): New.
>>         (arm_option_override): New error for unsupported cmse target.
>>         * config/arm/arm.h (arm_arch_cmse): New.
>>         * config/arm/arm.opt (mcmse): New.
>>         * doc/invoke.texi (ARM Options): Add -mcmse.
>>         * config/arm/arm_cmse.h: New file.
>>
>> *** libgcc/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/cmse.c: Likewise.
>>         * config/arm/t-arm (HAVE_CMSE): New.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/cmse.exp: New.
>>         * gcc.target/arm/cmse/cmse-1.c: New.
>>         * gcc.target/arm/cmse/cmse-12.c: New.
>>         * lib/target-supports.exp
>>         (check_effective_target_arm_cmse_ok): New.
>>
> 
> Added more documentation as requested.
> 
> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
> Security Extensions and supports the following intrinsics:
> cmse_TT
> cmse_TT_fptr
> cmse_TTT
> cmse_TTT_fptr
> cmse_TTA
> cmse_TTA_fptr
> cmse_TTAT
> cmse_TTAT_fptr
> cmse_check_address_range
> cmse_check_pointed_object
> cmse_is_nsfptr
> cmse_nsfptr_create
> 
> It also defines the mandatory cmse_address_info struct and the
> __ARM_FEATURE_CMSE macro.
> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
> Extensions: Requirements on Development Tools
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
> 
> *** gcc/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config.gcc (extra_headers): Added arm_cmse.h.
>         * config/arm/arm-arches.def (ARM_ARCH):
>         (armv8-m): Add FL2_CMSE.
>         (armv8-m.main): Likewise.
>         (armv8-m.main+dsp): Likewise.
>         * config/arm/arm-c.c
>         (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>         * config/arm/arm-protos.h
>         (arm_is_constant_pool_ref): Define FL2_CMSE.
>         * config/arm.c (arm_arch_cmse): New.
>         (arm_option_override): New error for unsupported cmse target.
>         * config/arm/arm.h (arm_arch_cmse): New.
>         * config/arm/arm.opt (mcmse): New.
>         * doc/invoke.texi (ARM Options): Add -mcmse.
>         * doc/extend.texi (ARM ARMv8-M Security Extensions): Add section.
>         * config/arm/arm_cmse.h: New file.
> 
> *** libgcc/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>         * config/arm/cmse.c: Likewise.
>         * config/arm/t-arm (HAVE_CMSE): New.
> 
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse.exp: New.
>         * gcc.target/arm/cmse/cmse-1.c: New.
>         * gcc.target/arm/cmse/cmse-12.c: New.
>         * lib/target-supports.exp
>         (check_effective_target_arm_cmse_ok): New.
> 
Hi,

Rebased previous patch on top of trunk as requested. No changes to
ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff1 --]
[-- Type: text/plain, Size: 23618 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 2143d632fd25892e3633abafe17eee9326b1efd8..63245ecec55c1712e8373b31bcf8c655b4ecfcea 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -322,7 +322,7 @@ arc*-*-*)
 arm*-*-*)
 	cpu_type=arm
 	extra_objs="arm-builtins.o aarch-common.o"
-	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_fp16.h"
+	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_fp16.h arm_cmse.h"
 	target_type_format_char='%'
 	c_target_objs="arm-c.o"
 	cxx_target_objs="arm-c.o"
diff --git a/gcc/config/arm/arm-arches.def b/gcc/config/arm/arm-arches.def
index 4b196a7d1188de5eca028e5c2597bbc20835201f..1bdcf5d9f92404d5d5abb2a53ff89ad3d3ff2794 100644
--- a/gcc/config/arm/arm-arches.def
+++ b/gcc/config/arm/arm-arches.def
@@ -70,10 +70,10 @@ ARM_ARCH ("armv8.2-a+fp16", cortexa53,  8A,
 	  ARM_FSET_MAKE (FL_CO_PROC | FL_CRC32 | FL_FOR_ARCH8A,
 			 FL2_FOR_ARCH8_2A | FL2_FP16INST))
 ARM_ARCH("armv8-m.base", cortexm0, 8M_BASE,
-	 ARM_FSET_MAKE_CPU1 (			      FL_FOR_ARCH8M_BASE))
+	 ARM_FSET_MAKE (			  FL_FOR_ARCH8M_BASE, FL2_CMSE))
 ARM_ARCH("armv8-m.main", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC |	      FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC |		  FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("armv8-m.main+dsp", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("iwmmxt",  iwmmxt,     5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT))
 ARM_ARCH("iwmmxt2", iwmmxt2,    5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT | FL_IWMMXT2))
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index df930f44801e9e5f481ee6eb990656dda4bf0cea..4031083893d8f9cbd44881e008b0cef40f3ad614 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -77,6 +77,14 @@ arm_cpu_builtins (struct cpp_reader* pfile)
 
   def_or_undef_macro (pfile, "__ARM_32BIT_STATE", TARGET_32BIT);
 
+  if (arm_arch8 && !arm_arch_notm)
+    {
+      if (arm_arch_cmse && use_cmse)
+	builtin_define_with_int_value ("__ARM_FEATURE_CMSE", 3);
+      else
+	builtin_define ("__ARM_FEATURE_CMSE");
+    }
+
   if (TARGET_ARM_FEATURE_LDREX)
     builtin_define_with_int_value ("__ARM_FEATURE_LDREX",
 				   TARGET_ARM_FEATURE_LDREX);
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index fd8b6d106d13faebedf7a3539d30159c14f061c6..e7d9f824596a62f5c99000940f6190ab6aee9255 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -396,6 +396,7 @@ extern bool arm_is_constant_pool_ref (rtx);
 #define FL2_ARCH8_2   (1 << 1)	      /* Architecture 8.2.  */
 #define FL2_FP16INST  (1 << 2)	      /* FP16 Instructions for ARMv8.2 and
 					 later.  */
+#define FL2_CMSE      (1 << 3)	      /* ARMv8-M Security Extensions.  */
 
 /* Flags that only effect tuning, not available instructions.  */
 #define FL_TUNE		(FL_WBUF | FL_VFPV2 | FL_STRONG | FL_LDSCHED \
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 8a076ba3d8eb66e237790d23dd7c2ecb4b6fd264..a370dccdaa9fa4c980c1df11cb95a65cad16ac85 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -524,6 +524,9 @@ extern bool arm_disable_literal_pool;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 extern int arm_arch_crc;
 
+/* Nonzero if chip supports the ARMv8-M Security Extensions.  */
+extern int arm_arch_cmse;
+
 #ifndef TARGET_DEFAULT
 #define TARGET_DEFAULT  (MASK_APCS_FRAME)
 #endif
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 022c1d72a1272e56397dc7e2018483e77f18b90d..44677c1bccad42c5ad603ea0951d62abcbd6f05d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -906,6 +906,9 @@ int arm_condexec_masklen = 0;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 int arm_arch_crc = 0;
 
+/* Nonzero if chip supports the ARMv8-M security extensions.  */
+int arm_arch_cmse = 0;
+
 /* Nonzero if the core has a very small, high-latency, multiply unit.  */
 int arm_m_profile_small_mul = 0;
 
@@ -3256,6 +3259,7 @@ arm_option_override (void)
   arm_arch_no_volatile_ce = ARM_FSET_HAS_CPU1 (insn_flags, FL_NO_VOLATILE_CE);
   arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0;
   arm_arch_crc = ARM_FSET_HAS_CPU1 (insn_flags, FL_CRC32);
+  arm_arch_cmse = ARM_FSET_HAS_CPU2 (insn_flags, FL2_CMSE);
   arm_m_profile_small_mul = ARM_FSET_HAS_CPU1 (insn_flags, FL_SMALLMUL);
   arm_fp16_inst = ARM_FSET_HAS_CPU2 (insn_flags, FL2_FP16INST);
   if (arm_fp16_inst)
@@ -3523,6 +3527,9 @@ arm_option_override (void)
   if (target_slow_flash_data || target_pure_code)
     arm_disable_literal_pool = true;
 
+  if (use_cmse && !arm_arch_cmse)
+    error ("target CPU does not support ARMv8-M Security Extensions");
+
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index 35f047e2de1659c2b426cf42dbbdae5be62cbfef..5fb645df71b93960e8cda38c4b5b1d9d37df125c 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -109,6 +109,10 @@ mfloat-abi=
 Target RejectNegative Joined Enum(float_abi_type) Var(arm_float_abi) Init(TARGET_DEFAULT_FLOAT_ABI)
 Specify if floating point hardware should be used.
 
+mcmse
+Target RejectNegative Var(use_cmse)
+Specify that the compiler should target secure code as per ARMv8-M Security Extensions.
+
 Enum
 Name(float_abi_type) Type(enum float_abi_type)
 Known floating-point ABIs (for use with the -mfloat-abi= option):
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
new file mode 100644
index 0000000000000000000000000000000000000000..b4232937c6ae04754a6bbc513b143672a4be5530
--- /dev/null
+++ b/gcc/config/arm/arm_cmse.h
@@ -0,0 +1,192 @@
+/* ARMv8-M Secure Extensions intrinsics include file.
+
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef _GCC_ARM_CMSE_H
+#define _GCC_ARM_CMSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __ARM_BIG_ENDIAN
+
+typedef union {
+  struct cmse_address_info {
+#if __ARM_FEATURE_CMSE & 2
+    unsigned idau_region:8;
+    unsigned idau_region_valid:1;
+    unsigned secure:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned nonsecure_read_ok:1;
+#else
+    unsigned :12;
+#endif
+    unsigned readwrite_ok:1;
+    unsigned read_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region:8;
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#else
+
+typedef union {
+  struct cmse_address_info {
+    unsigned mpu_region:8;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned read_ok:1;
+    unsigned readwrite_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned nonsecure_read_ok:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned secure:1;
+    unsigned idau_region_valid:1;
+    unsigned idau_region:8;
+#else
+    unsigned :12;
+#endif
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#endif /* __ARM_BIG_ENDIAN */
+
+#define cmse_TT_fptr(p) (__cmse_TT_fptr ((__cmse_fptr)(p)))
+
+typedef void (*__cmse_fptr)(void);
+
+#define __CMSE_TT_ASM(flags) \
+{ \
+  cmse_address_info_t __result; \
+   __asm__ ("tt" # flags " %0,%1" \
+	   : "=r"(__result) \
+	   : "r"(__p) \
+	   : "memory"); \
+  return __result; \
+}
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM ()
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT (void *__p)
+__CMSE_TT_ASM ()
+
+#define cmse_TTT_fptr(p) (__cmse_TTT_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TTT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (t)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT (void *__p)
+__CMSE_TT_ASM (t)
+
+#if __ARM_FEATURE_CMSE & 2
+
+#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TTA_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (a)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA (void *__p)
+__CMSE_TT_ASM (a)
+
+#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+__cmse_TTAT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (at)
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT (void *__p)
+__CMSE_TT_ASM (at)
+
+#define CMSE_AU_NONSECURE	2
+#define CMSE_MPU_NONSECURE	16
+#define CMSE_NONSECURE		18
+
+#endif /* __ARM_FEATURE_CMSE & 2 */
+
+#define CMSE_MPU_UNPRIV		4
+#define CMSE_MPU_READWRITE	1
+#define CMSE_MPU_READ		8
+
+__extension__ void *
+cmse_check_address_range (void *, size_t, int);
+
+#define cmse_check_pointed_object(p, f) \
+  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
+
+#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
+
+#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
+
+#endif /* __ARM_FEATURE_CMSE & 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GCC_ARM_CMSE_H */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0669f7999beb078822e471352036d8f13517812d..3f6fc27950fafa2e7649deb9dc5db44737cbb691 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -11753,6 +11753,7 @@ instructions, but allow the compiler to schedule those calls.
 * ARM iWMMXt Built-in Functions::
 * ARM C Language Extensions (ACLE)::
 * ARM Floating Point Status and Control Intrinsics::
+* ARM ARMv8-M Security Extensions::
 * AVR Built-in Functions::
 * Blackfin Built-in Functions::
 * FR-V Built-in Functions::
@@ -12598,6 +12599,31 @@ unsigned int __builtin_arm_get_fpscr ()
 void __builtin_arm_set_fpscr (unsigned int)
 @end smallexample
 
+@node ARM ARMv8-M Security Extensions
+@subsection ARM ARMv8-M Security Extensions
+
+GCC implements the ARMv8-M Security Extensions as described in the ARMv8-M
+Security Extensions: Requiremenets on Development Tools Engineering
+Specification, which can be found at
+@uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
+
+As part of the Security Extensions GCC implements the intrinsics below.  FPTR
+is used here to mean any function pointer type.
+
+@smallexample
+cmse_address_info_t cmse_TT (void *)
+cmse_address_info_t cmse_TT_fptr (FPTR)
+cmse_address_info_t cmse_TTT (void *)
+cmse_address_info_t cmse_TTT_fptr (FPTR)
+cmse_address_info_t cmse_TTA (void *)
+cmse_address_info_t cmse_TTA_fptr (FPTR)
+cmse_address_info_t cmse_TTAT (void *)
+cmse_address_info_t cmse_TTAT_fptr (FPTR)
+void * cmse_check_address_range (void *, size_t, int)
+typeof(p) cmse_nsfptr_create (FPTR p)
+intptr_t cmse_is_nsfptr (FPTR)
+@end smallexample
+
 @node AVR Built-in Functions
 @subsection AVR Built-in Functions
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5ccd4244ef396696f1a7ca962a7a7fe9973fcf6e..13caf3c3bef2564d2c0152a95d520b6869ffda36 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -645,7 +645,8 @@ Objective-C and Objective-C++ Dialects}.
 -mslow-flash-data @gol
 -masm-syntax-unified @gol
 -mrestrict-it @gol
--mpure-code}
+-mpure-code @gol
+-mcmse}
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol
@@ -15170,6 +15171,11 @@ Additionally, when compiling for ELF object format give all text sections the
 ELF processor-specific section attribute @code{SHF_ARM_PURECODE}.  This option
 is only available when generating non-pic code for ARMv7-M targets.
 
+@item -mcmse
+@opindex mcmse
+Generate secure code as per the "ARMv8-M Security Extensions: Requirements on
+Development Tools Engineering Specification", which can be found on
+@url{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 @end table
 
 @node AVR Options
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..d5b9a2d9d59569de170da814ae660e9fb2b943e7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mcmse -fdump-rtl-expand" }  */
+
+#include <arm_cmse.h>
+
+extern int a;
+extern int bar (void);
+
+int foo (char * p)
+{
+  cmse_address_info_t cait;
+
+  cait = cmse_TT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTA (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTA_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTAT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTAT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char), 0);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_READWRITE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV | CMSE_MPU_READ);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_AU_NONSECURE
+					 | CMSE_MPU_NONSECURE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  p = (char *) cmse_check_pointed_object (p, CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  return a;
+}
+/* { dg-final { scan-assembler-times "\ttt " 2 } } */
+/* { dg-final { scan-assembler-times "ttt " 2 } } */
+/* { dg-final { scan-assembler-times "tta " 2 } } */
+/* { dg-final { scan-assembler-times "ttat " 2 } } */
+/* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
+/* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
new file mode 100644
index 0000000000000000000000000000000000000000..87a2f1363a4e4bd817503e79e504980210e722c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+#include <arm_cmse.h>
+
+char *
+foo (char * p)
+{
+  if (!cmse_is_nsfptr (p))
+    return cmse_nsfptr_create (p);
+}
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler-not "cmse_is_nsfptr" } } */
+/* { dg-final { scan-assembler-not "cmse_nsfptr_create" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
new file mode 100644
index 0000000000000000000000000000000000000000..f797dba1901720e04249d61078c1cbf2a3e436a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -0,0 +1,50 @@
+#   Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite for ARMv8-M Security Extensions using the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Exit immediately if the target does not support -mcmse.
+if ![check_effective_target_arm_cmse_ok] then {
+    return
+}
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+set saved-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default "assemble"
+
+set saved-lto_torture_options ${LTO_TORTURE_OPTIONS}
+set LTO_TORTURE_OPTIONS ""
+
+# These are for both baseline and mainline.
+gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
+	"" $DEFAULT_CFLAGS
+
+set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index b5a9faab5a47d01371c6402a5b07d34071dbc34b..eaeaf056c611889993b118d48a7aeb20e95be477 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -3866,6 +3866,19 @@ proc check_effective_target_arm_thumb1_cbz_ok {} {
     }
 }
 
+# Return 1 if this is an ARM target where ARMv8-M Security Extensions is
+# available.
+
+proc check_effective_target_arm_cmse_ok {} {
+    return [check_no_compiler_messages arm_cmse object {
+	int
+	foo (void)
+	{
+	  asm ("bxns r0");
+	}
+    } "-mcmse"];
+}
+
 # Return 1 if this compilation turns on string_ops_prefer_neon on.
 
 proc check_effective_target_arm_tune_string_ops_prefer_neon { } {
diff --git a/libgcc/config/arm/cmse.c b/libgcc/config/arm/cmse.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe3a22967c8536f2a8c05b58627f964d3fb1d345
--- /dev/null
+++ b/libgcc/config/arm/cmse.c
@@ -0,0 +1,108 @@
+/* ARMv8-M Security Extensions routines.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <arm_cmse.h>
+
+/* ARM intrinsic function to perform a permission check on a given
+   address range.  See ACLE changes for ARMv8-M.  */
+
+void *
+cmse_check_address_range (void *p, size_t size, int flags)
+{
+  cmse_address_info_t permb, perme;
+  char *pb = (char *) p, *pe;
+
+  /* Check if the range wraps around.  */
+  if (UINTPTR_MAX - (uintptr_t) p < size)
+    return NULL;
+
+  /* Check if an unknown flag is present.  */
+  int known = CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE | CMSE_MPU_READ;
+  int known_secure_level = CMSE_MPU_UNPRIV;
+#if __ARM_FEATURE_CMSE & 2
+  known |= CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE;
+  known_secure_level |= CMSE_MPU_NONSECURE;
+#endif
+  if (flags & (~known))
+    return NULL;
+
+  /* Execute the right variant of the TT instructions.  */
+  pe = pb + size - 1;
+  const int singleCheck = (((uintptr_t) pb ^ (uintptr_t) pe) < 32);
+  switch (flags & known_secure_level)
+    {
+    case 0:
+      permb = cmse_TT (pb);
+      perme = singleCheck ? permb : cmse_TT (pe);
+      break;
+    case CMSE_MPU_UNPRIV:
+      permb = cmse_TTT (pb);
+      perme = singleCheck ? permb : cmse_TTT (pe);
+      break;
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_NONSECURE:
+      permb = cmse_TTA (pb);
+      perme = singleCheck ? permb : cmse_TTA (pe);
+      break;
+    case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+      permb = cmse_TTAT (pb);
+      perme = singleCheck ? permb : cmse_TTAT (pe);
+      break;
+#endif
+    default:
+      /* Invalid flag, eg.  CMSE_MPU_NONSECURE specified but
+	 __ARM_FEATURE_CMSE & 2 == 0.  */
+      return NULL;
+    }
+
+  /* Check that the range does not cross MPU, SAU, or IDAU boundaries.  */
+  if (permb.value != perme.value)
+    return NULL;
+
+  /* Check the permissions on the range.  */
+  switch (flags & (~known_secure_level))
+    {
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+    case		 CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_readwrite_ok	? p : NULL;
+    case CMSE_MPU_READ | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_read_ok	? p : NULL;
+    case CMSE_AU_NONSECURE:
+      return permb.flags.secure			? NULL : p;
+#endif
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE:
+    case		 CMSE_MPU_READWRITE:
+      return permb.flags.readwrite_ok		? p : NULL;
+    case CMSE_MPU_READ:
+      return permb.flags.read_ok		? p : NULL;
+    default:
+      return NULL;
+    }
+}
+
+
+#endif /* __ARM_FEATURE_CMSE & 1.  */
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 4e17e99b4a53bbafc0f1f8dddd02000f0e8f4f48..5618143bfd0f02b170db3f9e4c0a15cecb403cec 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -1,3 +1,15 @@
 LIB1ASMSRC = arm/lib1funcs.S
 LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
 	_thumb1_case_uhi _thumb1_case_si
+
+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),)
+CMSE_OPTS:=-mcmse
+endif
+
+ifdef HAVE_CMSE
+libgcc-objects += cmse.o cmse_nonsecure_call.o
+
+cmse.o: $(srcdir)/config/arm/cmse.c
+	$(gcc_compile) -c $(CMSE_OPTS) $<
+endif

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

* Re: [PATCHv2 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
  2016-08-24 11:01   ` [PATCHv2 " Andre Vieira (lists)
@ 2016-10-25 16:28     ` Andre Vieira (lists)
  2016-10-26  9:33       ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-25 16:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 24/08/16 12:00, Andre Vieira (lists) wrote:
> On 25/07/16 14:21, Andre Vieira (lists) wrote:
>> This patch adds support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_entry' attribute. In this patch we implement the
>> attribute handling and diagnosis around the attribute. See Section 5.4
>> of ARM®v8-M Security Extensions
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> *** gcc/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
>>         (arm_attribute_table): Added cmse_nonsecure_entry
>>         (arm_compute_func_type): Handle cmse_nonsecure_entry.
>>         (cmse_func_args_or_return_in_stack): New.
>>         (arm_handle_cmse_nonsecure_entry): New.
>>         * config/arm/arm.h (ARM_FT_CMSE_ENTRY): New macro define.
>>         (IS_CMSE_ENTRY): Likewise.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/cmse-3.c: New.
>>
> 
> Added more documentation as requested.
> 
> ----
> 
> This patch adds support for the ARMv8-M Security Extensions
> 'cmse_nonsecure_entry' attribute. In this patch we implement the
> attribute handling and diagnosis around the attribute. See Section 5.4
> of ARM®v8-M Security Extensions
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
> 
> *** gcc/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
>         (arm_attribute_table): Added cmse_nonsecure_entry
>         (arm_compute_func_type): Handle cmse_nonsecure_entry.
>         (cmse_func_args_or_return_in_stack): New.
>         (arm_handle_cmse_nonsecure_entry): New.
>         * config/arm/arm.h (ARM_FT_CMSE_ENTRY): New macro define.
>         (IS_CMSE_ENTRY): Likewise.
>         * doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse-3.c: New.
> 
Hi,

Rebased previous patch on top of trunk as requested. No changes to
ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff2 --]
[-- Type: text/plain, Size: 8021 bytes --]

diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index a370dccdaa9fa4c980c1df11cb95a65cad16ac85..44d1ac45b03dec210e6986f103bf8588119a8aa8 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -1386,6 +1386,7 @@ enum reg_class
 #define ARM_FT_VOLATILE		(1 << 4) /* Does not return.  */
 #define ARM_FT_NESTED		(1 << 5) /* Embedded inside another func.  */
 #define ARM_FT_STACKALIGN	(1 << 6) /* Called with misaligned stack.  */
+#define ARM_FT_CMSE_ENTRY	(1 << 7) /* ARMv8-M non-secure entry function.  */
 
 /* Some macros to test these flags.  */
 #define ARM_FUNC_TYPE(t)	(t & ARM_FT_TYPE_MASK)
@@ -1394,6 +1395,7 @@ enum reg_class
 #define IS_NAKED(t)        	(t & ARM_FT_NAKED)
 #define IS_NESTED(t)       	(t & ARM_FT_NESTED)
 #define IS_STACKALIGN(t)       	(t & ARM_FT_STACKALIGN)
+#define IS_CMSE_ENTRY(t)	(t & ARM_FT_CMSE_ENTRY)
 
 
 /* Structure used to hold the function stack frame layout.  Offsets are
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 44677c1bccad42c5ad603ea0951d62abcbd6f05d..996f917ae1dc8e16f219984738c3ac3f8b42f09f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -135,6 +135,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
+static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -347,6 +348,9 @@ static const struct attribute_spec arm_attribute_table[] =
   { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute,
     false },
 #endif
+  /* ARMv8-M Security Extensions support.  */
+  { "cmse_nonsecure_entry", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_entry, false },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -3662,6 +3666,9 @@ arm_compute_func_type (void)
   else
     type |= arm_isr_value (TREE_VALUE (a));
 
+  if (lookup_attribute ("cmse_nonsecure_entry", attr))
+    type |= ARM_FT_CMSE_ENTRY;
+
   return type;
 }
 
@@ -6661,6 +6668,110 @@ arm_handle_notshared_attribute (tree *node,
 }
 #endif
 
+/* This function returns true if a function with declaration FNDECL, name
+   NAME and type FNTYPE uses the stack to pass arguments or return variables
+   and false otherwise.  This is used for functions with the attributes
+   'cmse_nonsecure_call' or 'cmse_nonsecure_entry' and this function will issue
+   diagnostic messages if the stack is used.  */
+
+static bool
+cmse_func_args_or_return_in_stack (tree fndecl, tree name, tree fntype)
+{
+  function_args_iterator args_iter;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
+  bool first_param = true;
+  tree arg_type, prev_arg_type = NULL_TREE, ret_type;
+
+  /* Error out if any argument is passed on the stack.  */
+  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX, fndecl);
+  args_so_far = pack_cumulative_args (&args_so_far_v);
+  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+    {
+      rtx arg_rtx;
+      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+      prev_arg_type = arg_type;
+      if (VOID_TYPE_P (arg_type))
+	continue;
+
+      if (!first_param)
+	arm_function_arg_advance (args_so_far, arg_mode, arg_type, true);
+      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type, true);
+      if (!arg_rtx
+	  || arm_arg_partial_bytes (args_so_far, arg_mode, arg_type, true))
+	{
+	  error ("%qE attribute not available to functions with arguments "
+		 "passed on the stack", name);
+	  return true;
+	}
+      first_param = false;
+    }
+
+  /* Error out for variadic functions since we cannot control how many
+     arguments will be passed and thus stack could be used.  stdarg_p () is not
+     used for the checking to avoid browsing arguments twice.  */
+  if (prev_arg_type != NULL_TREE && !VOID_TYPE_P (prev_arg_type))
+    {
+      error ("%qE attribute not available to functions with variable number "
+	     "of arguments", name);
+      return true;
+    }
+
+  /* Error out if return value is passed on the stack.  */
+  ret_type = TREE_TYPE (fntype);
+  if (arm_return_in_memory (ret_type, fntype))
+    {
+      error ("%qE attribute not available to functions that return value on "
+	     "the stack", name);
+      return true;
+    }
+  return false;
+}
+
+/* Called upon detection of the use of the cmse_nonsecure_entry attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function declaration tree or otherwise issue a warning.  */
+
+static tree
+arm_handle_cmse_nonsecure_entry (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree fndecl;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Ignore attribute for function types.  */
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+	       name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  fndecl = *node;
+
+  /* Warn for static linkage functions.  */
+  if (!TREE_PUBLIC (fndecl))
+    {
+      warning (OPT_Wattributes, "%qE attribute has no effect on functions "
+	       "with static linkage", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (fndecl, name,
+						TREE_TYPE (fndecl));
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 3f6fc27950fafa2e7649deb9dc5db44737cbb691..e5b28032e5610b896908139ec285ce90a9dffd8a 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12607,6 +12607,9 @@ Security Extensions: Requiremenets on Development Tools Engineering
 Specification, which can be found at
 @uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 
+As part of the Security Extensions GCC implements a new function attribute
+@code{cmse_nonsecure_entry}.
+
 As part of the Security Extensions GCC implements the intrinsics below.  FPTR
 is used here to mean any function pointer type.
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c2920e1dc310106d83203eb51e1a68a275d0152
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+struct span2 {
+  float a, b, c, d;
+};
+
+union test_union
+{
+  long long a;
+  int b;
+  struct span2 c;
+} test_union;
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (long long a, int b, long long c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+bar (long long a, int b, struct span c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+baz (int a, ...) {} /* { dg-error "not available to functions with variable number of arguments" } */
+
+struct span __attribute__ ((cmse_nonsecure_entry))
+qux (void) { /* { dg-error "not available to functions that return value on the stack" } */
+  struct span ret = {0, 0};
+  return ret;
+}
+
+void __attribute__ ((cmse_nonsecure_entry))
+norf (struct span2 a) {}
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */

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

* Re: [PATCH 3/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return
  2016-07-25 13:23 ` [PATCH 3/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return Andre Vieira (lists)
@ 2016-10-25 16:29   ` Andre Vieira (lists)
  2016-10-26 10:03     ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-25 16:29 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 25/07/16 14:23, Andre Vieira (lists) wrote:
> This patch extends support for the ARMv8-M Security Extensions
> 'cmse_nonsecure_entry' attribute in two ways:
> 
> 1) Generate two labels for the function, the regular function name and
> one with the function's name appended to '__acle_se_', this will trigger
> the linker to create a secure gateway veneer for this entry function.
> 2) Return from cmse_nonsecure_entry marked functions using bxns.
> 
> See Section 5.4 of ARM®v8-M Security Extensions
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
> 
> 
> *** gcc/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (use_return_insn): Change to return with  bxns
>         when cmse_nonsecure_entry.
>         (output_return_instruction): Likewise.
>         (arm_output_function_prologue): Likewise.
>         (thumb_pop): Likewise.
>         (thumb_exit): Likewise.
>         (arm_function_ok_for_sibcall): Disable sibcall for entry functions.
>         (arm_asm_declare_function_name): New.
>         * config/arm/arm-protos.h (arm_asm_declare_function_name): New.
>         * config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
>         use arm_asm_declare_function_name.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse-2.c: New.
>         * gcc.target/arm/cmse/cmse-4.c: New.
> 
Hi,

Rebased previous patch on top of trunk as requested. No changes to
ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff3 --]
[-- Type: text/plain, Size: 10608 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index e7d9f824596a62f5c99000940f6190ab6aee9255..a9b8326c2770c1f9a9787743cb5faa549e6b7d02 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -31,6 +31,7 @@ extern int arm_volatile_func (void);
 extern void arm_expand_prologue (void);
 extern void arm_expand_epilogue (bool);
 extern void arm_declare_function_name (FILE *, const char *, tree);
+extern void arm_asm_declare_function_name (FILE *, const char *, tree);
 extern void thumb2_expand_return (bool);
 extern const char *arm_strip_name_encoding (const char *);
 extern void arm_asm_output_labelref (FILE *, const char *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 996f917ae1dc8e16f219984738c3ac3f8b42f09f..bb81e5662e81a26c7d3ccf9f749e8e356e6de35e 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3895,6 +3895,11 @@ use_return_insn (int iscond, rtx sibling)
 	return 0;
     }
 
+  /* 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))
+    return 0;
+
   /* If there are saved registers but the LR isn't saved, then we need
      two instructions for the return.  */
   if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
@@ -6930,6 +6935,11 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
   if (IS_INTERRUPT (func_type))
     return false;
 
+  /* ARMv8-M non-secure entry functions need to return with bxns which is only
+     generated for entry functions themselves.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    return false;
+
   if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
     {
       /* Check that the return value locations are the same.  For
@@ -19765,6 +19775,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	 (e.g. interworking) then we can load the return address
 	 directly into the PC.  Otherwise we must load it into LR.  */
       if (really_return
+	  && !IS_CMSE_ENTRY (func_type)
 	  && (IS_INTERRUPT (func_type) || !TARGET_INTERWORK))
 	return_reg = reg_names[PC_REGNUM];
       else
@@ -19905,8 +19916,10 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	  break;
 
 	default:
+	  if (IS_CMSE_ENTRY (func_type))
+	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
 	  /* Use bx if it's available.  */
-	  if (arm_arch5 || arm_arch4t)
+	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
 	  else
 	    sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
@@ -19919,6 +19932,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
   return "";
 }
 
+/* Output in FILE asm statements needed to declare the NAME of the function
+   defined by its DECL node.  */
+
+void
+arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
+{
+  size_t cmse_name_len;
+  char *cmse_name = 0;
+  char cmse_prefix[] = "__acle_se_";
+
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_entry",
+				    DECL_ATTRIBUTES (decl)))
+    {
+      cmse_name_len = sizeof (cmse_prefix) + strlen (name);
+      cmse_name = XALLOCAVEC (char, cmse_name_len);
+      snprintf (cmse_name, cmse_name_len, "%s%s", cmse_prefix, name);
+      targetm.asm_out.globalize_label (file, cmse_name);
+    }
+
+  if (cmse_name)
+    {
+      ARM_DECLARE_FUNCTION_NAME (file, cmse_name, decl);
+      ASM_OUTPUT_TYPE_DIRECTIVE (file, cmse_name, "function");
+    }
+
+  ARM_DECLARE_FUNCTION_NAME (file, name, decl);
+  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
+  ASM_OUTPUT_LABEL (file, name);
+
+  if (cmse_name)
+    ASM_OUTPUT_LABEL (file, cmse_name);
+
+  ARM_OUTPUT_FN_UNWIND (file, TRUE);
+}
+
 /* Write the function name into the code section, directly preceding
    the function prologue.
 
@@ -19968,10 +20017,6 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
 {
   unsigned long func_type;
 
-  /* ??? Do we want to print some of the below anyway?  */
-  if (TARGET_THUMB1)
-    return;
-
   /* Sanity check.  */
   gcc_assert (!arm_ccfsm_state && !arm_target_insn);
 
@@ -20006,6 +20051,8 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
     asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
   if (IS_STACKALIGN (func_type))
     asm_fprintf (f, "\t%@ Stack Align: May be called with mis-aligned SP.\n");
+  if (IS_CMSE_ENTRY (func_type))
+    asm_fprintf (f, "\t%@ Non-secure entry function: called from non-secure code.\n");
 
   asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
 	       crtl->args.size,
@@ -24072,8 +24119,8 @@ thumb_pop (FILE *f, unsigned long mask)
   if (mask & (1 << PC_REGNUM))
     {
       /* Catch popping the PC.  */
-      if (TARGET_INTERWORK || TARGET_BACKTRACE
-	  || crtl->calls_eh_return)
+      if (TARGET_INTERWORK || TARGET_BACKTRACE || crtl->calls_eh_return
+	  || IS_CMSE_ENTRY (arm_current_func_type ()))
 	{
 	  /* The PC is never poped directly, instead
 	     it is popped into r3 and then BX is used.  */
@@ -24134,7 +24181,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
       if (crtl->calls_eh_return)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
-      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+      else
+	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
     }
   /* Otherwise if we are not supporting interworking and we have not created
@@ -24143,7 +24193,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
   else if (!TARGET_INTERWORK
 	   && !TARGET_BACKTRACE
 	   && !is_called_in_ARM_mode (current_function_decl)
-	   && !crtl->calls_eh_return)
+	   && !crtl->calls_eh_return
+	   && !IS_CMSE_ENTRY (arm_current_func_type ()))
     {
       asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
       return;
@@ -24366,7 +24417,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
     asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
   /* Return to caller.  */
-  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+  else
+    asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
 \f
 /* Scan INSN just before assembler is output for it.
@@ -25247,6 +25301,12 @@ thumb2_expand_return (bool simple_return)
 
   if (!simple_return && saved_regs_mask)
     {
+      /* TODO: Verify that this path is never taken for cmse_nonsecure_entry
+	 functions or adapt code to handle according to ACLE.  This path should
+	 not be reachable for cmse_nonsecure_entry functions though we prefer
+	 to guard it for now to ensure that future code changes do not silently
+	 change this behavior.  */
+      gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
       if (num_regs == 1)
         {
           rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
@@ -25664,6 +25724,7 @@ arm_expand_epilogue (bool really_return)
 
       if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
           && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
+	  && !IS_CMSE_ENTRY (func_type)
           && !IS_STACKALIGN (func_type)
           && really_return
           && crtl->args.pretend_args_size == 0
diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h
index bc4eb86f1da5beabf32647637eb87a3fc17a6c6a..03931eee7390ab4d09522e7d8bea10449719ddba 100644
--- a/gcc/config/arm/elf.h
+++ b/gcc/config/arm/elf.h
@@ -75,16 +75,7 @@
 
 /* We might need a ARM specific header to function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_NAME
-#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)		\
-  do								\
-    {								\
-      ARM_DECLARE_FUNCTION_NAME (FILE, NAME, DECL);		\
-      ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");	\
-      ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));		\
-      ASM_OUTPUT_LABEL(FILE, NAME);				\
-      ARM_OUTPUT_FN_UNWIND (FILE, TRUE);			\
-    }								\
-  while (0)
+#define ASM_DECLARE_FUNCTION_NAME arm_asm_declare_function_name
 
 /* We might need an ARM specific trailer for function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_SIZE
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a91ac39ee37ef20495e047b402d3f5edc60a613
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+void
+foo (void) {}
+
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f930ab04a1097c64097a4e003296bbe85733319
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+
+extern int qux (void);
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (void) {}
+
+static void __attribute__ ((cmse_nonsecure_entry))
+bar (void) {} /* { dg-warning "has no effect on functions with static linkage" } */
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return qux ();
+}
+
+/* { dg-final { scan-assembler-times "bxns" 2 } } */
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..65200bcf29b219706911bbb799c847aefc92cb1c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
+
+
+int __attribute__ ((cmse_nonsecure_entry))
+foo (int a)
+{
+  return a + 1;
+}
+
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-08-24 11:01   ` [PATCHv2 " Andre Vieira (lists)
@ 2016-10-25 16:29     ` Andre Vieira (lists)
  2016-10-26 12:51       ` Kyrill Tkachov
  2016-10-26 14:14       ` [PATCHv2 4/7, GCC, ARM, V8M] " Kyrill Tkachov
  0 siblings, 2 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-25 16:29 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 24/08/16 12:01, Andre Vieira (lists) wrote:
> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>> This patch extends support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>> information through unbanked registers.
>>
>> When returning from a nonsecure entry function we clear all caller-saved
>> registers that are not used to pass return values, by writing either the
>> LR, in case of general purpose registers, or the value 0, in case of FP
>> registers. We use the LR to write to APSR and FPSCR too. We currently do
>> not support entry functions that pass arguments or return variables on
>> the stack and we diagnose this. This patch relies on the existing code
>> to make sure callee-saved registers used in cmse_nonsecure_entry
>> functions are saved and restored thus retaining their nonsecure mode
>> value, this should be happening already as it is required by AAPCS.
>>
>> This patch also clears padding bits for cmse_nonsecure_entry functions
>> with struct and union return types. For unions a bit is only considered
>> a padding bit if it is an unused bit in every field of that union. The
>> function that calculates these is used in a later patch to do the same
>> for arguments of cmse_nonsecure_call's.
>>
>> *** gcc/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm.c (output_return_instruction): Clear
>>         registers.
>>         (thumb2_expand_return): Likewise.
>>         (thumb1_expand_epilogue): Likewise.
>>         (thumb_exit): Likewise.
>>         (arm_expand_epilogue): Likewise.
>>         (cmse_nonsecure_entry_clear_before_return): New.
>>         (comp_not_to_clear_mask_str_un): New.
>>         (compute_not_to_clear_mask): New.
>>         * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
>>         * config/arm/thumb2.md (*thumb2_return): Likewise.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
>>         * gcc.target/arm/cmse/struct-1.c: New.
>>         * gcc.target/arm/cmse/bitfield-1.c: New.
>>         * gcc.target/arm/cmse/bitfield-2.c: New.
>>         * gcc.target/arm/cmse/bitfield-3.c: New.
>>         * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
>> cleared.
>>         * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>         * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>         * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>
> 
> Updated this patch to correctly clear only the cumulative
> exception-status (0-4,7) and the condition code bits (28-31) of the
> FPSCR. I also adapted the code to be handle the bigger floating point
> register files.
> 
> ----
> 
> This patch extends support for the ARMv8-M Security Extensions
> 'cmse_nonsecure_entry' attribute to safeguard against leak of
> information through unbanked registers.
> 
> When returning from a nonsecure entry function we clear all caller-saved
> registers that are not used to pass return values, by writing either the
> LR, in case of general purpose registers, or the value 0, in case of FP
> registers. We use the LR to write to APSR. For FPSCR we clear only the
> cumulative exception-status (0-4, 7) and the condition code bits
> (28-31). We currently do not support entry functions that pass arguments
> or return variables on the stack and we diagnose this. This patch relies
> on the existing code to make sure callee-saved registers used in
> cmse_nonsecure_entry functions are saved and restored thus retaining
> their nonsecure mode value, this should be happening already as it is
> required by AAPCS.
> 
> This patch also clears padding bits for cmse_nonsecure_entry functions
> with struct and union return types. For unions a bit is only considered
> a padding bit if it is an unused bit in every field of that union. The
> function that calculates these is used in a later patch to do the same
> for arguments of cmse_nonsecure_call's.
> 
> *** gcc/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (output_return_instruction): Clear
>         registers.
>         (thumb2_expand_return): Likewise.
>         (thumb1_expand_epilogue): Likewise.
>         (thumb_exit): Likewise.
>         (arm_expand_epilogue): Likewise.
>         (cmse_nonsecure_entry_clear_before_return): New.
>         (comp_not_to_clear_mask_str_un): New.
>         (compute_not_to_clear_mask): New.
>         * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
>         * config/arm/thumb2.md (*thumb2_return): Duplicate pattern for
>         cmse_nonsecure_entry functions.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
>         * gcc.target/arm/cmse/struct-1.c: New.
>         * gcc.target/arm/cmse/bitfield-1.c: New.
>         * gcc.target/arm/cmse/bitfield-2.c: New.
>         * gcc.target/arm/cmse/bitfield-3.c: New.
>         * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
> cleared.
>         * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>         * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>         * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>         * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
> 
Hi,

Rebased previous patch on top of trunk as requested. No changes to
ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff4 --]
[-- Type: text/plain, Size: 39141 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index bb81e5662e81a26c7d3ccf9f749e8e356e6de35e..c6260323ecfd2f2842e6a5aab06b67da16619c73 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17496,6 +17496,279 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
   return;
 }
 
+/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for structs
+   and unions in the context of ARMv8-M Security Extensions.  It is used as a
+   helper function for both 'cmse_nonsecure_call' and 'cmse_nonsecure_entry'
+   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to either one
+   or four masks, depending on whether it is being computed for a
+   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
+   respectively.  The tree for the type of the argument or a field within an
+   argument is passed in ARG_TYPE, the current register this argument or field
+   starts in is kept in the pointer REGNO and updated accordingly, the bit this
+   argument or field starts at is passed in STARTING_BIT and the last used bit
+   is kept in LAST_USED_BIT which is also updated accordingly.  */
+
+static unsigned HOST_WIDE_INT
+comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
+			       uint32_t * padding_bits_to_clear,
+			       unsigned starting_bit, int * last_used_bit)
+
+{
+  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
+
+  if (TREE_CODE (arg_type) == RECORD_TYPE)
+    {
+      unsigned current_bit = starting_bit;
+      tree field;
+      long int offset, size;
+
+
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  /* The offset within a structure is always an offset from
+	     the start of that structure.  Make sure we take that into the
+	     calculation of the register based offset that we use here.  */
+	  offset = starting_bit;
+	  offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
+	  offset %= 32;
+
+	  /* This is the actual size of the field, for bitfields this is the
+	     bitfield width and not the container size.  */
+	  size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+
+	  if (*last_used_bit != offset)
+	    {
+	      if (offset < *last_used_bit)
+		{
+		  /* This field's offset is before the 'last_used_bit', that
+		     means this field goes on the next register.  So we need to
+		     pad the rest of the current register and increase the
+		     register number.  */
+		  uint32_t mask;
+		  mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
+		  mask++;
+
+		  *(padding_bits_to_clear + *regno) |= mask;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      else
+		{
+		  /* Otherwise we pad the bits between the last field's end and
+		     the start of the new field.  */
+		  uint32_t mask;
+
+		  mask = UINT32_MAX >> (32 - offset);
+		  mask -= ((uint32_t) 1 << *last_used_bit) - 1;
+		  *(padding_bits_to_clear + *regno) |= mask;
+		}
+	      current_bit = offset;
+	    }
+
+	  /* Calculate further padding bits for inner structs/unions too.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	    {
+	      *last_used_bit = current_bit;
+	      not_to_clear_reg_mask
+		|= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
+						  padding_bits_to_clear, offset,
+						  last_used_bit);
+	    }
+	  else
+	    {
+	      /* Update 'current_bit' with this field's size.  If the
+		 'current_bit' lies in a subsequent register, update 'regno' and
+		 reset 'current_bit' to point to the current bit in that new
+		 register.  */
+	      current_bit += size;
+	      while (current_bit >= 32)
+		{
+		  current_bit-=32;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      *last_used_bit = current_bit;
+	    }
+
+	  field = TREE_CHAIN (field);
+	}
+      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+    }
+  else if (TREE_CODE (arg_type) == UNION_TYPE)
+    {
+      tree field, field_t;
+      int i, regno_t, field_size;
+      int max_reg = -1;
+      int max_bit = -1;
+      uint32_t mask;
+      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
+	= {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
+
+      /* To compute the padding bits in a union we only consider bits as
+	 padding bits if they are always either a padding bit or fall outside a
+	 fields size for all fields in the union.  */
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
+	    = {0U, 0U, 0U, 0U};
+	  int last_used_bit_t = *last_used_bit;
+	  regno_t = *regno;
+	  field_t = TREE_TYPE (field);
+
+	  /* If the field's type is either a record or a union make sure to
+	     compute their padding bits too.  */
+	  if (RECORD_OR_UNION_TYPE_P (field_t))
+	    not_to_clear_reg_mask
+	      |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
+						&padding_bits_to_clear_t[0],
+						starting_bit, &last_used_bit_t);
+	  else
+	    {
+	      field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+	      regno_t = (field_size / 32) + *regno;
+	      last_used_bit_t = (starting_bit + field_size) % 32;
+	    }
+
+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;
+
+	  /* Update the maximum size of the fields in terms of registers used
+	     ('max_reg') and the 'last_used_bit' in said register.  */
+	  if (max_reg < regno_t)
+	    {
+	      max_reg = regno_t;
+	      max_bit = last_used_bit_t;
+	    }
+	  else if (max_reg == regno_t && max_bit < last_used_bit_t)
+	    max_bit = last_used_bit_t;
+
+	  field = TREE_CHAIN (field);
+	}
+
+      /* Update the current padding_bits_to_clear using the intersection of the
+	 padding bits of all the fields.  */
+      for (i=*regno; i < max_reg; i++)
+	padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+
+      /* Do not keep trailing padding bits, we do not know yet whether this
+	 is the end of the argument.  */
+      mask = ((uint32_t) 1 << max_bit) - 1;
+      padding_bits_to_clear[max_reg]
+	|= padding_bits_to_clear_res[max_reg] & mask;
+
+      *regno = max_reg;
+      *last_used_bit = max_bit;
+    }
+  else
+    /* This function should only be used for structs and unions.  */
+    gcc_unreachable ();
+
+  return not_to_clear_reg_mask;
+}
+
+/* In the context of ARMv8-M Security Extensions, this function is used for both
+   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to compute what
+   registers are used when returning or passing arguments, which is then
+   returned as a mask.  It will also compute a mask to indicate padding/unused
+   bits for each of these registers, and passes this through the
+   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is passed in
+   ARG_TYPE, the rtl representation of the argument is passed in ARG_RTX and
+   the starting register used to pass this argument or return value is passed
+   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to compute these
+   for struct and union types.  */
+
+static unsigned HOST_WIDE_INT
+compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
+			     uint32_t * padding_bits_to_clear)
+
+{
+  int last_used_bit = 0;
+  unsigned HOST_WIDE_INT not_to_clear_mask;
+
+  if (RECORD_OR_UNION_TYPE_P (arg_type))
+    {
+      not_to_clear_mask
+	= comp_not_to_clear_mask_str_un (arg_type, &regno,
+					 padding_bits_to_clear, 0,
+					 &last_used_bit);
+
+
+      /* If the 'last_used_bit' is not zero, that means we are still using a
+	 part of the last 'regno'.  In such cases we must clear the trailing
+	 bits.  Otherwise we are not using regno and we should mark it as to
+	 clear.  */
+      if (last_used_bit != 0)
+	*(padding_bits_to_clear + regno)
+	  |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;
+      else
+	not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
+    }
+  else
+    {
+      not_to_clear_mask = 0;
+      /* We are not dealing with structs nor unions.  So these arguments may be
+	 passed in floating point registers too.  In some cases a BLKmode is
+	 used when returning or passing arguments in multiple VFP registers.  */
+      if (GET_MODE (arg_rtx) == BLKmode)
+	{
+	  int i, arg_regs;
+	  rtx reg;
+
+	  /* This should really only occur when dealing with the hard-float
+	     ABI.  */
+	  gcc_assert (TARGET_HARD_FLOAT_ABI);
+
+	  for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
+	    {
+	      reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
+	      gcc_assert (REG_P (reg));
+
+	      not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
+
+	      /* If we are dealing with DF mode, make sure we don't
+		 clear either of the registers it addresses.  */
+	      arg_regs = ARM_NUM_REGS (GET_MODE (reg));
+	      if (arg_regs > 1)
+		{
+		  unsigned HOST_WIDE_INT mask;
+		  mask = HOST_WIDE_INT_1U << (REGNO (reg) + arg_regs);
+		  mask -= HOST_WIDE_INT_1U << REGNO (reg);
+		  not_to_clear_mask |= mask;
+		}
+	    }
+	}
+      else
+	{
+	  /* Otherwise we can rely on the MODE to determine how many registers
+	     are being used by this argument.  */
+	  int arg_regs = ARM_NUM_REGS (GET_MODE (arg_rtx));
+	  not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	  if (arg_regs > 1)
+	    {
+	      unsigned HOST_WIDE_INT
+	      mask = HOST_WIDE_INT_1U << (REGNO (arg_rtx) + arg_regs);
+	      mask -= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	      not_to_clear_mask |= mask;
+	    }
+	}
+    }
+
+  return not_to_clear_mask;
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -19917,7 +20190,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
-	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    {
+	      /* 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);
+	      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).  */
+		  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");
+	    }
 	  /* Use bx if it's available.  */
 	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
@@ -24182,7 +24490,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
-	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	{
+	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+		       reg_containing_return_addr);
+	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	}
       else
 	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
@@ -24418,7 +24730,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
   /* Return to caller.  */
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
-    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    {
+      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
+      asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    }
   else
     asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
@@ -25280,6 +25595,134 @@ thumb1_expand_prologue (void)
     cfun->machine->lr_save_eliminated = 0;
 }
 
+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check TARGET_HARD_FLOAT to make sure these are
+     present.  */
+  if (TARGET_HARD_FLOAT)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      maxregno = LAST_VFP_REGNUM;
+
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask[0] |= float_mask;
+
+      float_mask = (1ULL << (maxregno - 63)) - 1;
+      to_clear_mask[1] = float_mask;
+
+      /* Make sure we dont clear the two scratch registers used to clear the
+	 relevant FPSCR bits in output_return_instruction.  We have only
+	 implemented the clearing of FP registers for Thumb-2, so we assert
+	 here that VFP was not enabled for Thumb-1 ARMv8-M targets.  */
+      gcc_assert (arm_arch_thumb2);
+      emit_use (gen_rtx_REG (SImode, IP_REGNUM));
+      to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+      emit_use (gen_rtx_REG (SImode, 4));
+      to_clear_mask[0] &= ~(1ULL << 4);
+    }
+
+  /* If the user has defined registers to be caller saved, these are no longer
+     restored by the function before returning and must thus be cleared for
+     security purposes.  */
+  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+    {
+      /* We do not touch registers that can be used to pass arguments as per
+	 the AAPCS, since these should never be made callee-saved by user
+	 options.  */
+      if (regno >= FIRST_VFP_REGNUM && regno <= D7_VFP_REGNUM)
+	continue;
+      if (regno >= IP_REGNUM && regno <= PC_REGNUM)
+	continue;
+      if (call_used_regs[regno])
+	to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+    }
+
+  /* Make sure we do not clear the registers used to return the result in.  */
+  result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+  if (!VOID_TYPE_P (result_type))
+    {
+      result_rtl = arm_function_value (result_type, current_function_decl, 0);
+
+      /* No need to check that we return in registers, because we don't
+	 support returning on stack yet.  */
+      to_clear_mask[0]
+	&= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
+				       padding_bits_to_clear_ptr);
+    }
+
+  if (padding_bits_to_clear != 0)
+    {
+      rtx reg_rtx;
+      /* Padding bits to clear is not 0 so we know we are dealing with
+	 returning a composite type, which only uses r0.  Let's make sure that
+	 r1-r3 is cleared too, we will use r1 as a scratch register.  */
+      gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
+
+      reg_rtx = gen_rtx_REG (SImode, 1);
+
+      /* Fill the lower half of the negated padding_bits_to_clear.  */
+      emit_move_insn (reg_rtx,
+		      GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
+
+      /* Also fill the top half of the negated padding_bits_to_clear.  */
+      if (((~padding_bits_to_clear) >> 16) > 0)
+	emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
+						      GEN_INT (16),
+						      GEN_INT (16)),
+				GEN_INT ((~padding_bits_to_clear) >> 16)));
+
+      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, 0),
+			   gen_rtx_REG (SImode, 0),
+			   reg_rtx));
+    }
+
+  for (regno = 0; regno <= maxregno; regno++)
+    {
+      if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
+	continue;
+
+      if (IS_VFP_REGNUM (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)
+	      && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 1)))
+	    {
+	      emit_move_insn (gen_rtx_REG (DFmode, regno++),
+			      CONST1_RTX (DFmode));
+	      emit_use (gen_rtx_REG (DFmode, 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 (SImode, regno),
+			  gen_rtx_REG (SImode, LR_REGNUM));
+	  emit_use (gen_rtx_REG (SImode, regno));
+	}
+    }
+}
+
 /* Generate pattern *pop_multiple_with_stack_update_and_return if single
    POP instruction can be generated.  LR should be replaced by PC.  All
    the checks required are already done by  USE_RETURN_INSN ().  Hence,
@@ -25329,6 +25772,8 @@ thumb2_expand_return (bool simple_return)
     }
   else
     {
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	cmse_nonsecure_entry_clear_before_return ();
       emit_jump_insn (simple_return_rtx);
     }
 }
@@ -25387,6 +25832,10 @@ thumb1_expand_epilogue (void)
 
   if (! df_regs_ever_live_p (LR_REGNUM))
     emit_use (gen_rtx_REG (SImode, LR_REGNUM));
+
+  /* Clear all caller-saved regs that are not used to return.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    cmse_nonsecure_entry_clear_before_return ();
 }
 
 /* Epilogue code for APCS frame.  */
@@ -25821,6 +26270,14 @@ 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 (!really_return)
     return;
 
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index cd98de7dcb40de483a9f93c0674bd216f4b0c56a..433fc79ae5810a4d3eb45d1ba80872a39e157e14 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1843,8 +1843,13 @@
   "*
     return thumb1_unexpanded_epilogue ();
   "
-  ; Length is absolute worst case
-  [(set_attr "length" "44")
+  ; Length is absolute worst case, when using CMSE and if this is an entry
+  ; function an extra 4 (MSR) bytes will be added.
+  [(set (attr "length")
+	(if_then_else
+	 (match_test "IS_CMSE_ENTRY (arm_current_func_type ())")
+	 (const_int 48)
+	 (const_int 44)))
    (set_attr "type" "block")
    ;; We don't clobber the conditions, but the potential length of this
    ;; operation is sufficient to make conditionalizing the sequence
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index affcd832b72b7d358347e7370265be492866bb90..f5033ef802c085bd0ce479bc7026db96d9e25632 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1114,12 +1114,31 @@
 
 (define_insn "*thumb2_return"
   [(simple_return)]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
   "* return output_return_instruction (const_true_rtx, true, false, true);"
   [(set_attr "type" "branch")
    (set_attr "length" "4")]
 )
 
+(define_insn "*thumb2_return"
+  [(simple_return)]
+  "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
+  "* return output_return_instruction (const_true_rtx, true, false, true);"
+  [(set_attr "type" "branch")
+   ; This is a return from a cmse_nonsecure_entry function so code will be
+   ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+   ; we adapt the length accordingly.
+   (set (attr "length")
+     (if_then_else (match_test "TARGET_HARD_FLOAT")
+      (const_int 12)
+      (const_int 8)))
+   ; We do not support predicate execution of returns from cmse_nonsecure_entry
+   ; functions because we need to clear the APSR.  Since predicable has to be
+   ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
+   ; functions.
+   (set_attr "predicable" "no")]
+)
+
 (define_insn_and_split "thumb2_eh_return"
   [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
 		    VUNSPEC_EH_RETURN)
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c6354c7a8cfead895e6c62d61c3f2a2bca1a1f2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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 "msr\tAPSR_nzcvq, r1" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..fccc51d5c82f7955ee4cb8256c1dd38f9ff2670d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned short  a : 6;
+  unsigned char	  b : 3;
+  unsigned char	  c;
+  unsigned short  d : 8;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 63u;
+  t.b = 7u;
+  t.c = 255u;
+  t.d = 255u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 63u
+      || t.b != 7u
+      || t.c != 255u
+      || t.d != 255u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6aee3c4c022d50baec8ab16443130897540e703
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a : 7;
+  signed char b : 3;
+  short	      c : 11;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -64;
+  t.b = -4 ;
+  t.c = -1024;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -64
+      || t.b != -4
+      || t.c != -1024)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..285a2b92f64c1913ef585b8daa4d27c6da0a3d2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a;
+  signed char b : 2;
+  short		: 1;
+  signed char c : 3;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -32768;
+  t.b = -2;
+  t.c = -4;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -32768
+      || t.b != -2
+      || t.c != -4)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index f797dba1901720e04249d61078c1cbf2a3e436a9..38f18414c2fefec56161e6ac3f7291b03a3b29a3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -43,6 +43,26 @@ set LTO_TORTURE_OPTIONS ""
 gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
 	"" $DEFAULT_CFLAGS
 
+if {[check_effective_target_arm_arch_v8m_base_ok]} then {
+    # Baseline only
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/baseline/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
+if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    # Mainline -mfloat-abi=soft
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
+	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
 set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
 set dg-do-what-default ${saved-dg-do-what-default}
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..88dec2762812614ee986ee1a023c0acce8f94c91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..29f60baf5212f9fa2e4436fe40c6abe4ac671254
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7229ea8eb2da1da264f58f8518daf303d1bdeda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..7734d77dc3812e6a158ea1f6b067930846fffccb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..6addaa1a4eda8e2930d5fe72c94697bcf6e604e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { 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
new file mode 100644
index 0000000000000000000000000000000000000000..2d366a944df692f29ab44e3ee4d33c777b126223
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 255u;
+  t.b = 32767u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 255u || t.b != 32767u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
+

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

* Re: [PATCHv2 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
  2016-08-24 11:01   ` [PATCHv2 " Andre Vieira (lists)
@ 2016-10-25 16:29     ` Andre Vieira (lists)
  2016-10-27 10:00       ` Andre Vieira (lists)
  2016-11-04  9:30       ` Kyrill Tkachov
  0 siblings, 2 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-25 16:29 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 24/08/16 12:01, Andre Vieira (lists) wrote:
> On 25/07/16 14:25, Andre Vieira (lists) wrote:
>> This patch adds support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_call' attribute. This attribute may only be used for
>> function types and when used in combination with the '-mcmse'
>> compilation flag. See Section 5.5 of ARM®v8-M Security Extensions
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> We currently do not support cmse_nonsecure_call functions that pass
>> arguments or return variables on the stack and we diagnose this.
>>
>> *** gcc/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm.c (gimplify.h): New include.
>>         (arm_handle_cmse_nonsecure_call): New.
>>         (arm_attribute_table): Added cmse_nonsecure_call.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/cmse-3.c: Add tests.
>>         * gcc.target/arm/cmse/cmse-4.c: Add tests.
>>
> 
> Added more documentation as requested.
> 
> ---
> 
> This patch adds support for the ARMv8-M Security Extensions
> 'cmse_nonsecure_call' attribute. This attribute may only be used for
> function types and when used in combination with the '-mcmse'
> compilation flag. See Section 5.5 of ARM®v8-M Security Extensions
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
> 
> We currently do not support cmse_nonsecure_call functions that pass
> arguments or return variables on the stack and we diagnose this.
> 
> *** gcc/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (gimplify.h): New include.
>         (arm_handle_cmse_nonsecure_call): New.
>         (arm_attribute_table): Added cmse_nonsecure_call.
>         * doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse-3.c: Add tests.
>         * gcc.target/arm/cmse/cmse-4.c: Add tests.
> 
Hi,

Rebased previous patch on top of trunk as requested. No changes to
ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff5 --]
[-- Type: text/plain, Size: 7129 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index c6260323ecfd2f2842e6a5aab06b67da16619c73..2e8fba85001e9f69eece789990d0b67f1e35bf76 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -62,6 +62,7 @@
 #include "builtins.h"
 #include "tm-constrs.h"
 #include "rtl-iter.h"
+#include "gimplify.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -136,6 +137,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
 static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
+static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -351,6 +353,8 @@ static const struct attribute_spec arm_attribute_table[] =
   /* ARMv8-M Security Extensions support.  */
   { "cmse_nonsecure_entry", 0, 0, true, false, false,
     arm_handle_cmse_nonsecure_entry, false },
+  { "cmse_nonsecure_call", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_call, false },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -6777,6 +6781,78 @@ arm_handle_cmse_nonsecure_entry (tree *node, tree name,
   return NULL_TREE;
 }
 
+
+/* Called upon detection of the use of the cmse_nonsecure_call attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function type tree or otherwise issue a diagnostic.  The
+   reason we check this at declaration time is to only allow the use of the
+   attribute with declarations of function pointers and not function
+   declarations.  This function checks NODE is of the expected type and issues
+   diagnostics otherwise using NAME.  If it is not of the expected type
+   *NO_ADD_ATTRS will be set to true.  */
+
+static tree
+arm_handle_cmse_nonsecure_call (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree decl = NULL_TREE;
+  tree type, fntype, main_variant;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == TYPE_DECL)
+    {
+      decl = *node;
+      type = TREE_TYPE (decl);
+    }
+
+  if (!decl
+      || (!(TREE_CODE (type) == POINTER_TYPE
+	    && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+	  && TREE_CODE (type) != FUNCTION_TYPE))
+    {
+	warning (OPT_Wattributes, "%qE attribute only applies to base type of a "
+		 "function pointer", name);
+	*no_add_attrs = true;
+	return NULL_TREE;
+    }
+
+  /* type is either a function pointer, when the attribute is used on a function
+   * pointer, or a function type when used in a typedef.  */
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    fntype = type;
+  else
+    fntype = TREE_TYPE (type);
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (NULL, name, fntype);
+
+  if (*no_add_attrs)
+    return NULL_TREE;
+
+  /* Prevent trees being shared among function types with and without
+     cmse_nonsecure_call attribute.  Do however make sure they keep the same
+     main_variant, this is required for correct DIE output.  */
+  main_variant = TYPE_MAIN_VARIANT (fntype);
+  fntype = build_distinct_type_copy (fntype);
+  TYPE_MAIN_VARIANT (fntype) = main_variant;
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    TREE_TYPE (decl) = fntype;
+  else
+    TREE_TYPE (type) = fntype;
+
+  /* Construct a type attribute and add it to the function type.  */
+  tree attrs = tree_cons (get_identifier ("cmse_nonsecure_call"), NULL_TREE,
+			  TYPE_ATTRIBUTES (fntype));
+  TYPE_ATTRIBUTES (fntype) = attrs;
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index e5b28032e5610b896908139ec285ce90a9dffd8a..462e6c71e20791b35f02adabfc97b9b013fd296a 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12607,8 +12607,8 @@ Security Extensions: Requiremenets on Development Tools Engineering
 Specification, which can be found at
 @uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 
-As part of the Security Extensions GCC implements a new function attribute
-@code{cmse_nonsecure_entry}.
+As part of the Security Extensions GCC implements two new function attributes:
+@code{cmse_nonsecure_entry} and @code{cmse_nonsecure_call}.
 
 As part of the Security Extensions GCC implements the intrinsics below.  FPTR
 is used here to mean any function pointer type.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
index 2c2920e1dc310106d83203eb51e1a68a275d0152..7f92a4c28b3333e4c8fdc256211f3ed74a383cd4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -35,3 +35,11 @@ norf (struct span2 a) {}
 
 void __attribute__ ((cmse_nonsecure_entry))
 foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) bar2 (long long a, int b, long long c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) baz2 (long long a, int b, struct span c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef struct span __attribute__ ((cmse_nonsecure_call)) qux2 (void); /* { dg-error "not available to functions that return value on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) norf2 (int a, ...); /* { dg-error "not available to functions with variable number of arguments" } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
index 6f930ab04a1097c64097a4e003296bbe85733319..d0999a4181ac022b115ae20cf3e1c8bf78f6becf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -19,9 +19,16 @@ baz (void)
   return qux ();
 }
 
+void __attribute__ ((cmse_nonsecure_call))
+quux (void) {} /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
+int __attribute__ ((cmse_nonsecure_call)) norf; /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
 /* { dg-final { scan-assembler-times "bxns" 2 } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
 /* { dg-final { scan-assembler "baz:" } } */
 /* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_quux:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_norf:" } } */

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

* Re: [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic
  2016-08-24 11:02   ` Andre Vieira (lists)
@ 2016-10-25 16:30     ` Andre Vieira (lists)
  2016-11-09 10:27       ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-25 16:30 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 24/08/16 12:01, Andre Vieira (lists) wrote:
> On 25/07/16 14:28, Andre Vieira (lists) wrote:
>> This patch adds support ARMv8-M's Security Extension's
>> cmse_nonsecure_caller intrinsic. This intrinsic is used to check whether
>> an entry function was called from a non-secure state.
>> See Section 5.4.3 of ARM®v8-M Security Extensions: Requirements on
>> Development Tools
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html)
>> for further details.
>>
>> The FIXME in config/arm/arm_cmse.h is for a diagnostic message that is
>> suggested in the ARMv8-M Security Extensions document mentioned above,
>> to diagnose the use of the cmse_nonsecure_caller intrinsic outside of
>> functions with the 'cmse_nonsecure_entry' attribute.  Checking whether
>> the intrinsic is called from within such functions can easily be done
>> inside 'arm_expand_builtin'. However, making the warning point to the
>> right location is more complicated.  The ARMv8-M Security Extensions
>> specification does mention that such a diagnostic might become
>> mandatory, so I might have to pick this up later, otherwise it is left
>> as a potential extra feature.
>>
>>
>> *** gcc/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm-builtins.c (arm_builtins): Define
>>         ARM_BUILTIN_CMSE_NONSECURE_CALLER.
>>         (bdesc_2arg): Add line for cmse_nonsecure_caller.
>>         (arm_expand_builtin): Handle cmse_nonsecure_caller.
>>         * config/arm/arm_cmse.h (cmse_nonsecure_caller): New.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/cmse-1.c: Add test for
>>         cmse_nonsecure_caller.
>>
> Added more documentation as requested.
> 
> ---
> 
> This patch adds support ARMv8-M's Security Extension's
> cmse_nonsecure_caller intrinsic. This intrinsic is used to check whether
> an entry function was called from a non-secure state.
> See Section 5.4.3 of ARM®v8-M Security Extensions: Requirements on
> Development Tools
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html)
> for further details.
> 
> The FIXME in config/arm/arm_cmse.h is for a diagnostic message that is
> suggested in the ARMv8-M Security Extensions document mentioned above,
> to diagnose the use of the cmse_nonsecure_caller intrinsic outside of
> functions with the 'cmse_nonsecure_entry' attribute.  Checking whether
> the intrinsic is called from within such functions can easily be done
> inside 'arm_expand_builtin'. However, making the warning point to the
> right location is more complicated.  The ARMv8-M Security Extensions
> specification does mention that such a diagnostic might become
> mandatory, so I might have to pick this up later, otherwise it is left
> as a potential extra feature.
> 
> 
> *** gcc/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm-builtins.c (arm_builtins): Define
>         ARM_BUILTIN_CMSE_NONSECURE_CALLER.
>         (bdesc_2arg): Add line for cmse_nonsecure_caller.
>         (arm_expand_builtin): Handle cmse_nonsecure_caller.
>         * config/arm/arm_cmse.h (cmse_nonsecure_caller): New.
>         * doc/extend.texi (ARM ARMv8-M Security Extensions): New intrinsic.
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse-1.c: Add test for
>         cmse_nonsecure_caller.
> 
Hi,

Rebased previous patch on top of trunk as requested. No changes to
ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff7 --]
[-- Type: text/plain, Size: 4022 bytes --]

diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index e73043db6db69fa64bb1e72cf71a36d7169062db..68fa17f07097bda9f8220d7e86ffd2dd4fdbf169 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -528,6 +528,8 @@ enum arm_builtins
   ARM_BUILTIN_GET_FPSCR,
   ARM_BUILTIN_SET_FPSCR,
 
+  ARM_BUILTIN_CMSE_NONSECURE_CALLER,
+
 #undef CRYPTO1
 #undef CRYPTO2
 #undef CRYPTO3
@@ -1832,6 +1834,17 @@ arm_init_builtins (void)
 	= add_builtin_function ("__builtin_arm_stfscr", ftype_set_fpscr,
 				ARM_BUILTIN_SET_FPSCR, BUILT_IN_MD, NULL, NULL_TREE);
     }
+
+  if (arm_arch_cmse)
+    {
+      tree ftype_cmse_nonsecure_caller
+	= build_function_type_list (unsigned_type_node, NULL);
+      arm_builtin_decls[ARM_BUILTIN_CMSE_NONSECURE_CALLER]
+	= add_builtin_function ("__builtin_arm_cmse_nonsecure_caller",
+				ftype_cmse_nonsecure_caller,
+				ARM_BUILTIN_CMSE_NONSECURE_CALLER, BUILT_IN_MD,
+				NULL, NULL_TREE);
+    }
 }
 
 /* Return the ARM builtin for CODE.  */
@@ -2452,6 +2465,12 @@ arm_expand_builtin (tree exp,
       emit_insn (pat);
       return target;
 
+    case ARM_BUILTIN_CMSE_NONSECURE_CALLER:
+      target = gen_reg_rtx (SImode);
+      op0 = arm_return_addr (0, NULL_RTX);
+      emit_insn (gen_addsi3 (target, op0, const1_rtx));
+      return target;
+
     case ARM_BUILTIN_TEXTRMSB:
     case ARM_BUILTIN_TEXTRMUB:
     case ARM_BUILTIN_TEXTRMSH:
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
index b4232937c6ae04754a6bbc513b143672a4be5530..d3f529cce90b8a7ecf8132ad40843270e0b229d2 100644
--- a/gcc/config/arm/arm_cmse.h
+++ b/gcc/config/arm/arm_cmse.h
@@ -163,6 +163,13 @@ __attribute__ ((__always_inline__))
 cmse_TTAT (void *__p)
 __CMSE_TT_ASM (at)
 
+/* FIXME: diagnose use outside cmse_nonsecure_entry functions.  */
+__extension__ static __inline int __attribute__ ((__always_inline__))
+cmse_nonsecure_caller (void)
+{
+  return __builtin_arm_cmse_nonsecure_caller ();
+}
+
 #define CMSE_AU_NONSECURE	2
 #define CMSE_MPU_NONSECURE	16
 #define CMSE_NONSECURE		18
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 462e6c71e20791b35f02adabfc97b9b013fd296a..88f6e014c3def8e6a2d2452df5d4937a4f0dd1ef 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12625,6 +12625,7 @@ cmse_address_info_t cmse_TTAT_fptr (FPTR)
 void * cmse_check_address_range (void *, size_t, int)
 typeof(p) cmse_nsfptr_create (FPTR p)
 intptr_t cmse_is_nsfptr (FPTR)
+int cmse_nonsecure_caller (void)
 @end smallexample
 
 @node AVR Built-in Functions
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index d5b9a2d9d59569de170da814ae660e9fb2b943e7..ddcf12a30a6c1806969d239c448da81ccf49532e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -65,3 +65,32 @@ int foo (char * p)
 /* { dg-final { scan-assembler-times "ttat " 2 } } */
 /* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
 /* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
+
+typedef int (*int_ret_funcptr_t) (void);
+typedef int __attribute__ ((cmse_nonsecure_call)) (*int_ret_nsfuncptr_t) (void);
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return cmse_nonsecure_caller ();
+}
+
+int __attribute__ ((cmse_nonsecure_entry))
+qux (int_ret_funcptr_t int_ret_funcptr)
+{
+  int_ret_nsfuncptr_t int_ret_nsfunc_ptr;
+
+  if (cmse_is_nsfptr (int_ret_funcptr))
+    {
+      int_ret_nsfunc_ptr = cmse_nsfptr_create (int_ret_funcptr);
+      return int_ret_nsfunc_ptr ();
+    }
+  return 0;
+}
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "\tcmse_nonsecure_caller" } } */
+/* { dg-final { scan-rtl-dump "and.*reg.*const_int 1" expand } } */
+/* { dg-final { scan-assembler "bic" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */

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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-08-24 11:02   ` [PATCHv2 " Andre Vieira (lists)
@ 2016-10-25 16:30     ` Andre Vieira (lists)
  2016-10-27 10:01       ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-25 16:30 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 24/08/16 12:01, Andre Vieira (lists) wrote:
> On 25/07/16 14:26, Andre Vieira (lists) wrote:
>> This patch extends support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_call' to use a new library function
>> '__gnu_cmse_nonsecure_call'. This library function is responsible for
>> (without using r0-r3 or d0-d7):
>> 1) saving and clearing all callee-saved registers using the secure stack
>> 2) clearing the LSB of the address passed in r4 and using blxns to
>> 'jump' to it
>> 3) clearing ASPR, including the 'ge bits' if DSP is enabled
>> 4) clearing FPSCR if using non-soft float-abi
>> 5) restoring callee-saved registers.
>>
>> The decisions whether to include DSP 'ge bits' clearing and floating
>> point registers (single/double precision) all depends on the multilib used.
>>
>> See Section 5.5 of ARM®v8-M Security Extensions
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> *** gcc/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>>         (cmse_nonsecure_call_clear_caller_saved): New.
>>         (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>>         * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>>         * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>>         (call_value): Likewise.
>>         (nonsecure_call_internal): New.
>>         (nonsecure_call_value_internal): New.
>>         * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>>         (*nonsecure_call_value_reg_thumb1_v5): New.
>>         * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>>         (*nonsecure_call_value_reg_thumb2): New.
>>         * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
>>
>> *** libgcc/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/cmse_nonsecure_call.S: New.
>> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
>>
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>>         * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>>         * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>>         * gcc.target/arm/cmse/baseline/cmse-11.c: New.
>> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
>>
> 
> Updated this patch to correctly clear only the cumulative
> exception-status (0-4,7) and the condition code bits (28-31) of the FPSCR.
> 
> ----
> 
> This patch extends support for the ARMv8-M Security Extensions
> 'cmse_nonsecure_call' to use a new library function
> '__gnu_cmse_nonsecure_call'. This library function is responsible for
> (without using r0-r3 or d0-d7):
> 1) saving and clearing all callee-saved registers using the secure stack
> 2) clearing the LSB of the address passed in r4 and using blxns to
> 'jump' to it
> 3) clearing ASPR, including the 'ge bits' if DSP is enabled
> 4) clearing the cumulative exception-status (0-4, 7) and the condition
> bits (28-31) of the FPSCR if using non-soft float-abi
> 5) restoring callee-saved registers.
> 
> The decisions whether to include DSP 'ge bits' clearing and floating
> point registers (single/double precision) all depends on the multilib used.
> 
> See Section 5.5 of ARM®v8-M Security Extensions
> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
> 
> *** gcc/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>         (cmse_nonsecure_call_clear_caller_saved): New.
>         (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>         * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>         * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>         (call_value): Likewise.
>         (nonsecure_call_internal): New.
>         (nonsecure_call_value_internal): New.
>         * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>         (*nonsecure_call_value_reg_thumb1_v5): New.
>         * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>         (*nonsecure_call_value_reg_thumb2): New.
>         * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
> 
> *** libgcc/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/cmse_nonsecure_call.S: New.
> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
> 
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>         * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>         * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>         * gcc.target/arm/cmse/baseline/cmse-11.c: New.
> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
> 
Hi,

Rebased previous patch on top of trunk as requested. No changes to
ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff6 --]
[-- Type: text/plain, Size: 81887 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index a9b8326c2770c1f9a9787743cb5faa549e6b7d02..2660bc3ba89c34b17911680c4e25eb2f6c0745fb 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -135,6 +135,7 @@ extern int arm_const_double_inline_cost (rtx);
 extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
+bool detect_cmse_nonsecure_call (tree);
 extern const char *output_call (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 2e8fba85001e9f69eece789990d0b67f1e35bf76..e2e7ad99d8d0524053b8e0fec3e646d1428712af 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17845,6 +17845,197 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Saves callee saved registers, clears callee saved registers and caller saved
+   registers not used to pass arguments before a cmse_nonsecure_call.  And
+   restores the callee saved registers after.  */
+
+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  uint64_t to_clear_mask, float_mask;
+	  rtx_insn *seq;
+	  rtx pat, call, unspec, reg, cleared_reg, tmp;
+	  unsigned int regno, maxregno;
+	  rtx address;
+	  CUMULATIVE_ARGS args_so_far_v;
+	  cumulative_args_t args_so_far;
+	  tree arg_type, fntype;
+	  bool using_r4, first_param = true;
+	  function_args_iterator args_iter;
+	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
+	  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
+
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  if (!CALL_P (insn))
+	    continue;
+
+	  pat = PATTERN (insn);
+	  gcc_assert (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 0);
+	  call = XVECEXP (pat, 0, 0);
+
+	  /* Get the real call RTX if the insn sets a value, ie. returns.  */
+	  if (GET_CODE (call) == SET)
+	      call = SET_SRC (call);
+
+	  /* Check if it is a cmse_nonsecure_call.  */
+	  unspec = XEXP (call, 0);
+	  if (GET_CODE (unspec) != UNSPEC
+	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
+	    continue;
+
+	  /* Determine the caller-saved registers we need to clear.  */
+	  to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
+	  maxregno = NUM_ARG_REGS - 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
+	     lazy store and loads which clear both caller- and callee-saved
+	     registers.  */
+	  if (TARGET_HARD_FLOAT_ABI)
+	    {
+	      float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
+	      float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
+	      to_clear_mask |= float_mask;
+	      maxregno = D7_VFP_REGNUM;
+	    }
+
+	  /* Make sure the register used to hold the function address is not
+	     cleared.  */
+	  address = RTVEC_ELT (XVEC (unspec, 0), 0);
+	  gcc_assert (MEM_P (address));
+	  gcc_assert (REG_P (XEXP (address, 0)));
+	  to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+
+	  /* Set basic block of call insn so that df rescan is performed on
+	     insns inserted here.  */
+	  set_block_for_insn (insn, bb);
+	  df_set_flags (DF_DEFER_INSN_RESCAN);
+	  start_sequence ();
+
+	  /* Make sure the scheduler doesn't schedule other insns beyond
+	     here.  */
+	  emit_insn (gen_blockage ());
+
+	  /* Walk through all arguments and clear registers appropriately.
+	  */
+	  fntype = TREE_TYPE (MEM_EXPR (address));
+	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
+				    NULL_TREE);
+	  args_so_far = pack_cumulative_args (&args_so_far_v);
+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask &=
+		~compute_not_to_clear_mask (arg_type, arg_rtx,
+					      REGNO (arg_rtx),
+					      padding_bits_to_clear_ptr);
+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = 0; regno < NUM_ARG_REGS; regno++)
+	    {
+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = 0; regno <= maxregno; regno++)
+	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST1_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST1_RTX (SFmode));
+		}
+	      else
+		emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+	    }
+
+	  seq = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (seq, insn);
+
+	}
+    }
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -18145,6 +18336,8 @@ arm_reorg (void)
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
+  if (use_cmse)
+    cmse_nonsecure_call_clear_caller_saved ();
   if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
@@ -18517,6 +18710,23 @@ vfp_emit_fstmd (int base_reg, int count)
   return count * 8;
 }
 
+/* Returns true if -mcmse has been passed and the function pointed to by 'addr'
+   has the cmse_nonsecure_call attribute and returns false otherwise.  */
+
+bool
+detect_cmse_nonsecure_call (tree addr)
+{
+  if (!addr)
+    return FALSE;
+
+  tree fntype = TREE_TYPE (addr);
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_call",
+				    TYPE_ATTRIBUTES (fntype)))
+    return TRUE;
+  return FALSE;
+}
+
+
 /* Emit a call instruction with pattern PAT.  ADDR is the address of
    the call target.  */
 
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 8393f65bcf4c9c3e61b91e5adcd5f59ff7c6ec3f..3e65a43d39fb20061ee531d58fd21fbbc9cd1bde 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -8024,6 +8024,7 @@
   "
   {
     rtx callee, pat;
+    tree addr = MEM_EXPR (operands[0]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[2] == NULL_RTX)
@@ -8038,8 +8039,17 @@
 	: !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_internal (operands[0], operands[1], operands[2]);
-    arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_internal (operands[0], operands[1],
+					   operands[2]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_internal (operands[0], operands[1], operands[2]);
+	arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+      }
     DONE;
   }"
 )
@@ -8050,6 +8060,24 @@
 	      (use (match_operand 2 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_internal"
+  [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand" "")]
+			       UNSPEC_NONSECURE_MEM)
+		    (match_operand 1 "general_operand" ""))
+	      (use (match_operand 2 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[0] = replace_equiv_address (operands[0], tmp);
+  }")
+
 (define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
@@ -8085,6 +8113,7 @@
   "
   {
     rtx pat, callee;
+    tree addr = MEM_EXPR (operands[1]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
@@ -8099,9 +8128,18 @@
 	: !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_value_internal (operands[0], operands[1],
-				   operands[2], operands[3]);
-    arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_value_internal (operands[0], operands[1],
+						 operands[2], operands[3]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_value_internal (operands[0], operands[1],
+				       operands[2], operands[3]);
+	arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+      }
     DONE;
   }"
 )
@@ -8113,6 +8151,25 @@
 	      (use (match_operand 3 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_value_internal"
+  [(parallel [(set (match_operand       0 "" "")
+		   (call (unspec:SI [(match_operand 1 "memory_operand" "")]
+				    UNSPEC_NONSECURE_MEM)
+			 (match_operand 2 "general_operand" "")))
+	      (use (match_operand 3 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[1] = replace_equiv_address (operands[1], tmp);
+  }")
+
 (define_insn "*call_value_reg_armv5"
   [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 433fc79ae5810a4d3eb45d1ba80872a39e157e14..63a400fbfd8015cbd5a70252e24beacde4a5354d 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1705,6 +1705,19 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb1_v5"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_reg_thumb1"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
 	 (match_operand 1 "" ""))
@@ -1737,6 +1750,21 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb1_v5"
+  [(set (match_operand 0 "" "")
+	(call (unspec:SI
+	       [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+	       UNSPEC_NONSECURE_MEM)
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB1 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb1"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index f5033ef802c085bd0ce479bc7026db96d9e25632..8618dc31b44f2a7f0e3b0cc60fd226859e7545ae 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -580,6 +580,19 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
@@ -591,6 +604,21 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+	(call
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "register_operand" "l*r"))]
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index bee8795f007accc623c82b73c41a8619ebc29209..1aa39e8e0b9ddf17bb535c4d82959e569d3c9fd5 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -84,6 +84,8 @@
   UNSPEC_VRINTA         ; Represent a float to integral float rounding
                         ; towards nearest, ties away from zero.
   UNSPEC_PROBE_STACK    ; Probe stack memory reference
+  UNSPEC_NONSECURE_MEM	; Represent non-secure memory in ARMv8-M with
+			; security extension
 ])
 
 (define_c_enum "unspec" [
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6c1386c06edbdb58e76fa5e612c918010c507f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51ce2d42c051aeda8b06ad97086f2563a5fc47d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e9104b546a7693fcb2399622e828b1197eac1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 1023" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "movt\tr4, 32767" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d8941bbfeebd59744c43f10c842816b36ec9915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ffbb718d34d5bb8f10e1f3c0505c7dc393c670c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a6141829237823b8734de045a590a1917fa60b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #1799" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..642f4e0346b5186c78645780b45fe9c838848d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #7939" } } */
+/* { dg-final { scan-assembler "movt\tr4, 15" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, 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/baseline/cmse-11.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
new file mode 100644
index 0000000000000000000000000000000000000000..3007409ad88b9d2312ece4d55f3695787a1aa566
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+
+int
+foo (int a)
+{
+  return bar (bar (a + 1));
+}
+
+/* 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 "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\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/baseline/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2b931be5912b421f8427535ded3298883bec639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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 "movs\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmovs\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmovs\tr2, r4\n\tmovs\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/baseline/cmse-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..95da045690ae170a101949134482e821f27fe3aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* Remember dont clear r0 and r1, because we are passing the double parameter
+ * for bar in them.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, 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/baseline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff18e839b02c19c2c77769b18ef5ee1cfacf0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8063" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2e024b7f0776381f511077af91bd1ee5632ff12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
index 65200bcf29b219706911bbb799c847aefc92cb1c..79ddc7cb1fe1724b82ae028c2ddf91321e855811 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -2,11 +2,19 @@
 /* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
 
 
+void __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+typedef void __attribute__ ((cmse_nonsecure_call)) baz (int);
+
 int __attribute__ ((cmse_nonsecure_entry))
-foo (int a)
+foo (int a, baz b)
 {
+  bar (a);
+  b (a);
   return a + 1;
 }
 
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler-not "blxns" } } */
+/* { dg-final { scan-assembler-not "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 38f18414c2fefec56161e6ac3f7291b03a3b29a3..66a8b7da005f7dfeffbded61b02fd6a7473a1dcf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -50,6 +50,8 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
+	    "" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
 	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b1396d52e742a1710ed5ad33fbeb559d866f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d029044aa9aa1d412c28ee5d18a8e3d0be36546
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..005515ab9cb85c201a2a8b2f6417d73ceeacbc60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dd218e62fdee2a6af819079ba1ea1909185d076
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { 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/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..c833bcb0ae978572fad46780bc180f61ccb14345
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cdb8c44b19c811f3a7b4fbce102a6c768f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e139ba61af57f06cff5a9d121c97bbf41e170bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { 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/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..285fa854b3d61c4d856e9be863ee73a87f1b11a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f56aaf2a97e740a77473cab245614b6fa696c04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..749f8a7278cb4ea9fd4462887ce7f37b57f83248
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad5068aac263f1c2edb17b8707fc9d1c0af6959
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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\.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/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..b18259eaef6da1933ef2d58d63b97d4bb4e450f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..182ddf9540374f30ae3694259f1edb62161455e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd262c89085eb0dc8737ad7955c3a12531492b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..e33568400ef830abaa019b5c2727a9f3b5d5704b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..024a12e0a414730eb1cbebfca8574d548238ab28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb195eb58d59fe9ea5ed74af79646199c61bcdae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..22ed3f8af882f96da49919c60fc6f4cd74dfc54b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634065e7cb64a5069cbb3c9be4b8cf9177f5e29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..04f8466cc112c03ee5a05e6e5223d2c66a033bbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffe94de85417b81f9dcb366eb1b40dc1661c91b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc846cd7a51303ec00f8f512a54cd697fbd0682
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d0f136ef171111c1cca6cd24c4f46b9fcb7fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/libgcc/config/arm/cmse_nonsecure_call.S b/libgcc/config/arm/cmse_nonsecure_call.S
new file mode 100644
index 0000000000000000000000000000000000000000..2944858d5e896dd8cabee3eae2558799776d9016
--- /dev/null
+++ b/libgcc/config/arm/cmse_nonsecure_call.S
@@ -0,0 +1,142 @@
+/* CMSE wrapper function used to save, clear and restore callee saved registers
+   for cmse_nonsecure_call's.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+.syntax unified
+.thumb
+.global __gnu_cmse_nonsecure_call
+__gnu_cmse_nonsecure_call:
+#if defined(__ARM_ARCH_8M_MAIN__)
+push	    {r5-r11,lr}
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+
+/* Save and clear callee-saved registers only if we are dealing with hard float
+   ABI.  The unused caller-saved registers have already been cleared by GCC
+   generated code.  */
+#ifdef __ARM_PCS_VFP
+vpush.f64   {d8-d15}
+#if __ARM_FP & 0x04
+vmov.f32    s16, #1.00000
+vmov.f32    s17, #1.00000
+vmov.f32    s18, #1.00000
+vmov.f32    s19, #1.00000
+vmov.f32    s20, #1.00000
+vmov.f32    s21, #1.00000
+vmov.f32    s22, #1.00000
+vmov.f32    s23, #1.00000
+vmov.f32    s24, #1.00000
+vmov.f32    s25, #1.00000
+vmov.f32    s26, #1.00000
+vmov.f32    s27, #1.00000
+vmov.f32    s28, #1.00000
+vmov.f32    s29, #1.00000
+vmov.f32    s30, #1.00000
+vmov.f32    s31, #1.00000
+#elif __ARM_FP & 0x08
+vmov.f64    d8, #1.00000
+vmov.f64    d9, #1.00000
+vmov.f64    d10, #1.00000
+vmov.f64    d11, #1.00000
+vmov.f64    d12, #1.00000
+vmov.f64    d13, #1.00000
+vmov.f64    d14, #1.00000
+vmov.f64    d15, #1.00000
+#else
+#error "Half precision implementation not supported."
+#endif
+/* Clear the cumulative exception-status bits (0-4,7) and the
+   condition code bits (28-31) of the FPSCR.  */
+vmrs	    r5, fpscr
+movw	    r6, #65376
+movt	    r6, #4095
+ands	    r5, r6
+vmsr	    fpscr, r5
+
+/* We are not dealing with hard float ABI, so we can safely use the vlstm and
+   vlldm instructions without needing to preserve the registers used for
+   argument passing.  */
+#else
+sub	    sp, sp, #0x88 /* Reserve stack space to save all floating point
+			     registers, including FPSCR.  */
+vlstm	    sp		  /* Lazy store and clearance of d0-d16 and FPSCR.  */
+#endif /* __ARM_PCS_VFP */
+
+/* Make sure to clear the 'GE' bits of the APSR register if 32-bit SIMD
+   instructions are available.  */
+#if defined(__ARM_FEATURE_SIMD32)
+msr	    APSR_nzcvqg, r4
+#else
+msr	    APSR_nzcvq, r4
+#endif
+
+mov	    r5, r4
+mov	    r6, r4
+blxns	    r4
+
+#ifdef __ARM_PCS_VFP
+vpop.f64    {d8-d15}
+#else
+vlldm	    sp		  /* Lazy restore of d0-d16 and FPSCR.  */
+add	    sp, sp, #0x88 /* Free space used to save floating point registers.  */
+#endif /* __ARM_PCS_VFP */
+
+pop	    {r5-r11}
+
+#elif defined (__ARM_ARCH_8M_BASE__)
+push	    {r5-r7}
+mov	    r5, r8
+mov	    r6, r9
+mov	    r7, r10
+push	    {r5-r7}
+mov	    r5, r11
+mov	    r6, lr
+push	    {r5,r6}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+msr	    APSR_nzcvq, r4
+blxns	    r4
+pop	    {r5, r6}
+mov	    lr, r6
+mov	    r11, r5
+pop	    {r5-r7}
+mov	    r10, r7
+mov	    r9, r6
+mov	    r8, r5
+pop	    {r5-r7}
+blx	    lr
+
+#else
+#error "This should only be used for armv8-m base- and mainline."
+#endif
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 5618143bfd0f02b170db3f9e4c0a15cecb403cec..9e85ac06b146feaa14ab83374a0156737b870310 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -12,4 +12,6 @@ libgcc-objects += cmse.o cmse_nonsecure_call.o
 
 cmse.o: $(srcdir)/config/arm/cmse.c
 	$(gcc_compile) -c $(CMSE_OPTS) $<
+cmse_nonsecure_call.o: $(srcdir)/config/arm/cmse_nonsecure_call.S
+		       $(gcc_compile) -c $<
 endif

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

* Re: [PATCHv2 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics
  2016-10-25 16:26     ` Andre Vieira (lists)
@ 2016-10-26  9:13       ` Kyrill Tkachov
  2016-10-26 13:00         ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-26  9:13 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

Hi Andre, thanks for resending them.

On 25/10/16 17:26, Andre Vieira (lists) wrote:
> On 24/08/16 12:00, Andre Vieira (lists) wrote:
>> On 25/07/16 14:19, Andre Vieira (lists) wrote:
>>> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
>>> Security Extensions and supports the following intrinsics:
>>> cmse_TT
>>> cmse_TT_fptr
>>> cmse_TTT
>>> cmse_TTT_fptr
>>> cmse_TTA
>>> cmse_TTA_fptr
>>> cmse_TTAT
>>> cmse_TTAT_fptr
>>> cmse_check_address_range
>>> cmse_check_pointed_object
>>> cmse_is_nsfptr
>>> cmse_nsfptr_create
>>>
>>> It also defines the mandatory cmse_address_info struct and the
>>> __ARM_FEATURE_CMSE macro.
>>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>>> Extensions: Requirements on Development Tools
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config.gcc (extra_headers): Added arm_cmse.h.
>>>          * config/arm/arm-arches.def (ARM_ARCH):
>>>          (armv8-m): Add FL2_CMSE.
>>>          (armv8-m.main): Likewise.
>>>          (armv8-m.main+dsp): Likewise.
>>>          * config/arm/arm-c.c
>>>          (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>>          * config/arm/arm-protos.h
>>>          (arm_is_constant_pool_ref): Define FL2_CMSE.
>>>          * config/arm.c (arm_arch_cmse): New.
>>>          (arm_option_override): New error for unsupported cmse target.
>>>          * config/arm/arm.h (arm_arch_cmse): New.
>>>          * config/arm/arm.opt (mcmse): New.
>>>          * doc/invoke.texi (ARM Options): Add -mcmse.
>>>          * config/arm/arm_cmse.h: New file.
>>>
>>> *** libgcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/cmse.c: Likewise.
>>>          * config/arm/t-arm (HAVE_CMSE): New.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse.exp: New.
>>>          * gcc.target/arm/cmse/cmse-1.c: New.
>>>          * gcc.target/arm/cmse/cmse-12.c: New.
>>>          * lib/target-supports.exp
>>>          (check_effective_target_arm_cmse_ok): New.
>>>
>> Added more documentation as requested.
>>
>> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
>> Security Extensions and supports the following intrinsics:
>> cmse_TT
>> cmse_TT_fptr
>> cmse_TTT
>> cmse_TTT_fptr
>> cmse_TTA
>> cmse_TTA_fptr
>> cmse_TTAT
>> cmse_TTAT_fptr
>> cmse_check_address_range
>> cmse_check_pointed_object
>> cmse_is_nsfptr
>> cmse_nsfptr_create
>>
>> It also defines the mandatory cmse_address_info struct and the
>> __ARM_FEATURE_CMSE macro.
>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>> Extensions: Requirements on Development Tools
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> *** gcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config.gcc (extra_headers): Added arm_cmse.h.
>>          * config/arm/arm-arches.def (ARM_ARCH):
>>          (armv8-m): Add FL2_CMSE.
>>          (armv8-m.main): Likewise.
>>          (armv8-m.main+dsp): Likewise.
>>          * config/arm/arm-c.c
>>          (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>          * config/arm/arm-protos.h
>>          (arm_is_constant_pool_ref): Define FL2_CMSE.
>>          * config/arm.c (arm_arch_cmse): New.
>>          (arm_option_override): New error for unsupported cmse target.
>>          * config/arm/arm.h (arm_arch_cmse): New.
>>          * config/arm/arm.opt (mcmse): New.
>>          * doc/invoke.texi (ARM Options): Add -mcmse.
>>          * doc/extend.texi (ARM ARMv8-M Security Extensions): Add section.
>>          * config/arm/arm_cmse.h: New file.
>>
>> *** libgcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>          * config/arm/cmse.c: Likewise.
>>          * config/arm/t-arm (HAVE_CMSE): New.
>>
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * gcc.target/arm/cmse/cmse.exp: New.
>>          * gcc.target/arm/cmse/cmse-1.c: New.
>>          * gcc.target/arm/cmse/cmse-12.c: New.
>>          * lib/target-supports.exp
>>          (check_effective_target_arm_cmse_ok): New.
>>
> Hi,
>
> Rebased previous patch on top of trunk as requested. No changes to
> ChangeLog.
>
> Cheers,
> Andre

diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
new file mode 100644
index 0000000000000000000000000000000000000000..b4232937c6ae04754a6bbc513b143672a4be5530
--- /dev/null
+++ b/gcc/config/arm/arm_cmse.h

<snip>

+
+#if __ARM_FEATURE_CMSE & 2
+
+#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TTA_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (a)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA (void *__p)
+__CMSE_TT_ASM (a)
+
+#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+__cmse_TTAT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (at)
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT (void *__p)
+__CMSE_TT_ASM (at)
+
+#define CMSE_AU_NONSECURE	2
+#define CMSE_MPU_NONSECURE	16
+#define CMSE_NONSECURE		18
+
+#endif /* __ARM_FEATURE_CMSE & 2 */
+
+#define CMSE_MPU_UNPRIV		4
+#define CMSE_MPU_READWRITE	1
+#define CMSE_MPU_READ		8
+
+__extension__ void *
+cmse_check_address_range (void *, size_t, int);
+
+#define cmse_check_pointed_object(p, f) \
+  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
+
+#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
+
+#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
+
+#endif /* __ARM_FEATURE_CMSE & 1 */

 From my reading of the spec (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf)
cmse_nsfptr_create and cmse_is_nsfptr should be defined if bit 1 of __ARM_FEATURE_CMSE is set.
But in your patch they fall under the "#if __ARM_FEATURE_CMSE & 1" check which checks bit 0.
They should be in the "__ARM_FEATURE_CMSE & 2" block. Please double check the other defines against the SPEC to make sure they
match the feature bit in __ARM_FEATURE_CMSE.

The patch is ok with that resolved if bootstrap and test on a normal arm-none-linux-gnueabihf configuration
shows no problems.
Thanks,
Kyrill

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

* Re: [PATCHv2 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
  2016-10-25 16:28     ` Andre Vieira (lists)
@ 2016-10-26  9:33       ` Kyrill Tkachov
  2016-10-26 16:28         ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-26  9:33 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

Hi Andre,

On 25/10/16 17:28, Andre Vieira (lists) wrote:
> On 24/08/16 12:00, Andre Vieira (lists) wrote:
>> On 25/07/16 14:21, Andre Vieira (lists) wrote:
>>> This patch adds support for the ARMv8-M Security Extensions
>>> 'cmse_nonsecure_entry' attribute. In this patch we implement the
>>> attribute handling and diagnosis around the attribute. See Section 5.4
>>> of ARM®v8-M Security Extensions
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
>>>          (arm_attribute_table): Added cmse_nonsecure_entry
>>>          (arm_compute_func_type): Handle cmse_nonsecure_entry.
>>>          (cmse_func_args_or_return_in_stack): New.
>>>          (arm_handle_cmse_nonsecure_entry): New.
>>>          * config/arm/arm.h (ARM_FT_CMSE_ENTRY): New macro define.
>>>          (IS_CMSE_ENTRY): Likewise.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse-3.c: New.
>>>
>> Added more documentation as requested.
>>
>> ----
>>
>> This patch adds support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_entry' attribute. In this patch we implement the
>> attribute handling and diagnosis around the attribute. See Section 5.4
>> of ARM®v8-M Security Extensions
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> *** gcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
>>          (arm_attribute_table): Added cmse_nonsecure_entry
>>          (arm_compute_func_type): Handle cmse_nonsecure_entry.
>>          (cmse_func_args_or_return_in_stack): New.
>>          (arm_handle_cmse_nonsecure_entry): New.
>>          * config/arm/arm.h (ARM_FT_CMSE_ENTRY): New macro define.
>>          (IS_CMSE_ENTRY): Likewise.
>>          * doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * gcc.target/arm/cmse/cmse-3.c: New.
>>
> Hi,
>
> Rebased previous patch on top of trunk as requested. No changes to
> ChangeLog.
>
> Cheers,
> Andre


@@ -6661,6 +6668,110 @@ arm_handle_notshared_attribute (tree *node,
  }
  #endif

+/* This function returns true if a function with declaration FNDECL, name
+   NAME and type FNTYPE uses the stack to pass arguments or return variables
+   and false otherwise.  This is used for functions with the attributes
+   'cmse_nonsecure_call' or 'cmse_nonsecure_entry' and this function will issue
+   diagnostic messages if the stack is used.  */
+

I think NAME is the name of the attribute, not the function. The comment here is
misleading, otherwise the error message in this function doesn't make sense.
Please fix the description.

+static bool
+cmse_func_args_or_return_in_stack (tree fndecl, tree name, tree fntype)
+{
+  function_args_iterator args_iter;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
+  bool first_param = true;
+  tree arg_type, prev_arg_type = NULL_TREE, ret_type;
+
+  /* Error out if any argument is passed on the stack.  */
+  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX, fndecl);
+  args_so_far = pack_cumulative_args (&args_so_far_v);
+  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+    {
+      rtx arg_rtx;
+      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+      prev_arg_type = arg_type;
+      if (VOID_TYPE_P (arg_type))
+    continue;
+
+      if (!first_param)
+    arm_function_arg_advance (args_so_far, arg_mode, arg_type, true);
+      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type, true);
+      if (!arg_rtx
+      || arm_arg_partial_bytes (args_so_far, arg_mode, arg_type, true))
+    {
+      error ("%qE attribute not available to functions with arguments "
+         "passed on the stack", name);
+      return true;
+    }
+      first_param = false;
+    }
+
+  /* Error out for variadic functions since we cannot control how many
+     arguments will be passed and thus stack could be used. stdarg_p () is not
+     used for the checking to avoid browsing arguments twice.  */
+  if (prev_arg_type != NULL_TREE && !VOID_TYPE_P (prev_arg_type))
+    {
+      error ("%qE attribute not available to functions with variable number "
+         "of arguments", name);
+      return true;
+    }
+
+  /* Error out if return value is passed on the stack.  */
+  ret_type = TREE_TYPE (fntype);
+  if (arm_return_in_memory (ret_type, fntype))
+    {
+      error ("%qE attribute not available to functions that return value on "
+         "the stack", name);
+      return true;
+    }
+  return false;
+}
+
+/* Called upon detection of the use of the cmse_nonsecure_entry attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function declaration tree or otherwise issue a warning.  */
+
+static tree
+arm_handle_cmse_nonsecure_entry (tree *node, tree name,
+                 tree /* args */,
+                 int /* flags */,
+                 bool *no_add_attrs)
+{
+  tree fndecl;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }

Do you also want to warn the user here that the attribute will be ignored?
This looks ok to me otherwise.

Thanks,
Kyrill

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

* Re: [PATCH 3/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return
  2016-10-25 16:29   ` Andre Vieira (lists)
@ 2016-10-26 10:03     ` Kyrill Tkachov
  2016-10-27  9:55       ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-26 10:03 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

Hi Andre,

On 25/10/16 17:28, Andre Vieira (lists) wrote:
> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>> This patch extends support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_entry' attribute in two ways:
>>
>> 1) Generate two labels for the function, the regular function name and
>> one with the function's name appended to '__acle_se_', this will trigger
>> the linker to create a secure gateway veneer for this entry function.
>> 2) Return from cmse_nonsecure_entry marked functions using bxns.
>>
>> See Section 5.4 of ARM®v8-M Security Extensions
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>>
>> *** gcc/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config/arm/arm.c (use_return_insn): Change to return with  bxns
>>          when cmse_nonsecure_entry.
>>          (output_return_instruction): Likewise.
>>          (arm_output_function_prologue): Likewise.
>>          (thumb_pop): Likewise.
>>          (thumb_exit): Likewise.
>>          (arm_function_ok_for_sibcall): Disable sibcall for entry functions.
>>          (arm_asm_declare_function_name): New.
>>          * config/arm/arm-protos.h (arm_asm_declare_function_name): New.
>>          * config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
>>          use arm_asm_declare_function_name.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * gcc.target/arm/cmse/cmse-2.c: New.
>>          * gcc.target/arm/cmse/cmse-4.c: New.
>>
> Hi,
>
> Rebased previous patch on top of trunk as requested. No changes to
> ChangeLog.
>
> Cheers,
> Andre

@@ -19919,6 +19932,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
    return "";
  }
  
+/* Output in FILE asm statements needed to declare the NAME of the function
+   defined by its DECL node.  */
+
+void
+arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
+{
+  size_t cmse_name_len;
+  char *cmse_name = 0;
+  char cmse_prefix[] = "__acle_se_";
+
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_entry",
+				    DECL_ATTRIBUTES (decl)))
+    {
+      cmse_name_len = sizeof (cmse_prefix) + strlen (name);
+      cmse_name = XALLOCAVEC (char, cmse_name_len);
+      snprintf (cmse_name, cmse_name_len, "%s%s", cmse_prefix, name);
+      targetm.asm_out.globalize_label (file, cmse_name);
+    }
+

I think this definitely warrants a quick comment explaining why you're adding
__acle_se_ to the function label

  
  /* Scan INSN just before assembler is output for it.
@@ -25247,6 +25301,12 @@ thumb2_expand_return (bool simple_return)
  
    if (!simple_return && saved_regs_mask)
      {
+      /* TODO: Verify that this path is never taken for cmse_nonsecure_entry
+	 functions or adapt code to handle according to ACLE.  This path should
+	 not be reachable for cmse_nonsecure_entry functions though we prefer
+	 to guard it for now to ensure that future code changes do not silently
+	 change this behavior.  */

I think you mean s/guard/assert/

  +      gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
        if (num_regs == 1)
          {
            rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));

This is ok with those changes.
Thanks,
Kyrill

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-10-25 16:29     ` Andre Vieira (lists)
@ 2016-10-26 12:51       ` Kyrill Tkachov
  2016-10-26 16:26         ` Andre Vieira (lists)
  2016-10-26 14:14       ` [PATCHv2 4/7, GCC, ARM, V8M] " Kyrill Tkachov
  1 sibling, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-26 12:51 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

Hi Andre,

On 25/10/16 17:29, Andre Vieira (lists) wrote:
> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>> This patch extends support for the ARMv8-M Security Extensions
>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>> information through unbanked registers.
>>>
>>> When returning from a nonsecure entry function we clear all caller-saved
>>> registers that are not used to pass return values, by writing either the
>>> LR, in case of general purpose registers, or the value 0, in case of FP
>>> registers. We use the LR to write to APSR and FPSCR too. We currently do
>>> not support entry functions that pass arguments or return variables on
>>> the stack and we diagnose this. This patch relies on the existing code
>>> to make sure callee-saved registers used in cmse_nonsecure_entry
>>> functions are saved and restored thus retaining their nonsecure mode
>>> value, this should be happening already as it is required by AAPCS.
>>>
>>> This patch also clears padding bits for cmse_nonsecure_entry functions
>>> with struct and union return types. For unions a bit is only considered
>>> a padding bit if it is an unused bit in every field of that union. The
>>> function that calculates these is used in a later patch to do the same
>>> for arguments of cmse_nonsecure_call's.
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/arm.c (output_return_instruction): Clear
>>>          registers.
>>>          (thumb2_expand_return): Likewise.
>>>          (thumb1_expand_epilogue): Likewise.
>>>          (thumb_exit): Likewise.
>>>          (arm_expand_epilogue): Likewise.
>>>          (cmse_nonsecure_entry_clear_before_return): New.
>>>          (comp_not_to_clear_mask_str_un): New.
>>>          (compute_not_to_clear_mask): New.
>>>          * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
>>>          * config/arm/thumb2.md (*thumb2_return): Likewise.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
>>>          * gcc.target/arm/cmse/struct-1.c: New.
>>>          * gcc.target/arm/cmse/bitfield-1.c: New.
>>>          * gcc.target/arm/cmse/bitfield-2.c: New.
>>>          * gcc.target/arm/cmse/bitfield-3.c: New.
>>>          * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
>>> cleared.
>>>          * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>
>> Updated this patch to correctly clear only the cumulative
>> exception-status (0-4,7) and the condition code bits (28-31) of the
>> FPSCR. I also adapted the code to be handle the bigger floating point
>> register files.
>>
>> ----
>>
>> This patch extends support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>> information through unbanked registers.
>>
>> When returning from a nonsecure entry function we clear all caller-saved
>> registers that are not used to pass return values, by writing either the
>> LR, in case of general purpose registers, or the value 0, in case of FP
>> registers. We use the LR to write to APSR. For FPSCR we clear only the
>> cumulative exception-status (0-4, 7) and the condition code bits
>> (28-31). We currently do not support entry functions that pass arguments
>> or return variables on the stack and we diagnose this. This patch relies
>> on the existing code to make sure callee-saved registers used in
>> cmse_nonsecure_entry functions are saved and restored thus retaining
>> their nonsecure mode value, this should be happening already as it is
>> required by AAPCS.
>>
>> This patch also clears padding bits for cmse_nonsecure_entry functions
>> with struct and union return types. For unions a bit is only considered
>> a padding bit if it is an unused bit in every field of that union. The
>> function that calculates these is used in a later patch to do the same
>> for arguments of cmse_nonsecure_call's.
>>
>> *** gcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config/arm/arm.c (output_return_instruction): Clear
>>          registers.
>>          (thumb2_expand_return): Likewise.
>>          (thumb1_expand_epilogue): Likewise.
>>          (thumb_exit): Likewise.
>>          (arm_expand_epilogue): Likewise.
>>          (cmse_nonsecure_entry_clear_before_return): New.
>>          (comp_not_to_clear_mask_str_un): New.
>>          (compute_not_to_clear_mask): New.
>>          * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
>>          * config/arm/thumb2.md (*thumb2_return): Duplicate pattern for
>>          cmse_nonsecure_entry functions.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
>>          * gcc.target/arm/cmse/struct-1.c: New.
>>          * gcc.target/arm/cmse/bitfield-1.c: New.
>>          * gcc.target/arm/cmse/bitfield-2.c: New.
>>          * gcc.target/arm/cmse/bitfield-3.c: New.
>>          * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
>> cleared.
>>          * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>          * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>          * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>          * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>          * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>
> Hi,
>
> Rebased previous patch on top of trunk as requested. No changes to
> ChangeLog.
>
> Cheers,
> Andre

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index bb81e5662e81a26c7d3ccf9f749e8e356e6de35e..c6260323ecfd2f2842e6a5aab06b67da16619c73 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17496,6 +17496,279 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
    return;
  }
  
+/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for structs
+   and unions in the context of ARMv8-M Security Extensions.  It is used as a
+   helper function for both 'cmse_nonsecure_call' and 'cmse_nonsecure_entry'
+   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to either one
+   or four masks, depending on whether it is being computed for a
+   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
+   respectively.  The tree for the type of the argument or a field within an
+   argument is passed in ARG_TYPE, the current register this argument or field
+   starts in is kept in the pointer REGNO and updated accordingly, the bit this
+   argument or field starts at is passed in STARTING_BIT and the last used bit
+   is kept in LAST_USED_BIT which is also updated accordingly.  */
+
+static unsigned HOST_WIDE_INT
+comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
+			       uint32_t * padding_bits_to_clear,
+			       unsigned starting_bit, int * last_used_bit)
+
+{
+  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
+
+  if (TREE_CODE (arg_type) == RECORD_TYPE)
+    {
+      unsigned current_bit = starting_bit;
+      tree field;
+      long int offset, size;
+
+
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  /* The offset within a structure is always an offset from
+	     the start of that structure.  Make sure we take that into the
+	     calculation of the register based offset that we use here.  */
+	  offset = starting_bit;
+	  offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
+	  offset %= 32;
+
+	  /* This is the actual size of the field, for bitfields this is the
+	     bitfield width and not the container size.  */
+	  size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+
+	  if (*last_used_bit != offset)
+	    {
+	      if (offset < *last_used_bit)
+		{
+		  /* This field's offset is before the 'last_used_bit', that
+		     means this field goes on the next register.  So we need to
+		     pad the rest of the current register and increase the
+		     register number.  */
+		  uint32_t mask;
+		  mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
+		  mask++;
+
+		  *(padding_bits_to_clear + *regno) |= mask;

padding_bits_to_clear[*regno] |= mask;

+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      else
+		{
+		  /* Otherwise we pad the bits between the last field's end and
+		     the start of the new field.  */
+		  uint32_t mask;
+
+		  mask = UINT32_MAX >> (32 - offset);
+		  mask -= ((uint32_t) 1 << *last_used_bit) - 1;
+		  *(padding_bits_to_clear + *regno) |= mask;

Likewise.

+		}
+	      current_bit = offset;
+	    }
+
+	  /* Calculate further padding bits for inner structs/unions too.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	    {
+	      *last_used_bit = current_bit;
+	      not_to_clear_reg_mask
+		|= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
+						  padding_bits_to_clear, offset,
+						  last_used_bit);
+	    }
+	  else
+	    {
+	      /* Update 'current_bit' with this field's size.  If the
+		 'current_bit' lies in a subsequent register, update 'regno' and
+		 reset 'current_bit' to point to the current bit in that new
+		 register.  */
+	      current_bit += size;
+	      while (current_bit >= 32)
+		{
+		  current_bit-=32;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      *last_used_bit = current_bit;
+	    }
+
+	  field = TREE_CHAIN (field);
+	}
+      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+    }
+  else if (TREE_CODE (arg_type) == UNION_TYPE)
+    {
+      tree field, field_t;
+      int i, regno_t, field_size;
+      int max_reg = -1;
+      int max_bit = -1;
+      uint32_t mask;
+      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
+	= {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
+
+      /* To compute the padding bits in a union we only consider bits as
+	 padding bits if they are always either a padding bit or fall outside a
+	 fields size for all fields in the union.  */
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
+	    = {0U, 0U, 0U, 0U};
+	  int last_used_bit_t = *last_used_bit;
+	  regno_t = *regno;
+	  field_t = TREE_TYPE (field);
+
+	  /* If the field's type is either a record or a union make sure to
+	     compute their padding bits too.  */
+	  if (RECORD_OR_UNION_TYPE_P (field_t))
+	    not_to_clear_reg_mask
+	      |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
+						&padding_bits_to_clear_t[0],
+						starting_bit, &last_used_bit_t);
+	  else
+	    {
+	      field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+	      regno_t = (field_size / 32) + *regno;
+	      last_used_bit_t = (starting_bit + field_size) % 32;
+	    }
+
+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;
+
+	  /* Update the maximum size of the fields in terms of registers used
+	     ('max_reg') and the 'last_used_bit' in said register.  */
+	  if (max_reg < regno_t)
+	    {
+	      max_reg = regno_t;
+	      max_bit = last_used_bit_t;
+	    }
+	  else if (max_reg == regno_t && max_bit < last_used_bit_t)
+	    max_bit = last_used_bit_t;
+
+	  field = TREE_CHAIN (field);
+	}
+
+      /* Update the current padding_bits_to_clear using the intersection of the
+	 padding bits of all the fields.  */
+      for (i=*regno; i < max_reg; i++)
+	padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+

watch the spacing in the 'for' definition.

  +      /* Do not keep trailing padding bits, we do not know yet whether this
+	 is the end of the argument.  */
+      mask = ((uint32_t) 1 << max_bit) - 1;
+      padding_bits_to_clear[max_reg]
+	|= padding_bits_to_clear_res[max_reg] & mask;
+
+      *regno = max_reg;
+      *last_used_bit = max_bit;
+    }
+  else
+    /* This function should only be used for structs and unions.  */
+    gcc_unreachable ();
+
+  return not_to_clear_reg_mask;
+}
+
+/* In the context of ARMv8-M Security Extensions, this function is used for both
+   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to compute what
+   registers are used when returning or passing arguments, which is then
+   returned as a mask.  It will also compute a mask to indicate padding/unused
+   bits for each of these registers, and passes this through the
+   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is passed in
+   ARG_TYPE, the rtl representation of the argument is passed in ARG_RTX and
+   the starting register used to pass this argument or return value is passed
+   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to compute these
+   for struct and union types.  */
+
+static unsigned HOST_WIDE_INT
+compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
+			     uint32_t * padding_bits_to_clear)
+
+{
+  int last_used_bit = 0;
+  unsigned HOST_WIDE_INT not_to_clear_mask;
+
+  if (RECORD_OR_UNION_TYPE_P (arg_type))
+    {
+      not_to_clear_mask
+	= comp_not_to_clear_mask_str_un (arg_type, &regno,
+					 padding_bits_to_clear, 0,
+					 &last_used_bit);
+
+
+      /* If the 'last_used_bit' is not zero, that means we are still using a
+	 part of the last 'regno'.  In such cases we must clear the trailing
+	 bits.  Otherwise we are not using regno and we should mark it as to
+	 clear.  */
+      if (last_used_bit != 0)
+	*(padding_bits_to_clear + regno)
+	  |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;

padding_bits_to_clear[regno] |= ...

+      else
+	not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
+    }
+  else
+    {
+      not_to_clear_mask = 0;
+      /* We are not dealing with structs nor unions.  So these arguments may be
+	 passed in floating point registers too.  In some cases a BLKmode is
+	 used when returning or passing arguments in multiple VFP registers.  */
+      if (GET_MODE (arg_rtx) == BLKmode)
+	{
+	  int i, arg_regs;
+	  rtx reg;
+
+	  /* This should really only occur when dealing with the hard-float
+	     ABI.  */
+	  gcc_assert (TARGET_HARD_FLOAT_ABI);
+
+	  for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
+	    {
+	      reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
+	      gcc_assert (REG_P (reg));
+
+	      not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
+
+	      /* If we are dealing with DF mode, make sure we don't
+		 clear either of the registers it addresses.  */
+	      arg_regs = ARM_NUM_REGS (GET_MODE (reg));

Better assert here that you're indeed dealing with DFmode and/or you have 2 registers.

<snip>
  
+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check TARGET_HARD_FLOAT to make sure these are
+     present.  */
+  if (TARGET_HARD_FLOAT)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      maxregno = LAST_VFP_REGNUM;
+
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask[0] |= float_mask;
+
+      float_mask = (1ULL << (maxregno - 63)) - 1;
+      to_clear_mask[1] = float_mask;
+
+      /* Make sure we dont clear the two scratch registers used to clear the
+	 relevant FPSCR bits in output_return_instruction.  We have only
+	 implemented the clearing of FP registers for Thumb-2, so we assert
+	 here that VFP was not enabled for Thumb-1 ARMv8-M targets.  */
+      gcc_assert (arm_arch_thumb2);
+      emit_use (gen_rtx_REG (SImode, IP_REGNUM));
+      to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+      emit_use (gen_rtx_REG (SImode, 4));
+      to_clear_mask[0] &= ~(1ULL << 4);
+    }
+
+  /* If the user has defined registers to be caller saved, these are no longer
+     restored by the function before returning and must thus be cleared for
+     security purposes.  */
+  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+    {
+      /* We do not touch registers that can be used to pass arguments as per
+	 the AAPCS, since these should never be made callee-saved by user
+	 options.  */
+      if (regno >= FIRST_VFP_REGNUM && regno <= D7_VFP_REGNUM)
+	continue;
+      if (regno >= IP_REGNUM && regno <= PC_REGNUM)
+	continue;

Please use IN_RANGE.

+      if (call_used_regs[regno])
+	to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+    }
+
+  /* Make sure we do not clear the registers used to return the result in.  */
+  result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+  if (!VOID_TYPE_P (result_type))
+    {
+      result_rtl = arm_function_value (result_type, current_function_decl, 0);
+
+      /* No need to check that we return in registers, because we don't
+	 support returning on stack yet.  */
+      to_clear_mask[0]
+	&= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
+				       padding_bits_to_clear_ptr);
+    }
+
+  if (padding_bits_to_clear != 0)
+    {
+      rtx reg_rtx;
+      /* Padding bits to clear is not 0 so we know we are dealing with
+	 returning a composite type, which only uses r0.  Let's make sure that
+	 r1-r3 is cleared too, we will use r1 as a scratch register.  */
+      gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
+
+      reg_rtx = gen_rtx_REG (SImode, 1);
+

Use R1_REGNUM.

+      /* Fill the lower half of the negated padding_bits_to_clear.  */
+      emit_move_insn (reg_rtx,
+		      GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
+
+      /* Also fill the top half of the negated padding_bits_to_clear.  */
+      if (((~padding_bits_to_clear) >> 16) > 0)
+	emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
+						      GEN_INT (16),
+						      GEN_INT (16)),
+				GEN_INT ((~padding_bits_to_clear) >> 16)));
+
+      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, 0),
+			   gen_rtx_REG (SImode, 0),
+			   reg_rtx));

Likewise, use R0_REGNUM.

<snip>

This is ok with the changes above.
Thanks,
Kyrill

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

* Re: [PATCHv2 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics
  2016-10-26  9:13       ` Kyrill Tkachov
@ 2016-10-26 13:00         ` Kyrill Tkachov
  2016-10-27  9:54           ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-26 13:00 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 26/10/16 10:12, Kyrill Tkachov wrote:
> Hi Andre, thanks for resending them.
>
> On 25/10/16 17:26, Andre Vieira (lists) wrote:
>> On 24/08/16 12:00, Andre Vieira (lists) wrote:
>>> On 25/07/16 14:19, Andre Vieira (lists) wrote:
>>>> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
>>>> Security Extensions and supports the following intrinsics:
>>>> cmse_TT
>>>> cmse_TT_fptr
>>>> cmse_TTT
>>>> cmse_TTT_fptr
>>>> cmse_TTA
>>>> cmse_TTA_fptr
>>>> cmse_TTAT
>>>> cmse_TTAT_fptr
>>>> cmse_check_address_range
>>>> cmse_check_pointed_object
>>>> cmse_is_nsfptr
>>>> cmse_nsfptr_create
>>>>
>>>> It also defines the mandatory cmse_address_info struct and the
>>>> __ARM_FEATURE_CMSE macro.
>>>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>>>> Extensions: Requirements on Development Tools
>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>
>>>> *** gcc/ChangeLog ***
>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>
>>>>          * config.gcc (extra_headers): Added arm_cmse.h.
>>>>          * config/arm/arm-arches.def (ARM_ARCH):
>>>>          (armv8-m): Add FL2_CMSE.
>>>>          (armv8-m.main): Likewise.
>>>>          (armv8-m.main+dsp): Likewise.
>>>>          * config/arm/arm-c.c
>>>>          (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>>>          * config/arm/arm-protos.h
>>>>          (arm_is_constant_pool_ref): Define FL2_CMSE.
>>>>          * config/arm.c (arm_arch_cmse): New.
>>>>          (arm_option_override): New error for unsupported cmse target.
>>>>          * config/arm/arm.h (arm_arch_cmse): New.
>>>>          * config/arm/arm.opt (mcmse): New.
>>>>          * doc/invoke.texi (ARM Options): Add -mcmse.
>>>>          * config/arm/arm_cmse.h: New file.
>>>>
>>>> *** libgcc/ChangeLog ***
>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>
>>>>          * config/arm/cmse.c: Likewise.
>>>>          * config/arm/t-arm (HAVE_CMSE): New.
>>>>
>>>> *** gcc/testsuite/ChangeLog ***
>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>
>>>>          * gcc.target/arm/cmse/cmse.exp: New.
>>>>          * gcc.target/arm/cmse/cmse-1.c: New.
>>>>          * gcc.target/arm/cmse/cmse-12.c: New.
>>>>          * lib/target-supports.exp
>>>>          (check_effective_target_arm_cmse_ok): New.


Just remembered, new effective target checks should be documented in sourcebuild.texi
Kyrill

>>>>
>>> Added more documentation as requested.
>>>
>>> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
>>> Security Extensions and supports the following intrinsics:
>>> cmse_TT
>>> cmse_TT_fptr
>>> cmse_TTT
>>> cmse_TTT_fptr
>>> cmse_TTA
>>> cmse_TTA_fptr
>>> cmse_TTAT
>>> cmse_TTAT_fptr
>>> cmse_check_address_range
>>> cmse_check_pointed_object
>>> cmse_is_nsfptr
>>> cmse_nsfptr_create
>>>
>>> It also defines the mandatory cmse_address_info struct and the
>>> __ARM_FEATURE_CMSE macro.
>>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>>> Extensions: Requirements on Development Tools
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>
>>>          * config.gcc (extra_headers): Added arm_cmse.h.
>>>          * config/arm/arm-arches.def (ARM_ARCH):
>>>          (armv8-m): Add FL2_CMSE.
>>>          (armv8-m.main): Likewise.
>>>          (armv8-m.main+dsp): Likewise.
>>>          * config/arm/arm-c.c
>>>          (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>>          * config/arm/arm-protos.h
>>>          (arm_is_constant_pool_ref): Define FL2_CMSE.
>>>          * config/arm.c (arm_arch_cmse): New.
>>>          (arm_option_override): New error for unsupported cmse target.
>>>          * config/arm/arm.h (arm_arch_cmse): New.
>>>          * config/arm/arm.opt (mcmse): New.
>>>          * doc/invoke.texi (ARM Options): Add -mcmse.
>>>          * doc/extend.texi (ARM ARMv8-M Security Extensions): Add section.
>>>          * config/arm/arm_cmse.h: New file.
>>>
>>> *** libgcc/ChangeLog ***
>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>          * config/arm/cmse.c: Likewise.
>>>          * config/arm/t-arm (HAVE_CMSE): New.
>>>
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse.exp: New.
>>>          * gcc.target/arm/cmse/cmse-1.c: New.
>>>          * gcc.target/arm/cmse/cmse-12.c: New.
>>>          * lib/target-supports.exp
>>>          (check_effective_target_arm_cmse_ok): New.
>>>
>> Hi,
>>
>> Rebased previous patch on top of trunk as requested. No changes to
>> ChangeLog.
>>
>> Cheers,
>> Andre
>
> diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..b4232937c6ae04754a6bbc513b143672a4be5530
> --- /dev/null
> +++ b/gcc/config/arm/arm_cmse.h
>
> <snip>
>
> +
> +#if __ARM_FEATURE_CMSE & 2
> +
> +#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
> +
> +__extension__ static __inline __attribute__ ((__always_inline__))
> +cmse_address_info_t
> +__cmse_TTA_fptr (__cmse_fptr __p)
> +__CMSE_TT_ASM (a)
> +
> +__extension__ static __inline __attribute__ ((__always_inline__))
> +cmse_address_info_t
> +cmse_TTA (void *__p)
> +__CMSE_TT_ASM (a)
> +
> +#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
> +
> +__extension__ static __inline cmse_address_info_t
> +__attribute__ ((__always_inline__))
> +__cmse_TTAT_fptr (__cmse_fptr __p)
> +__CMSE_TT_ASM (at)
> +
> +__extension__ static __inline cmse_address_info_t
> +__attribute__ ((__always_inline__))
> +cmse_TTAT (void *__p)
> +__CMSE_TT_ASM (at)
> +
> +#define CMSE_AU_NONSECURE    2
> +#define CMSE_MPU_NONSECURE    16
> +#define CMSE_NONSECURE        18
> +
> +#endif /* __ARM_FEATURE_CMSE & 2 */
> +
> +#define CMSE_MPU_UNPRIV        4
> +#define CMSE_MPU_READWRITE    1
> +#define CMSE_MPU_READ        8
> +
> +__extension__ void *
> +cmse_check_address_range (void *, size_t, int);
> +
> +#define cmse_check_pointed_object(p, f) \
> +  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
> +
> +#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
> +
> +#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
> +
> +#endif /* __ARM_FEATURE_CMSE & 1 */
>
> From my reading of the spec (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf)
> cmse_nsfptr_create and cmse_is_nsfptr should be defined if bit 1 of __ARM_FEATURE_CMSE is set.
> But in your patch they fall under the "#if __ARM_FEATURE_CMSE & 1" check which checks bit 0.
> They should be in the "__ARM_FEATURE_CMSE & 2" block. Please double check the other defines against the SPEC to make sure they
> match the feature bit in __ARM_FEATURE_CMSE.
>
> The patch is ok with that resolved if bootstrap and test on a normal arm-none-linux-gnueabihf configuration
> shows no problems.
> Thanks,
> Kyrill
>

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-10-25 16:29     ` Andre Vieira (lists)
  2016-10-26 12:51       ` Kyrill Tkachov
@ 2016-10-26 14:14       ` Kyrill Tkachov
  1 sibling, 0 replies; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-26 14:14 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

Hi Andre,

On 25/10/16 17:29, Andre Vieira (lists) wrote:
> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>> This patch extends support for the ARMv8-M Security Extensions
>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>> information through unbanked registers.
>>>
>>> When returning from a nonsecure entry function we clear all caller-saved
>>> registers that are not used to pass return values, by writing either the
>>> LR, in case of general purpose registers, or the value 0, in case of FP
>>> registers. We use the LR to write to APSR and FPSCR too. We currently do
>>> not support entry functions that pass arguments or return variables on
>>> the stack and we diagnose this. This patch relies on the existing code
>>> to make sure callee-saved registers used in cmse_nonsecure_entry
>>> functions are saved and restored thus retaining their nonsecure mode
>>> value, this should be happening already as it is required by AAPCS.
>>>
>>> This patch also clears padding bits for cmse_nonsecure_entry functions
>>> with struct and union return types. For unions a bit is only considered
>>> a padding bit if it is an unused bit in every field of that union. The
>>> function that calculates these is used in a later patch to do the same
>>> for arguments of cmse_nonsecure_call's.
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/arm.c (output_return_instruction): Clear
>>>          registers.
>>>          (thumb2_expand_return): Likewise.
>>>          (thumb1_expand_epilogue): Likewise.
>>>          (thumb_exit): Likewise.
>>>          (arm_expand_epilogue): Likewise.
>>>          (cmse_nonsecure_entry_clear_before_return): New.
>>>          (comp_not_to_clear_mask_str_un): New.
>>>          (compute_not_to_clear_mask): New.
>>>          * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
>>>          * config/arm/thumb2.md (*thumb2_return): Likewise.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
>>>          * gcc.target/arm/cmse/struct-1.c: New.
>>>          * gcc.target/arm/cmse/bitfield-1.c: New.
>>>          * gcc.target/arm/cmse/bitfield-2.c: New.
>>>          * gcc.target/arm/cmse/bitfield-3.c: New.
>>>          * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
>>> cleared.
>>>          * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>
>> Updated this patch to correctly clear only the cumulative
>> exception-status (0-4,7) and the condition code bits (28-31) of the
>> FPSCR. I also adapted the code to be handle the bigger floating point
>> register files.
>>
>> ----
>>
>> This patch extends support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>> information through unbanked registers.
>>
>> When returning from a nonsecure entry function we clear all caller-saved
>> registers that are not used to pass return values, by writing either the
>> LR, in case of general purpose registers, or the value 0, in case of FP
>> registers. We use the LR to write to APSR. For FPSCR we clear only the
>> cumulative exception-status (0-4, 7) and the condition code bits
>> (28-31). We currently do not support entry functions that pass arguments
>> or return variables on the stack and we diagnose this. This patch relies
>> on the existing code to make sure callee-saved registers used in
>> cmse_nonsecure_entry functions are saved and restored thus retaining
>> their nonsecure mode value, this should be happening already as it is
>> required by AAPCS.
>>
>> This patch also clears padding bits for cmse_nonsecure_entry functions
>> with struct and union return types. For unions a bit is only considered
>> a padding bit if it is an unused bit in every field of that union. The
>> function that calculates these is used in a later patch to do the same
>> for arguments of cmse_nonsecure_call's.
>>
>> *** gcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config/arm/arm.c (output_return_instruction): Clear
>>          registers.
>>          (thumb2_expand_return): Likewise.
>>          (thumb1_expand_epilogue): Likewise.
>>          (thumb_exit): Likewise.
>>          (arm_expand_epilogue): Likewise.
>>          (cmse_nonsecure_entry_clear_before_return): New.
>>          (comp_not_to_clear_mask_str_un): New.
>>          (compute_not_to_clear_mask): New.
>>          * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
>>          * config/arm/thumb2.md (*thumb2_return): Duplicate pattern for
>>          cmse_nonsecure_entry functions.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
>>          * gcc.target/arm/cmse/struct-1.c: New.
>>          * gcc.target/arm/cmse/bitfield-1.c: New.
>>          * gcc.target/arm/cmse/bitfield-2.c: New.
>>          * gcc.target/arm/cmse/bitfield-3.c: New.
>>          * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
>> cleared.
>>          * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>          * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>          * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>          * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>          * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>
> Hi,
>
> Rebased previous patch on top of trunk as requested. No changes to
> ChangeLog.
>
> Cheers,
> Andre

+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;

I tried this on a clean trunk (without any of my patches) and I'm getting a build error
about UINT32_MAX not being defined. Did you have some other patches in your tree that masked this?
I think avoiding UINT32_MAX would be sensible here. I don't see it used anywhere else in gcc.
Perhaps just using (uint32_t)-1 would work? Or reuse the 64-bit HOST_WIDE_INT_M1U to get a mask of all ones.

Kyrill

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-10-26 12:51       ` Kyrill Tkachov
@ 2016-10-26 16:26         ` Andre Vieira (lists)
  2016-10-26 16:30           ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-26 16:26 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches

On 26/10/16 13:51, Kyrill Tkachov wrote:
> Hi Andre,
> 
> On 25/10/16 17:29, Andre Vieira (lists) wrote:
>> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>>> This patch extends support for the ARMv8-M Security Extensions
>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>> information through unbanked registers.
>>>>
>>>> When returning from a nonsecure entry function we clear all
>>>> caller-saved
>>>> registers that are not used to pass return values, by writing either
>>>> the
>>>> LR, in case of general purpose registers, or the value 0, in case of FP
>>>> registers. We use the LR to write to APSR and FPSCR too. We
>>>> currently do
>>>> not support entry functions that pass arguments or return variables on
>>>> the stack and we diagnose this. This patch relies on the existing code
>>>> to make sure callee-saved registers used in cmse_nonsecure_entry
>>>> functions are saved and restored thus retaining their nonsecure mode
>>>> value, this should be happening already as it is required by AAPCS.
>>>>
>>>> This patch also clears padding bits for cmse_nonsecure_entry functions
>>>> with struct and union return types. For unions a bit is only considered
>>>> a padding bit if it is an unused bit in every field of that union. The
>>>> function that calculates these is used in a later patch to do the same
>>>> for arguments of cmse_nonsecure_call's.
>>>>
>>>> *** gcc/ChangeLog ***
>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>          * config/arm/arm.c (output_return_instruction): Clear
>>>>          registers.
>>>>          (thumb2_expand_return): Likewise.
>>>>          (thumb1_expand_epilogue): Likewise.
>>>>          (thumb_exit): Likewise.
>>>>          (arm_expand_epilogue): Likewise.
>>>>          (cmse_nonsecure_entry_clear_before_return): New.
>>>>          (comp_not_to_clear_mask_str_un): New.
>>>>          (compute_not_to_clear_mask): New.
>>>>          * config/arm/thumb1.md (*epilogue_insns): Change length
>>>> attribute.
>>>>          * config/arm/thumb2.md (*thumb2_return): Likewise.
>>>>
>>>> *** gcc/testsuite/ChangeLog ***
>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>          * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>> separate.
>>>>          * gcc.target/arm/cmse/struct-1.c: New.
>>>>          * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>          * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>          * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>          * gcc.target/arm/cmse/baseline/cmse-2.c: Test that
>>>> registers are
>>>> cleared.
>>>>          * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>          * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>          * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>          * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>          * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>
>>> Updated this patch to correctly clear only the cumulative
>>> exception-status (0-4,7) and the condition code bits (28-31) of the
>>> FPSCR. I also adapted the code to be handle the bigger floating point
>>> register files.
>>>
>>> ----
>>>
>>> This patch extends support for the ARMv8-M Security Extensions
>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>> information through unbanked registers.
>>>
>>> When returning from a nonsecure entry function we clear all caller-saved
>>> registers that are not used to pass return values, by writing either the
>>> LR, in case of general purpose registers, or the value 0, in case of FP
>>> registers. We use the LR to write to APSR. For FPSCR we clear only the
>>> cumulative exception-status (0-4, 7) and the condition code bits
>>> (28-31). We currently do not support entry functions that pass arguments
>>> or return variables on the stack and we diagnose this. This patch relies
>>> on the existing code to make sure callee-saved registers used in
>>> cmse_nonsecure_entry functions are saved and restored thus retaining
>>> their nonsecure mode value, this should be happening already as it is
>>> required by AAPCS.
>>>
>>> This patch also clears padding bits for cmse_nonsecure_entry functions
>>> with struct and union return types. For unions a bit is only considered
>>> a padding bit if it is an unused bit in every field of that union. The
>>> function that calculates these is used in a later patch to do the same
>>> for arguments of cmse_nonsecure_call's.
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/arm.c (output_return_instruction): Clear
>>>          registers.
>>>          (thumb2_expand_return): Likewise.
>>>          (thumb1_expand_epilogue): Likewise.
>>>          (thumb_exit): Likewise.
>>>          (arm_expand_epilogue): Likewise.
>>>          (cmse_nonsecure_entry_clear_before_return): New.
>>>          (comp_not_to_clear_mask_str_un): New.
>>>          (compute_not_to_clear_mask): New.
>>>          * config/arm/thumb1.md (*epilogue_insns): Change length
>>> attribute.
>>>          * config/arm/thumb2.md (*thumb2_return): Duplicate pattern for
>>>          cmse_nonsecure_entry functions.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>> separate.
>>>          * gcc.target/arm/cmse/struct-1.c: New.
>>>          * gcc.target/arm/cmse/bitfield-1.c: New.
>>>          * gcc.target/arm/cmse/bitfield-2.c: New.
>>>          * gcc.target/arm/cmse/bitfield-3.c: New.
>>>          * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers
>>> are
>>> cleared.
>>>          * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>          * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>
>> Hi,
>>
>> Rebased previous patch on top of trunk as requested. No changes to
>> ChangeLog.
>>
>> Cheers,
>> Andre
> 
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index
> bb81e5662e81a26c7d3ccf9f749e8e356e6de35e..c6260323ecfd2f2842e6a5aab06b67da16619c73
> 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -17496,6 +17496,279 @@ note_invalid_constants (rtx_insn *insn,
> HOST_WIDE_INT address, int do_pushes)
>    return;
>  }
>  
> +/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for
> structs
> +   and unions in the context of ARMv8-M Security Extensions.  It is
> used as a
> +   helper function for both 'cmse_nonsecure_call' and
> 'cmse_nonsecure_entry'
> +   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to
> either one
> +   or four masks, depending on whether it is being computed for a
> +   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
> +   respectively.  The tree for the type of the argument or a field
> within an
> +   argument is passed in ARG_TYPE, the current register this argument
> or field
> +   starts in is kept in the pointer REGNO and updated accordingly, the
> bit this
> +   argument or field starts at is passed in STARTING_BIT and the last
> used bit
> +   is kept in LAST_USED_BIT which is also updated accordingly.  */
> +
> +static unsigned HOST_WIDE_INT
> +comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
> +                   uint32_t * padding_bits_to_clear,
> +                   unsigned starting_bit, int * last_used_bit)
> +
> +{
> +  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
> +
> +  if (TREE_CODE (arg_type) == RECORD_TYPE)
> +    {
> +      unsigned current_bit = starting_bit;
> +      tree field;
> +      long int offset, size;
> +
> +
> +      field = TYPE_FIELDS (arg_type);
> +      while (field)
> +    {
> +      /* The offset within a structure is always an offset from
> +         the start of that structure.  Make sure we take that into the
> +         calculation of the register based offset that we use here.  */
> +      offset = starting_bit;
> +      offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
> +      offset %= 32;
> +
> +      /* This is the actual size of the field, for bitfields this is the
> +         bitfield width and not the container size.  */
> +      size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
> +
> +      if (*last_used_bit != offset)
> +        {
> +          if (offset < *last_used_bit)
> +        {
> +          /* This field's offset is before the 'last_used_bit', that
> +             means this field goes on the next register.  So we need to
> +             pad the rest of the current register and increase the
> +             register number.  */
> +          uint32_t mask;
> +          mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
> +          mask++;
> +
> +          *(padding_bits_to_clear + *regno) |= mask;
> 
> padding_bits_to_clear[*regno] |= mask;
> 
> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
> +          (*regno)++;
> +        }
> +          else
> +        {
> +          /* Otherwise we pad the bits between the last field's end and
> +             the start of the new field.  */
> +          uint32_t mask;
> +
> +          mask = UINT32_MAX >> (32 - offset);
> +          mask -= ((uint32_t) 1 << *last_used_bit) - 1;
> +          *(padding_bits_to_clear + *regno) |= mask;
> 
> Likewise.
> 
> +        }
> +          current_bit = offset;
> +        }
> +
> +      /* Calculate further padding bits for inner structs/unions too.  */
> +      if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
> +        {
> +          *last_used_bit = current_bit;
> +          not_to_clear_reg_mask
> +        |= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
> +                          padding_bits_to_clear, offset,
> +                          last_used_bit);
> +        }
> +      else
> +        {
> +          /* Update 'current_bit' with this field's size.  If the
> +         'current_bit' lies in a subsequent register, update 'regno' and
> +         reset 'current_bit' to point to the current bit in that new
> +         register.  */
> +          current_bit += size;
> +          while (current_bit >= 32)
> +        {
> +          current_bit-=32;
> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
> +          (*regno)++;
> +        }
> +          *last_used_bit = current_bit;
> +        }
> +
> +      field = TREE_CHAIN (field);
> +    }
> +      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
> +    }
> +  else if (TREE_CODE (arg_type) == UNION_TYPE)
> +    {
> +      tree field, field_t;
> +      int i, regno_t, field_size;
> +      int max_reg = -1;
> +      int max_bit = -1;
> +      uint32_t mask;
> +      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
> +    = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
> +
> +      /* To compute the padding bits in a union we only consider bits as
> +     padding bits if they are always either a padding bit or fall
> outside a
> +     fields size for all fields in the union.  */
> +      field = TYPE_FIELDS (arg_type);
> +      while (field)
> +    {
> +      uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
> +        = {0U, 0U, 0U, 0U};
> +      int last_used_bit_t = *last_used_bit;
> +      regno_t = *regno;
> +      field_t = TREE_TYPE (field);
> +
> +      /* If the field's type is either a record or a union make sure to
> +         compute their padding bits too.  */
> +      if (RECORD_OR_UNION_TYPE_P (field_t))
> +        not_to_clear_reg_mask
> +          |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
> +                        &padding_bits_to_clear_t[0],
> +                        starting_bit, &last_used_bit_t);
> +      else
> +        {
> +          field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
> +          regno_t = (field_size / 32) + *regno;
> +          last_used_bit_t = (starting_bit + field_size) % 32;
> +        }
> +
> +      for (i = *regno; i < regno_t; i++)
> +        {
> +          /* For all but the last register used by this field only keep
> the
> +         padding bits that were padding bits in this field.  */
> +          padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
> +        }
> +
> +        /* For the last register, keep all padding bits that were padding
> +           bits in this field and any padding bits that are still valid
> +           as padding bits but fall outside of this field's size.  */
> +        mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
> +        padding_bits_to_clear_res[regno_t]
> +          &= padding_bits_to_clear_t[regno_t] | mask;
> +
> +      /* Update the maximum size of the fields in terms of registers used
> +         ('max_reg') and the 'last_used_bit' in said register.  */
> +      if (max_reg < regno_t)
> +        {
> +          max_reg = regno_t;
> +          max_bit = last_used_bit_t;
> +        }
> +      else if (max_reg == regno_t && max_bit < last_used_bit_t)
> +        max_bit = last_used_bit_t;
> +
> +      field = TREE_CHAIN (field);
> +    }
> +
> +      /* Update the current padding_bits_to_clear using the
> intersection of the
> +     padding bits of all the fields.  */
> +      for (i=*regno; i < max_reg; i++)
> +    padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
> +
> 
> watch the spacing in the 'for' definition.
> 
>  +      /* Do not keep trailing padding bits, we do not know yet whether
> this
> +     is the end of the argument.  */
> +      mask = ((uint32_t) 1 << max_bit) - 1;
> +      padding_bits_to_clear[max_reg]
> +    |= padding_bits_to_clear_res[max_reg] & mask;
> +
> +      *regno = max_reg;
> +      *last_used_bit = max_bit;
> +    }
> +  else
> +    /* This function should only be used for structs and unions.  */
> +    gcc_unreachable ();
> +
> +  return not_to_clear_reg_mask;
> +}
> +
> +/* In the context of ARMv8-M Security Extensions, this function is used
> for both
> +   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to
> compute what
> +   registers are used when returning or passing arguments, which is then
> +   returned as a mask.  It will also compute a mask to indicate
> padding/unused
> +   bits for each of these registers, and passes this through the
> +   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is
> passed in
> +   ARG_TYPE, the rtl representation of the argument is passed in
> ARG_RTX and
> +   the starting register used to pass this argument or return value is
> passed
> +   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to
> compute these
> +   for struct and union types.  */
> +
> +static unsigned HOST_WIDE_INT
> +compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
> +                 uint32_t * padding_bits_to_clear)
> +
> +{
> +  int last_used_bit = 0;
> +  unsigned HOST_WIDE_INT not_to_clear_mask;
> +
> +  if (RECORD_OR_UNION_TYPE_P (arg_type))
> +    {
> +      not_to_clear_mask
> +    = comp_not_to_clear_mask_str_un (arg_type, &regno,
> +                     padding_bits_to_clear, 0,
> +                     &last_used_bit);
> +
> +
> +      /* If the 'last_used_bit' is not zero, that means we are still
> using a
> +     part of the last 'regno'.  In such cases we must clear the trailing
> +     bits.  Otherwise we are not using regno and we should mark it as to
> +     clear.  */
> +      if (last_used_bit != 0)
> +    *(padding_bits_to_clear + regno)
> +      |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;
> 
> padding_bits_to_clear[regno] |= ...
> 
> +      else
> +    not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
> +    }
> +  else
> +    {
> +      not_to_clear_mask = 0;
> +      /* We are not dealing with structs nor unions.  So these
> arguments may be
> +     passed in floating point registers too.  In some cases a BLKmode is
> +     used when returning or passing arguments in multiple VFP
> registers.  */
> +      if (GET_MODE (arg_rtx) == BLKmode)
> +    {
> +      int i, arg_regs;
> +      rtx reg;
> +
> +      /* This should really only occur when dealing with the hard-float
> +         ABI.  */
> +      gcc_assert (TARGET_HARD_FLOAT_ABI);
> +
> +      for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
> +        {
> +          reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
> +          gcc_assert (REG_P (reg));
> +
> +          not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
> +
> +          /* If we are dealing with DF mode, make sure we don't
> +         clear either of the registers it addresses.  */
> +          arg_regs = ARM_NUM_REGS (GET_MODE (reg));
> 
> Better assert here that you're indeed dealing with DFmode and/or you
> have 2 registers.
> 
The current code actually works for larger modes too. I don't think code
will ever be generated with larger types, but why assert if it works anyway?

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

* Re: [PATCHv2 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
  2016-10-26 16:28         ` Andre Vieira (lists)
@ 2016-10-26 16:28           ` Kyrill Tkachov
  2016-10-27  9:54             ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-26 16:28 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 26/10/16 17:28, Andre Vieira (lists) wrote:
> On 26/10/16 10:33, Kyrill Tkachov wrote:
>> +static tree
>> +arm_handle_cmse_nonsecure_entry (tree *node, tree name,
>> +                 tree /* args */,
>> +                 int /* flags */,
>> +                 bool *no_add_attrs)
>> +{
>> +  tree fndecl;
>> +
>> +  if (!use_cmse)
>> +    {
>> +      *no_add_attrs = true;
>> +      return NULL_TREE;
>> +    }
>>
>> Do you also want to warn the user here that the attribute will be ignored?
>> This looks ok to me otherwise.
>>
> Can easily do and might be more user friendly. How about
> "<attribute_name> attribute ignored without -mcmse option."

Yes, that's fine (without the full stop at the end)
Kyrill

> Cheers,
> Andre
>

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

* Re: [PATCHv2 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
  2016-10-26  9:33       ` Kyrill Tkachov
@ 2016-10-26 16:28         ` Andre Vieira (lists)
  2016-10-26 16:28           ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-26 16:28 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches

On 26/10/16 10:33, Kyrill Tkachov wrote:
> 
> +static tree
> +arm_handle_cmse_nonsecure_entry (tree *node, tree name,
> +                 tree /* args */,
> +                 int /* flags */,
> +                 bool *no_add_attrs)
> +{
> +  tree fndecl;
> +
> +  if (!use_cmse)
> +    {
> +      *no_add_attrs = true;
> +      return NULL_TREE;
> +    }
> 
> Do you also want to warn the user here that the attribute will be ignored?
> This looks ok to me otherwise.
> 

Can easily do and might be more user friendly. How about
"<attribute_name> attribute ignored without -mcmse option."

Cheers,
Andre

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-10-26 16:26         ` Andre Vieira (lists)
@ 2016-10-26 16:30           ` Kyrill Tkachov
  2016-10-27 10:00             ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-26 16:30 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 26/10/16 17:26, Andre Vieira (lists) wrote:
> On 26/10/16 13:51, Kyrill Tkachov wrote:
>> Hi Andre,
>>
>> On 25/10/16 17:29, Andre Vieira (lists) wrote:
>>> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>>>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>>> information through unbanked registers.
>>>>>
>>>>> When returning from a nonsecure entry function we clear all
>>>>> caller-saved
>>>>> registers that are not used to pass return values, by writing either
>>>>> the
>>>>> LR, in case of general purpose registers, or the value 0, in case of FP
>>>>> registers. We use the LR to write to APSR and FPSCR too. We
>>>>> currently do
>>>>> not support entry functions that pass arguments or return variables on
>>>>> the stack and we diagnose this. This patch relies on the existing code
>>>>> to make sure callee-saved registers used in cmse_nonsecure_entry
>>>>> functions are saved and restored thus retaining their nonsecure mode
>>>>> value, this should be happening already as it is required by AAPCS.
>>>>>
>>>>> This patch also clears padding bits for cmse_nonsecure_entry functions
>>>>> with struct and union return types. For unions a bit is only considered
>>>>> a padding bit if it is an unused bit in every field of that union. The
>>>>> function that calculates these is used in a later patch to do the same
>>>>> for arguments of cmse_nonsecure_call's.
>>>>>
>>>>> *** gcc/ChangeLog ***
>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>
>>>>>           * config/arm/arm.c (output_return_instruction): Clear
>>>>>           registers.
>>>>>           (thumb2_expand_return): Likewise.
>>>>>           (thumb1_expand_epilogue): Likewise.
>>>>>           (thumb_exit): Likewise.
>>>>>           (arm_expand_epilogue): Likewise.
>>>>>           (cmse_nonsecure_entry_clear_before_return): New.
>>>>>           (comp_not_to_clear_mask_str_un): New.
>>>>>           (compute_not_to_clear_mask): New.
>>>>>           * config/arm/thumb1.md (*epilogue_insns): Change length
>>>>> attribute.
>>>>>           * config/arm/thumb2.md (*thumb2_return): Likewise.
>>>>>
>>>>> *** gcc/testsuite/ChangeLog ***
>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>
>>>>>           * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>>> separate.
>>>>>           * gcc.target/arm/cmse/struct-1.c: New.
>>>>>           * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>>           * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>>           * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>>           * gcc.target/arm/cmse/baseline/cmse-2.c: Test that
>>>>> registers are
>>>>> cleared.
>>>>>           * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>>           * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>>           * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>>           * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>>           * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>>
>>>> Updated this patch to correctly clear only the cumulative
>>>> exception-status (0-4,7) and the condition code bits (28-31) of the
>>>> FPSCR. I also adapted the code to be handle the bigger floating point
>>>> register files.
>>>>
>>>> ----
>>>>
>>>> This patch extends support for the ARMv8-M Security Extensions
>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>> information through unbanked registers.
>>>>
>>>> When returning from a nonsecure entry function we clear all caller-saved
>>>> registers that are not used to pass return values, by writing either the
>>>> LR, in case of general purpose registers, or the value 0, in case of FP
>>>> registers. We use the LR to write to APSR. For FPSCR we clear only the
>>>> cumulative exception-status (0-4, 7) and the condition code bits
>>>> (28-31). We currently do not support entry functions that pass arguments
>>>> or return variables on the stack and we diagnose this. This patch relies
>>>> on the existing code to make sure callee-saved registers used in
>>>> cmse_nonsecure_entry functions are saved and restored thus retaining
>>>> their nonsecure mode value, this should be happening already as it is
>>>> required by AAPCS.
>>>>
>>>> This patch also clears padding bits for cmse_nonsecure_entry functions
>>>> with struct and union return types. For unions a bit is only considered
>>>> a padding bit if it is an unused bit in every field of that union. The
>>>> function that calculates these is used in a later patch to do the same
>>>> for arguments of cmse_nonsecure_call's.
>>>>
>>>> *** gcc/ChangeLog ***
>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>           * config/arm/arm.c (output_return_instruction): Clear
>>>>           registers.
>>>>           (thumb2_expand_return): Likewise.
>>>>           (thumb1_expand_epilogue): Likewise.
>>>>           (thumb_exit): Likewise.
>>>>           (arm_expand_epilogue): Likewise.
>>>>           (cmse_nonsecure_entry_clear_before_return): New.
>>>>           (comp_not_to_clear_mask_str_un): New.
>>>>           (compute_not_to_clear_mask): New.
>>>>           * config/arm/thumb1.md (*epilogue_insns): Change length
>>>> attribute.
>>>>           * config/arm/thumb2.md (*thumb2_return): Duplicate pattern for
>>>>           cmse_nonsecure_entry functions.
>>>>
>>>> *** gcc/testsuite/ChangeLog ***
>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>           * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>> separate.
>>>>           * gcc.target/arm/cmse/struct-1.c: New.
>>>>           * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>           * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>           * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>           * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers
>>>> are
>>>> cleared.
>>>>           * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>           * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>           * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>           * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>           * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>
>>> Hi,
>>>
>>> Rebased previous patch on top of trunk as requested. No changes to
>>> ChangeLog.
>>>
>>> Cheers,
>>> Andre
>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>> index
>> bb81e5662e81a26c7d3ccf9f749e8e356e6de35e..c6260323ecfd2f2842e6a5aab06b67da16619c73
>> 100644
>> --- a/gcc/config/arm/arm.c
>> +++ b/gcc/config/arm/arm.c
>> @@ -17496,6 +17496,279 @@ note_invalid_constants (rtx_insn *insn,
>> HOST_WIDE_INT address, int do_pushes)
>>     return;
>>   }
>>   
>> +/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for
>> structs
>> +   and unions in the context of ARMv8-M Security Extensions.  It is
>> used as a
>> +   helper function for both 'cmse_nonsecure_call' and
>> 'cmse_nonsecure_entry'
>> +   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to
>> either one
>> +   or four masks, depending on whether it is being computed for a
>> +   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
>> +   respectively.  The tree for the type of the argument or a field
>> within an
>> +   argument is passed in ARG_TYPE, the current register this argument
>> or field
>> +   starts in is kept in the pointer REGNO and updated accordingly, the
>> bit this
>> +   argument or field starts at is passed in STARTING_BIT and the last
>> used bit
>> +   is kept in LAST_USED_BIT which is also updated accordingly.  */
>> +
>> +static unsigned HOST_WIDE_INT
>> +comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
>> +                   uint32_t * padding_bits_to_clear,
>> +                   unsigned starting_bit, int * last_used_bit)
>> +
>> +{
>> +  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
>> +
>> +  if (TREE_CODE (arg_type) == RECORD_TYPE)
>> +    {
>> +      unsigned current_bit = starting_bit;
>> +      tree field;
>> +      long int offset, size;
>> +
>> +
>> +      field = TYPE_FIELDS (arg_type);
>> +      while (field)
>> +    {
>> +      /* The offset within a structure is always an offset from
>> +         the start of that structure.  Make sure we take that into the
>> +         calculation of the register based offset that we use here.  */
>> +      offset = starting_bit;
>> +      offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
>> +      offset %= 32;
>> +
>> +      /* This is the actual size of the field, for bitfields this is the
>> +         bitfield width and not the container size.  */
>> +      size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>> +
>> +      if (*last_used_bit != offset)
>> +        {
>> +          if (offset < *last_used_bit)
>> +        {
>> +          /* This field's offset is before the 'last_used_bit', that
>> +             means this field goes on the next register.  So we need to
>> +             pad the rest of the current register and increase the
>> +             register number.  */
>> +          uint32_t mask;
>> +          mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
>> +          mask++;
>> +
>> +          *(padding_bits_to_clear + *regno) |= mask;
>>
>> padding_bits_to_clear[*regno] |= mask;
>>
>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>> +          (*regno)++;
>> +        }
>> +          else
>> +        {
>> +          /* Otherwise we pad the bits between the last field's end and
>> +             the start of the new field.  */
>> +          uint32_t mask;
>> +
>> +          mask = UINT32_MAX >> (32 - offset);
>> +          mask -= ((uint32_t) 1 << *last_used_bit) - 1;
>> +          *(padding_bits_to_clear + *regno) |= mask;
>>
>> Likewise.
>>
>> +        }
>> +          current_bit = offset;
>> +        }
>> +
>> +      /* Calculate further padding bits for inner structs/unions too.  */
>> +      if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
>> +        {
>> +          *last_used_bit = current_bit;
>> +          not_to_clear_reg_mask
>> +        |= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
>> +                          padding_bits_to_clear, offset,
>> +                          last_used_bit);
>> +        }
>> +      else
>> +        {
>> +          /* Update 'current_bit' with this field's size.  If the
>> +         'current_bit' lies in a subsequent register, update 'regno' and
>> +         reset 'current_bit' to point to the current bit in that new
>> +         register.  */
>> +          current_bit += size;
>> +          while (current_bit >= 32)
>> +        {
>> +          current_bit-=32;
>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>> +          (*regno)++;
>> +        }
>> +          *last_used_bit = current_bit;
>> +        }
>> +
>> +      field = TREE_CHAIN (field);
>> +    }
>> +      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>> +    }
>> +  else if (TREE_CODE (arg_type) == UNION_TYPE)
>> +    {
>> +      tree field, field_t;
>> +      int i, regno_t, field_size;
>> +      int max_reg = -1;
>> +      int max_bit = -1;
>> +      uint32_t mask;
>> +      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
>> +    = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
>> +
>> +      /* To compute the padding bits in a union we only consider bits as
>> +     padding bits if they are always either a padding bit or fall
>> outside a
>> +     fields size for all fields in the union.  */
>> +      field = TYPE_FIELDS (arg_type);
>> +      while (field)
>> +    {
>> +      uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
>> +        = {0U, 0U, 0U, 0U};
>> +      int last_used_bit_t = *last_used_bit;
>> +      regno_t = *regno;
>> +      field_t = TREE_TYPE (field);
>> +
>> +      /* If the field's type is either a record or a union make sure to
>> +         compute their padding bits too.  */
>> +      if (RECORD_OR_UNION_TYPE_P (field_t))
>> +        not_to_clear_reg_mask
>> +          |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
>> +                        &padding_bits_to_clear_t[0],
>> +                        starting_bit, &last_used_bit_t);
>> +      else
>> +        {
>> +          field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>> +          regno_t = (field_size / 32) + *regno;
>> +          last_used_bit_t = (starting_bit + field_size) % 32;
>> +        }
>> +
>> +      for (i = *regno; i < regno_t; i++)
>> +        {
>> +          /* For all but the last register used by this field only keep
>> the
>> +         padding bits that were padding bits in this field.  */
>> +          padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
>> +        }
>> +
>> +        /* For the last register, keep all padding bits that were padding
>> +           bits in this field and any padding bits that are still valid
>> +           as padding bits but fall outside of this field's size.  */
>> +        mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
>> +        padding_bits_to_clear_res[regno_t]
>> +          &= padding_bits_to_clear_t[regno_t] | mask;
>> +
>> +      /* Update the maximum size of the fields in terms of registers used
>> +         ('max_reg') and the 'last_used_bit' in said register.  */
>> +      if (max_reg < regno_t)
>> +        {
>> +          max_reg = regno_t;
>> +          max_bit = last_used_bit_t;
>> +        }
>> +      else if (max_reg == regno_t && max_bit < last_used_bit_t)
>> +        max_bit = last_used_bit_t;
>> +
>> +      field = TREE_CHAIN (field);
>> +    }
>> +
>> +      /* Update the current padding_bits_to_clear using the
>> intersection of the
>> +     padding bits of all the fields.  */
>> +      for (i=*regno; i < max_reg; i++)
>> +    padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
>> +
>>
>> watch the spacing in the 'for' definition.
>>
>>   +      /* Do not keep trailing padding bits, we do not know yet whether
>> this
>> +     is the end of the argument.  */
>> +      mask = ((uint32_t) 1 << max_bit) - 1;
>> +      padding_bits_to_clear[max_reg]
>> +    |= padding_bits_to_clear_res[max_reg] & mask;
>> +
>> +      *regno = max_reg;
>> +      *last_used_bit = max_bit;
>> +    }
>> +  else
>> +    /* This function should only be used for structs and unions.  */
>> +    gcc_unreachable ();
>> +
>> +  return not_to_clear_reg_mask;
>> +}
>> +
>> +/* In the context of ARMv8-M Security Extensions, this function is used
>> for both
>> +   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to
>> compute what
>> +   registers are used when returning or passing arguments, which is then
>> +   returned as a mask.  It will also compute a mask to indicate
>> padding/unused
>> +   bits for each of these registers, and passes this through the
>> +   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is
>> passed in
>> +   ARG_TYPE, the rtl representation of the argument is passed in
>> ARG_RTX and
>> +   the starting register used to pass this argument or return value is
>> passed
>> +   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to
>> compute these
>> +   for struct and union types.  */
>> +
>> +static unsigned HOST_WIDE_INT
>> +compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
>> +                 uint32_t * padding_bits_to_clear)
>> +
>> +{
>> +  int last_used_bit = 0;
>> +  unsigned HOST_WIDE_INT not_to_clear_mask;
>> +
>> +  if (RECORD_OR_UNION_TYPE_P (arg_type))
>> +    {
>> +      not_to_clear_mask
>> +    = comp_not_to_clear_mask_str_un (arg_type, &regno,
>> +                     padding_bits_to_clear, 0,
>> +                     &last_used_bit);
>> +
>> +
>> +      /* If the 'last_used_bit' is not zero, that means we are still
>> using a
>> +     part of the last 'regno'.  In such cases we must clear the trailing
>> +     bits.  Otherwise we are not using regno and we should mark it as to
>> +     clear.  */
>> +      if (last_used_bit != 0)
>> +    *(padding_bits_to_clear + regno)
>> +      |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;
>>
>> padding_bits_to_clear[regno] |= ...
>>
>> +      else
>> +    not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
>> +    }
>> +  else
>> +    {
>> +      not_to_clear_mask = 0;
>> +      /* We are not dealing with structs nor unions.  So these
>> arguments may be
>> +     passed in floating point registers too.  In some cases a BLKmode is
>> +     used when returning or passing arguments in multiple VFP
>> registers.  */
>> +      if (GET_MODE (arg_rtx) == BLKmode)
>> +    {
>> +      int i, arg_regs;
>> +      rtx reg;
>> +
>> +      /* This should really only occur when dealing with the hard-float
>> +         ABI.  */
>> +      gcc_assert (TARGET_HARD_FLOAT_ABI);
>> +
>> +      for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
>> +        {
>> +          reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
>> +          gcc_assert (REG_P (reg));
>> +
>> +          not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
>> +
>> +          /* If we are dealing with DF mode, make sure we don't
>> +         clear either of the registers it addresses.  */
>> +          arg_regs = ARM_NUM_REGS (GET_MODE (reg));
>>
>> Better assert here that you're indeed dealing with DFmode and/or you
>> have 2 registers.
>>
> The current code actually works for larger modes too. I don't think code
> will ever be generated with larger types, but why assert if it works anyway?

ok, no need to assert here then.
I suppose it doesn't add much if the code handles the other modes fine.

Kyrill

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

* Re: [PATCHv2 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics
  2016-10-26 13:00         ` Kyrill Tkachov
@ 2016-10-27  9:54           ` Andre Vieira (lists)
  2016-10-27 10:01             ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-27  9:54 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches

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

On 26/10/16 14:00, Kyrill Tkachov wrote:
> 
> On 26/10/16 10:12, Kyrill Tkachov wrote:
>> Hi Andre, thanks for resending them.
>>
>> On 25/10/16 17:26, Andre Vieira (lists) wrote:
>>> On 24/08/16 12:00, Andre Vieira (lists) wrote:
>>>> On 25/07/16 14:19, Andre Vieira (lists) wrote:
>>>>> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
>>>>> Security Extensions and supports the following intrinsics:
>>>>> cmse_TT
>>>>> cmse_TT_fptr
>>>>> cmse_TTT
>>>>> cmse_TTT_fptr
>>>>> cmse_TTA
>>>>> cmse_TTA_fptr
>>>>> cmse_TTAT
>>>>> cmse_TTAT_fptr
>>>>> cmse_check_address_range
>>>>> cmse_check_pointed_object
>>>>> cmse_is_nsfptr
>>>>> cmse_nsfptr_create
>>>>>
>>>>> It also defines the mandatory cmse_address_info struct and the
>>>>> __ARM_FEATURE_CMSE macro.
>>>>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>>>>> Extensions: Requirements on Development Tools
>>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>>
>>>>>
>>>>> *** gcc/ChangeLog ***
>>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>
>>>>>          * config.gcc (extra_headers): Added arm_cmse.h.
>>>>>          * config/arm/arm-arches.def (ARM_ARCH):
>>>>>          (armv8-m): Add FL2_CMSE.
>>>>>          (armv8-m.main): Likewise.
>>>>>          (armv8-m.main+dsp): Likewise.
>>>>>          * config/arm/arm-c.c
>>>>>          (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>>>>          * config/arm/arm-protos.h
>>>>>          (arm_is_constant_pool_ref): Define FL2_CMSE.
>>>>>          * config/arm.c (arm_arch_cmse): New.
>>>>>          (arm_option_override): New error for unsupported cmse target.
>>>>>          * config/arm/arm.h (arm_arch_cmse): New.
>>>>>          * config/arm/arm.opt (mcmse): New.
>>>>>          * doc/invoke.texi (ARM Options): Add -mcmse.
>>>>>          * config/arm/arm_cmse.h: New file.
>>>>>
>>>>> *** libgcc/ChangeLog ***
>>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>
>>>>>          * config/arm/cmse.c: Likewise.
>>>>>          * config/arm/t-arm (HAVE_CMSE): New.
>>>>>
>>>>> *** gcc/testsuite/ChangeLog ***
>>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>
>>>>>          * gcc.target/arm/cmse/cmse.exp: New.
>>>>>          * gcc.target/arm/cmse/cmse-1.c: New.
>>>>>          * gcc.target/arm/cmse/cmse-12.c: New.
>>>>>          * lib/target-supports.exp
>>>>>          (check_effective_target_arm_cmse_ok): New.
> 
> 
> Just remembered, new effective target checks should be documented in
> sourcebuild.texi
> Kyrill
> 
>>>>>
>>>> Added more documentation as requested.
>>>>
>>>> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
>>>> Security Extensions and supports the following intrinsics:
>>>> cmse_TT
>>>> cmse_TT_fptr
>>>> cmse_TTT
>>>> cmse_TTT_fptr
>>>> cmse_TTA
>>>> cmse_TTA_fptr
>>>> cmse_TTAT
>>>> cmse_TTAT_fptr
>>>> cmse_check_address_range
>>>> cmse_check_pointed_object
>>>> cmse_is_nsfptr
>>>> cmse_nsfptr_create
>>>>
>>>> It also defines the mandatory cmse_address_info struct and the
>>>> __ARM_FEATURE_CMSE macro.
>>>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>>>> Extensions: Requirements on Development Tools
>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>
>>>>
>>>> *** gcc/ChangeLog ***
>>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>
>>>>          * config.gcc (extra_headers): Added arm_cmse.h.
>>>>          * config/arm/arm-arches.def (ARM_ARCH):
>>>>          (armv8-m): Add FL2_CMSE.
>>>>          (armv8-m.main): Likewise.
>>>>          (armv8-m.main+dsp): Likewise.
>>>>          * config/arm/arm-c.c
>>>>          (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>>>          * config/arm/arm-protos.h
>>>>          (arm_is_constant_pool_ref): Define FL2_CMSE.
>>>>          * config/arm.c (arm_arch_cmse): New.
>>>>          (arm_option_override): New error for unsupported cmse target.
>>>>          * config/arm/arm.h (arm_arch_cmse): New.
>>>>          * config/arm/arm.opt (mcmse): New.
>>>>          * doc/invoke.texi (ARM Options): Add -mcmse.
>>>>          * doc/extend.texi (ARM ARMv8-M Security Extensions): Add
>>>> section.
>>>>          * config/arm/arm_cmse.h: New file.
>>>>
>>>> *** libgcc/ChangeLog ***
>>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>          * config/arm/cmse.c: Likewise.
>>>>          * config/arm/t-arm (HAVE_CMSE): New.
>>>>
>>>>
>>>> *** gcc/testsuite/ChangeLog ***
>>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>
>>>>          * gcc.target/arm/cmse/cmse.exp: New.
>>>>          * gcc.target/arm/cmse/cmse-1.c: New.
>>>>          * gcc.target/arm/cmse/cmse-12.c: New.
>>>>          * lib/target-supports.exp
>>>>          (check_effective_target_arm_cmse_ok): New.
>>>>
>>> Hi,
>>>
>>> Rebased previous patch on top of trunk as requested. No changes to
>>> ChangeLog.
>>>
>>> Cheers,
>>> Andre
>>
>> diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
>> new file mode 100644
>> index
>> 0000000000000000000000000000000000000000..b4232937c6ae04754a6bbc513b143672a4be5530
>>
>> --- /dev/null
>> +++ b/gcc/config/arm/arm_cmse.h
>>
>> <snip>
>>
>> +
>> +#if __ARM_FEATURE_CMSE & 2
>> +
>> +#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
>> +
>> +__extension__ static __inline __attribute__ ((__always_inline__))
>> +cmse_address_info_t
>> +__cmse_TTA_fptr (__cmse_fptr __p)
>> +__CMSE_TT_ASM (a)
>> +
>> +__extension__ static __inline __attribute__ ((__always_inline__))
>> +cmse_address_info_t
>> +cmse_TTA (void *__p)
>> +__CMSE_TT_ASM (a)
>> +
>> +#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
>> +
>> +__extension__ static __inline cmse_address_info_t
>> +__attribute__ ((__always_inline__))
>> +__cmse_TTAT_fptr (__cmse_fptr __p)
>> +__CMSE_TT_ASM (at)
>> +
>> +__extension__ static __inline cmse_address_info_t
>> +__attribute__ ((__always_inline__))
>> +cmse_TTAT (void *__p)
>> +__CMSE_TT_ASM (at)
>> +
>> +#define CMSE_AU_NONSECURE    2
>> +#define CMSE_MPU_NONSECURE    16
>> +#define CMSE_NONSECURE        18
>> +
>> +#endif /* __ARM_FEATURE_CMSE & 2 */
>> +
>> +#define CMSE_MPU_UNPRIV        4
>> +#define CMSE_MPU_READWRITE    1
>> +#define CMSE_MPU_READ        8
>> +
>> +__extension__ void *
>> +cmse_check_address_range (void *, size_t, int);
>> +
>> +#define cmse_check_pointed_object(p, f) \
>> +  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
>> +
>> +#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
>> +
>> +#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
>> +
>> +#endif /* __ARM_FEATURE_CMSE & 1 */
>>
>> From my reading of the spec
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf)
>>
>> cmse_nsfptr_create and cmse_is_nsfptr should be defined if bit 1 of
>> __ARM_FEATURE_CMSE is set.
>> But in your patch they fall under the "#if __ARM_FEATURE_CMSE & 1"
>> check which checks bit 0.
>> They should be in the "__ARM_FEATURE_CMSE & 2" block. Please double
>> check the other defines against the SPEC to make sure they
>> match the feature bit in __ARM_FEATURE_CMSE.
>>
>> The patch is ok with that resolved if bootstrap and test on a normal
>> arm-none-linux-gnueabihf configuration
>> shows no problems.
>> Thanks,
>> Kyrill
>>
> 
Hi,

Reworked comments.

Is this OK?

Cheers,
Andre

*** gcc/ChangeLog ***
2016-10-27  Andre Vieira <andre.simoesdiasvieira@arm.com>
             Thomas Preud'homme <thomas.preudhomme@arm.com>

         * config.gcc (extra_headers): Added arm_cmse.h.
         * config/arm/arm-arches.def (ARM_ARCH):
         (armv8-m): Add FL2_CMSE.
         (armv8-m.main): Likewise.
         (armv8-m.main+dsp): Likewise.
         * config/arm/arm-c.c
         (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
         * config/arm/arm-protos.h
         (arm_is_constant_pool_ref): Define FL2_CMSE.
         * config/arm.c (arm_arch_cmse): New.
         (arm_option_override): New error for unsupported cmse target.
         * config/arm/arm.h (arm_arch_cmse): New.
         * config/arm/arm.opt (mcmse): New.
         * doc/invoke.texi (ARM Options): Add -mcmse.
         * config/arm/arm_cmse.h: New file.
         * doc/sourcebuild.texi (arm_cmse_ok): Add new effective target.

*** libgcc/ChangeLog ***
2016-10-27  Andre Vieira <andre.simoesdiasvieira@arm.com>
             Thomas Preud'homme <thomas.preudhomme@arm.com>

         * config/arm/cmse.c: Likewise.
         * config/arm/t-arm (HAVE_CMSE): New.

*** gcc/testsuite/ChangeLog ***
2016-10-27  Andre Vieira <andre.simoesdiasvieira@arm.com>
             Thomas Preud'homme <thomas.preudhomme@arm.com>

         * gcc.target/arm/cmse/cmse.exp: New.
         * gcc.target/arm/cmse/cmse-1.c: New.
         * gcc.target/arm/cmse/cmse-12.c: New.
         * lib/target-supports.exp
         (check_effective_target_arm_cmse_ok): New.


[-- Attachment #2: diff1 --]
[-- Type: text/plain, Size: 24184 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 2143d632fd25892e3633abafe17eee9326b1efd8..63245ecec55c1712e8373b31bcf8c655b4ecfcea 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -322,7 +322,7 @@ arc*-*-*)
 arm*-*-*)
 	cpu_type=arm
 	extra_objs="arm-builtins.o aarch-common.o"
-	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_fp16.h"
+	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_fp16.h arm_cmse.h"
 	target_type_format_char='%'
 	c_target_objs="arm-c.o"
 	cxx_target_objs="arm-c.o"
diff --git a/gcc/config/arm/arm-arches.def b/gcc/config/arm/arm-arches.def
index 4b196a7d1188de5eca028e5c2597bbc20835201f..1bdcf5d9f92404d5d5abb2a53ff89ad3d3ff2794 100644
--- a/gcc/config/arm/arm-arches.def
+++ b/gcc/config/arm/arm-arches.def
@@ -70,10 +70,10 @@ ARM_ARCH ("armv8.2-a+fp16", cortexa53,  8A,
 	  ARM_FSET_MAKE (FL_CO_PROC | FL_CRC32 | FL_FOR_ARCH8A,
 			 FL2_FOR_ARCH8_2A | FL2_FP16INST))
 ARM_ARCH("armv8-m.base", cortexm0, 8M_BASE,
-	 ARM_FSET_MAKE_CPU1 (			      FL_FOR_ARCH8M_BASE))
+	 ARM_FSET_MAKE (			  FL_FOR_ARCH8M_BASE, FL2_CMSE))
 ARM_ARCH("armv8-m.main", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC |	      FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC |		  FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("armv8-m.main+dsp", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("iwmmxt",  iwmmxt,     5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT))
 ARM_ARCH("iwmmxt2", iwmmxt2,    5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT | FL_IWMMXT2))
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index df930f44801e9e5f481ee6eb990656dda4bf0cea..4031083893d8f9cbd44881e008b0cef40f3ad614 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -77,6 +77,14 @@ arm_cpu_builtins (struct cpp_reader* pfile)
 
   def_or_undef_macro (pfile, "__ARM_32BIT_STATE", TARGET_32BIT);
 
+  if (arm_arch8 && !arm_arch_notm)
+    {
+      if (arm_arch_cmse && use_cmse)
+	builtin_define_with_int_value ("__ARM_FEATURE_CMSE", 3);
+      else
+	builtin_define ("__ARM_FEATURE_CMSE");
+    }
+
   if (TARGET_ARM_FEATURE_LDREX)
     builtin_define_with_int_value ("__ARM_FEATURE_LDREX",
 				   TARGET_ARM_FEATURE_LDREX);
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index fd8b6d106d13faebedf7a3539d30159c14f061c6..e7d9f824596a62f5c99000940f6190ab6aee9255 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -396,6 +396,7 @@ extern bool arm_is_constant_pool_ref (rtx);
 #define FL2_ARCH8_2   (1 << 1)	      /* Architecture 8.2.  */
 #define FL2_FP16INST  (1 << 2)	      /* FP16 Instructions for ARMv8.2 and
 					 later.  */
+#define FL2_CMSE      (1 << 3)	      /* ARMv8-M Security Extensions.  */
 
 /* Flags that only effect tuning, not available instructions.  */
 #define FL_TUNE		(FL_WBUF | FL_VFPV2 | FL_STRONG | FL_LDSCHED \
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 8a076ba3d8eb66e237790d23dd7c2ecb4b6fd264..a370dccdaa9fa4c980c1df11cb95a65cad16ac85 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -524,6 +524,9 @@ extern bool arm_disable_literal_pool;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 extern int arm_arch_crc;
 
+/* Nonzero if chip supports the ARMv8-M Security Extensions.  */
+extern int arm_arch_cmse;
+
 #ifndef TARGET_DEFAULT
 #define TARGET_DEFAULT  (MASK_APCS_FRAME)
 #endif
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 022c1d72a1272e56397dc7e2018483e77f18b90d..44677c1bccad42c5ad603ea0951d62abcbd6f05d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -906,6 +906,9 @@ int arm_condexec_masklen = 0;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 int arm_arch_crc = 0;
 
+/* Nonzero if chip supports the ARMv8-M security extensions.  */
+int arm_arch_cmse = 0;
+
 /* Nonzero if the core has a very small, high-latency, multiply unit.  */
 int arm_m_profile_small_mul = 0;
 
@@ -3256,6 +3259,7 @@ arm_option_override (void)
   arm_arch_no_volatile_ce = ARM_FSET_HAS_CPU1 (insn_flags, FL_NO_VOLATILE_CE);
   arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0;
   arm_arch_crc = ARM_FSET_HAS_CPU1 (insn_flags, FL_CRC32);
+  arm_arch_cmse = ARM_FSET_HAS_CPU2 (insn_flags, FL2_CMSE);
   arm_m_profile_small_mul = ARM_FSET_HAS_CPU1 (insn_flags, FL_SMALLMUL);
   arm_fp16_inst = ARM_FSET_HAS_CPU2 (insn_flags, FL2_FP16INST);
   if (arm_fp16_inst)
@@ -3523,6 +3527,9 @@ arm_option_override (void)
   if (target_slow_flash_data || target_pure_code)
     arm_disable_literal_pool = true;
 
+  if (use_cmse && !arm_arch_cmse)
+    error ("target CPU does not support ARMv8-M Security Extensions");
+
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index 35f047e2de1659c2b426cf42dbbdae5be62cbfef..5fb645df71b93960e8cda38c4b5b1d9d37df125c 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -109,6 +109,10 @@ mfloat-abi=
 Target RejectNegative Joined Enum(float_abi_type) Var(arm_float_abi) Init(TARGET_DEFAULT_FLOAT_ABI)
 Specify if floating point hardware should be used.
 
+mcmse
+Target RejectNegative Var(use_cmse)
+Specify that the compiler should target secure code as per ARMv8-M Security Extensions.
+
 Enum
 Name(float_abi_type) Type(enum float_abi_type)
 Known floating-point ABIs (for use with the -mfloat-abi= option):
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
new file mode 100644
index 0000000000000000000000000000000000000000..894343bb835b61e09c14668d45aa43a8693fd011
--- /dev/null
+++ b/gcc/config/arm/arm_cmse.h
@@ -0,0 +1,192 @@
+/* ARMv8-M Secure Extensions intrinsics include file.
+
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef _GCC_ARM_CMSE_H
+#define _GCC_ARM_CMSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __ARM_BIG_ENDIAN
+
+typedef union {
+  struct cmse_address_info {
+#if __ARM_FEATURE_CMSE & 2
+    unsigned idau_region:8;
+    unsigned idau_region_valid:1;
+    unsigned secure:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned nonsecure_read_ok:1;
+#else
+    unsigned :12;
+#endif
+    unsigned readwrite_ok:1;
+    unsigned read_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region:8;
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#else
+
+typedef union {
+  struct cmse_address_info {
+    unsigned mpu_region:8;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned read_ok:1;
+    unsigned readwrite_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned nonsecure_read_ok:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned secure:1;
+    unsigned idau_region_valid:1;
+    unsigned idau_region:8;
+#else
+    unsigned :12;
+#endif
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#endif /* __ARM_BIG_ENDIAN */
+
+#define cmse_TT_fptr(p) (__cmse_TT_fptr ((__cmse_fptr)(p)))
+
+typedef void (*__cmse_fptr)(void);
+
+#define __CMSE_TT_ASM(flags) \
+{ \
+  cmse_address_info_t __result; \
+   __asm__ ("tt" # flags " %0,%1" \
+	   : "=r"(__result) \
+	   : "r"(__p) \
+	   : "memory"); \
+  return __result; \
+}
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM ()
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT (void *__p)
+__CMSE_TT_ASM ()
+
+#define cmse_TTT_fptr(p) (__cmse_TTT_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TTT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (t)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT (void *__p)
+__CMSE_TT_ASM (t)
+
+#if __ARM_FEATURE_CMSE & 2
+
+#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TTA_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (a)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA (void *__p)
+__CMSE_TT_ASM (a)
+
+#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+__cmse_TTAT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (at)
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT (void *__p)
+__CMSE_TT_ASM (at)
+
+#define CMSE_AU_NONSECURE	2
+#define CMSE_MPU_NONSECURE	16
+#define CMSE_NONSECURE		18
+
+#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
+
+#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
+
+#endif /* __ARM_FEATURE_CMSE & 2 */
+
+#define CMSE_MPU_UNPRIV		4
+#define CMSE_MPU_READWRITE	1
+#define CMSE_MPU_READ		8
+
+__extension__ void *
+cmse_check_address_range (void *, size_t, int);
+
+#define cmse_check_pointed_object(p, f) \
+  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
+
+#endif /* __ARM_FEATURE_CMSE & 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GCC_ARM_CMSE_H */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0669f7999beb078822e471352036d8f13517812d..3f6fc27950fafa2e7649deb9dc5db44737cbb691 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -11753,6 +11753,7 @@ instructions, but allow the compiler to schedule those calls.
 * ARM iWMMXt Built-in Functions::
 * ARM C Language Extensions (ACLE)::
 * ARM Floating Point Status and Control Intrinsics::
+* ARM ARMv8-M Security Extensions::
 * AVR Built-in Functions::
 * Blackfin Built-in Functions::
 * FR-V Built-in Functions::
@@ -12598,6 +12599,31 @@ unsigned int __builtin_arm_get_fpscr ()
 void __builtin_arm_set_fpscr (unsigned int)
 @end smallexample
 
+@node ARM ARMv8-M Security Extensions
+@subsection ARM ARMv8-M Security Extensions
+
+GCC implements the ARMv8-M Security Extensions as described in the ARMv8-M
+Security Extensions: Requiremenets on Development Tools Engineering
+Specification, which can be found at
+@uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
+
+As part of the Security Extensions GCC implements the intrinsics below.  FPTR
+is used here to mean any function pointer type.
+
+@smallexample
+cmse_address_info_t cmse_TT (void *)
+cmse_address_info_t cmse_TT_fptr (FPTR)
+cmse_address_info_t cmse_TTT (void *)
+cmse_address_info_t cmse_TTT_fptr (FPTR)
+cmse_address_info_t cmse_TTA (void *)
+cmse_address_info_t cmse_TTA_fptr (FPTR)
+cmse_address_info_t cmse_TTAT (void *)
+cmse_address_info_t cmse_TTAT_fptr (FPTR)
+void * cmse_check_address_range (void *, size_t, int)
+typeof(p) cmse_nsfptr_create (FPTR p)
+intptr_t cmse_is_nsfptr (FPTR)
+@end smallexample
+
 @node AVR Built-in Functions
 @subsection AVR Built-in Functions
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5ccd4244ef396696f1a7ca962a7a7fe9973fcf6e..13caf3c3bef2564d2c0152a95d520b6869ffda36 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -645,7 +645,8 @@ Objective-C and Objective-C++ Dialects}.
 -mslow-flash-data @gol
 -masm-syntax-unified @gol
 -mrestrict-it @gol
--mpure-code}
+-mpure-code @gol
+-mcmse}
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol
@@ -15170,6 +15171,11 @@ Additionally, when compiling for ELF object format give all text sections the
 ELF processor-specific section attribute @code{SHF_ARM_PURECODE}.  This option
 is only available when generating non-pic code for ARMv7-M targets.
 
+@item -mcmse
+@opindex mcmse
+Generate secure code as per the "ARMv8-M Security Extensions: Requirements on
+Development Tools Engineering Specification", which can be found on
+@url{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 @end table
 
 @node AVR Options
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 07c75e2847ae37ec22ce1f6483c3d201ac001725..74d7af40568aec9bb86111974a925b188c192ffb 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -1675,6 +1675,10 @@ and @code{MOVT} instructions available.
 ARM target generates Thumb-1 code for @code{-mthumb} with
 @code{CBZ} and @code{CBNZ} instructions available.
 
+@item arm_cmse_ok
+ARM target supports ARMv8-M Security Extensions, enabled by the @code{-mcmse}
+option.
+
 @end table
 
 @subsubsection AArch64-specific attributes
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..d5b9a2d9d59569de170da814ae660e9fb2b943e7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mcmse -fdump-rtl-expand" }  */
+
+#include <arm_cmse.h>
+
+extern int a;
+extern int bar (void);
+
+int foo (char * p)
+{
+  cmse_address_info_t cait;
+
+  cait = cmse_TT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTA (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTA_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTAT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTAT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char), 0);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_READWRITE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV | CMSE_MPU_READ);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_AU_NONSECURE
+					 | CMSE_MPU_NONSECURE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  p = (char *) cmse_check_pointed_object (p, CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  return a;
+}
+/* { dg-final { scan-assembler-times "\ttt " 2 } } */
+/* { dg-final { scan-assembler-times "ttt " 2 } } */
+/* { dg-final { scan-assembler-times "tta " 2 } } */
+/* { dg-final { scan-assembler-times "ttat " 2 } } */
+/* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
+/* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
new file mode 100644
index 0000000000000000000000000000000000000000..87a2f1363a4e4bd817503e79e504980210e722c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+#include <arm_cmse.h>
+
+char *
+foo (char * p)
+{
+  if (!cmse_is_nsfptr (p))
+    return cmse_nsfptr_create (p);
+}
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler-not "cmse_is_nsfptr" } } */
+/* { dg-final { scan-assembler-not "cmse_nsfptr_create" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
new file mode 100644
index 0000000000000000000000000000000000000000..f797dba1901720e04249d61078c1cbf2a3e436a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -0,0 +1,50 @@
+#   Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite for ARMv8-M Security Extensions using the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Exit immediately if the target does not support -mcmse.
+if ![check_effective_target_arm_cmse_ok] then {
+    return
+}
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+set saved-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default "assemble"
+
+set saved-lto_torture_options ${LTO_TORTURE_OPTIONS}
+set LTO_TORTURE_OPTIONS ""
+
+# These are for both baseline and mainline.
+gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
+	"" $DEFAULT_CFLAGS
+
+set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index b5a9faab5a47d01371c6402a5b07d34071dbc34b..eaeaf056c611889993b118d48a7aeb20e95be477 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -3866,6 +3866,19 @@ proc check_effective_target_arm_thumb1_cbz_ok {} {
     }
 }
 
+# Return 1 if this is an ARM target where ARMv8-M Security Extensions is
+# available.
+
+proc check_effective_target_arm_cmse_ok {} {
+    return [check_no_compiler_messages arm_cmse object {
+	int
+	foo (void)
+	{
+	  asm ("bxns r0");
+	}
+    } "-mcmse"];
+}
+
 # Return 1 if this compilation turns on string_ops_prefer_neon on.
 
 proc check_effective_target_arm_tune_string_ops_prefer_neon { } {
diff --git a/libgcc/config/arm/cmse.c b/libgcc/config/arm/cmse.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe3a22967c8536f2a8c05b58627f964d3fb1d345
--- /dev/null
+++ b/libgcc/config/arm/cmse.c
@@ -0,0 +1,108 @@
+/* ARMv8-M Security Extensions routines.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <arm_cmse.h>
+
+/* ARM intrinsic function to perform a permission check on a given
+   address range.  See ACLE changes for ARMv8-M.  */
+
+void *
+cmse_check_address_range (void *p, size_t size, int flags)
+{
+  cmse_address_info_t permb, perme;
+  char *pb = (char *) p, *pe;
+
+  /* Check if the range wraps around.  */
+  if (UINTPTR_MAX - (uintptr_t) p < size)
+    return NULL;
+
+  /* Check if an unknown flag is present.  */
+  int known = CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE | CMSE_MPU_READ;
+  int known_secure_level = CMSE_MPU_UNPRIV;
+#if __ARM_FEATURE_CMSE & 2
+  known |= CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE;
+  known_secure_level |= CMSE_MPU_NONSECURE;
+#endif
+  if (flags & (~known))
+    return NULL;
+
+  /* Execute the right variant of the TT instructions.  */
+  pe = pb + size - 1;
+  const int singleCheck = (((uintptr_t) pb ^ (uintptr_t) pe) < 32);
+  switch (flags & known_secure_level)
+    {
+    case 0:
+      permb = cmse_TT (pb);
+      perme = singleCheck ? permb : cmse_TT (pe);
+      break;
+    case CMSE_MPU_UNPRIV:
+      permb = cmse_TTT (pb);
+      perme = singleCheck ? permb : cmse_TTT (pe);
+      break;
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_NONSECURE:
+      permb = cmse_TTA (pb);
+      perme = singleCheck ? permb : cmse_TTA (pe);
+      break;
+    case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+      permb = cmse_TTAT (pb);
+      perme = singleCheck ? permb : cmse_TTAT (pe);
+      break;
+#endif
+    default:
+      /* Invalid flag, eg.  CMSE_MPU_NONSECURE specified but
+	 __ARM_FEATURE_CMSE & 2 == 0.  */
+      return NULL;
+    }
+
+  /* Check that the range does not cross MPU, SAU, or IDAU boundaries.  */
+  if (permb.value != perme.value)
+    return NULL;
+
+  /* Check the permissions on the range.  */
+  switch (flags & (~known_secure_level))
+    {
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+    case		 CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_readwrite_ok	? p : NULL;
+    case CMSE_MPU_READ | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_read_ok	? p : NULL;
+    case CMSE_AU_NONSECURE:
+      return permb.flags.secure			? NULL : p;
+#endif
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE:
+    case		 CMSE_MPU_READWRITE:
+      return permb.flags.readwrite_ok		? p : NULL;
+    case CMSE_MPU_READ:
+      return permb.flags.read_ok		? p : NULL;
+    default:
+      return NULL;
+    }
+}
+
+
+#endif /* __ARM_FEATURE_CMSE & 1.  */
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 4e17e99b4a53bbafc0f1f8dddd02000f0e8f4f48..5618143bfd0f02b170db3f9e4c0a15cecb403cec 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -1,3 +1,15 @@
 LIB1ASMSRC = arm/lib1funcs.S
 LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
 	_thumb1_case_uhi _thumb1_case_si
+
+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),)
+CMSE_OPTS:=-mcmse
+endif
+
+ifdef HAVE_CMSE
+libgcc-objects += cmse.o cmse_nonsecure_call.o
+
+cmse.o: $(srcdir)/config/arm/cmse.c
+	$(gcc_compile) -c $(CMSE_OPTS) $<
+endif

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

* Re: [PATCHv2 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
  2016-10-26 16:28           ` Kyrill Tkachov
@ 2016-10-27  9:54             ` Andre Vieira (lists)
  2016-10-27 10:19               ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-27  9:54 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches

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

On 26/10/16 17:28, Kyrill Tkachov wrote:
> 
> On 26/10/16 17:28, Andre Vieira (lists) wrote:
>> On 26/10/16 10:33, Kyrill Tkachov wrote:
>>> +static tree
>>> +arm_handle_cmse_nonsecure_entry (tree *node, tree name,
>>> +                 tree /* args */,
>>> +                 int /* flags */,
>>> +                 bool *no_add_attrs)
>>> +{
>>> +  tree fndecl;
>>> +
>>> +  if (!use_cmse)
>>> +    {
>>> +      *no_add_attrs = true;
>>> +      return NULL_TREE;
>>> +    }
>>>
>>> Do you also want to warn the user here that the attribute will be
>>> ignored?
>>> This looks ok to me otherwise.
>>>
>> Can easily do and might be more user friendly. How about
>> "<attribute_name> attribute ignored without -mcmse option."
> 
> Yes, that's fine (without the full stop at the end)
> Kyrill
> 
>> Cheers,
>> Andre
>>
> 

Hi,

Reworked comments. No change to ChangeLogs.

Cheers,
Andre

[-- Attachment #2: diff2 --]
[-- Type: text/plain, Size: 8152 bytes --]

diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index a370dccdaa9fa4c980c1df11cb95a65cad16ac85..44d1ac45b03dec210e6986f103bf8588119a8aa8 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -1386,6 +1386,7 @@ enum reg_class
 #define ARM_FT_VOLATILE		(1 << 4) /* Does not return.  */
 #define ARM_FT_NESTED		(1 << 5) /* Embedded inside another func.  */
 #define ARM_FT_STACKALIGN	(1 << 6) /* Called with misaligned stack.  */
+#define ARM_FT_CMSE_ENTRY	(1 << 7) /* ARMv8-M non-secure entry function.  */
 
 /* Some macros to test these flags.  */
 #define ARM_FUNC_TYPE(t)	(t & ARM_FT_TYPE_MASK)
@@ -1394,6 +1395,7 @@ enum reg_class
 #define IS_NAKED(t)        	(t & ARM_FT_NAKED)
 #define IS_NESTED(t)       	(t & ARM_FT_NESTED)
 #define IS_STACKALIGN(t)       	(t & ARM_FT_STACKALIGN)
+#define IS_CMSE_ENTRY(t)	(t & ARM_FT_CMSE_ENTRY)
 
 
 /* Structure used to hold the function stack frame layout.  Offsets are
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 44677c1bccad42c5ad603ea0951d62abcbd6f05d..40edd3c7fb9567fadfddc36be777fbf53cbb8e9f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -135,6 +135,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
+static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -347,6 +348,9 @@ static const struct attribute_spec arm_attribute_table[] =
   { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute,
     false },
 #endif
+  /* ARMv8-M Security Extensions support.  */
+  { "cmse_nonsecure_entry", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_entry, false },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -3662,6 +3666,9 @@ arm_compute_func_type (void)
   else
     type |= arm_isr_value (TREE_VALUE (a));
 
+  if (lookup_attribute ("cmse_nonsecure_entry", attr))
+    type |= ARM_FT_CMSE_ENTRY;
+
   return type;
 }
 
@@ -6661,6 +6668,113 @@ arm_handle_notshared_attribute (tree *node,
 }
 #endif
 
+/* This function returns true if a function with declaration FNDECL and type
+   FNTYPE uses the stack to pass arguments or return variables and false
+   otherwise.  This is used for functions with the attributes
+   'cmse_nonsecure_call' or 'cmse_nonsecure_entry' and this function will issue
+   diagnostic messages if the stack is used.  NAME is the name of the attribute
+   used.  */
+
+static bool
+cmse_func_args_or_return_in_stack (tree fndecl, tree name, tree fntype)
+{
+  function_args_iterator args_iter;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
+  bool first_param = true;
+  tree arg_type, prev_arg_type = NULL_TREE, ret_type;
+
+  /* Error out if any argument is passed on the stack.  */
+  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX, fndecl);
+  args_so_far = pack_cumulative_args (&args_so_far_v);
+  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+    {
+      rtx arg_rtx;
+      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+      prev_arg_type = arg_type;
+      if (VOID_TYPE_P (arg_type))
+	continue;
+
+      if (!first_param)
+	arm_function_arg_advance (args_so_far, arg_mode, arg_type, true);
+      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type, true);
+      if (!arg_rtx
+	  || arm_arg_partial_bytes (args_so_far, arg_mode, arg_type, true))
+	{
+	  error ("%qE attribute not available to functions with arguments "
+		 "passed on the stack", name);
+	  return true;
+	}
+      first_param = false;
+    }
+
+  /* Error out for variadic functions since we cannot control how many
+     arguments will be passed and thus stack could be used.  stdarg_p () is not
+     used for the checking to avoid browsing arguments twice.  */
+  if (prev_arg_type != NULL_TREE && !VOID_TYPE_P (prev_arg_type))
+    {
+      error ("%qE attribute not available to functions with variable number "
+	     "of arguments", name);
+      return true;
+    }
+
+  /* Error out if return value is passed on the stack.  */
+  ret_type = TREE_TYPE (fntype);
+  if (arm_return_in_memory (ret_type, fntype))
+    {
+      error ("%qE attribute not available to functions that return value on "
+	     "the stack", name);
+      return true;
+    }
+  return false;
+}
+
+/* Called upon detection of the use of the cmse_nonsecure_entry attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function declaration tree or otherwise issue a warning.  */
+
+static tree
+arm_handle_cmse_nonsecure_entry (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree fndecl;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored without -mcmse option.",
+	       name);
+      return NULL_TREE;
+    }
+
+  /* Ignore attribute for function types.  */
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+	       name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  fndecl = *node;
+
+  /* Warn for static linkage functions.  */
+  if (!TREE_PUBLIC (fndecl))
+    {
+      warning (OPT_Wattributes, "%qE attribute has no effect on functions "
+	       "with static linkage", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (fndecl, name,
+						TREE_TYPE (fndecl));
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 3f6fc27950fafa2e7649deb9dc5db44737cbb691..e5b28032e5610b896908139ec285ce90a9dffd8a 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12607,6 +12607,9 @@ Security Extensions: Requiremenets on Development Tools Engineering
 Specification, which can be found at
 @uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 
+As part of the Security Extensions GCC implements a new function attribute
+@code{cmse_nonsecure_entry}.
+
 As part of the Security Extensions GCC implements the intrinsics below.  FPTR
 is used here to mean any function pointer type.
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c2920e1dc310106d83203eb51e1a68a275d0152
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+struct span2 {
+  float a, b, c, d;
+};
+
+union test_union
+{
+  long long a;
+  int b;
+  struct span2 c;
+} test_union;
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (long long a, int b, long long c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+bar (long long a, int b, struct span c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+baz (int a, ...) {} /* { dg-error "not available to functions with variable number of arguments" } */
+
+struct span __attribute__ ((cmse_nonsecure_entry))
+qux (void) { /* { dg-error "not available to functions that return value on the stack" } */
+  struct span ret = {0, 0};
+  return ret;
+}
+
+void __attribute__ ((cmse_nonsecure_entry))
+norf (struct span2 a) {}
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */

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

* Re: [PATCH 3/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return
  2016-10-26 10:03     ` Kyrill Tkachov
@ 2016-10-27  9:55       ` Andre Vieira (lists)
  2016-12-05 11:34         ` [arm-embedded][committed][PATCH 3/7] " Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-27  9:55 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches

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

On 26/10/16 11:03, Kyrill Tkachov wrote:
> Hi Andre,
> 
> On 25/10/16 17:28, Andre Vieira (lists) wrote:
>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>> This patch extends support for the ARMv8-M Security Extensions
>>> 'cmse_nonsecure_entry' attribute in two ways:
>>>
>>> 1) Generate two labels for the function, the regular function name and
>>> one with the function's name appended to '__acle_se_', this will trigger
>>> the linker to create a secure gateway veneer for this entry function.
>>> 2) Return from cmse_nonsecure_entry marked functions using bxns.
>>>
>>> See Section 5.4 of ARM®v8-M Security Extensions
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>
>>>
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/arm.c (use_return_insn): Change to return with 
>>> bxns
>>>          when cmse_nonsecure_entry.
>>>          (output_return_instruction): Likewise.
>>>          (arm_output_function_prologue): Likewise.
>>>          (thumb_pop): Likewise.
>>>          (thumb_exit): Likewise.
>>>          (arm_function_ok_for_sibcall): Disable sibcall for entry
>>> functions.
>>>          (arm_asm_declare_function_name): New.
>>>          * config/arm/arm-protos.h (arm_asm_declare_function_name): New.
>>>          * config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
>>>          use arm_asm_declare_function_name.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse-2.c: New.
>>>          * gcc.target/arm/cmse/cmse-4.c: New.
>>>
>> Hi,
>>
>> Rebased previous patch on top of trunk as requested. No changes to
>> ChangeLog.
>>
>> Cheers,
>> Andre
> 
> @@ -19919,6 +19932,42 @@ output_return_instruction (rtx operand, bool
> really_return, bool reverse,
>    return "";
>  }
>  
> +/* Output in FILE asm statements needed to declare the NAME of the
> function
> +   defined by its DECL node.  */
> +
> +void
> +arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
> +{
> +  size_t cmse_name_len;
> +  char *cmse_name = 0;
> +  char cmse_prefix[] = "__acle_se_";
> +
> +  if (use_cmse && lookup_attribute ("cmse_nonsecure_entry",
> +                    DECL_ATTRIBUTES (decl)))
> +    {
> +      cmse_name_len = sizeof (cmse_prefix) + strlen (name);
> +      cmse_name = XALLOCAVEC (char, cmse_name_len);
> +      snprintf (cmse_name, cmse_name_len, "%s%s", cmse_prefix, name);
> +      targetm.asm_out.globalize_label (file, cmse_name);
> +    }
> +
> 
> I think this definitely warrants a quick comment explaining why you're
> adding
> __acle_se_ to the function label
> 
>  
>  /* Scan INSN just before assembler is output for it.
> @@ -25247,6 +25301,12 @@ thumb2_expand_return (bool simple_return)
>  
>    if (!simple_return && saved_regs_mask)
>      {
> +      /* TODO: Verify that this path is never taken for
> cmse_nonsecure_entry
> +     functions or adapt code to handle according to ACLE.  This path
> should
> +     not be reachable for cmse_nonsecure_entry functions though we prefer
> +     to guard it for now to ensure that future code changes do not
> silently
> +     change this behavior.  */
> 
> I think you mean s/guard/assert/
> 
>  +      gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
>        if (num_regs == 1)
>          {
>            rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
> 
> This is ok with those changes.
> Thanks,
> Kyrill
> 
Hi,

Reworked comments. Also got rid of a redundant 'if (cmse_name)' in
'arm_asm_declare_function_name'. No change to ChangeLogs.

Cheers,
Andre

[-- Attachment #2: diff3 --]
[-- Type: text/plain, Size: 10983 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index e7d9f824596a62f5c99000940f6190ab6aee9255..a9b8326c2770c1f9a9787743cb5faa549e6b7d02 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -31,6 +31,7 @@ extern int arm_volatile_func (void);
 extern void arm_expand_prologue (void);
 extern void arm_expand_epilogue (bool);
 extern void arm_declare_function_name (FILE *, const char *, tree);
+extern void arm_asm_declare_function_name (FILE *, const char *, tree);
 extern void thumb2_expand_return (bool);
 extern const char *arm_strip_name_encoding (const char *);
 extern void arm_asm_output_labelref (FILE *, const char *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 40edd3c7fb9567fadfddc36be777fbf53cbb8e9f..fdbdd423236e7388802bc4bd568f260d95485bbe 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3895,6 +3895,11 @@ use_return_insn (int iscond, rtx sibling)
 	return 0;
     }
 
+  /* 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))
+    return 0;
+
   /* If there are saved registers but the LR isn't saved, then we need
      two instructions for the return.  */
   if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
@@ -6933,6 +6938,11 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
   if (IS_INTERRUPT (func_type))
     return false;
 
+  /* ARMv8-M non-secure entry functions need to return with bxns which is only
+     generated for entry functions themselves.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    return false;
+
   if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
     {
       /* Check that the return value locations are the same.  For
@@ -19768,6 +19778,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	 (e.g. interworking) then we can load the return address
 	 directly into the PC.  Otherwise we must load it into LR.  */
       if (really_return
+	  && !IS_CMSE_ENTRY (func_type)
 	  && (IS_INTERRUPT (func_type) || !TARGET_INTERWORK))
 	return_reg = reg_names[PC_REGNUM];
       else
@@ -19908,8 +19919,10 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	  break;
 
 	default:
+	  if (IS_CMSE_ENTRY (func_type))
+	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
 	  /* Use bx if it's available.  */
-	  if (arm_arch5 || arm_arch4t)
+	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
 	  else
 	    sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
@@ -19922,6 +19935,44 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
   return "";
 }
 
+/* Output in FILE asm statements needed to declare the NAME of the function
+   defined by its DECL node.  */
+
+void
+arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
+{
+  size_t cmse_name_len;
+  char *cmse_name = 0;
+  char cmse_prefix[] = "__acle_se_";
+
+  /* When compiling with ARMv8-M Security Extensions enabled, we should print an
+     extra function label for each function with the 'cmse_nonsecure_entry'
+     attribute.  This extra function label should be prepended with
+     '__acle_se_', telling the linker that it needs to create secure gateway
+     veneers for this function.  */
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_entry",
+				    DECL_ATTRIBUTES (decl)))
+    {
+      cmse_name_len = sizeof (cmse_prefix) + strlen (name);
+      cmse_name = XALLOCAVEC (char, cmse_name_len);
+      snprintf (cmse_name, cmse_name_len, "%s%s", cmse_prefix, name);
+      targetm.asm_out.globalize_label (file, cmse_name);
+
+      ARM_DECLARE_FUNCTION_NAME (file, cmse_name, decl);
+      ASM_OUTPUT_TYPE_DIRECTIVE (file, cmse_name, "function");
+    }
+
+  ARM_DECLARE_FUNCTION_NAME (file, name, decl);
+  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
+  ASM_OUTPUT_LABEL (file, name);
+
+  if (cmse_name)
+    ASM_OUTPUT_LABEL (file, cmse_name);
+
+  ARM_OUTPUT_FN_UNWIND (file, TRUE);
+}
+
 /* Write the function name into the code section, directly preceding
    the function prologue.
 
@@ -19971,10 +20022,6 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
 {
   unsigned long func_type;
 
-  /* ??? Do we want to print some of the below anyway?  */
-  if (TARGET_THUMB1)
-    return;
-
   /* Sanity check.  */
   gcc_assert (!arm_ccfsm_state && !arm_target_insn);
 
@@ -20009,6 +20056,8 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
     asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
   if (IS_STACKALIGN (func_type))
     asm_fprintf (f, "\t%@ Stack Align: May be called with mis-aligned SP.\n");
+  if (IS_CMSE_ENTRY (func_type))
+    asm_fprintf (f, "\t%@ Non-secure entry function: called from non-secure code.\n");
 
   asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
 	       crtl->args.size,
@@ -24075,8 +24124,8 @@ thumb_pop (FILE *f, unsigned long mask)
   if (mask & (1 << PC_REGNUM))
     {
       /* Catch popping the PC.  */
-      if (TARGET_INTERWORK || TARGET_BACKTRACE
-	  || crtl->calls_eh_return)
+      if (TARGET_INTERWORK || TARGET_BACKTRACE || crtl->calls_eh_return
+	  || IS_CMSE_ENTRY (arm_current_func_type ()))
 	{
 	  /* The PC is never poped directly, instead
 	     it is popped into r3 and then BX is used.  */
@@ -24137,7 +24186,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
       if (crtl->calls_eh_return)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
-      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+      else
+	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
     }
   /* Otherwise if we are not supporting interworking and we have not created
@@ -24146,7 +24198,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
   else if (!TARGET_INTERWORK
 	   && !TARGET_BACKTRACE
 	   && !is_called_in_ARM_mode (current_function_decl)
-	   && !crtl->calls_eh_return)
+	   && !crtl->calls_eh_return
+	   && !IS_CMSE_ENTRY (arm_current_func_type ()))
     {
       asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
       return;
@@ -24369,7 +24422,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
     asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
   /* Return to caller.  */
-  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+  else
+    asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
 \f
 /* Scan INSN just before assembler is output for it.
@@ -25250,6 +25306,12 @@ thumb2_expand_return (bool simple_return)
 
   if (!simple_return && saved_regs_mask)
     {
+      /* TODO: Verify that this path is never taken for cmse_nonsecure_entry
+	 functions or adapt code to handle according to ACLE.  This path should
+	 not be reachable for cmse_nonsecure_entry functions though we prefer
+	 to assert it for now to ensure that future code changes do not silently
+	 change this behavior.  */
+      gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
       if (num_regs == 1)
         {
           rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
@@ -25667,6 +25729,7 @@ arm_expand_epilogue (bool really_return)
 
       if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
           && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
+	  && !IS_CMSE_ENTRY (func_type)
           && !IS_STACKALIGN (func_type)
           && really_return
           && crtl->args.pretend_args_size == 0
diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h
index bc4eb86f1da5beabf32647637eb87a3fc17a6c6a..03931eee7390ab4d09522e7d8bea10449719ddba 100644
--- a/gcc/config/arm/elf.h
+++ b/gcc/config/arm/elf.h
@@ -75,16 +75,7 @@
 
 /* We might need a ARM specific header to function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_NAME
-#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)		\
-  do								\
-    {								\
-      ARM_DECLARE_FUNCTION_NAME (FILE, NAME, DECL);		\
-      ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");	\
-      ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));		\
-      ASM_OUTPUT_LABEL(FILE, NAME);				\
-      ARM_OUTPUT_FN_UNWIND (FILE, TRUE);			\
-    }								\
-  while (0)
+#define ASM_DECLARE_FUNCTION_NAME arm_asm_declare_function_name
 
 /* We might need an ARM specific trailer for function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_SIZE
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a91ac39ee37ef20495e047b402d3f5edc60a613
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+void
+foo (void) {}
+
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f930ab04a1097c64097a4e003296bbe85733319
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+
+extern int qux (void);
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (void) {}
+
+static void __attribute__ ((cmse_nonsecure_entry))
+bar (void) {} /* { dg-warning "has no effect on functions with static linkage" } */
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return qux ();
+}
+
+/* { dg-final { scan-assembler-times "bxns" 2 } } */
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..1d97f0e1a37209bd129ffe96ce92a86bc2e0d5d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
+
+
+int __attribute__ ((cmse_nonsecure_entry))
+foo (int a)
+{ /* { dg-warning "attribute ignored without -mcmse option" } */
+  return a + 1;
+}
+
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-10-26 16:30           ` Kyrill Tkachov
@ 2016-10-27 10:00             ` Andre Vieira (lists)
  2016-10-27 10:44               ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-27 10:00 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches

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

On 26/10/16 17:30, Kyrill Tkachov wrote:
> 
> On 26/10/16 17:26, Andre Vieira (lists) wrote:
>> On 26/10/16 13:51, Kyrill Tkachov wrote:
>>> Hi Andre,
>>>
>>> On 25/10/16 17:29, Andre Vieira (lists) wrote:
>>>> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>>>>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>>>> information through unbanked registers.
>>>>>>
>>>>>> When returning from a nonsecure entry function we clear all
>>>>>> caller-saved
>>>>>> registers that are not used to pass return values, by writing either
>>>>>> the
>>>>>> LR, in case of general purpose registers, or the value 0, in case
>>>>>> of FP
>>>>>> registers. We use the LR to write to APSR and FPSCR too. We
>>>>>> currently do
>>>>>> not support entry functions that pass arguments or return
>>>>>> variables on
>>>>>> the stack and we diagnose this. This patch relies on the existing
>>>>>> code
>>>>>> to make sure callee-saved registers used in cmse_nonsecure_entry
>>>>>> functions are saved and restored thus retaining their nonsecure mode
>>>>>> value, this should be happening already as it is required by AAPCS.
>>>>>>
>>>>>> This patch also clears padding bits for cmse_nonsecure_entry
>>>>>> functions
>>>>>> with struct and union return types. For unions a bit is only
>>>>>> considered
>>>>>> a padding bit if it is an unused bit in every field of that union.
>>>>>> The
>>>>>> function that calculates these is used in a later patch to do the
>>>>>> same
>>>>>> for arguments of cmse_nonsecure_call's.
>>>>>>
>>>>>> *** gcc/ChangeLog ***
>>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>
>>>>>>           * config/arm/arm.c (output_return_instruction): Clear
>>>>>>           registers.
>>>>>>           (thumb2_expand_return): Likewise.
>>>>>>           (thumb1_expand_epilogue): Likewise.
>>>>>>           (thumb_exit): Likewise.
>>>>>>           (arm_expand_epilogue): Likewise.
>>>>>>           (cmse_nonsecure_entry_clear_before_return): New.
>>>>>>           (comp_not_to_clear_mask_str_un): New.
>>>>>>           (compute_not_to_clear_mask): New.
>>>>>>           * config/arm/thumb1.md (*epilogue_insns): Change length
>>>>>> attribute.
>>>>>>           * config/arm/thumb2.md (*thumb2_return): Likewise.
>>>>>>
>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>
>>>>>>           * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>>>> separate.
>>>>>>           * gcc.target/arm/cmse/struct-1.c: New.
>>>>>>           * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>>>           * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>>>           * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>>>           * gcc.target/arm/cmse/baseline/cmse-2.c: Test that
>>>>>> registers are
>>>>>> cleared.
>>>>>>           * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>>>           * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>>>           * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>>>           * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>>>           * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>>>
>>>>> Updated this patch to correctly clear only the cumulative
>>>>> exception-status (0-4,7) and the condition code bits (28-31) of the
>>>>> FPSCR. I also adapted the code to be handle the bigger floating point
>>>>> register files.
>>>>>
>>>>> ----
>>>>>
>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>>> information through unbanked registers.
>>>>>
>>>>> When returning from a nonsecure entry function we clear all
>>>>> caller-saved
>>>>> registers that are not used to pass return values, by writing
>>>>> either the
>>>>> LR, in case of general purpose registers, or the value 0, in case
>>>>> of FP
>>>>> registers. We use the LR to write to APSR. For FPSCR we clear only the
>>>>> cumulative exception-status (0-4, 7) and the condition code bits
>>>>> (28-31). We currently do not support entry functions that pass
>>>>> arguments
>>>>> or return variables on the stack and we diagnose this. This patch
>>>>> relies
>>>>> on the existing code to make sure callee-saved registers used in
>>>>> cmse_nonsecure_entry functions are saved and restored thus retaining
>>>>> their nonsecure mode value, this should be happening already as it is
>>>>> required by AAPCS.
>>>>>
>>>>> This patch also clears padding bits for cmse_nonsecure_entry functions
>>>>> with struct and union return types. For unions a bit is only
>>>>> considered
>>>>> a padding bit if it is an unused bit in every field of that union. The
>>>>> function that calculates these is used in a later patch to do the same
>>>>> for arguments of cmse_nonsecure_call's.
>>>>>
>>>>> *** gcc/ChangeLog ***
>>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>
>>>>>           * config/arm/arm.c (output_return_instruction): Clear
>>>>>           registers.
>>>>>           (thumb2_expand_return): Likewise.
>>>>>           (thumb1_expand_epilogue): Likewise.
>>>>>           (thumb_exit): Likewise.
>>>>>           (arm_expand_epilogue): Likewise.
>>>>>           (cmse_nonsecure_entry_clear_before_return): New.
>>>>>           (comp_not_to_clear_mask_str_un): New.
>>>>>           (compute_not_to_clear_mask): New.
>>>>>           * config/arm/thumb1.md (*epilogue_insns): Change length
>>>>> attribute.
>>>>>           * config/arm/thumb2.md (*thumb2_return): Duplicate
>>>>> pattern for
>>>>>           cmse_nonsecure_entry functions.
>>>>>
>>>>> *** gcc/testsuite/ChangeLog ***
>>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>
>>>>>           * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>>> separate.
>>>>>           * gcc.target/arm/cmse/struct-1.c: New.
>>>>>           * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>>           * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>>           * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>>           * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers
>>>>> are
>>>>> cleared.
>>>>>           * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>>           * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>>           * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>>           * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>>           * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>>
>>>> Hi,
>>>>
>>>> Rebased previous patch on top of trunk as requested. No changes to
>>>> ChangeLog.
>>>>
>>>> Cheers,
>>>> Andre
>>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>> index
>>> bb81e5662e81a26c7d3ccf9f749e8e356e6de35e..c6260323ecfd2f2842e6a5aab06b67da16619c73
>>>
>>> 100644
>>> --- a/gcc/config/arm/arm.c
>>> +++ b/gcc/config/arm/arm.c
>>> @@ -17496,6 +17496,279 @@ note_invalid_constants (rtx_insn *insn,
>>> HOST_WIDE_INT address, int do_pushes)
>>>     return;
>>>   }
>>>   +/* This function computes the clear mask and PADDING_BITS_TO_CLEAR
>>> for
>>> structs
>>> +   and unions in the context of ARMv8-M Security Extensions.  It is
>>> used as a
>>> +   helper function for both 'cmse_nonsecure_call' and
>>> 'cmse_nonsecure_entry'
>>> +   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to
>>> either one
>>> +   or four masks, depending on whether it is being computed for a
>>> +   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call'
>>> argument
>>> +   respectively.  The tree for the type of the argument or a field
>>> within an
>>> +   argument is passed in ARG_TYPE, the current register this argument
>>> or field
>>> +   starts in is kept in the pointer REGNO and updated accordingly, the
>>> bit this
>>> +   argument or field starts at is passed in STARTING_BIT and the last
>>> used bit
>>> +   is kept in LAST_USED_BIT which is also updated accordingly.  */
>>> +
>>> +static unsigned HOST_WIDE_INT
>>> +comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
>>> +                   uint32_t * padding_bits_to_clear,
>>> +                   unsigned starting_bit, int * last_used_bit)
>>> +
>>> +{
>>> +  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
>>> +
>>> +  if (TREE_CODE (arg_type) == RECORD_TYPE)
>>> +    {
>>> +      unsigned current_bit = starting_bit;
>>> +      tree field;
>>> +      long int offset, size;
>>> +
>>> +
>>> +      field = TYPE_FIELDS (arg_type);
>>> +      while (field)
>>> +    {
>>> +      /* The offset within a structure is always an offset from
>>> +         the start of that structure.  Make sure we take that into the
>>> +         calculation of the register based offset that we use here.  */
>>> +      offset = starting_bit;
>>> +      offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
>>> +      offset %= 32;
>>> +
>>> +      /* This is the actual size of the field, for bitfields this is
>>> the
>>> +         bitfield width and not the container size.  */
>>> +      size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>>> +
>>> +      if (*last_used_bit != offset)
>>> +        {
>>> +          if (offset < *last_used_bit)
>>> +        {
>>> +          /* This field's offset is before the 'last_used_bit', that
>>> +             means this field goes on the next register.  So we need to
>>> +             pad the rest of the current register and increase the
>>> +             register number.  */
>>> +          uint32_t mask;
>>> +          mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
>>> +          mask++;
>>> +
>>> +          *(padding_bits_to_clear + *regno) |= mask;
>>>
>>> padding_bits_to_clear[*regno] |= mask;
>>>
>>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>> +          (*regno)++;
>>> +        }
>>> +          else
>>> +        {
>>> +          /* Otherwise we pad the bits between the last field's end and
>>> +             the start of the new field.  */
>>> +          uint32_t mask;
>>> +
>>> +          mask = UINT32_MAX >> (32 - offset);
>>> +          mask -= ((uint32_t) 1 << *last_used_bit) - 1;
>>> +          *(padding_bits_to_clear + *regno) |= mask;
>>>
>>> Likewise.
>>>
>>> +        }
>>> +          current_bit = offset;
>>> +        }
>>> +
>>> +      /* Calculate further padding bits for inner structs/unions
>>> too.  */
>>> +      if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
>>> +        {
>>> +          *last_used_bit = current_bit;
>>> +          not_to_clear_reg_mask
>>> +        |= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
>>> +                          padding_bits_to_clear, offset,
>>> +                          last_used_bit);
>>> +        }
>>> +      else
>>> +        {
>>> +          /* Update 'current_bit' with this field's size.  If the
>>> +         'current_bit' lies in a subsequent register, update 'regno'
>>> and
>>> +         reset 'current_bit' to point to the current bit in that new
>>> +         register.  */
>>> +          current_bit += size;
>>> +          while (current_bit >= 32)
>>> +        {
>>> +          current_bit-=32;
>>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>> +          (*regno)++;
>>> +        }
>>> +          *last_used_bit = current_bit;
>>> +        }
>>> +
>>> +      field = TREE_CHAIN (field);
>>> +    }
>>> +      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>> +    }
>>> +  else if (TREE_CODE (arg_type) == UNION_TYPE)
>>> +    {
>>> +      tree field, field_t;
>>> +      int i, regno_t, field_size;
>>> +      int max_reg = -1;
>>> +      int max_bit = -1;
>>> +      uint32_t mask;
>>> +      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
>>> +    = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
>>> +
>>> +      /* To compute the padding bits in a union we only consider
>>> bits as
>>> +     padding bits if they are always either a padding bit or fall
>>> outside a
>>> +     fields size for all fields in the union.  */
>>> +      field = TYPE_FIELDS (arg_type);
>>> +      while (field)
>>> +    {
>>> +      uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
>>> +        = {0U, 0U, 0U, 0U};
>>> +      int last_used_bit_t = *last_used_bit;
>>> +      regno_t = *regno;
>>> +      field_t = TREE_TYPE (field);
>>> +
>>> +      /* If the field's type is either a record or a union make sure to
>>> +         compute their padding bits too.  */
>>> +      if (RECORD_OR_UNION_TYPE_P (field_t))
>>> +        not_to_clear_reg_mask
>>> +          |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
>>> +                        &padding_bits_to_clear_t[0],
>>> +                        starting_bit, &last_used_bit_t);
>>> +      else
>>> +        {
>>> +          field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>>> +          regno_t = (field_size / 32) + *regno;
>>> +          last_used_bit_t = (starting_bit + field_size) % 32;
>>> +        }
>>> +
>>> +      for (i = *regno; i < regno_t; i++)
>>> +        {
>>> +          /* For all but the last register used by this field only keep
>>> the
>>> +         padding bits that were padding bits in this field.  */
>>> +          padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
>>> +        }
>>> +
>>> +        /* For the last register, keep all padding bits that were
>>> padding
>>> +           bits in this field and any padding bits that are still valid
>>> +           as padding bits but fall outside of this field's size.  */
>>> +        mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
>>> +        padding_bits_to_clear_res[regno_t]
>>> +          &= padding_bits_to_clear_t[regno_t] | mask;
>>> +
>>> +      /* Update the maximum size of the fields in terms of registers
>>> used
>>> +         ('max_reg') and the 'last_used_bit' in said register.  */
>>> +      if (max_reg < regno_t)
>>> +        {
>>> +          max_reg = regno_t;
>>> +          max_bit = last_used_bit_t;
>>> +        }
>>> +      else if (max_reg == regno_t && max_bit < last_used_bit_t)
>>> +        max_bit = last_used_bit_t;
>>> +
>>> +      field = TREE_CHAIN (field);
>>> +    }
>>> +
>>> +      /* Update the current padding_bits_to_clear using the
>>> intersection of the
>>> +     padding bits of all the fields.  */
>>> +      for (i=*regno; i < max_reg; i++)
>>> +    padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
>>> +
>>>
>>> watch the spacing in the 'for' definition.
>>>
>>>   +      /* Do not keep trailing padding bits, we do not know yet
>>> whether
>>> this
>>> +     is the end of the argument.  */
>>> +      mask = ((uint32_t) 1 << max_bit) - 1;
>>> +      padding_bits_to_clear[max_reg]
>>> +    |= padding_bits_to_clear_res[max_reg] & mask;
>>> +
>>> +      *regno = max_reg;
>>> +      *last_used_bit = max_bit;
>>> +    }
>>> +  else
>>> +    /* This function should only be used for structs and unions.  */
>>> +    gcc_unreachable ();
>>> +
>>> +  return not_to_clear_reg_mask;
>>> +}
>>> +
>>> +/* In the context of ARMv8-M Security Extensions, this function is used
>>> for both
>>> +   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to
>>> compute what
>>> +   registers are used when returning or passing arguments, which is
>>> then
>>> +   returned as a mask.  It will also compute a mask to indicate
>>> padding/unused
>>> +   bits for each of these registers, and passes this through the
>>> +   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is
>>> passed in
>>> +   ARG_TYPE, the rtl representation of the argument is passed in
>>> ARG_RTX and
>>> +   the starting register used to pass this argument or return value is
>>> passed
>>> +   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to
>>> compute these
>>> +   for struct and union types.  */
>>> +
>>> +static unsigned HOST_WIDE_INT
>>> +compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
>>> +                 uint32_t * padding_bits_to_clear)
>>> +
>>> +{
>>> +  int last_used_bit = 0;
>>> +  unsigned HOST_WIDE_INT not_to_clear_mask;
>>> +
>>> +  if (RECORD_OR_UNION_TYPE_P (arg_type))
>>> +    {
>>> +      not_to_clear_mask
>>> +    = comp_not_to_clear_mask_str_un (arg_type, &regno,
>>> +                     padding_bits_to_clear, 0,
>>> +                     &last_used_bit);
>>> +
>>> +
>>> +      /* If the 'last_used_bit' is not zero, that means we are still
>>> using a
>>> +     part of the last 'regno'.  In such cases we must clear the
>>> trailing
>>> +     bits.  Otherwise we are not using regno and we should mark it
>>> as to
>>> +     clear.  */
>>> +      if (last_used_bit != 0)
>>> +    *(padding_bits_to_clear + regno)
>>> +      |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;
>>>
>>> padding_bits_to_clear[regno] |= ...
>>>
>>> +      else
>>> +    not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
>>> +    }
>>> +  else
>>> +    {
>>> +      not_to_clear_mask = 0;
>>> +      /* We are not dealing with structs nor unions.  So these
>>> arguments may be
>>> +     passed in floating point registers too.  In some cases a
>>> BLKmode is
>>> +     used when returning or passing arguments in multiple VFP
>>> registers.  */
>>> +      if (GET_MODE (arg_rtx) == BLKmode)
>>> +    {
>>> +      int i, arg_regs;
>>> +      rtx reg;
>>> +
>>> +      /* This should really only occur when dealing with the hard-float
>>> +         ABI.  */
>>> +      gcc_assert (TARGET_HARD_FLOAT_ABI);
>>> +
>>> +      for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
>>> +        {
>>> +          reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
>>> +          gcc_assert (REG_P (reg));
>>> +
>>> +          not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
>>> +
>>> +          /* If we are dealing with DF mode, make sure we don't
>>> +         clear either of the registers it addresses.  */
>>> +          arg_regs = ARM_NUM_REGS (GET_MODE (reg));
>>>
>>> Better assert here that you're indeed dealing with DFmode and/or you
>>> have 2 registers.
>>>
>> The current code actually works for larger modes too. I don't think code
>> will ever be generated with larger types, but why assert if it works
>> anyway?
> 
> ok, no need to assert here then.
> I suppose it doesn't add much if the code handles the other modes fine.
> 
> Kyrill
> 
Hi,

Reworked comments. No change to ChangeLogs.

Cheers,
Andre

[-- Attachment #2: diff4 --]
[-- Type: text/plain, Size: 39134 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index fdbdd423236e7388802bc4bd568f260d95485bbe..9fa216c3a5a3a466448b45a3038d87aecd883433 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17499,6 +17499,279 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
   return;
 }
 
+/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for structs
+   and unions in the context of ARMv8-M Security Extensions.  It is used as a
+   helper function for both 'cmse_nonsecure_call' and 'cmse_nonsecure_entry'
+   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to either one
+   or four masks, depending on whether it is being computed for a
+   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
+   respectively.  The tree for the type of the argument or a field within an
+   argument is passed in ARG_TYPE, the current register this argument or field
+   starts in is kept in the pointer REGNO and updated accordingly, the bit this
+   argument or field starts at is passed in STARTING_BIT and the last used bit
+   is kept in LAST_USED_BIT which is also updated accordingly.  */
+
+static unsigned HOST_WIDE_INT
+comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
+			       uint32_t * padding_bits_to_clear,
+			       unsigned starting_bit, int * last_used_bit)
+
+{
+  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
+
+  if (TREE_CODE (arg_type) == RECORD_TYPE)
+    {
+      unsigned current_bit = starting_bit;
+      tree field;
+      long int offset, size;
+
+
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  /* The offset within a structure is always an offset from
+	     the start of that structure.  Make sure we take that into the
+	     calculation of the register based offset that we use here.  */
+	  offset = starting_bit;
+	  offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
+	  offset %= 32;
+
+	  /* This is the actual size of the field, for bitfields this is the
+	     bitfield width and not the container size.  */
+	  size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+
+	  if (*last_used_bit != offset)
+	    {
+	      if (offset < *last_used_bit)
+		{
+		  /* This field's offset is before the 'last_used_bit', that
+		     means this field goes on the next register.  So we need to
+		     pad the rest of the current register and increase the
+		     register number.  */
+		  uint32_t mask;
+		  mask  = ((uint32_t)-1) - ((uint32_t) 1 << *last_used_bit);
+		  mask++;
+
+		  padding_bits_to_clear[*regno] |= mask;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      else
+		{
+		  /* Otherwise we pad the bits between the last field's end and
+		     the start of the new field.  */
+		  uint32_t mask;
+
+		  mask = ((uint32_t)-1) >> (32 - offset);
+		  mask -= ((uint32_t) 1 << *last_used_bit) - 1;
+		  padding_bits_to_clear[*regno] |= mask;
+		}
+	      current_bit = offset;
+	    }
+
+	  /* Calculate further padding bits for inner structs/unions too.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	    {
+	      *last_used_bit = current_bit;
+	      not_to_clear_reg_mask
+		|= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
+						  padding_bits_to_clear, offset,
+						  last_used_bit);
+	    }
+	  else
+	    {
+	      /* Update 'current_bit' with this field's size.  If the
+		 'current_bit' lies in a subsequent register, update 'regno' and
+		 reset 'current_bit' to point to the current bit in that new
+		 register.  */
+	      current_bit += size;
+	      while (current_bit >= 32)
+		{
+		  current_bit-=32;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      *last_used_bit = current_bit;
+	    }
+
+	  field = TREE_CHAIN (field);
+	}
+      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+    }
+  else if (TREE_CODE (arg_type) == UNION_TYPE)
+    {
+      tree field, field_t;
+      int i, regno_t, field_size;
+      int max_reg = -1;
+      int max_bit = -1;
+      uint32_t mask;
+      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
+	= {-1, -1, -1, -1};
+
+      /* To compute the padding bits in a union we only consider bits as
+	 padding bits if they are always either a padding bit or fall outside a
+	 fields size for all fields in the union.  */
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
+	    = {0U, 0U, 0U, 0U};
+	  int last_used_bit_t = *last_used_bit;
+	  regno_t = *regno;
+	  field_t = TREE_TYPE (field);
+
+	  /* If the field's type is either a record or a union make sure to
+	     compute their padding bits too.  */
+	  if (RECORD_OR_UNION_TYPE_P (field_t))
+	    not_to_clear_reg_mask
+	      |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
+						&padding_bits_to_clear_t[0],
+						starting_bit, &last_used_bit_t);
+	  else
+	    {
+	      field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+	      regno_t = (field_size / 32) + *regno;
+	      last_used_bit_t = (starting_bit + field_size) % 32;
+	    }
+
+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (((uint32_t) -1) - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;
+
+	  /* Update the maximum size of the fields in terms of registers used
+	     ('max_reg') and the 'last_used_bit' in said register.  */
+	  if (max_reg < regno_t)
+	    {
+	      max_reg = regno_t;
+	      max_bit = last_used_bit_t;
+	    }
+	  else if (max_reg == regno_t && max_bit < last_used_bit_t)
+	    max_bit = last_used_bit_t;
+
+	  field = TREE_CHAIN (field);
+	}
+
+      /* Update the current padding_bits_to_clear using the intersection of the
+	 padding bits of all the fields.  */
+      for (i=*regno; i < max_reg; i++)
+	padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+
+      /* Do not keep trailing padding bits, we do not know yet whether this
+	 is the end of the argument.  */
+      mask = ((uint32_t) 1 << max_bit) - 1;
+      padding_bits_to_clear[max_reg]
+	|= padding_bits_to_clear_res[max_reg] & mask;
+
+      *regno = max_reg;
+      *last_used_bit = max_bit;
+    }
+  else
+    /* This function should only be used for structs and unions.  */
+    gcc_unreachable ();
+
+  return not_to_clear_reg_mask;
+}
+
+/* In the context of ARMv8-M Security Extensions, this function is used for both
+   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to compute what
+   registers are used when returning or passing arguments, which is then
+   returned as a mask.  It will also compute a mask to indicate padding/unused
+   bits for each of these registers, and passes this through the
+   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is passed in
+   ARG_TYPE, the rtl representation of the argument is passed in ARG_RTX and
+   the starting register used to pass this argument or return value is passed
+   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to compute these
+   for struct and union types.  */
+
+static unsigned HOST_WIDE_INT
+compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
+			     uint32_t * padding_bits_to_clear)
+
+{
+  int last_used_bit = 0;
+  unsigned HOST_WIDE_INT not_to_clear_mask;
+
+  if (RECORD_OR_UNION_TYPE_P (arg_type))
+    {
+      not_to_clear_mask
+	= comp_not_to_clear_mask_str_un (arg_type, &regno,
+					 padding_bits_to_clear, 0,
+					 &last_used_bit);
+
+
+      /* If the 'last_used_bit' is not zero, that means we are still using a
+	 part of the last 'regno'.  In such cases we must clear the trailing
+	 bits.  Otherwise we are not using regno and we should mark it as to
+	 clear.  */
+      if (last_used_bit != 0)
+	padding_bits_to_clear[regno]
+	  |= ((uint32_t)-1) - ((uint32_t) 1 << last_used_bit) + 1;
+      else
+	not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
+    }
+  else
+    {
+      not_to_clear_mask = 0;
+      /* We are not dealing with structs nor unions.  So these arguments may be
+	 passed in floating point registers too.  In some cases a BLKmode is
+	 used when returning or passing arguments in multiple VFP registers.  */
+      if (GET_MODE (arg_rtx) == BLKmode)
+	{
+	  int i, arg_regs;
+	  rtx reg;
+
+	  /* This should really only occur when dealing with the hard-float
+	     ABI.  */
+	  gcc_assert (TARGET_HARD_FLOAT_ABI);
+
+	  for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
+	    {
+	      reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
+	      gcc_assert (REG_P (reg));
+
+	      not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
+
+	      /* If we are dealing with DF mode, make sure we don't
+		 clear either of the registers it addresses.  */
+	      arg_regs = ARM_NUM_REGS (GET_MODE (reg));
+	      if (arg_regs > 1)
+		{
+		  unsigned HOST_WIDE_INT mask;
+		  mask = HOST_WIDE_INT_1U << (REGNO (reg) + arg_regs);
+		  mask -= HOST_WIDE_INT_1U << REGNO (reg);
+		  not_to_clear_mask |= mask;
+		}
+	    }
+	}
+      else
+	{
+	  /* Otherwise we can rely on the MODE to determine how many registers
+	     are being used by this argument.  */
+	  int arg_regs = ARM_NUM_REGS (GET_MODE (arg_rtx));
+	  not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	  if (arg_regs > 1)
+	    {
+	      unsigned HOST_WIDE_INT
+	      mask = HOST_WIDE_INT_1U << (REGNO (arg_rtx) + arg_regs);
+	      mask -= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	      not_to_clear_mask |= mask;
+	    }
+	}
+    }
+
+  return not_to_clear_mask;
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -19920,7 +20193,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
-	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    {
+	      /* 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);
+	      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).  */
+		  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");
+	    }
 	  /* Use bx if it's available.  */
 	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
@@ -24187,7 +24495,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
-	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	{
+	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+		       reg_containing_return_addr);
+	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	}
       else
 	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
@@ -24423,7 +24735,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
   /* Return to caller.  */
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
-    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    {
+      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
+      asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    }
   else
     asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
@@ -25285,6 +25600,134 @@ thumb1_expand_prologue (void)
     cfun->machine->lr_save_eliminated = 0;
 }
 
+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check TARGET_HARD_FLOAT to make sure these are
+     present.  */
+  if (TARGET_HARD_FLOAT)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      maxregno = LAST_VFP_REGNUM;
+
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask[0] |= float_mask;
+
+      float_mask = (1ULL << (maxregno - 63)) - 1;
+      to_clear_mask[1] = float_mask;
+
+      /* Make sure we dont clear the two scratch registers used to clear the
+	 relevant FPSCR bits in output_return_instruction.  We have only
+	 implemented the clearing of FP registers for Thumb-2, so we assert
+	 here that VFP was not enabled for Thumb-1 ARMv8-M targets.  */
+      gcc_assert (arm_arch_thumb2);
+      emit_use (gen_rtx_REG (SImode, IP_REGNUM));
+      to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+      emit_use (gen_rtx_REG (SImode, 4));
+      to_clear_mask[0] &= ~(1ULL << 4);
+    }
+
+  /* If the user has defined registers to be caller saved, these are no longer
+     restored by the function before returning and must thus be cleared for
+     security purposes.  */
+  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+    {
+      /* We do not touch registers that can be used to pass arguments as per
+	 the AAPCS, since these should never be made callee-saved by user
+	 options.  */
+      if (IN_RANGE (regno, FIRST_VFP_REGNUM, D7_VFP_REGNUM))
+	continue;
+      if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
+	continue;
+      if (call_used_regs[regno])
+	to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+    }
+
+  /* Make sure we do not clear the registers used to return the result in.  */
+  result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+  if (!VOID_TYPE_P (result_type))
+    {
+      result_rtl = arm_function_value (result_type, current_function_decl, 0);
+
+      /* No need to check that we return in registers, because we don't
+	 support returning on stack yet.  */
+      to_clear_mask[0]
+	&= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
+				       padding_bits_to_clear_ptr);
+    }
+
+  if (padding_bits_to_clear != 0)
+    {
+      rtx reg_rtx;
+      /* Padding bits to clear is not 0 so we know we are dealing with
+	 returning a composite type, which only uses r0.  Let's make sure that
+	 r1-r3 is cleared too, we will use r1 as a scratch register.  */
+      gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
+
+      reg_rtx = gen_rtx_REG (SImode, R1_REGNUM);
+
+      /* Fill the lower half of the negated padding_bits_to_clear.  */
+      emit_move_insn (reg_rtx,
+		      GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
+
+      /* Also fill the top half of the negated padding_bits_to_clear.  */
+      if (((~padding_bits_to_clear) >> 16) > 0)
+	emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
+						      GEN_INT (16),
+						      GEN_INT (16)),
+				GEN_INT ((~padding_bits_to_clear) >> 16)));
+
+      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, R0_REGNUM),
+			   gen_rtx_REG (SImode, R0_REGNUM),
+			   reg_rtx));
+    }
+
+  for (regno = 0; regno <= maxregno; regno++)
+    {
+      if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
+	continue;
+
+      if (IS_VFP_REGNUM (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)
+	      && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 1)))
+	    {
+	      emit_move_insn (gen_rtx_REG (DFmode, regno++),
+			      CONST1_RTX (DFmode));
+	      emit_use (gen_rtx_REG (DFmode, 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 (SImode, regno),
+			  gen_rtx_REG (SImode, LR_REGNUM));
+	  emit_use (gen_rtx_REG (SImode, regno));
+	}
+    }
+}
+
 /* Generate pattern *pop_multiple_with_stack_update_and_return if single
    POP instruction can be generated.  LR should be replaced by PC.  All
    the checks required are already done by  USE_RETURN_INSN ().  Hence,
@@ -25334,6 +25777,8 @@ thumb2_expand_return (bool simple_return)
     }
   else
     {
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	cmse_nonsecure_entry_clear_before_return ();
       emit_jump_insn (simple_return_rtx);
     }
 }
@@ -25392,6 +25837,10 @@ thumb1_expand_epilogue (void)
 
   if (! df_regs_ever_live_p (LR_REGNUM))
     emit_use (gen_rtx_REG (SImode, LR_REGNUM));
+
+  /* Clear all caller-saved regs that are not used to return.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    cmse_nonsecure_entry_clear_before_return ();
 }
 
 /* Epilogue code for APCS frame.  */
@@ -25826,6 +26275,14 @@ 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 (!really_return)
     return;
 
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index cd98de7dcb40de483a9f93c0674bd216f4b0c56a..433fc79ae5810a4d3eb45d1ba80872a39e157e14 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1843,8 +1843,13 @@
   "*
     return thumb1_unexpanded_epilogue ();
   "
-  ; Length is absolute worst case
-  [(set_attr "length" "44")
+  ; Length is absolute worst case, when using CMSE and if this is an entry
+  ; function an extra 4 (MSR) bytes will be added.
+  [(set (attr "length")
+	(if_then_else
+	 (match_test "IS_CMSE_ENTRY (arm_current_func_type ())")
+	 (const_int 48)
+	 (const_int 44)))
    (set_attr "type" "block")
    ;; We don't clobber the conditions, but the potential length of this
    ;; operation is sufficient to make conditionalizing the sequence
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index affcd832b72b7d358347e7370265be492866bb90..f5033ef802c085bd0ce479bc7026db96d9e25632 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1114,12 +1114,31 @@
 
 (define_insn "*thumb2_return"
   [(simple_return)]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
   "* return output_return_instruction (const_true_rtx, true, false, true);"
   [(set_attr "type" "branch")
    (set_attr "length" "4")]
 )
 
+(define_insn "*thumb2_return"
+  [(simple_return)]
+  "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
+  "* return output_return_instruction (const_true_rtx, true, false, true);"
+  [(set_attr "type" "branch")
+   ; This is a return from a cmse_nonsecure_entry function so code will be
+   ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+   ; we adapt the length accordingly.
+   (set (attr "length")
+     (if_then_else (match_test "TARGET_HARD_FLOAT")
+      (const_int 12)
+      (const_int 8)))
+   ; We do not support predicate execution of returns from cmse_nonsecure_entry
+   ; functions because we need to clear the APSR.  Since predicable has to be
+   ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
+   ; functions.
+   (set_attr "predicable" "no")]
+)
+
 (define_insn_and_split "thumb2_eh_return"
   [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
 		    VUNSPEC_EH_RETURN)
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c6354c7a8cfead895e6c62d61c3f2a2bca1a1f2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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 "msr\tAPSR_nzcvq, r1" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..fccc51d5c82f7955ee4cb8256c1dd38f9ff2670d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned short  a : 6;
+  unsigned char	  b : 3;
+  unsigned char	  c;
+  unsigned short  d : 8;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 63u;
+  t.b = 7u;
+  t.c = 255u;
+  t.d = 255u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 63u
+      || t.b != 7u
+      || t.c != 255u
+      || t.d != 255u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6aee3c4c022d50baec8ab16443130897540e703
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a : 7;
+  signed char b : 3;
+  short	      c : 11;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -64;
+  t.b = -4 ;
+  t.c = -1024;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -64
+      || t.b != -4
+      || t.c != -1024)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..285a2b92f64c1913ef585b8daa4d27c6da0a3d2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a;
+  signed char b : 2;
+  short		: 1;
+  signed char c : 3;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -32768;
+  t.b = -2;
+  t.c = -4;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -32768
+      || t.b != -2
+      || t.c != -4)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index f797dba1901720e04249d61078c1cbf2a3e436a9..38f18414c2fefec56161e6ac3f7291b03a3b29a3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -43,6 +43,26 @@ set LTO_TORTURE_OPTIONS ""
 gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
 	"" $DEFAULT_CFLAGS
 
+if {[check_effective_target_arm_arch_v8m_base_ok]} then {
+    # Baseline only
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/baseline/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
+if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    # Mainline -mfloat-abi=soft
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
+	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
 set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
 set dg-do-what-default ${saved-dg-do-what-default}
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..88dec2762812614ee986ee1a023c0acce8f94c91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..29f60baf5212f9fa2e4436fe40c6abe4ac671254
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7229ea8eb2da1da264f58f8518daf303d1bdeda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..7734d77dc3812e6a158ea1f6b067930846fffccb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..6addaa1a4eda8e2930d5fe72c94697bcf6e604e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { 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
new file mode 100644
index 0000000000000000000000000000000000000000..2d366a944df692f29ab44e3ee4d33c777b126223
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 255u;
+  t.b = 32767u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 255u || t.b != 32767u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
+

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

* Re: [PATCHv2 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
  2016-10-25 16:29     ` Andre Vieira (lists)
@ 2016-10-27 10:00       ` Andre Vieira (lists)
  2016-11-04  9:30       ` Kyrill Tkachov
  1 sibling, 0 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-27 10:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 25/10/16 17:29, Andre Vieira (lists) wrote:
> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>> On 25/07/16 14:25, Andre Vieira (lists) wrote:
>>> This patch adds support for the ARMv8-M Security Extensions
>>> 'cmse_nonsecure_call' attribute. This attribute may only be used for
>>> function types and when used in combination with the '-mcmse'
>>> compilation flag. See Section 5.5 of ARM®v8-M Security Extensions
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>
>>> We currently do not support cmse_nonsecure_call functions that pass
>>> arguments or return variables on the stack and we diagnose this.
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>         * config/arm/arm.c (gimplify.h): New include.
>>>         (arm_handle_cmse_nonsecure_call): New.
>>>         (arm_attribute_table): Added cmse_nonsecure_call.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>         * gcc.target/arm/cmse/cmse-3.c: Add tests.
>>>         * gcc.target/arm/cmse/cmse-4.c: Add tests.
>>>
>>
>> Added more documentation as requested.
>>
>> ---
>>
>> This patch adds support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_call' attribute. This attribute may only be used for
>> function types and when used in combination with the '-mcmse'
>> compilation flag. See Section 5.5 of ARM®v8-M Security Extensions
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> We currently do not support cmse_nonsecure_call functions that pass
>> arguments or return variables on the stack and we diagnose this.
>>
>> *** gcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm.c (gimplify.h): New include.
>>         (arm_handle_cmse_nonsecure_call): New.
>>         (arm_attribute_table): Added cmse_nonsecure_call.
>>         * doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/cmse-3.c: Add tests.
>>         * gcc.target/arm/cmse/cmse-4.c: Add tests.
>>
> Hi,
> 
> Rebased previous patch on top of trunk as requested. No changes to
> ChangeLog.
> 
> Cheers,
> Andre
> 
Hi,

Added the same warning for cmse_nonsecure_call attribute as a result of
the comments for 2/7 of this series. No change to ChangeLogs.

Cheers,
Andre

[-- Attachment #2: diff5 --]
[-- Type: text/plain, Size: 7226 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9fa216c3a5a3a466448b45a3038d87aecd883433..cc458108f1371b31ea5a10aa8e226ae1bbc7e058 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -62,6 +62,7 @@
 #include "builtins.h"
 #include "tm-constrs.h"
 #include "rtl-iter.h"
+#include "gimplify.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -136,6 +137,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
 static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
+static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -351,6 +353,8 @@ static const struct attribute_spec arm_attribute_table[] =
   /* ARMv8-M Security Extensions support.  */
   { "cmse_nonsecure_entry", 0, 0, true, false, false,
     arm_handle_cmse_nonsecure_entry, false },
+  { "cmse_nonsecure_call", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_call, false },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -6780,6 +6784,80 @@ arm_handle_cmse_nonsecure_entry (tree *node, tree name,
   return NULL_TREE;
 }
 
+
+/* Called upon detection of the use of the cmse_nonsecure_call attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function type tree or otherwise issue a diagnostic.  The
+   reason we check this at declaration time is to only allow the use of the
+   attribute with declarations of function pointers and not function
+   declarations.  This function checks NODE is of the expected type and issues
+   diagnostics otherwise using NAME.  If it is not of the expected type
+   *NO_ADD_ATTRS will be set to true.  */
+
+static tree
+arm_handle_cmse_nonsecure_call (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree decl = NULL_TREE;
+  tree type, fntype, main_variant;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored without -mcmse option.",
+	       name);
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == TYPE_DECL)
+    {
+      decl = *node;
+      type = TREE_TYPE (decl);
+    }
+
+  if (!decl
+      || (!(TREE_CODE (type) == POINTER_TYPE
+	    && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+	  && TREE_CODE (type) != FUNCTION_TYPE))
+    {
+	warning (OPT_Wattributes, "%qE attribute only applies to base type of a "
+		 "function pointer", name);
+	*no_add_attrs = true;
+	return NULL_TREE;
+    }
+
+  /* type is either a function pointer, when the attribute is used on a function
+   * pointer, or a function type when used in a typedef.  */
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    fntype = type;
+  else
+    fntype = TREE_TYPE (type);
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (NULL, name, fntype);
+
+  if (*no_add_attrs)
+    return NULL_TREE;
+
+  /* Prevent trees being shared among function types with and without
+     cmse_nonsecure_call attribute.  Do however make sure they keep the same
+     main_variant, this is required for correct DIE output.  */
+  main_variant = TYPE_MAIN_VARIANT (fntype);
+  fntype = build_distinct_type_copy (fntype);
+  TYPE_MAIN_VARIANT (fntype) = main_variant;
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    TREE_TYPE (decl) = fntype;
+  else
+    TREE_TYPE (type) = fntype;
+
+  /* Construct a type attribute and add it to the function type.  */
+  tree attrs = tree_cons (get_identifier ("cmse_nonsecure_call"), NULL_TREE,
+			  TYPE_ATTRIBUTES (fntype));
+  TYPE_ATTRIBUTES (fntype) = attrs;
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index e5b28032e5610b896908139ec285ce90a9dffd8a..462e6c71e20791b35f02adabfc97b9b013fd296a 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12607,8 +12607,8 @@ Security Extensions: Requiremenets on Development Tools Engineering
 Specification, which can be found at
 @uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 
-As part of the Security Extensions GCC implements a new function attribute
-@code{cmse_nonsecure_entry}.
+As part of the Security Extensions GCC implements two new function attributes:
+@code{cmse_nonsecure_entry} and @code{cmse_nonsecure_call}.
 
 As part of the Security Extensions GCC implements the intrinsics below.  FPTR
 is used here to mean any function pointer type.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
index 2c2920e1dc310106d83203eb51e1a68a275d0152..7f92a4c28b3333e4c8fdc256211f3ed74a383cd4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -35,3 +35,11 @@ norf (struct span2 a) {}
 
 void __attribute__ ((cmse_nonsecure_entry))
 foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) bar2 (long long a, int b, long long c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) baz2 (long long a, int b, struct span c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef struct span __attribute__ ((cmse_nonsecure_call)) qux2 (void); /* { dg-error "not available to functions that return value on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) norf2 (int a, ...); /* { dg-error "not available to functions with variable number of arguments" } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
index 6f930ab04a1097c64097a4e003296bbe85733319..d0999a4181ac022b115ae20cf3e1c8bf78f6becf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -19,9 +19,16 @@ baz (void)
   return qux ();
 }
 
+void __attribute__ ((cmse_nonsecure_call))
+quux (void) {} /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
+int __attribute__ ((cmse_nonsecure_call)) norf; /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
 /* { dg-final { scan-assembler-times "bxns" 2 } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
 /* { dg-final { scan-assembler "baz:" } } */
 /* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_quux:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_norf:" } } */

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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-10-25 16:30     ` Andre Vieira (lists)
@ 2016-10-27 10:01       ` Andre Vieira (lists)
  2016-11-09 14:54         ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-27 10:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 25/10/16 17:30, Andre Vieira (lists) wrote:
> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>> On 25/07/16 14:26, Andre Vieira (lists) wrote:
>>> This patch extends support for the ARMv8-M Security Extensions
>>> 'cmse_nonsecure_call' to use a new library function
>>> '__gnu_cmse_nonsecure_call'. This library function is responsible for
>>> (without using r0-r3 or d0-d7):
>>> 1) saving and clearing all callee-saved registers using the secure stack
>>> 2) clearing the LSB of the address passed in r4 and using blxns to
>>> 'jump' to it
>>> 3) clearing ASPR, including the 'ge bits' if DSP is enabled
>>> 4) clearing FPSCR if using non-soft float-abi
>>> 5) restoring callee-saved registers.
>>>
>>> The decisions whether to include DSP 'ge bits' clearing and floating
>>> point registers (single/double precision) all depends on the multilib used.
>>>
>>> See Section 5.5 of ARM®v8-M Security Extensions
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>         * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>>>         (cmse_nonsecure_call_clear_caller_saved): New.
>>>         (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>>>         * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>>>         * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>>>         (call_value): Likewise.
>>>         (nonsecure_call_internal): New.
>>>         (nonsecure_call_value_internal): New.
>>>         * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>>>         (*nonsecure_call_value_reg_thumb1_v5): New.
>>>         * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>>>         (*nonsecure_call_value_reg_thumb2): New.
>>>         * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
>>>
>>> *** libgcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>         * config/arm/cmse_nonsecure_call.S: New.
>>> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
>>>
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>         * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>>>         * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>>>         * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>>>         * gcc.target/arm/cmse/baseline/cmse-11.c: New.
>>> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
>>>
>>
>> Updated this patch to correctly clear only the cumulative
>> exception-status (0-4,7) and the condition code bits (28-31) of the FPSCR.
>>
>> ----
>>
>> This patch extends support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_call' to use a new library function
>> '__gnu_cmse_nonsecure_call'. This library function is responsible for
>> (without using r0-r3 or d0-d7):
>> 1) saving and clearing all callee-saved registers using the secure stack
>> 2) clearing the LSB of the address passed in r4 and using blxns to
>> 'jump' to it
>> 3) clearing ASPR, including the 'ge bits' if DSP is enabled
>> 4) clearing the cumulative exception-status (0-4, 7) and the condition
>> bits (28-31) of the FPSCR if using non-soft float-abi
>> 5) restoring callee-saved registers.
>>
>> The decisions whether to include DSP 'ge bits' clearing and floating
>> point registers (single/double precision) all depends on the multilib used.
>>
>> See Section 5.5 of ARM®v8-M Security Extensions
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> *** gcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>>         (cmse_nonsecure_call_clear_caller_saved): New.
>>         (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>>         * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>>         * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>>         (call_value): Likewise.
>>         (nonsecure_call_internal): New.
>>         (nonsecure_call_value_internal): New.
>>         * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>>         (*nonsecure_call_value_reg_thumb1_v5): New.
>>         * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>>         (*nonsecure_call_value_reg_thumb2): New.
>>         * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
>>
>> *** libgcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * config/arm/cmse_nonsecure_call.S: New.
>> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
>>
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>         * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>>         * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>>         * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>>         * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>>         * gcc.target/arm/cmse/baseline/cmse-11.c: New.
>> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
>>
> Hi,
> 
> Rebased previous patch on top of trunk as requested. No changes to
> ChangeLog.
> 
> Cheers,
> Andre
> 

Hi,

Reworked the testcase for compiling without -mcmse to catch the warning
added in 5/7. Also took the opportunity to improve the code in the
cmse_nonsecure_call library wrapper.

Cheers,
Andre

[-- Attachment #2: diff6 --]
[-- Type: text/plain, Size: 81892 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index a9b8326c2770c1f9a9787743cb5faa549e6b7d02..2660bc3ba89c34b17911680c4e25eb2f6c0745fb 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -135,6 +135,7 @@ extern int arm_const_double_inline_cost (rtx);
 extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
+bool detect_cmse_nonsecure_call (tree);
 extern const char *output_call (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index cc458108f1371b31ea5a10aa8e226ae1bbc7e058..8ba3e966f367626af8d3c1b52fcb7fb2e7db24e2 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17850,6 +17850,197 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Saves callee saved registers, clears callee saved registers and caller saved
+   registers not used to pass arguments before a cmse_nonsecure_call.  And
+   restores the callee saved registers after.  */
+
+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  uint64_t to_clear_mask, float_mask;
+	  rtx_insn *seq;
+	  rtx pat, call, unspec, reg, cleared_reg, tmp;
+	  unsigned int regno, maxregno;
+	  rtx address;
+	  CUMULATIVE_ARGS args_so_far_v;
+	  cumulative_args_t args_so_far;
+	  tree arg_type, fntype;
+	  bool using_r4, first_param = true;
+	  function_args_iterator args_iter;
+	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
+	  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
+
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  if (!CALL_P (insn))
+	    continue;
+
+	  pat = PATTERN (insn);
+	  gcc_assert (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 0);
+	  call = XVECEXP (pat, 0, 0);
+
+	  /* Get the real call RTX if the insn sets a value, ie. returns.  */
+	  if (GET_CODE (call) == SET)
+	      call = SET_SRC (call);
+
+	  /* Check if it is a cmse_nonsecure_call.  */
+	  unspec = XEXP (call, 0);
+	  if (GET_CODE (unspec) != UNSPEC
+	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
+	    continue;
+
+	  /* Determine the caller-saved registers we need to clear.  */
+	  to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
+	  maxregno = NUM_ARG_REGS - 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
+	     lazy store and loads which clear both caller- and callee-saved
+	     registers.  */
+	  if (TARGET_HARD_FLOAT_ABI)
+	    {
+	      float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
+	      float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
+	      to_clear_mask |= float_mask;
+	      maxregno = D7_VFP_REGNUM;
+	    }
+
+	  /* Make sure the register used to hold the function address is not
+	     cleared.  */
+	  address = RTVEC_ELT (XVEC (unspec, 0), 0);
+	  gcc_assert (MEM_P (address));
+	  gcc_assert (REG_P (XEXP (address, 0)));
+	  to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+
+	  /* Set basic block of call insn so that df rescan is performed on
+	     insns inserted here.  */
+	  set_block_for_insn (insn, bb);
+	  df_set_flags (DF_DEFER_INSN_RESCAN);
+	  start_sequence ();
+
+	  /* Make sure the scheduler doesn't schedule other insns beyond
+	     here.  */
+	  emit_insn (gen_blockage ());
+
+	  /* Walk through all arguments and clear registers appropriately.
+	  */
+	  fntype = TREE_TYPE (MEM_EXPR (address));
+	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
+				    NULL_TREE);
+	  args_so_far = pack_cumulative_args (&args_so_far_v);
+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask &=
+		~compute_not_to_clear_mask (arg_type, arg_rtx,
+					      REGNO (arg_rtx),
+					      padding_bits_to_clear_ptr);
+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = 0; regno < NUM_ARG_REGS; regno++)
+	    {
+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = 0; regno <= maxregno; regno++)
+	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST1_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST1_RTX (SFmode));
+		}
+	      else
+		emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+	    }
+
+	  seq = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (seq, insn);
+
+	}
+    }
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -18150,6 +18341,8 @@ arm_reorg (void)
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
+  if (use_cmse)
+    cmse_nonsecure_call_clear_caller_saved ();
   if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
@@ -18522,6 +18715,23 @@ vfp_emit_fstmd (int base_reg, int count)
   return count * 8;
 }
 
+/* Returns true if -mcmse has been passed and the function pointed to by 'addr'
+   has the cmse_nonsecure_call attribute and returns false otherwise.  */
+
+bool
+detect_cmse_nonsecure_call (tree addr)
+{
+  if (!addr)
+    return FALSE;
+
+  tree fntype = TREE_TYPE (addr);
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_call",
+				    TYPE_ATTRIBUTES (fntype)))
+    return TRUE;
+  return FALSE;
+}
+
+
 /* Emit a call instruction with pattern PAT.  ADDR is the address of
    the call target.  */
 
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 8393f65bcf4c9c3e61b91e5adcd5f59ff7c6ec3f..3e65a43d39fb20061ee531d58fd21fbbc9cd1bde 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -8024,6 +8024,7 @@
   "
   {
     rtx callee, pat;
+    tree addr = MEM_EXPR (operands[0]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[2] == NULL_RTX)
@@ -8038,8 +8039,17 @@
 	: !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_internal (operands[0], operands[1], operands[2]);
-    arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_internal (operands[0], operands[1],
+					   operands[2]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_internal (operands[0], operands[1], operands[2]);
+	arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+      }
     DONE;
   }"
 )
@@ -8050,6 +8060,24 @@
 	      (use (match_operand 2 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_internal"
+  [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand" "")]
+			       UNSPEC_NONSECURE_MEM)
+		    (match_operand 1 "general_operand" ""))
+	      (use (match_operand 2 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[0] = replace_equiv_address (operands[0], tmp);
+  }")
+
 (define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
@@ -8085,6 +8113,7 @@
   "
   {
     rtx pat, callee;
+    tree addr = MEM_EXPR (operands[1]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
@@ -8099,9 +8128,18 @@
 	: !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_value_internal (operands[0], operands[1],
-				   operands[2], operands[3]);
-    arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_value_internal (operands[0], operands[1],
+						 operands[2], operands[3]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_value_internal (operands[0], operands[1],
+				       operands[2], operands[3]);
+	arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+      }
     DONE;
   }"
 )
@@ -8113,6 +8151,25 @@
 	      (use (match_operand 3 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_value_internal"
+  [(parallel [(set (match_operand       0 "" "")
+		   (call (unspec:SI [(match_operand 1 "memory_operand" "")]
+				    UNSPEC_NONSECURE_MEM)
+			 (match_operand 2 "general_operand" "")))
+	      (use (match_operand 3 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[1] = replace_equiv_address (operands[1], tmp);
+  }")
+
 (define_insn "*call_value_reg_armv5"
   [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 433fc79ae5810a4d3eb45d1ba80872a39e157e14..63a400fbfd8015cbd5a70252e24beacde4a5354d 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1705,6 +1705,19 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb1_v5"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_reg_thumb1"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
 	 (match_operand 1 "" ""))
@@ -1737,6 +1750,21 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb1_v5"
+  [(set (match_operand 0 "" "")
+	(call (unspec:SI
+	       [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+	       UNSPEC_NONSECURE_MEM)
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB1 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb1"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index f5033ef802c085bd0ce479bc7026db96d9e25632..8618dc31b44f2a7f0e3b0cc60fd226859e7545ae 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -580,6 +580,19 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
@@ -591,6 +604,21 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+	(call
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "register_operand" "l*r"))]
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index bee8795f007accc623c82b73c41a8619ebc29209..1aa39e8e0b9ddf17bb535c4d82959e569d3c9fd5 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -84,6 +84,8 @@
   UNSPEC_VRINTA         ; Represent a float to integral float rounding
                         ; towards nearest, ties away from zero.
   UNSPEC_PROBE_STACK    ; Probe stack memory reference
+  UNSPEC_NONSECURE_MEM	; Represent non-secure memory in ARMv8-M with
+			; security extension
 ])
 
 (define_c_enum "unspec" [
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6c1386c06edbdb58e76fa5e612c918010c507f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51ce2d42c051aeda8b06ad97086f2563a5fc47d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e9104b546a7693fcb2399622e828b1197eac1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 1023" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "movt\tr4, 32767" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d8941bbfeebd59744c43f10c842816b36ec9915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ffbb718d34d5bb8f10e1f3c0505c7dc393c670c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a6141829237823b8734de045a590a1917fa60b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #1799" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..642f4e0346b5186c78645780b45fe9c838848d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #7939" } } */
+/* { dg-final { scan-assembler "movt\tr4, 15" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, 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/baseline/cmse-11.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
new file mode 100644
index 0000000000000000000000000000000000000000..3007409ad88b9d2312ece4d55f3695787a1aa566
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+
+int
+foo (int a)
+{
+  return bar (bar (a + 1));
+}
+
+/* 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 "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\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/baseline/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2b931be5912b421f8427535ded3298883bec639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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 "movs\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmovs\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmovs\tr2, r4\n\tmovs\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/baseline/cmse-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..95da045690ae170a101949134482e821f27fe3aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* Remember dont clear r0 and r1, because we are passing the double parameter
+ * for bar in them.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, 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/baseline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff18e839b02c19c2c77769b18ef5ee1cfacf0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8063" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2e024b7f0776381f511077af91bd1ee5632ff12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
index 1d97f0e1a37209bd129ffe96ce92a86bc2e0d5d1..9e81e30c891bbc1f9d2d1d68d03bacad9ce65fe1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -2,11 +2,19 @@
 /* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
 
 
+void __attribute__ ((cmse_nonsecure_call)) (*bar) (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+typedef void __attribute__ ((cmse_nonsecure_call)) baz (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+
 int __attribute__ ((cmse_nonsecure_entry))
-foo (int a)
+foo (int a, baz b)
 { /* { dg-warning "attribute ignored without -mcmse option" } */
+  bar (a);
+  b (a);
   return a + 1;
 }
 
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler-not "blxns" } } */
+/* { dg-final { scan-assembler-not "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 38f18414c2fefec56161e6ac3f7291b03a3b29a3..66a8b7da005f7dfeffbded61b02fd6a7473a1dcf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -50,6 +50,8 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
+	    "" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
 	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b1396d52e742a1710ed5ad33fbeb559d866f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d029044aa9aa1d412c28ee5d18a8e3d0be36546
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..005515ab9cb85c201a2a8b2f6417d73ceeacbc60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dd218e62fdee2a6af819079ba1ea1909185d076
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { 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/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..c833bcb0ae978572fad46780bc180f61ccb14345
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cdb8c44b19c811f3a7b4fbce102a6c768f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e139ba61af57f06cff5a9d121c97bbf41e170bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { 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/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..285fa854b3d61c4d856e9be863ee73a87f1b11a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f56aaf2a97e740a77473cab245614b6fa696c04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..749f8a7278cb4ea9fd4462887ce7f37b57f83248
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad5068aac263f1c2edb17b8707fc9d1c0af6959
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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\.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/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..b18259eaef6da1933ef2d58d63b97d4bb4e450f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..182ddf9540374f30ae3694259f1edb62161455e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd262c89085eb0dc8737ad7955c3a12531492b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..e33568400ef830abaa019b5c2727a9f3b5d5704b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..024a12e0a414730eb1cbebfca8574d548238ab28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb195eb58d59fe9ea5ed74af79646199c61bcdae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..22ed3f8af882f96da49919c60fc6f4cd74dfc54b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634065e7cb64a5069cbb3c9be4b8cf9177f5e29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..04f8466cc112c03ee5a05e6e5223d2c66a033bbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffe94de85417b81f9dcb366eb1b40dc1661c91b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc846cd7a51303ec00f8f512a54cd697fbd0682
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d0f136ef171111c1cca6cd24c4f46b9fcb7fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/libgcc/config/arm/cmse_nonsecure_call.S b/libgcc/config/arm/cmse_nonsecure_call.S
new file mode 100644
index 0000000000000000000000000000000000000000..12685b1fac5fd73d74b8249076026fde8a5841b8
--- /dev/null
+++ b/libgcc/config/arm/cmse_nonsecure_call.S
@@ -0,0 +1,136 @@
+/* CMSE wrapper function used to save, clear and restore callee saved registers
+   for cmse_nonsecure_call's.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+.syntax unified
+.thumb
+.global __gnu_cmse_nonsecure_call
+__gnu_cmse_nonsecure_call:
+#if defined(__ARM_ARCH_8M_MAIN__)
+push	    {r5-r11,lr}
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+
+/* Save and clear callee-saved registers only if we are dealing with hard float
+   ABI.  The unused caller-saved registers have already been cleared by GCC
+   generated code.  */
+#ifdef __ARM_PCS_VFP
+vpush.f64   {d8-d15}
+#if __ARM_FP & 0x04
+mov	    r5, #0
+mov	    r6, #0
+vmov	    s16, s17, r5, r6
+vmov	    s18, s19, r5, r6
+vmov	    s20, s21, r5, r6
+vmov	    s22, s23, r5, r6
+vmov	    s24, s25, r5, r6
+vmov	    s26, s27, r5, r6
+vmov	    s28, s29, r5, r6
+vmov	    s30, s31, r5, r6
+#elif __ARM_FP & 0x08
+vmov.f64    d8, #0.00000
+vmov.f64    d9, #0.00000
+vmov.f64    d10, #0.00000
+vmov.f64    d11, #0.00000
+vmov.f64    d12, #0.00000
+vmov.f64    d13, #0.00000
+vmov.f64    d14, #0.00000
+vmov.f64    d15, #0.00000
+#else
+#error "Half precision implementation not supported."
+#endif
+/* Clear the cumulative exception-status bits (0-4,7) and the
+   condition code bits (28-31) of the FPSCR.  */
+vmrs	    r5, fpscr
+movw	    r6, #65376
+movt	    r6, #4095
+ands	    r5, r6
+vmsr	    fpscr, r5
+
+/* We are not dealing with hard float ABI, so we can safely use the vlstm and
+   vlldm instructions without needing to preserve the registers used for
+   argument passing.  */
+#else
+sub	    sp, sp, #0x88 /* Reserve stack space to save all floating point
+			     registers, including FPSCR.  */
+vlstm	    sp		  /* Lazy store and clearance of d0-d16 and FPSCR.  */
+#endif /* __ARM_PCS_VFP */
+
+/* Make sure to clear the 'GE' bits of the APSR register if 32-bit SIMD
+   instructions are available.  */
+#if defined(__ARM_FEATURE_SIMD32)
+msr	    APSR_nzcvqg, r4
+#else
+msr	    APSR_nzcvq, r4
+#endif
+
+mov	    r5, r4
+mov	    r6, r4
+blxns	    r4
+
+#ifdef __ARM_PCS_VFP
+vpop.f64    {d8-d15}
+#else
+vlldm	    sp		  /* Lazy restore of d0-d16 and FPSCR.  */
+add	    sp, sp, #0x88 /* Free space used to save floating point registers.  */
+#endif /* __ARM_PCS_VFP */
+
+pop	    {r5-r11}
+
+#elif defined (__ARM_ARCH_8M_BASE__)
+push	    {r5-r7}
+mov	    r5, r8
+mov	    r6, r9
+mov	    r7, r10
+push	    {r5-r7}
+mov	    r5, r11
+mov	    r6, lr
+push	    {r5,r6}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+msr	    APSR_nzcvq, r4
+blxns	    r4
+pop	    {r5, r6}
+mov	    lr, r6
+mov	    r11, r5
+pop	    {r5-r7}
+mov	    r10, r7
+mov	    r9, r6
+mov	    r8, r5
+pop	    {r5-r7}
+blx	    lr
+
+#else
+#error "This should only be used for armv8-m base- and mainline."
+#endif
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 5618143bfd0f02b170db3f9e4c0a15cecb403cec..9e85ac06b146feaa14ab83374a0156737b870310 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -12,4 +12,6 @@ libgcc-objects += cmse.o cmse_nonsecure_call.o
 
 cmse.o: $(srcdir)/config/arm/cmse.c
 	$(gcc_compile) -c $(CMSE_OPTS) $<
+cmse_nonsecure_call.o: $(srcdir)/config/arm/cmse_nonsecure_call.S
+		       $(gcc_compile) -c $<
 endif

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

* Re: [PATCHv2 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics
  2016-10-27  9:54           ` Andre Vieira (lists)
@ 2016-10-27 10:01             ` Kyrill Tkachov
  2016-12-05 11:27               ` [arm-embedded][committed][PATCH 1/7] " Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-27 10:01 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 27/10/16 10:53, Andre Vieira (lists) wrote:
> On 26/10/16 14:00, Kyrill Tkachov wrote:
>> On 26/10/16 10:12, Kyrill Tkachov wrote:
>>> Hi Andre, thanks for resending them.
>>>
>>> On 25/10/16 17:26, Andre Vieira (lists) wrote:
>>>> On 24/08/16 12:00, Andre Vieira (lists) wrote:
>>>>> On 25/07/16 14:19, Andre Vieira (lists) wrote:
>>>>>> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
>>>>>> Security Extensions and supports the following intrinsics:
>>>>>> cmse_TT
>>>>>> cmse_TT_fptr
>>>>>> cmse_TTT
>>>>>> cmse_TTT_fptr
>>>>>> cmse_TTA
>>>>>> cmse_TTA_fptr
>>>>>> cmse_TTAT
>>>>>> cmse_TTAT_fptr
>>>>>> cmse_check_address_range
>>>>>> cmse_check_pointed_object
>>>>>> cmse_is_nsfptr
>>>>>> cmse_nsfptr_create
>>>>>>
>>>>>> It also defines the mandatory cmse_address_info struct and the
>>>>>> __ARM_FEATURE_CMSE macro.
>>>>>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>>>>>> Extensions: Requirements on Development Tools
>>>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>>>
>>>>>>
>>>>>> *** gcc/ChangeLog ***
>>>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>>
>>>>>>           * config.gcc (extra_headers): Added arm_cmse.h.
>>>>>>           * config/arm/arm-arches.def (ARM_ARCH):
>>>>>>           (armv8-m): Add FL2_CMSE.
>>>>>>           (armv8-m.main): Likewise.
>>>>>>           (armv8-m.main+dsp): Likewise.
>>>>>>           * config/arm/arm-c.c
>>>>>>           (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>>>>>           * config/arm/arm-protos.h
>>>>>>           (arm_is_constant_pool_ref): Define FL2_CMSE.
>>>>>>           * config/arm.c (arm_arch_cmse): New.
>>>>>>           (arm_option_override): New error for unsupported cmse target.
>>>>>>           * config/arm/arm.h (arm_arch_cmse): New.
>>>>>>           * config/arm/arm.opt (mcmse): New.
>>>>>>           * doc/invoke.texi (ARM Options): Add -mcmse.
>>>>>>           * config/arm/arm_cmse.h: New file.
>>>>>>
>>>>>> *** libgcc/ChangeLog ***
>>>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>>
>>>>>>           * config/arm/cmse.c: Likewise.
>>>>>>           * config/arm/t-arm (HAVE_CMSE): New.
>>>>>>
>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>>
>>>>>>           * gcc.target/arm/cmse/cmse.exp: New.
>>>>>>           * gcc.target/arm/cmse/cmse-1.c: New.
>>>>>>           * gcc.target/arm/cmse/cmse-12.c: New.
>>>>>>           * lib/target-supports.exp
>>>>>>           (check_effective_target_arm_cmse_ok): New.
>>
>> Just remembered, new effective target checks should be documented in
>> sourcebuild.texi
>> Kyrill
>>
>>>>> Added more documentation as requested.
>>>>>
>>>>> This patch adds the support of the '-mcmse' option to enable ARMv8-M's
>>>>> Security Extensions and supports the following intrinsics:
>>>>> cmse_TT
>>>>> cmse_TT_fptr
>>>>> cmse_TTT
>>>>> cmse_TTT_fptr
>>>>> cmse_TTA
>>>>> cmse_TTA_fptr
>>>>> cmse_TTAT
>>>>> cmse_TTAT_fptr
>>>>> cmse_check_address_range
>>>>> cmse_check_pointed_object
>>>>> cmse_is_nsfptr
>>>>> cmse_nsfptr_create
>>>>>
>>>>> It also defines the mandatory cmse_address_info struct and the
>>>>> __ARM_FEATURE_CMSE macro.
>>>>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>>>>> Extensions: Requirements on Development Tools
>>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>>
>>>>>
>>>>> *** gcc/ChangeLog ***
>>>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>
>>>>>           * config.gcc (extra_headers): Added arm_cmse.h.
>>>>>           * config/arm/arm-arches.def (ARM_ARCH):
>>>>>           (armv8-m): Add FL2_CMSE.
>>>>>           (armv8-m.main): Likewise.
>>>>>           (armv8-m.main+dsp): Likewise.
>>>>>           * config/arm/arm-c.c
>>>>>           (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>>>>           * config/arm/arm-protos.h
>>>>>           (arm_is_constant_pool_ref): Define FL2_CMSE.
>>>>>           * config/arm.c (arm_arch_cmse): New.
>>>>>           (arm_option_override): New error for unsupported cmse target.
>>>>>           * config/arm/arm.h (arm_arch_cmse): New.
>>>>>           * config/arm/arm.opt (mcmse): New.
>>>>>           * doc/invoke.texi (ARM Options): Add -mcmse.
>>>>>           * doc/extend.texi (ARM ARMv8-M Security Extensions): Add
>>>>> section.
>>>>>           * config/arm/arm_cmse.h: New file.
>>>>>
>>>>> *** libgcc/ChangeLog ***
>>>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>           * config/arm/cmse.c: Likewise.
>>>>>           * config/arm/t-arm (HAVE_CMSE): New.
>>>>>
>>>>>
>>>>> *** gcc/testsuite/ChangeLog ***
>>>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>
>>>>>           * gcc.target/arm/cmse/cmse.exp: New.
>>>>>           * gcc.target/arm/cmse/cmse-1.c: New.
>>>>>           * gcc.target/arm/cmse/cmse-12.c: New.
>>>>>           * lib/target-supports.exp
>>>>>           (check_effective_target_arm_cmse_ok): New.
>>>>>
>>>> Hi,
>>>>
>>>> Rebased previous patch on top of trunk as requested. No changes to
>>>> ChangeLog.
>>>>
>>>> Cheers,
>>>> Andre
>>> diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
>>> new file mode 100644
>>> index
>>> 0000000000000000000000000000000000000000..b4232937c6ae04754a6bbc513b143672a4be5530
>>>
>>> --- /dev/null
>>> +++ b/gcc/config/arm/arm_cmse.h
>>>
>>> <snip>
>>>
>>> +
>>> +#if __ARM_FEATURE_CMSE & 2
>>> +
>>> +#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
>>> +
>>> +__extension__ static __inline __attribute__ ((__always_inline__))
>>> +cmse_address_info_t
>>> +__cmse_TTA_fptr (__cmse_fptr __p)
>>> +__CMSE_TT_ASM (a)
>>> +
>>> +__extension__ static __inline __attribute__ ((__always_inline__))
>>> +cmse_address_info_t
>>> +cmse_TTA (void *__p)
>>> +__CMSE_TT_ASM (a)
>>> +
>>> +#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
>>> +
>>> +__extension__ static __inline cmse_address_info_t
>>> +__attribute__ ((__always_inline__))
>>> +__cmse_TTAT_fptr (__cmse_fptr __p)
>>> +__CMSE_TT_ASM (at)
>>> +
>>> +__extension__ static __inline cmse_address_info_t
>>> +__attribute__ ((__always_inline__))
>>> +cmse_TTAT (void *__p)
>>> +__CMSE_TT_ASM (at)
>>> +
>>> +#define CMSE_AU_NONSECURE    2
>>> +#define CMSE_MPU_NONSECURE    16
>>> +#define CMSE_NONSECURE        18
>>> +
>>> +#endif /* __ARM_FEATURE_CMSE & 2 */
>>> +
>>> +#define CMSE_MPU_UNPRIV        4
>>> +#define CMSE_MPU_READWRITE    1
>>> +#define CMSE_MPU_READ        8
>>> +
>>> +__extension__ void *
>>> +cmse_check_address_range (void *, size_t, int);
>>> +
>>> +#define cmse_check_pointed_object(p, f) \
>>> +  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
>>> +
>>> +#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
>>> +
>>> +#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
>>> +
>>> +#endif /* __ARM_FEATURE_CMSE & 1 */
>>>
>>>  From my reading of the spec
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf)
>>>
>>> cmse_nsfptr_create and cmse_is_nsfptr should be defined if bit 1 of
>>> __ARM_FEATURE_CMSE is set.
>>> But in your patch they fall under the "#if __ARM_FEATURE_CMSE & 1"
>>> check which checks bit 0.
>>> They should be in the "__ARM_FEATURE_CMSE & 2" block. Please double
>>> check the other defines against the SPEC to make sure they
>>> match the feature bit in __ARM_FEATURE_CMSE.
>>>
>>> The patch is ok with that resolved if bootstrap and test on a normal
>>> arm-none-linux-gnueabihf configuration
>>> shows no problems.
>>> Thanks,
>>> Kyrill
>>>
> Hi,
>
> Reworked comments.
>
> Is this OK?

Yes, thanks.
Please hold off committing until the whole series is approved.
Kyrill

> Cheers,
> Andre
>
> *** gcc/ChangeLog ***
> 2016-10-27  Andre Vieira <andre.simoesdiasvieira@arm.com>
>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>           * config.gcc (extra_headers): Added arm_cmse.h.
>           * config/arm/arm-arches.def (ARM_ARCH):
>           (armv8-m): Add FL2_CMSE.
>           (armv8-m.main): Likewise.
>           (armv8-m.main+dsp): Likewise.
>           * config/arm/arm-c.c
>           (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>           * config/arm/arm-protos.h
>           (arm_is_constant_pool_ref): Define FL2_CMSE.
>           * config/arm.c (arm_arch_cmse): New.
>           (arm_option_override): New error for unsupported cmse target.
>           * config/arm/arm.h (arm_arch_cmse): New.
>           * config/arm/arm.opt (mcmse): New.
>           * doc/invoke.texi (ARM Options): Add -mcmse.
>           * config/arm/arm_cmse.h: New file.
>           * doc/sourcebuild.texi (arm_cmse_ok): Add new effective target.
>
> *** libgcc/ChangeLog ***
> 2016-10-27  Andre Vieira <andre.simoesdiasvieira@arm.com>
>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>           * config/arm/cmse.c: Likewise.
>           * config/arm/t-arm (HAVE_CMSE): New.
>
> *** gcc/testsuite/ChangeLog ***
> 2016-10-27  Andre Vieira <andre.simoesdiasvieira@arm.com>
>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>
>           * gcc.target/arm/cmse/cmse.exp: New.
>           * gcc.target/arm/cmse/cmse-1.c: New.
>           * gcc.target/arm/cmse/cmse-12.c: New.
>           * lib/target-supports.exp
>           (check_effective_target_arm_cmse_ok): New.
>

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

* Re: [PATCHv2 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
  2016-10-27  9:54             ` Andre Vieira (lists)
@ 2016-10-27 10:19               ` Kyrill Tkachov
  2016-12-05 11:31                 ` [arm-embedded][committed][PATCH 2/7] " Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-27 10:19 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 27/10/16 10:54, Andre Vieira (lists) wrote:
> On 26/10/16 17:28, Kyrill Tkachov wrote:
>> On 26/10/16 17:28, Andre Vieira (lists) wrote:
>>> On 26/10/16 10:33, Kyrill Tkachov wrote:
>>>> +static tree
>>>> +arm_handle_cmse_nonsecure_entry (tree *node, tree name,
>>>> +                 tree /* args */,
>>>> +                 int /* flags */,
>>>> +                 bool *no_add_attrs)
>>>> +{
>>>> +  tree fndecl;
>>>> +
>>>> +  if (!use_cmse)
>>>> +    {
>>>> +      *no_add_attrs = true;
>>>> +      return NULL_TREE;
>>>> +    }
>>>>
>>>> Do you also want to warn the user here that the attribute will be
>>>> ignored?
>>>> This looks ok to me otherwise.
>>>>
>>> Can easily do and might be more user friendly. How about
>>> "<attribute_name> attribute ignored without -mcmse option."
>> Yes, that's fine (without the full stop at the end)
>> Kyrill
>>
>>> Cheers,
>>> Andre
>>>
> Hi,
>
> Reworked comments. No change to ChangeLogs.

Ok.
Thanks,
Kyrill

> Cheers,
> Andre

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-10-27 10:00             ` Andre Vieira (lists)
@ 2016-10-27 10:44               ` Kyrill Tkachov
  2016-10-28 16:08                 ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-10-27 10:44 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 27/10/16 11:00, Andre Vieira (lists) wrote:
> On 26/10/16 17:30, Kyrill Tkachov wrote:
>> On 26/10/16 17:26, Andre Vieira (lists) wrote:
>>> On 26/10/16 13:51, Kyrill Tkachov wrote:
>>>> Hi Andre,
>>>>
>>>> On 25/10/16 17:29, Andre Vieira (lists) wrote:
>>>>> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>>>>>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>>>>> information through unbanked registers.
>>>>>>>
>>>>>>> When returning from a nonsecure entry function we clear all
>>>>>>> caller-saved
>>>>>>> registers that are not used to pass return values, by writing either
>>>>>>> the
>>>>>>> LR, in case of general purpose registers, or the value 0, in case
>>>>>>> of FP
>>>>>>> registers. We use the LR to write to APSR and FPSCR too. We
>>>>>>> currently do
>>>>>>> not support entry functions that pass arguments or return
>>>>>>> variables on
>>>>>>> the stack and we diagnose this. This patch relies on the existing
>>>>>>> code
>>>>>>> to make sure callee-saved registers used in cmse_nonsecure_entry
>>>>>>> functions are saved and restored thus retaining their nonsecure mode
>>>>>>> value, this should be happening already as it is required by AAPCS.
>>>>>>>
>>>>>>> This patch also clears padding bits for cmse_nonsecure_entry
>>>>>>> functions
>>>>>>> with struct and union return types. For unions a bit is only
>>>>>>> considered
>>>>>>> a padding bit if it is an unused bit in every field of that union.
>>>>>>> The
>>>>>>> function that calculates these is used in a later patch to do the
>>>>>>> same
>>>>>>> for arguments of cmse_nonsecure_call's.
>>>>>>>
>>>>>>> *** gcc/ChangeLog ***
>>>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>                Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>
>>>>>>>            * config/arm/arm.c (output_return_instruction): Clear
>>>>>>>            registers.
>>>>>>>            (thumb2_expand_return): Likewise.
>>>>>>>            (thumb1_expand_epilogue): Likewise.
>>>>>>>            (thumb_exit): Likewise.
>>>>>>>            (arm_expand_epilogue): Likewise.
>>>>>>>            (cmse_nonsecure_entry_clear_before_return): New.
>>>>>>>            (comp_not_to_clear_mask_str_un): New.
>>>>>>>            (compute_not_to_clear_mask): New.
>>>>>>>            * config/arm/thumb1.md (*epilogue_insns): Change length
>>>>>>> attribute.
>>>>>>>            * config/arm/thumb2.md (*thumb2_return): Likewise.
>>>>>>>
>>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>                Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>
>>>>>>>            * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>>>>> separate.
>>>>>>>            * gcc.target/arm/cmse/struct-1.c: New.
>>>>>>>            * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>>>>            * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>>>>            * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>>>>            * gcc.target/arm/cmse/baseline/cmse-2.c: Test that
>>>>>>> registers are
>>>>>>> cleared.
>>>>>>>            * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>>>>            * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>>>>            * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>>>>            * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>>>>            * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>>>>
>>>>>> Updated this patch to correctly clear only the cumulative
>>>>>> exception-status (0-4,7) and the condition code bits (28-31) of the
>>>>>> FPSCR. I also adapted the code to be handle the bigger floating point
>>>>>> register files.
>>>>>>
>>>>>> ----
>>>>>>
>>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>>>> information through unbanked registers.
>>>>>>
>>>>>> When returning from a nonsecure entry function we clear all
>>>>>> caller-saved
>>>>>> registers that are not used to pass return values, by writing
>>>>>> either the
>>>>>> LR, in case of general purpose registers, or the value 0, in case
>>>>>> of FP
>>>>>> registers. We use the LR to write to APSR. For FPSCR we clear only the
>>>>>> cumulative exception-status (0-4, 7) and the condition code bits
>>>>>> (28-31). We currently do not support entry functions that pass
>>>>>> arguments
>>>>>> or return variables on the stack and we diagnose this. This patch
>>>>>> relies
>>>>>> on the existing code to make sure callee-saved registers used in
>>>>>> cmse_nonsecure_entry functions are saved and restored thus retaining
>>>>>> their nonsecure mode value, this should be happening already as it is
>>>>>> required by AAPCS.
>>>>>>
>>>>>> This patch also clears padding bits for cmse_nonsecure_entry functions
>>>>>> with struct and union return types. For unions a bit is only
>>>>>> considered
>>>>>> a padding bit if it is an unused bit in every field of that union. The
>>>>>> function that calculates these is used in a later patch to do the same
>>>>>> for arguments of cmse_nonsecure_call's.
>>>>>>
>>>>>> *** gcc/ChangeLog ***
>>>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>                Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>
>>>>>>            * config/arm/arm.c (output_return_instruction): Clear
>>>>>>            registers.
>>>>>>            (thumb2_expand_return): Likewise.
>>>>>>            (thumb1_expand_epilogue): Likewise.
>>>>>>            (thumb_exit): Likewise.
>>>>>>            (arm_expand_epilogue): Likewise.
>>>>>>            (cmse_nonsecure_entry_clear_before_return): New.
>>>>>>            (comp_not_to_clear_mask_str_un): New.
>>>>>>            (compute_not_to_clear_mask): New.
>>>>>>            * config/arm/thumb1.md (*epilogue_insns): Change length
>>>>>> attribute.
>>>>>>            * config/arm/thumb2.md (*thumb2_return): Duplicate
>>>>>> pattern for
>>>>>>            cmse_nonsecure_entry functions.
>>>>>>
>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>                Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>
>>>>>>            * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>>>> separate.
>>>>>>            * gcc.target/arm/cmse/struct-1.c: New.
>>>>>>            * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>>>            * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>>>            * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>>>            * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers
>>>>>> are
>>>>>> cleared.
>>>>>>            * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>>>            * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>>>            * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>>>            * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>>>            * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>>>
>>>>> Hi,
>>>>>
>>>>> Rebased previous patch on top of trunk as requested. No changes to
>>>>> ChangeLog.
>>>>>
>>>>> Cheers,
>>>>> Andre
>>>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>>> index
>>>> bb81e5662e81a26c7d3ccf9f749e8e356e6de35e..c6260323ecfd2f2842e6a5aab06b67da16619c73
>>>>
>>>> 100644
>>>> --- a/gcc/config/arm/arm.c
>>>> +++ b/gcc/config/arm/arm.c
>>>> @@ -17496,6 +17496,279 @@ note_invalid_constants (rtx_insn *insn,
>>>> HOST_WIDE_INT address, int do_pushes)
>>>>      return;
>>>>    }
>>>>    +/* This function computes the clear mask and PADDING_BITS_TO_CLEAR
>>>> for
>>>> structs
>>>> +   and unions in the context of ARMv8-M Security Extensions.  It is
>>>> used as a
>>>> +   helper function for both 'cmse_nonsecure_call' and
>>>> 'cmse_nonsecure_entry'
>>>> +   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to
>>>> either one
>>>> +   or four masks, depending on whether it is being computed for a
>>>> +   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call'
>>>> argument
>>>> +   respectively.  The tree for the type of the argument or a field
>>>> within an
>>>> +   argument is passed in ARG_TYPE, the current register this argument
>>>> or field
>>>> +   starts in is kept in the pointer REGNO and updated accordingly, the
>>>> bit this
>>>> +   argument or field starts at is passed in STARTING_BIT and the last
>>>> used bit
>>>> +   is kept in LAST_USED_BIT which is also updated accordingly.  */
>>>> +
>>>> +static unsigned HOST_WIDE_INT
>>>> +comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
>>>> +                   uint32_t * padding_bits_to_clear,
>>>> +                   unsigned starting_bit, int * last_used_bit)
>>>> +
>>>> +{
>>>> +  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
>>>> +
>>>> +  if (TREE_CODE (arg_type) == RECORD_TYPE)
>>>> +    {
>>>> +      unsigned current_bit = starting_bit;
>>>> +      tree field;
>>>> +      long int offset, size;
>>>> +
>>>> +
>>>> +      field = TYPE_FIELDS (arg_type);
>>>> +      while (field)
>>>> +    {
>>>> +      /* The offset within a structure is always an offset from
>>>> +         the start of that structure.  Make sure we take that into the
>>>> +         calculation of the register based offset that we use here.  */
>>>> +      offset = starting_bit;
>>>> +      offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
>>>> +      offset %= 32;
>>>> +
>>>> +      /* This is the actual size of the field, for bitfields this is
>>>> the
>>>> +         bitfield width and not the container size.  */
>>>> +      size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>>>> +
>>>> +      if (*last_used_bit != offset)
>>>> +        {
>>>> +          if (offset < *last_used_bit)
>>>> +        {
>>>> +          /* This field's offset is before the 'last_used_bit', that
>>>> +             means this field goes on the next register.  So we need to
>>>> +             pad the rest of the current register and increase the
>>>> +             register number.  */
>>>> +          uint32_t mask;
>>>> +          mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
>>>> +          mask++;
>>>> +
>>>> +          *(padding_bits_to_clear + *regno) |= mask;
>>>>
>>>> padding_bits_to_clear[*regno] |= mask;
>>>>
>>>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>>> +          (*regno)++;
>>>> +        }
>>>> +          else
>>>> +        {
>>>> +          /* Otherwise we pad the bits between the last field's end and
>>>> +             the start of the new field.  */
>>>> +          uint32_t mask;
>>>> +
>>>> +          mask = UINT32_MAX >> (32 - offset);
>>>> +          mask -= ((uint32_t) 1 << *last_used_bit) - 1;
>>>> +          *(padding_bits_to_clear + *regno) |= mask;
>>>>
>>>> Likewise.
>>>>
>>>> +        }
>>>> +          current_bit = offset;
>>>> +        }
>>>> +
>>>> +      /* Calculate further padding bits for inner structs/unions
>>>> too.  */
>>>> +      if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
>>>> +        {
>>>> +          *last_used_bit = current_bit;
>>>> +          not_to_clear_reg_mask
>>>> +        |= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
>>>> +                          padding_bits_to_clear, offset,
>>>> +                          last_used_bit);
>>>> +        }
>>>> +      else
>>>> +        {
>>>> +          /* Update 'current_bit' with this field's size.  If the
>>>> +         'current_bit' lies in a subsequent register, update 'regno'
>>>> and
>>>> +         reset 'current_bit' to point to the current bit in that new
>>>> +         register.  */
>>>> +          current_bit += size;
>>>> +          while (current_bit >= 32)
>>>> +        {
>>>> +          current_bit-=32;
>>>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>>> +          (*regno)++;
>>>> +        }
>>>> +          *last_used_bit = current_bit;
>>>> +        }
>>>> +
>>>> +      field = TREE_CHAIN (field);
>>>> +    }
>>>> +      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>>> +    }
>>>> +  else if (TREE_CODE (arg_type) == UNION_TYPE)
>>>> +    {
>>>> +      tree field, field_t;
>>>> +      int i, regno_t, field_size;
>>>> +      int max_reg = -1;
>>>> +      int max_bit = -1;
>>>> +      uint32_t mask;
>>>> +      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
>>>> +    = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
>>>> +
>>>> +      /* To compute the padding bits in a union we only consider
>>>> bits as
>>>> +     padding bits if they are always either a padding bit or fall
>>>> outside a
>>>> +     fields size for all fields in the union.  */
>>>> +      field = TYPE_FIELDS (arg_type);
>>>> +      while (field)
>>>> +    {
>>>> +      uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
>>>> +        = {0U, 0U, 0U, 0U};
>>>> +      int last_used_bit_t = *last_used_bit;
>>>> +      regno_t = *regno;
>>>> +      field_t = TREE_TYPE (field);
>>>> +
>>>> +      /* If the field's type is either a record or a union make sure to
>>>> +         compute their padding bits too.  */
>>>> +      if (RECORD_OR_UNION_TYPE_P (field_t))
>>>> +        not_to_clear_reg_mask
>>>> +          |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
>>>> +                        &padding_bits_to_clear_t[0],
>>>> +                        starting_bit, &last_used_bit_t);
>>>> +      else
>>>> +        {
>>>> +          field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>>>> +          regno_t = (field_size / 32) + *regno;
>>>> +          last_used_bit_t = (starting_bit + field_size) % 32;
>>>> +        }
>>>> +
>>>> +      for (i = *regno; i < regno_t; i++)
>>>> +        {
>>>> +          /* For all but the last register used by this field only keep
>>>> the
>>>> +         padding bits that were padding bits in this field.  */
>>>> +          padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
>>>> +        }
>>>> +
>>>> +        /* For the last register, keep all padding bits that were
>>>> padding
>>>> +           bits in this field and any padding bits that are still valid
>>>> +           as padding bits but fall outside of this field's size.  */
>>>> +        mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
>>>> +        padding_bits_to_clear_res[regno_t]
>>>> +          &= padding_bits_to_clear_t[regno_t] | mask;
>>>> +
>>>> +      /* Update the maximum size of the fields in terms of registers
>>>> used
>>>> +         ('max_reg') and the 'last_used_bit' in said register.  */
>>>> +      if (max_reg < regno_t)
>>>> +        {
>>>> +          max_reg = regno_t;
>>>> +          max_bit = last_used_bit_t;
>>>> +        }
>>>> +      else if (max_reg == regno_t && max_bit < last_used_bit_t)
>>>> +        max_bit = last_used_bit_t;
>>>> +
>>>> +      field = TREE_CHAIN (field);
>>>> +    }
>>>> +
>>>> +      /* Update the current padding_bits_to_clear using the
>>>> intersection of the
>>>> +     padding bits of all the fields.  */
>>>> +      for (i=*regno; i < max_reg; i++)
>>>> +    padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
>>>> +
>>>>
>>>> watch the spacing in the 'for' definition.
>>>>
>>>>    +      /* Do not keep trailing padding bits, we do not know yet
>>>> whether
>>>> this
>>>> +     is the end of the argument.  */
>>>> +      mask = ((uint32_t) 1 << max_bit) - 1;
>>>> +      padding_bits_to_clear[max_reg]
>>>> +    |= padding_bits_to_clear_res[max_reg] & mask;
>>>> +
>>>> +      *regno = max_reg;
>>>> +      *last_used_bit = max_bit;
>>>> +    }
>>>> +  else
>>>> +    /* This function should only be used for structs and unions.  */
>>>> +    gcc_unreachable ();
>>>> +
>>>> +  return not_to_clear_reg_mask;
>>>> +}
>>>> +
>>>> +/* In the context of ARMv8-M Security Extensions, this function is used
>>>> for both
>>>> +   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to
>>>> compute what
>>>> +   registers are used when returning or passing arguments, which is
>>>> then
>>>> +   returned as a mask.  It will also compute a mask to indicate
>>>> padding/unused
>>>> +   bits for each of these registers, and passes this through the
>>>> +   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is
>>>> passed in
>>>> +   ARG_TYPE, the rtl representation of the argument is passed in
>>>> ARG_RTX and
>>>> +   the starting register used to pass this argument or return value is
>>>> passed
>>>> +   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to
>>>> compute these
>>>> +   for struct and union types.  */
>>>> +
>>>> +static unsigned HOST_WIDE_INT
>>>> +compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
>>>> +                 uint32_t * padding_bits_to_clear)
>>>> +
>>>> +{
>>>> +  int last_used_bit = 0;
>>>> +  unsigned HOST_WIDE_INT not_to_clear_mask;
>>>> +
>>>> +  if (RECORD_OR_UNION_TYPE_P (arg_type))
>>>> +    {
>>>> +      not_to_clear_mask
>>>> +    = comp_not_to_clear_mask_str_un (arg_type, &regno,
>>>> +                     padding_bits_to_clear, 0,
>>>> +                     &last_used_bit);
>>>> +
>>>> +
>>>> +      /* If the 'last_used_bit' is not zero, that means we are still
>>>> using a
>>>> +     part of the last 'regno'.  In such cases we must clear the
>>>> trailing
>>>> +     bits.  Otherwise we are not using regno and we should mark it
>>>> as to
>>>> +     clear.  */
>>>> +      if (last_used_bit != 0)
>>>> +    *(padding_bits_to_clear + regno)
>>>> +      |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;
>>>>
>>>> padding_bits_to_clear[regno] |= ...
>>>>
>>>> +      else
>>>> +    not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
>>>> +    }
>>>> +  else
>>>> +    {
>>>> +      not_to_clear_mask = 0;
>>>> +      /* We are not dealing with structs nor unions.  So these
>>>> arguments may be
>>>> +     passed in floating point registers too.  In some cases a
>>>> BLKmode is
>>>> +     used when returning or passing arguments in multiple VFP
>>>> registers.  */
>>>> +      if (GET_MODE (arg_rtx) == BLKmode)
>>>> +    {
>>>> +      int i, arg_regs;
>>>> +      rtx reg;
>>>> +
>>>> +      /* This should really only occur when dealing with the hard-float
>>>> +         ABI.  */
>>>> +      gcc_assert (TARGET_HARD_FLOAT_ABI);
>>>> +
>>>> +      for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
>>>> +        {
>>>> +          reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
>>>> +          gcc_assert (REG_P (reg));
>>>> +
>>>> +          not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
>>>> +
>>>> +          /* If we are dealing with DF mode, make sure we don't
>>>> +         clear either of the registers it addresses.  */
>>>> +          arg_regs = ARM_NUM_REGS (GET_MODE (reg));
>>>>
>>>> Better assert here that you're indeed dealing with DFmode and/or you
>>>> have 2 registers.
>>>>
>>> The current code actually works for larger modes too. I don't think code
>>> will ever be generated with larger types, but why assert if it works
>>> anyway?
>> ok, no need to assert here then.
>> I suppose it doesn't add much if the code handles the other modes fine.
>>
>> Kyrill
>>
> Hi,
>
> Reworked comments. No change to ChangeLogs.
>
> Cheers,
> Andre


+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check TARGET_HARD_FLOAT to make sure these are
+     present.  */
+  if (TARGET_HARD_FLOAT)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      maxregno = LAST_VFP_REGNUM;
+
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask[0] |= float_mask;
+
+      float_mask = (1ULL << (maxregno - 63)) - 1;
+      to_clear_mask[1] = float_mask;
+
+      /* Make sure we dont clear the two scratch registers used to clear the
+	 relevant FPSCR bits in output_return_instruction.  We have only
+	 implemented the clearing of FP registers for Thumb-2, so we assert
+	 here that VFP was not enabled for Thumb-1 ARMv8-M targets.  */
+      gcc_assert (arm_arch_thumb2);

I see this assert triggering when running the testsuite cmse.exp with /-march=armv8-m.base/-mfloat-abi=softfp/-mfpu=fpv5-d16
from a toolchain configured with "--with-cpu=cortex-a15 --with-float=hard --with-mode=thumb --with-fpu=neon-vfpv4".
I think some more validation needs to happen to reject the attributes for invalid configurations.

Kyrill



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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-10-27 10:44               ` Kyrill Tkachov
@ 2016-10-28 16:08                 ` Andre Vieira (lists)
  2016-11-08 12:16                   ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-10-28 16:08 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches

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

On 27/10/16 11:44, Kyrill Tkachov wrote:
> 
> On 27/10/16 11:00, Andre Vieira (lists) wrote:
>> On 26/10/16 17:30, Kyrill Tkachov wrote:
>>> On 26/10/16 17:26, Andre Vieira (lists) wrote:
>>>> On 26/10/16 13:51, Kyrill Tkachov wrote:
>>>>> Hi Andre,
>>>>>
>>>>> On 25/10/16 17:29, Andre Vieira (lists) wrote:
>>>>>> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>>>>>>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>>>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>>>>>> information through unbanked registers.
>>>>>>>>
>>>>>>>> When returning from a nonsecure entry function we clear all
>>>>>>>> caller-saved
>>>>>>>> registers that are not used to pass return values, by writing
>>>>>>>> either
>>>>>>>> the
>>>>>>>> LR, in case of general purpose registers, or the value 0, in case
>>>>>>>> of FP
>>>>>>>> registers. We use the LR to write to APSR and FPSCR too. We
>>>>>>>> currently do
>>>>>>>> not support entry functions that pass arguments or return
>>>>>>>> variables on
>>>>>>>> the stack and we diagnose this. This patch relies on the existing
>>>>>>>> code
>>>>>>>> to make sure callee-saved registers used in cmse_nonsecure_entry
>>>>>>>> functions are saved and restored thus retaining their nonsecure
>>>>>>>> mode
>>>>>>>> value, this should be happening already as it is required by AAPCS.
>>>>>>>>
>>>>>>>> This patch also clears padding bits for cmse_nonsecure_entry
>>>>>>>> functions
>>>>>>>> with struct and union return types. For unions a bit is only
>>>>>>>> considered
>>>>>>>> a padding bit if it is an unused bit in every field of that union.
>>>>>>>> The
>>>>>>>> function that calculates these is used in a later patch to do the
>>>>>>>> same
>>>>>>>> for arguments of cmse_nonsecure_call's.
>>>>>>>>
>>>>>>>> *** gcc/ChangeLog ***
>>>>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>>                Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>>
>>>>>>>>            * config/arm/arm.c (output_return_instruction): Clear
>>>>>>>>            registers.
>>>>>>>>            (thumb2_expand_return): Likewise.
>>>>>>>>            (thumb1_expand_epilogue): Likewise.
>>>>>>>>            (thumb_exit): Likewise.
>>>>>>>>            (arm_expand_epilogue): Likewise.
>>>>>>>>            (cmse_nonsecure_entry_clear_before_return): New.
>>>>>>>>            (comp_not_to_clear_mask_str_un): New.
>>>>>>>>            (compute_not_to_clear_mask): New.
>>>>>>>>            * config/arm/thumb1.md (*epilogue_insns): Change length
>>>>>>>> attribute.
>>>>>>>>            * config/arm/thumb2.md (*thumb2_return): Likewise.
>>>>>>>>
>>>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>>                Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>>
>>>>>>>>            * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>>>>>> separate.
>>>>>>>>            * gcc.target/arm/cmse/struct-1.c: New.
>>>>>>>>            * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>>>>>            * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>>>>>            * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>>>>>            * gcc.target/arm/cmse/baseline/cmse-2.c: Test that
>>>>>>>> registers are
>>>>>>>> cleared.
>>>>>>>>            * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>>>>>            * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>>>>>            * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>>>>>            * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>>>>>            * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>>>>>
>>>>>>> Updated this patch to correctly clear only the cumulative
>>>>>>> exception-status (0-4,7) and the condition code bits (28-31) of the
>>>>>>> FPSCR. I also adapted the code to be handle the bigger floating
>>>>>>> point
>>>>>>> register files.
>>>>>>>
>>>>>>> ----
>>>>>>>
>>>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>>>>> information through unbanked registers.
>>>>>>>
>>>>>>> When returning from a nonsecure entry function we clear all
>>>>>>> caller-saved
>>>>>>> registers that are not used to pass return values, by writing
>>>>>>> either the
>>>>>>> LR, in case of general purpose registers, or the value 0, in case
>>>>>>> of FP
>>>>>>> registers. We use the LR to write to APSR. For FPSCR we clear
>>>>>>> only the
>>>>>>> cumulative exception-status (0-4, 7) and the condition code bits
>>>>>>> (28-31). We currently do not support entry functions that pass
>>>>>>> arguments
>>>>>>> or return variables on the stack and we diagnose this. This patch
>>>>>>> relies
>>>>>>> on the existing code to make sure callee-saved registers used in
>>>>>>> cmse_nonsecure_entry functions are saved and restored thus retaining
>>>>>>> their nonsecure mode value, this should be happening already as
>>>>>>> it is
>>>>>>> required by AAPCS.
>>>>>>>
>>>>>>> This patch also clears padding bits for cmse_nonsecure_entry
>>>>>>> functions
>>>>>>> with struct and union return types. For unions a bit is only
>>>>>>> considered
>>>>>>> a padding bit if it is an unused bit in every field of that
>>>>>>> union. The
>>>>>>> function that calculates these is used in a later patch to do the
>>>>>>> same
>>>>>>> for arguments of cmse_nonsecure_call's.
>>>>>>>
>>>>>>> *** gcc/ChangeLog ***
>>>>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>                Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>
>>>>>>>            * config/arm/arm.c (output_return_instruction): Clear
>>>>>>>            registers.
>>>>>>>            (thumb2_expand_return): Likewise.
>>>>>>>            (thumb1_expand_epilogue): Likewise.
>>>>>>>            (thumb_exit): Likewise.
>>>>>>>            (arm_expand_epilogue): Likewise.
>>>>>>>            (cmse_nonsecure_entry_clear_before_return): New.
>>>>>>>            (comp_not_to_clear_mask_str_un): New.
>>>>>>>            (compute_not_to_clear_mask): New.
>>>>>>>            * config/arm/thumb1.md (*epilogue_insns): Change length
>>>>>>> attribute.
>>>>>>>            * config/arm/thumb2.md (*thumb2_return): Duplicate
>>>>>>> pattern for
>>>>>>>            cmse_nonsecure_entry functions.
>>>>>>>
>>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>                Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>
>>>>>>>            * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>>>>> separate.
>>>>>>>            * gcc.target/arm/cmse/struct-1.c: New.
>>>>>>>            * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>>>>            * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>>>>            * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>>>>            * gcc.target/arm/cmse/baseline/cmse-2.c: Test that
>>>>>>> registers
>>>>>>> are
>>>>>>> cleared.
>>>>>>>            * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>>>>            * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>>>>            * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>>>>            * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>>>>            * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Rebased previous patch on top of trunk as requested. No changes to
>>>>>> ChangeLog.
>>>>>>
>>>>>> Cheers,
>>>>>> Andre
>>>>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>>>> index
>>>>> bb81e5662e81a26c7d3ccf9f749e8e356e6de35e..c6260323ecfd2f2842e6a5aab06b67da16619c73
>>>>>
>>>>>
>>>>> 100644
>>>>> --- a/gcc/config/arm/arm.c
>>>>> +++ b/gcc/config/arm/arm.c
>>>>> @@ -17496,6 +17496,279 @@ note_invalid_constants (rtx_insn *insn,
>>>>> HOST_WIDE_INT address, int do_pushes)
>>>>>      return;
>>>>>    }
>>>>>    +/* This function computes the clear mask and PADDING_BITS_TO_CLEAR
>>>>> for
>>>>> structs
>>>>> +   and unions in the context of ARMv8-M Security Extensions.  It is
>>>>> used as a
>>>>> +   helper function for both 'cmse_nonsecure_call' and
>>>>> 'cmse_nonsecure_entry'
>>>>> +   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to
>>>>> either one
>>>>> +   or four masks, depending on whether it is being computed for a
>>>>> +   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call'
>>>>> argument
>>>>> +   respectively.  The tree for the type of the argument or a field
>>>>> within an
>>>>> +   argument is passed in ARG_TYPE, the current register this argument
>>>>> or field
>>>>> +   starts in is kept in the pointer REGNO and updated accordingly,
>>>>> the
>>>>> bit this
>>>>> +   argument or field starts at is passed in STARTING_BIT and the last
>>>>> used bit
>>>>> +   is kept in LAST_USED_BIT which is also updated accordingly.  */
>>>>> +
>>>>> +static unsigned HOST_WIDE_INT
>>>>> +comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
>>>>> +                   uint32_t * padding_bits_to_clear,
>>>>> +                   unsigned starting_bit, int * last_used_bit)
>>>>> +
>>>>> +{
>>>>> +  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
>>>>> +
>>>>> +  if (TREE_CODE (arg_type) == RECORD_TYPE)
>>>>> +    {
>>>>> +      unsigned current_bit = starting_bit;
>>>>> +      tree field;
>>>>> +      long int offset, size;
>>>>> +
>>>>> +
>>>>> +      field = TYPE_FIELDS (arg_type);
>>>>> +      while (field)
>>>>> +    {
>>>>> +      /* The offset within a structure is always an offset from
>>>>> +         the start of that structure.  Make sure we take that into
>>>>> the
>>>>> +         calculation of the register based offset that we use
>>>>> here.  */
>>>>> +      offset = starting_bit;
>>>>> +      offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
>>>>> +      offset %= 32;
>>>>> +
>>>>> +      /* This is the actual size of the field, for bitfields this is
>>>>> the
>>>>> +         bitfield width and not the container size.  */
>>>>> +      size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>>>>> +
>>>>> +      if (*last_used_bit != offset)
>>>>> +        {
>>>>> +          if (offset < *last_used_bit)
>>>>> +        {
>>>>> +          /* This field's offset is before the 'last_used_bit', that
>>>>> +             means this field goes on the next register.  So we
>>>>> need to
>>>>> +             pad the rest of the current register and increase the
>>>>> +             register number.  */
>>>>> +          uint32_t mask;
>>>>> +          mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
>>>>> +          mask++;
>>>>> +
>>>>> +          *(padding_bits_to_clear + *regno) |= mask;
>>>>>
>>>>> padding_bits_to_clear[*regno] |= mask;
>>>>>
>>>>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>>>> +          (*regno)++;
>>>>> +        }
>>>>> +          else
>>>>> +        {
>>>>> +          /* Otherwise we pad the bits between the last field's
>>>>> end and
>>>>> +             the start of the new field.  */
>>>>> +          uint32_t mask;
>>>>> +
>>>>> +          mask = UINT32_MAX >> (32 - offset);
>>>>> +          mask -= ((uint32_t) 1 << *last_used_bit) - 1;
>>>>> +          *(padding_bits_to_clear + *regno) |= mask;
>>>>>
>>>>> Likewise.
>>>>>
>>>>> +        }
>>>>> +          current_bit = offset;
>>>>> +        }
>>>>> +
>>>>> +      /* Calculate further padding bits for inner structs/unions
>>>>> too.  */
>>>>> +      if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
>>>>> +        {
>>>>> +          *last_used_bit = current_bit;
>>>>> +          not_to_clear_reg_mask
>>>>> +        |= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
>>>>> +                          padding_bits_to_clear, offset,
>>>>> +                          last_used_bit);
>>>>> +        }
>>>>> +      else
>>>>> +        {
>>>>> +          /* Update 'current_bit' with this field's size.  If the
>>>>> +         'current_bit' lies in a subsequent register, update 'regno'
>>>>> and
>>>>> +         reset 'current_bit' to point to the current bit in that new
>>>>> +         register.  */
>>>>> +          current_bit += size;
>>>>> +          while (current_bit >= 32)
>>>>> +        {
>>>>> +          current_bit-=32;
>>>>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>>>> +          (*regno)++;
>>>>> +        }
>>>>> +          *last_used_bit = current_bit;
>>>>> +        }
>>>>> +
>>>>> +      field = TREE_CHAIN (field);
>>>>> +    }
>>>>> +      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>>>> +    }
>>>>> +  else if (TREE_CODE (arg_type) == UNION_TYPE)
>>>>> +    {
>>>>> +      tree field, field_t;
>>>>> +      int i, regno_t, field_size;
>>>>> +      int max_reg = -1;
>>>>> +      int max_bit = -1;
>>>>> +      uint32_t mask;
>>>>> +      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
>>>>> +    = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
>>>>> +
>>>>> +      /* To compute the padding bits in a union we only consider
>>>>> bits as
>>>>> +     padding bits if they are always either a padding bit or fall
>>>>> outside a
>>>>> +     fields size for all fields in the union.  */
>>>>> +      field = TYPE_FIELDS (arg_type);
>>>>> +      while (field)
>>>>> +    {
>>>>> +      uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
>>>>> +        = {0U, 0U, 0U, 0U};
>>>>> +      int last_used_bit_t = *last_used_bit;
>>>>> +      regno_t = *regno;
>>>>> +      field_t = TREE_TYPE (field);
>>>>> +
>>>>> +      /* If the field's type is either a record or a union make
>>>>> sure to
>>>>> +         compute their padding bits too.  */
>>>>> +      if (RECORD_OR_UNION_TYPE_P (field_t))
>>>>> +        not_to_clear_reg_mask
>>>>> +          |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
>>>>> +                        &padding_bits_to_clear_t[0],
>>>>> +                        starting_bit, &last_used_bit_t);
>>>>> +      else
>>>>> +        {
>>>>> +          field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>>>>> +          regno_t = (field_size / 32) + *regno;
>>>>> +          last_used_bit_t = (starting_bit + field_size) % 32;
>>>>> +        }
>>>>> +
>>>>> +      for (i = *regno; i < regno_t; i++)
>>>>> +        {
>>>>> +          /* For all but the last register used by this field only
>>>>> keep
>>>>> the
>>>>> +         padding bits that were padding bits in this field.  */
>>>>> +          padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
>>>>> +        }
>>>>> +
>>>>> +        /* For the last register, keep all padding bits that were
>>>>> padding
>>>>> +           bits in this field and any padding bits that are still
>>>>> valid
>>>>> +           as padding bits but fall outside of this field's size.  */
>>>>> +        mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
>>>>> +        padding_bits_to_clear_res[regno_t]
>>>>> +          &= padding_bits_to_clear_t[regno_t] | mask;
>>>>> +
>>>>> +      /* Update the maximum size of the fields in terms of registers
>>>>> used
>>>>> +         ('max_reg') and the 'last_used_bit' in said register.  */
>>>>> +      if (max_reg < regno_t)
>>>>> +        {
>>>>> +          max_reg = regno_t;
>>>>> +          max_bit = last_used_bit_t;
>>>>> +        }
>>>>> +      else if (max_reg == regno_t && max_bit < last_used_bit_t)
>>>>> +        max_bit = last_used_bit_t;
>>>>> +
>>>>> +      field = TREE_CHAIN (field);
>>>>> +    }
>>>>> +
>>>>> +      /* Update the current padding_bits_to_clear using the
>>>>> intersection of the
>>>>> +     padding bits of all the fields.  */
>>>>> +      for (i=*regno; i < max_reg; i++)
>>>>> +    padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
>>>>> +
>>>>>
>>>>> watch the spacing in the 'for' definition.
>>>>>
>>>>>    +      /* Do not keep trailing padding bits, we do not know yet
>>>>> whether
>>>>> this
>>>>> +     is the end of the argument.  */
>>>>> +      mask = ((uint32_t) 1 << max_bit) - 1;
>>>>> +      padding_bits_to_clear[max_reg]
>>>>> +    |= padding_bits_to_clear_res[max_reg] & mask;
>>>>> +
>>>>> +      *regno = max_reg;
>>>>> +      *last_used_bit = max_bit;
>>>>> +    }
>>>>> +  else
>>>>> +    /* This function should only be used for structs and unions.  */
>>>>> +    gcc_unreachable ();
>>>>> +
>>>>> +  return not_to_clear_reg_mask;
>>>>> +}
>>>>> +
>>>>> +/* In the context of ARMv8-M Security Extensions, this function is
>>>>> used
>>>>> for both
>>>>> +   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to
>>>>> compute what
>>>>> +   registers are used when returning or passing arguments, which is
>>>>> then
>>>>> +   returned as a mask.  It will also compute a mask to indicate
>>>>> padding/unused
>>>>> +   bits for each of these registers, and passes this through the
>>>>> +   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is
>>>>> passed in
>>>>> +   ARG_TYPE, the rtl representation of the argument is passed in
>>>>> ARG_RTX and
>>>>> +   the starting register used to pass this argument or return
>>>>> value is
>>>>> passed
>>>>> +   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to
>>>>> compute these
>>>>> +   for struct and union types.  */
>>>>> +
>>>>> +static unsigned HOST_WIDE_INT
>>>>> +compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
>>>>> +                 uint32_t * padding_bits_to_clear)
>>>>> +
>>>>> +{
>>>>> +  int last_used_bit = 0;
>>>>> +  unsigned HOST_WIDE_INT not_to_clear_mask;
>>>>> +
>>>>> +  if (RECORD_OR_UNION_TYPE_P (arg_type))
>>>>> +    {
>>>>> +      not_to_clear_mask
>>>>> +    = comp_not_to_clear_mask_str_un (arg_type, &regno,
>>>>> +                     padding_bits_to_clear, 0,
>>>>> +                     &last_used_bit);
>>>>> +
>>>>> +
>>>>> +      /* If the 'last_used_bit' is not zero, that means we are still
>>>>> using a
>>>>> +     part of the last 'regno'.  In such cases we must clear the
>>>>> trailing
>>>>> +     bits.  Otherwise we are not using regno and we should mark it
>>>>> as to
>>>>> +     clear.  */
>>>>> +      if (last_used_bit != 0)
>>>>> +    *(padding_bits_to_clear + regno)
>>>>> +      |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;
>>>>>
>>>>> padding_bits_to_clear[regno] |= ...
>>>>>
>>>>> +      else
>>>>> +    not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
>>>>> +    }
>>>>> +  else
>>>>> +    {
>>>>> +      not_to_clear_mask = 0;
>>>>> +      /* We are not dealing with structs nor unions.  So these
>>>>> arguments may be
>>>>> +     passed in floating point registers too.  In some cases a
>>>>> BLKmode is
>>>>> +     used when returning or passing arguments in multiple VFP
>>>>> registers.  */
>>>>> +      if (GET_MODE (arg_rtx) == BLKmode)
>>>>> +    {
>>>>> +      int i, arg_regs;
>>>>> +      rtx reg;
>>>>> +
>>>>> +      /* This should really only occur when dealing with the
>>>>> hard-float
>>>>> +         ABI.  */
>>>>> +      gcc_assert (TARGET_HARD_FLOAT_ABI);
>>>>> +
>>>>> +      for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
>>>>> +        {
>>>>> +          reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
>>>>> +          gcc_assert (REG_P (reg));
>>>>> +
>>>>> +          not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
>>>>> +
>>>>> +          /* If we are dealing with DF mode, make sure we don't
>>>>> +         clear either of the registers it addresses.  */
>>>>> +          arg_regs = ARM_NUM_REGS (GET_MODE (reg));
>>>>>
>>>>> Better assert here that you're indeed dealing with DFmode and/or you
>>>>> have 2 registers.
>>>>>
>>>> The current code actually works for larger modes too. I don't think
>>>> code
>>>> will ever be generated with larger types, but why assert if it works
>>>> anyway?
>>> ok, no need to assert here then.
>>> I suppose it doesn't add much if the code handles the other modes fine.
>>>
>>> Kyrill
>>>
>> Hi,
>>
>> Reworked comments. No change to ChangeLogs.
>>
>> Cheers,
>> Andre
> 
> 
> +/* Clear caller saved registers not used to pass return values and leaked
> +   condition flags before exiting a cmse_nonsecure_entry function.  */
> +
> +void
> +cmse_nonsecure_entry_clear_before_return (void)
> +{
> +  uint64_t to_clear_mask[2];
> +  uint32_t padding_bits_to_clear = 0;
> +  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
> +  int regno, maxregno = IP_REGNUM;
> +  tree result_type;
> +  rtx result_rtl;
> +
> +  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
> +  to_clear_mask[0] |= (1ULL << IP_REGNUM);
> +  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
> +     registers.  We also check TARGET_HARD_FLOAT to make sure these are
> +     present.  */
> +  if (TARGET_HARD_FLOAT)
> +    {
> +      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
> +      maxregno = LAST_VFP_REGNUM;
> +
> +      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
> +      to_clear_mask[0] |= float_mask;
> +
> +      float_mask = (1ULL << (maxregno - 63)) - 1;
> +      to_clear_mask[1] = float_mask;
> +
> +      /* Make sure we dont clear the two scratch registers used to
> clear the
> +     relevant FPSCR bits in output_return_instruction.  We have only
> +     implemented the clearing of FP registers for Thumb-2, so we assert
> +     here that VFP was not enabled for Thumb-1 ARMv8-M targets.  */
> +      gcc_assert (arm_arch_thumb2);
> 
> I see this assert triggering when running the testsuite cmse.exp with
> /-march=armv8-m.base/-mfloat-abi=softfp/-mfpu=fpv5-d16
> from a toolchain configured with "--with-cpu=cortex-a15
> --with-float=hard --with-mode=thumb --with-fpu=neon-vfpv4".
> I think some more validation needs to happen to reject the attributes
> for invalid configurations.
> 
> Kyrill
> 
> 
> 
Hi,

So I believe the option is there to allow for interworking on targets
that support 16bit Thumb (but not 32bit Thumb), using pragmas and
compiling with -mfloat-abi=softfp. Yes, I agree it doesn't make sense to
allow it for targets like ARMv6-M or ARMv8-M Baseline, but we can look
at that separately.

For now I changed the checks for clearing FP registers to check not only
for 'TARGET_HARD_FLOAT' but also '!TARGET_THUMB1'.

I suggest we re-evaluate the definition of 'TARGET_HARD_FLOAT' at a
later point, either adding a '&& !TARGET_THUMB1' or change the comment
above it. The comment reads 'Use hardware floating point instructions',
which is wrong as we have seen from this exercise. I also got rid of the
assert you were hitting, since given the changes it is impossible to hit
it. I did add a test to the testsuite checking that we don't generate FP
instructions when compiling with '-march=armv8-m.base -mfloat-abi=softfp'.

Is this OK?

Cheers,
Andre

*** gcc/ChangeLog ***
2016-10-28  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (output_return_instruction): Clear
        registers.
        (thumb2_expand_return): Likewise.
        (thumb1_expand_epilogue): Likewise.
        (thumb_exit): Likewise.
        (arm_expand_epilogue): Likewise.
        (cmse_nonsecure_entry_clear_before_return): New.
        (comp_not_to_clear_mask_str_un): New.
        (compute_not_to_clear_mask): New.
        * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
        * config/arm/thumb2.md (*thumb2_return): Duplicate pattern for
        cmse_nonsecure_entry functions.

*** gcc/testsuite/ChangeLog ***
2016-10-28  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
        * gcc.target/arm/cmse/struct-1.c: New.
        * gcc.target/arm/cmse/bitfield-1.c: New.
        * gcc.target/arm/cmse/bitfield-2.c: New.
        * gcc.target/arm/cmse/bitfield-3.c: New.
        * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
cleared.
        * gcc.target/arm/cmse/baseline/softfp.c: New.
        * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
        * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.

[-- Attachment #2: diff4 --]
[-- Type: text/plain, Size: 40248 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index fdbdd423236e7388802bc4bd568f260d95485bbe..5dc569aa8ccca8f37f47b326d5b6d68e87b8c6d3 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17499,6 +17499,279 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
   return;
 }
 
+/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for structs
+   and unions in the context of ARMv8-M Security Extensions.  It is used as a
+   helper function for both 'cmse_nonsecure_call' and 'cmse_nonsecure_entry'
+   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to either one
+   or four masks, depending on whether it is being computed for a
+   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
+   respectively.  The tree for the type of the argument or a field within an
+   argument is passed in ARG_TYPE, the current register this argument or field
+   starts in is kept in the pointer REGNO and updated accordingly, the bit this
+   argument or field starts at is passed in STARTING_BIT and the last used bit
+   is kept in LAST_USED_BIT which is also updated accordingly.  */
+
+static unsigned HOST_WIDE_INT
+comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
+			       uint32_t * padding_bits_to_clear,
+			       unsigned starting_bit, int * last_used_bit)
+
+{
+  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
+
+  if (TREE_CODE (arg_type) == RECORD_TYPE)
+    {
+      unsigned current_bit = starting_bit;
+      tree field;
+      long int offset, size;
+
+
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  /* The offset within a structure is always an offset from
+	     the start of that structure.  Make sure we take that into the
+	     calculation of the register based offset that we use here.  */
+	  offset = starting_bit;
+	  offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
+	  offset %= 32;
+
+	  /* This is the actual size of the field, for bitfields this is the
+	     bitfield width and not the container size.  */
+	  size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+
+	  if (*last_used_bit != offset)
+	    {
+	      if (offset < *last_used_bit)
+		{
+		  /* This field's offset is before the 'last_used_bit', that
+		     means this field goes on the next register.  So we need to
+		     pad the rest of the current register and increase the
+		     register number.  */
+		  uint32_t mask;
+		  mask  = ((uint32_t)-1) - ((uint32_t) 1 << *last_used_bit);
+		  mask++;
+
+		  padding_bits_to_clear[*regno] |= mask;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      else
+		{
+		  /* Otherwise we pad the bits between the last field's end and
+		     the start of the new field.  */
+		  uint32_t mask;
+
+		  mask = ((uint32_t)-1) >> (32 - offset);
+		  mask -= ((uint32_t) 1 << *last_used_bit) - 1;
+		  padding_bits_to_clear[*regno] |= mask;
+		}
+	      current_bit = offset;
+	    }
+
+	  /* Calculate further padding bits for inner structs/unions too.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	    {
+	      *last_used_bit = current_bit;
+	      not_to_clear_reg_mask
+		|= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
+						  padding_bits_to_clear, offset,
+						  last_used_bit);
+	    }
+	  else
+	    {
+	      /* Update 'current_bit' with this field's size.  If the
+		 'current_bit' lies in a subsequent register, update 'regno' and
+		 reset 'current_bit' to point to the current bit in that new
+		 register.  */
+	      current_bit += size;
+	      while (current_bit >= 32)
+		{
+		  current_bit-=32;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      *last_used_bit = current_bit;
+	    }
+
+	  field = TREE_CHAIN (field);
+	}
+      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+    }
+  else if (TREE_CODE (arg_type) == UNION_TYPE)
+    {
+      tree field, field_t;
+      int i, regno_t, field_size;
+      int max_reg = -1;
+      int max_bit = -1;
+      uint32_t mask;
+      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
+	= {-1, -1, -1, -1};
+
+      /* To compute the padding bits in a union we only consider bits as
+	 padding bits if they are always either a padding bit or fall outside a
+	 fields size for all fields in the union.  */
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
+	    = {0U, 0U, 0U, 0U};
+	  int last_used_bit_t = *last_used_bit;
+	  regno_t = *regno;
+	  field_t = TREE_TYPE (field);
+
+	  /* If the field's type is either a record or a union make sure to
+	     compute their padding bits too.  */
+	  if (RECORD_OR_UNION_TYPE_P (field_t))
+	    not_to_clear_reg_mask
+	      |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
+						&padding_bits_to_clear_t[0],
+						starting_bit, &last_used_bit_t);
+	  else
+	    {
+	      field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+	      regno_t = (field_size / 32) + *regno;
+	      last_used_bit_t = (starting_bit + field_size) % 32;
+	    }
+
+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (((uint32_t) -1) - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;
+
+	  /* Update the maximum size of the fields in terms of registers used
+	     ('max_reg') and the 'last_used_bit' in said register.  */
+	  if (max_reg < regno_t)
+	    {
+	      max_reg = regno_t;
+	      max_bit = last_used_bit_t;
+	    }
+	  else if (max_reg == regno_t && max_bit < last_used_bit_t)
+	    max_bit = last_used_bit_t;
+
+	  field = TREE_CHAIN (field);
+	}
+
+      /* Update the current padding_bits_to_clear using the intersection of the
+	 padding bits of all the fields.  */
+      for (i=*regno; i < max_reg; i++)
+	padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+
+      /* Do not keep trailing padding bits, we do not know yet whether this
+	 is the end of the argument.  */
+      mask = ((uint32_t) 1 << max_bit) - 1;
+      padding_bits_to_clear[max_reg]
+	|= padding_bits_to_clear_res[max_reg] & mask;
+
+      *regno = max_reg;
+      *last_used_bit = max_bit;
+    }
+  else
+    /* This function should only be used for structs and unions.  */
+    gcc_unreachable ();
+
+  return not_to_clear_reg_mask;
+}
+
+/* In the context of ARMv8-M Security Extensions, this function is used for both
+   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to compute what
+   registers are used when returning or passing arguments, which is then
+   returned as a mask.  It will also compute a mask to indicate padding/unused
+   bits for each of these registers, and passes this through the
+   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is passed in
+   ARG_TYPE, the rtl representation of the argument is passed in ARG_RTX and
+   the starting register used to pass this argument or return value is passed
+   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to compute these
+   for struct and union types.  */
+
+static unsigned HOST_WIDE_INT
+compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
+			     uint32_t * padding_bits_to_clear)
+
+{
+  int last_used_bit = 0;
+  unsigned HOST_WIDE_INT not_to_clear_mask;
+
+  if (RECORD_OR_UNION_TYPE_P (arg_type))
+    {
+      not_to_clear_mask
+	= comp_not_to_clear_mask_str_un (arg_type, &regno,
+					 padding_bits_to_clear, 0,
+					 &last_used_bit);
+
+
+      /* If the 'last_used_bit' is not zero, that means we are still using a
+	 part of the last 'regno'.  In such cases we must clear the trailing
+	 bits.  Otherwise we are not using regno and we should mark it as to
+	 clear.  */
+      if (last_used_bit != 0)
+	padding_bits_to_clear[regno]
+	  |= ((uint32_t)-1) - ((uint32_t) 1 << last_used_bit) + 1;
+      else
+	not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
+    }
+  else
+    {
+      not_to_clear_mask = 0;
+      /* We are not dealing with structs nor unions.  So these arguments may be
+	 passed in floating point registers too.  In some cases a BLKmode is
+	 used when returning or passing arguments in multiple VFP registers.  */
+      if (GET_MODE (arg_rtx) == BLKmode)
+	{
+	  int i, arg_regs;
+	  rtx reg;
+
+	  /* This should really only occur when dealing with the hard-float
+	     ABI.  */
+	  gcc_assert (TARGET_HARD_FLOAT_ABI);
+
+	  for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
+	    {
+	      reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
+	      gcc_assert (REG_P (reg));
+
+	      not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
+
+	      /* If we are dealing with DF mode, make sure we don't
+		 clear either of the registers it addresses.  */
+	      arg_regs = ARM_NUM_REGS (GET_MODE (reg));
+	      if (arg_regs > 1)
+		{
+		  unsigned HOST_WIDE_INT mask;
+		  mask = HOST_WIDE_INT_1U << (REGNO (reg) + arg_regs);
+		  mask -= HOST_WIDE_INT_1U << REGNO (reg);
+		  not_to_clear_mask |= mask;
+		}
+	    }
+	}
+      else
+	{
+	  /* Otherwise we can rely on the MODE to determine how many registers
+	     are being used by this argument.  */
+	  int arg_regs = ARM_NUM_REGS (GET_MODE (arg_rtx));
+	  not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	  if (arg_regs > 1)
+	    {
+	      unsigned HOST_WIDE_INT
+	      mask = HOST_WIDE_INT_1U << (REGNO (arg_rtx) + arg_regs);
+	      mask -= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	      not_to_clear_mask |= mask;
+	    }
+	}
+    }
+
+  return not_to_clear_mask;
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -19920,7 +20193,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
-	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    {
+	      /* 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);
+	      if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+		{
+		  /* 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");
+		  output_asm_insn (instr, & operand);
+		}
+	      snprintf (instr, sizeof (instr), "bxns\t%%|lr");
+	    }
 	  /* Use bx if it's available.  */
 	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
@@ -24187,7 +24495,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
-	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	{
+	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+		       reg_containing_return_addr);
+	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	}
       else
 	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
@@ -24423,7 +24735,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
   /* Return to caller.  */
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
-    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    {
+      asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n", reg_containing_return_addr);
+      asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    }
   else
     asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
@@ -25285,6 +25600,132 @@ thumb1_expand_prologue (void)
     cfun->machine->lr_save_eliminated = 0;
 }
 
+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check that TARGET_HARD_FLOAT and !TARGET_THUMB1 hold
+     to make sure the instructions used to clear them are present.  */
+  if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      maxregno = LAST_VFP_REGNUM;
+
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask[0] |= float_mask;
+
+      float_mask = (1ULL << (maxregno - 63)) - 1;
+      to_clear_mask[1] = float_mask;
+
+      /* 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));
+      to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+      emit_use (gen_rtx_REG (SImode, 4));
+      to_clear_mask[0] &= ~(1ULL << 4);
+    }
+
+  /* If the user has defined registers to be caller saved, these are no longer
+     restored by the function before returning and must thus be cleared for
+     security purposes.  */
+  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+    {
+      /* We do not touch registers that can be used to pass arguments as per
+	 the AAPCS, since these should never be made callee-saved by user
+	 options.  */
+      if (IN_RANGE (regno, FIRST_VFP_REGNUM, D7_VFP_REGNUM))
+	continue;
+      if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
+	continue;
+      if (call_used_regs[regno])
+	to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+    }
+
+  /* Make sure we do not clear the registers used to return the result in.  */
+  result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+  if (!VOID_TYPE_P (result_type))
+    {
+      result_rtl = arm_function_value (result_type, current_function_decl, 0);
+
+      /* No need to check that we return in registers, because we don't
+	 support returning on stack yet.  */
+      to_clear_mask[0]
+	&= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
+				       padding_bits_to_clear_ptr);
+    }
+
+  if (padding_bits_to_clear != 0)
+    {
+      rtx reg_rtx;
+      /* Padding bits to clear is not 0 so we know we are dealing with
+	 returning a composite type, which only uses r0.  Let's make sure that
+	 r1-r3 is cleared too, we will use r1 as a scratch register.  */
+      gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
+
+      reg_rtx = gen_rtx_REG (SImode, R1_REGNUM);
+
+      /* Fill the lower half of the negated padding_bits_to_clear.  */
+      emit_move_insn (reg_rtx,
+		      GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
+
+      /* Also fill the top half of the negated padding_bits_to_clear.  */
+      if (((~padding_bits_to_clear) >> 16) > 0)
+	emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
+						      GEN_INT (16),
+						      GEN_INT (16)),
+				GEN_INT ((~padding_bits_to_clear) >> 16)));
+
+      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, R0_REGNUM),
+			   gen_rtx_REG (SImode, R0_REGNUM),
+			   reg_rtx));
+    }
+
+  for (regno = 0; regno <= maxregno; regno++)
+    {
+      if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
+	continue;
+
+      if (IS_VFP_REGNUM (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)
+	      && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 1)))
+	    {
+	      emit_move_insn (gen_rtx_REG (DFmode, regno++),
+			      CONST1_RTX (DFmode));
+	      emit_use (gen_rtx_REG (DFmode, 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 (SImode, regno),
+			  gen_rtx_REG (SImode, LR_REGNUM));
+	  emit_use (gen_rtx_REG (SImode, regno));
+	}
+    }
+}
+
 /* Generate pattern *pop_multiple_with_stack_update_and_return if single
    POP instruction can be generated.  LR should be replaced by PC.  All
    the checks required are already done by  USE_RETURN_INSN ().  Hence,
@@ -25334,6 +25775,8 @@ thumb2_expand_return (bool simple_return)
     }
   else
     {
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	cmse_nonsecure_entry_clear_before_return ();
       emit_jump_insn (simple_return_rtx);
     }
 }
@@ -25392,6 +25835,10 @@ thumb1_expand_epilogue (void)
 
   if (! df_regs_ever_live_p (LR_REGNUM))
     emit_use (gen_rtx_REG (SImode, LR_REGNUM));
+
+  /* Clear all caller-saved regs that are not used to return.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    cmse_nonsecure_entry_clear_before_return ();
 }
 
 /* Epilogue code for APCS frame.  */
@@ -25826,6 +26273,14 @@ 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 (!really_return)
     return;
 
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index cd98de7dcb40de483a9f93c0674bd216f4b0c56a..433fc79ae5810a4d3eb45d1ba80872a39e157e14 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1843,8 +1843,13 @@
   "*
     return thumb1_unexpanded_epilogue ();
   "
-  ; Length is absolute worst case
-  [(set_attr "length" "44")
+  ; Length is absolute worst case, when using CMSE and if this is an entry
+  ; function an extra 4 (MSR) bytes will be added.
+  [(set (attr "length")
+	(if_then_else
+	 (match_test "IS_CMSE_ENTRY (arm_current_func_type ())")
+	 (const_int 48)
+	 (const_int 44)))
    (set_attr "type" "block")
    ;; We don't clobber the conditions, but the potential length of this
    ;; operation is sufficient to make conditionalizing the sequence
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index affcd832b72b7d358347e7370265be492866bb90..f5033ef802c085bd0ce479bc7026db96d9e25632 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1114,12 +1114,31 @@
 
 (define_insn "*thumb2_return"
   [(simple_return)]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
   "* return output_return_instruction (const_true_rtx, true, false, true);"
   [(set_attr "type" "branch")
    (set_attr "length" "4")]
 )
 
+(define_insn "*thumb2_return"
+  [(simple_return)]
+  "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
+  "* return output_return_instruction (const_true_rtx, true, false, true);"
+  [(set_attr "type" "branch")
+   ; This is a return from a cmse_nonsecure_entry function so code will be
+   ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+   ; we adapt the length accordingly.
+   (set (attr "length")
+     (if_then_else (match_test "TARGET_HARD_FLOAT")
+      (const_int 12)
+      (const_int 8)))
+   ; We do not support predicate execution of returns from cmse_nonsecure_entry
+   ; functions because we need to clear the APSR.  Since predicable has to be
+   ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
+   ; functions.
+   (set_attr "predicable" "no")]
+)
+
 (define_insn_and_split "thumb2_eh_return"
   [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
 		    VUNSPEC_EH_RETURN)
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c6354c7a8cfead895e6c62d61c3f2a2bca1a1f2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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 "msr\tAPSR_nzcvq, r1" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c
new file mode 100644
index 0000000000000000000000000000000000000000..0069fcdaebfd9caea02751856039a3aaefd3ffab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse -mfloat-abi=softfp" } */
+
+double __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+double
+foo (double a)
+{
+  return bar (1.0f, 2.0) + a;
+}
+
+float __attribute__ ((cmse_nonsecure_entry))
+baz (float a, double b)
+{
+  return (float) bar (a, b);
+}
+
+/* Make sure we are not using FP instructions, since ARMv8-M Baseline does not
+   support such instructions.  */
+/* { dg-final { scan-assembler-not "vmov" } } */
+/* { dg-final { scan-assembler-not "vmsr" } } */
+/* { dg-final { scan-assembler-not "vmrs" } } */
+
+/* Just double checking that we are still doing cmse though.  */
+/* { dg-final { scan-assembler-not "vmrs" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..fccc51d5c82f7955ee4cb8256c1dd38f9ff2670d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned short  a : 6;
+  unsigned char	  b : 3;
+  unsigned char	  c;
+  unsigned short  d : 8;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 63u;
+  t.b = 7u;
+  t.c = 255u;
+  t.d = 255u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 63u
+      || t.b != 7u
+      || t.c != 255u
+      || t.d != 255u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6aee3c4c022d50baec8ab16443130897540e703
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a : 7;
+  signed char b : 3;
+  short	      c : 11;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -64;
+  t.b = -4 ;
+  t.c = -1024;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -64
+      || t.b != -4
+      || t.c != -1024)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..285a2b92f64c1913ef585b8daa4d27c6da0a3d2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a;
+  signed char b : 2;
+  short		: 1;
+  signed char c : 3;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -32768;
+  t.b = -2;
+  t.c = -4;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -32768
+      || t.b != -2
+      || t.c != -4)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index f797dba1901720e04249d61078c1cbf2a3e436a9..38f18414c2fefec56161e6ac3f7291b03a3b29a3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -43,6 +43,26 @@ set LTO_TORTURE_OPTIONS ""
 gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
 	"" $DEFAULT_CFLAGS
 
+if {[check_effective_target_arm_arch_v8m_base_ok]} then {
+    # Baseline only
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/baseline/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
+if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    # Mainline -mfloat-abi=soft
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
+	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
 set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
 set dg-do-what-default ${saved-dg-do-what-default}
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..88dec2762812614ee986ee1a023c0acce8f94c91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..29f60baf5212f9fa2e4436fe40c6abe4ac671254
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7229ea8eb2da1da264f58f8518daf303d1bdeda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..7734d77dc3812e6a158ea1f6b067930846fffccb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..6addaa1a4eda8e2930d5fe72c94697bcf6e604e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { 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
new file mode 100644
index 0000000000000000000000000000000000000000..2d366a944df692f29ab44e3ee4d33c777b126223
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 255u;
+  t.b = 32767u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 255u || t.b != 32767u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
+

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

* Re: [PATCHv2 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
  2016-10-25 16:29     ` Andre Vieira (lists)
  2016-10-27 10:00       ` Andre Vieira (lists)
@ 2016-11-04  9:30       ` Kyrill Tkachov
  2016-11-30 12:05         ` [PATCHv3 " Andre Vieira (lists)
  1 sibling, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-11-04  9:30 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

Hi Andre,

On 25/10/16 17:29, Andre Vieira (lists) wrote:
> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>> On 25/07/16 14:25, Andre Vieira (lists) wrote:
>>> This patch adds support for the ARMv8-M Security Extensions
>>> 'cmse_nonsecure_call' attribute. This attribute may only be used for
>>> function types and when used in combination with the '-mcmse'
>>> compilation flag. See Section 5.5 of ARM®v8-M Security Extensions
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>
>>> We currently do not support cmse_nonsecure_call functions that pass
>>> arguments or return variables on the stack and we diagnose this.
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/arm.c (gimplify.h): New include.
>>>          (arm_handle_cmse_nonsecure_call): New.
>>>          (arm_attribute_table): Added cmse_nonsecure_call.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse-3.c: Add tests.
>>>          * gcc.target/arm/cmse/cmse-4.c: Add tests.
>>>
>> Added more documentation as requested.
>>
>> ---
>>
>> This patch adds support for the ARMv8-M Security Extensions
>> 'cmse_nonsecure_call' attribute. This attribute may only be used for
>> function types and when used in combination with the '-mcmse'
>> compilation flag. See Section 5.5 of ARM®v8-M Security Extensions
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>
>> We currently do not support cmse_nonsecure_call functions that pass
>> arguments or return variables on the stack and we diagnose this.
>>
>> *** gcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config/arm/arm.c (gimplify.h): New include.
>>          (arm_handle_cmse_nonsecure_call): New.
>>          (arm_attribute_table): Added cmse_nonsecure_call.
>>          * doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * gcc.target/arm/cmse/cmse-3.c: Add tests.
>>          * gcc.target/arm/cmse/cmse-4.c: Add tests.
>>
> Hi,
>
> Rebased previous patch on top of trunk as requested. No changes to
> ChangeLog.

This looks ok to me.
Thanks,
Kyrill

> Cheers,
> Andre

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-10-28 16:08                 ` Andre Vieira (lists)
@ 2016-11-08 12:16                   ` Kyrill Tkachov
  2016-11-23 11:52                     ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-11-08 12:16 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 28/10/16 17:07, Andre Vieira (lists) wrote:
> On 27/10/16 11:44, Kyrill Tkachov wrote:
>> On 27/10/16 11:00, Andre Vieira (lists) wrote:
>>> On 26/10/16 17:30, Kyrill Tkachov wrote:
>>>> On 26/10/16 17:26, Andre Vieira (lists) wrote:
>>>>> On 26/10/16 13:51, Kyrill Tkachov wrote:
>>>>>> Hi Andre,
>>>>>>
>>>>>> On 25/10/16 17:29, Andre Vieira (lists) wrote:
>>>>>>> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>>>>>>>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>>>>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>>>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>>>>>>> information through unbanked registers.
>>>>>>>>>
>>>>>>>>> When returning from a nonsecure entry function we clear all
>>>>>>>>> caller-saved
>>>>>>>>> registers that are not used to pass return values, by writing
>>>>>>>>> either
>>>>>>>>> the
>>>>>>>>> LR, in case of general purpose registers, or the value 0, in case
>>>>>>>>> of FP
>>>>>>>>> registers. We use the LR to write to APSR and FPSCR too. We
>>>>>>>>> currently do
>>>>>>>>> not support entry functions that pass arguments or return
>>>>>>>>> variables on
>>>>>>>>> the stack and we diagnose this. This patch relies on the existing
>>>>>>>>> code
>>>>>>>>> to make sure callee-saved registers used in cmse_nonsecure_entry
>>>>>>>>> functions are saved and restored thus retaining their nonsecure
>>>>>>>>> mode
>>>>>>>>> value, this should be happening already as it is required by AAPCS.
>>>>>>>>>
>>>>>>>>> This patch also clears padding bits for cmse_nonsecure_entry
>>>>>>>>> functions
>>>>>>>>> with struct and union return types. For unions a bit is only
>>>>>>>>> considered
>>>>>>>>> a padding bit if it is an unused bit in every field of that union.
>>>>>>>>> The
>>>>>>>>> function that calculates these is used in a later patch to do the
>>>>>>>>> same
>>>>>>>>> for arguments of cmse_nonsecure_call's.
>>>>>>>>>
>>>>>>>>> *** gcc/ChangeLog ***
>>>>>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>>>                 Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>>>
>>>>>>>>>             * config/arm/arm.c (output_return_instruction): Clear
>>>>>>>>>             registers.
>>>>>>>>>             (thumb2_expand_return): Likewise.
>>>>>>>>>             (thumb1_expand_epilogue): Likewise.
>>>>>>>>>             (thumb_exit): Likewise.
>>>>>>>>>             (arm_expand_epilogue): Likewise.
>>>>>>>>>             (cmse_nonsecure_entry_clear_before_return): New.
>>>>>>>>>             (comp_not_to_clear_mask_str_un): New.
>>>>>>>>>             (compute_not_to_clear_mask): New.
>>>>>>>>>             * config/arm/thumb1.md (*epilogue_insns): Change length
>>>>>>>>> attribute.
>>>>>>>>>             * config/arm/thumb2.md (*thumb2_return): Likewise.
>>>>>>>>>
>>>>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>>>                 Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>>>
>>>>>>>>>             * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>>>>>>> separate.
>>>>>>>>>             * gcc.target/arm/cmse/struct-1.c: New.
>>>>>>>>>             * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>>>>>>             * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>>>>>>             * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>>>>>>             * gcc.target/arm/cmse/baseline/cmse-2.c: Test that
>>>>>>>>> registers are
>>>>>>>>> cleared.
>>>>>>>>>             * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>>>>>>             * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>>>>>>             * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>>>>>>             * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>>>>>>             * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>>>>>>
>>>>>>>> Updated this patch to correctly clear only the cumulative
>>>>>>>> exception-status (0-4,7) and the condition code bits (28-31) of the
>>>>>>>> FPSCR. I also adapted the code to be handle the bigger floating
>>>>>>>> point
>>>>>>>> register files.
>>>>>>>>
>>>>>>>> ----
>>>>>>>>
>>>>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>>>>> 'cmse_nonsecure_entry' attribute to safeguard against leak of
>>>>>>>> information through unbanked registers.
>>>>>>>>
>>>>>>>> When returning from a nonsecure entry function we clear all
>>>>>>>> caller-saved
>>>>>>>> registers that are not used to pass return values, by writing
>>>>>>>> either the
>>>>>>>> LR, in case of general purpose registers, or the value 0, in case
>>>>>>>> of FP
>>>>>>>> registers. We use the LR to write to APSR. For FPSCR we clear
>>>>>>>> only the
>>>>>>>> cumulative exception-status (0-4, 7) and the condition code bits
>>>>>>>> (28-31). We currently do not support entry functions that pass
>>>>>>>> arguments
>>>>>>>> or return variables on the stack and we diagnose this. This patch
>>>>>>>> relies
>>>>>>>> on the existing code to make sure callee-saved registers used in
>>>>>>>> cmse_nonsecure_entry functions are saved and restored thus retaining
>>>>>>>> their nonsecure mode value, this should be happening already as
>>>>>>>> it is
>>>>>>>> required by AAPCS.
>>>>>>>>
>>>>>>>> This patch also clears padding bits for cmse_nonsecure_entry
>>>>>>>> functions
>>>>>>>> with struct and union return types. For unions a bit is only
>>>>>>>> considered
>>>>>>>> a padding bit if it is an unused bit in every field of that
>>>>>>>> union. The
>>>>>>>> function that calculates these is used in a later patch to do the
>>>>>>>> same
>>>>>>>> for arguments of cmse_nonsecure_call's.
>>>>>>>>
>>>>>>>> *** gcc/ChangeLog ***
>>>>>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>>                 Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>>
>>>>>>>>             * config/arm/arm.c (output_return_instruction): Clear
>>>>>>>>             registers.
>>>>>>>>             (thumb2_expand_return): Likewise.
>>>>>>>>             (thumb1_expand_epilogue): Likewise.
>>>>>>>>             (thumb_exit): Likewise.
>>>>>>>>             (arm_expand_epilogue): Likewise.
>>>>>>>>             (cmse_nonsecure_entry_clear_before_return): New.
>>>>>>>>             (comp_not_to_clear_mask_str_un): New.
>>>>>>>>             (compute_not_to_clear_mask): New.
>>>>>>>>             * config/arm/thumb1.md (*epilogue_insns): Change length
>>>>>>>> attribute.
>>>>>>>>             * config/arm/thumb2.md (*thumb2_return): Duplicate
>>>>>>>> pattern for
>>>>>>>>             cmse_nonsecure_entry functions.
>>>>>>>>
>>>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>>>>                 Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>>>>
>>>>>>>>             * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>>>>>>>> separate.
>>>>>>>>             * gcc.target/arm/cmse/struct-1.c: New.
>>>>>>>>             * gcc.target/arm/cmse/bitfield-1.c: New.
>>>>>>>>             * gcc.target/arm/cmse/bitfield-2.c: New.
>>>>>>>>             * gcc.target/arm/cmse/bitfield-3.c: New.
>>>>>>>>             * gcc.target/arm/cmse/baseline/cmse-2.c: Test that
>>>>>>>> registers
>>>>>>>> are
>>>>>>>> cleared.
>>>>>>>>             * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>>>>>>>             * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>>>>>>>             * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>>>>>>>             * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>>>>>>>             * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
>>>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> Rebased previous patch on top of trunk as requested. No changes to
>>>>>>> ChangeLog.
>>>>>>>
>>>>>>> Cheers,
>>>>>>> Andre
>>>>>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>>>>>> index
>>>>>> bb81e5662e81a26c7d3ccf9f749e8e356e6de35e..c6260323ecfd2f2842e6a5aab06b67da16619c73
>>>>>>
>>>>>>
>>>>>> 100644
>>>>>> --- a/gcc/config/arm/arm.c
>>>>>> +++ b/gcc/config/arm/arm.c
>>>>>> @@ -17496,6 +17496,279 @@ note_invalid_constants (rtx_insn *insn,
>>>>>> HOST_WIDE_INT address, int do_pushes)
>>>>>>       return;
>>>>>>     }
>>>>>>     +/* This function computes the clear mask and PADDING_BITS_TO_CLEAR
>>>>>> for
>>>>>> structs
>>>>>> +   and unions in the context of ARMv8-M Security Extensions.  It is
>>>>>> used as a
>>>>>> +   helper function for both 'cmse_nonsecure_call' and
>>>>>> 'cmse_nonsecure_entry'
>>>>>> +   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to
>>>>>> either one
>>>>>> +   or four masks, depending on whether it is being computed for a
>>>>>> +   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call'
>>>>>> argument
>>>>>> +   respectively.  The tree for the type of the argument or a field
>>>>>> within an
>>>>>> +   argument is passed in ARG_TYPE, the current register this argument
>>>>>> or field
>>>>>> +   starts in is kept in the pointer REGNO and updated accordingly,
>>>>>> the
>>>>>> bit this
>>>>>> +   argument or field starts at is passed in STARTING_BIT and the last
>>>>>> used bit
>>>>>> +   is kept in LAST_USED_BIT which is also updated accordingly.  */
>>>>>> +
>>>>>> +static unsigned HOST_WIDE_INT
>>>>>> +comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
>>>>>> +                   uint32_t * padding_bits_to_clear,
>>>>>> +                   unsigned starting_bit, int * last_used_bit)
>>>>>> +
>>>>>> +{
>>>>>> +  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
>>>>>> +
>>>>>> +  if (TREE_CODE (arg_type) == RECORD_TYPE)
>>>>>> +    {
>>>>>> +      unsigned current_bit = starting_bit;
>>>>>> +      tree field;
>>>>>> +      long int offset, size;
>>>>>> +
>>>>>> +
>>>>>> +      field = TYPE_FIELDS (arg_type);
>>>>>> +      while (field)
>>>>>> +    {
>>>>>> +      /* The offset within a structure is always an offset from
>>>>>> +         the start of that structure.  Make sure we take that into
>>>>>> the
>>>>>> +         calculation of the register based offset that we use
>>>>>> here.  */
>>>>>> +      offset = starting_bit;
>>>>>> +      offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
>>>>>> +      offset %= 32;
>>>>>> +
>>>>>> +      /* This is the actual size of the field, for bitfields this is
>>>>>> the
>>>>>> +         bitfield width and not the container size.  */
>>>>>> +      size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>>>>>> +
>>>>>> +      if (*last_used_bit != offset)
>>>>>> +        {
>>>>>> +          if (offset < *last_used_bit)
>>>>>> +        {
>>>>>> +          /* This field's offset is before the 'last_used_bit', that
>>>>>> +             means this field goes on the next register.  So we
>>>>>> need to
>>>>>> +             pad the rest of the current register and increase the
>>>>>> +             register number.  */
>>>>>> +          uint32_t mask;
>>>>>> +          mask  = UINT32_MAX - ((uint32_t) 1 << *last_used_bit);
>>>>>> +          mask++;
>>>>>> +
>>>>>> +          *(padding_bits_to_clear + *regno) |= mask;
>>>>>>
>>>>>> padding_bits_to_clear[*regno] |= mask;
>>>>>>
>>>>>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>>>>> +          (*regno)++;
>>>>>> +        }
>>>>>> +          else
>>>>>> +        {
>>>>>> +          /* Otherwise we pad the bits between the last field's
>>>>>> end and
>>>>>> +             the start of the new field.  */
>>>>>> +          uint32_t mask;
>>>>>> +
>>>>>> +          mask = UINT32_MAX >> (32 - offset);
>>>>>> +          mask -= ((uint32_t) 1 << *last_used_bit) - 1;
>>>>>> +          *(padding_bits_to_clear + *regno) |= mask;
>>>>>>
>>>>>> Likewise.
>>>>>>
>>>>>> +        }
>>>>>> +          current_bit = offset;
>>>>>> +        }
>>>>>> +
>>>>>> +      /* Calculate further padding bits for inner structs/unions
>>>>>> too.  */
>>>>>> +      if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
>>>>>> +        {
>>>>>> +          *last_used_bit = current_bit;
>>>>>> +          not_to_clear_reg_mask
>>>>>> +        |= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
>>>>>> +                          padding_bits_to_clear, offset,
>>>>>> +                          last_used_bit);
>>>>>> +        }
>>>>>> +      else
>>>>>> +        {
>>>>>> +          /* Update 'current_bit' with this field's size.  If the
>>>>>> +         'current_bit' lies in a subsequent register, update 'regno'
>>>>>> and
>>>>>> +         reset 'current_bit' to point to the current bit in that new
>>>>>> +         register.  */
>>>>>> +          current_bit += size;
>>>>>> +          while (current_bit >= 32)
>>>>>> +        {
>>>>>> +          current_bit-=32;
>>>>>> +          not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>>>>> +          (*regno)++;
>>>>>> +        }
>>>>>> +          *last_used_bit = current_bit;
>>>>>> +        }
>>>>>> +
>>>>>> +      field = TREE_CHAIN (field);
>>>>>> +    }
>>>>>> +      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
>>>>>> +    }
>>>>>> +  else if (TREE_CODE (arg_type) == UNION_TYPE)
>>>>>> +    {
>>>>>> +      tree field, field_t;
>>>>>> +      int i, regno_t, field_size;
>>>>>> +      int max_reg = -1;
>>>>>> +      int max_bit = -1;
>>>>>> +      uint32_t mask;
>>>>>> +      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
>>>>>> +    = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
>>>>>> +
>>>>>> +      /* To compute the padding bits in a union we only consider
>>>>>> bits as
>>>>>> +     padding bits if they are always either a padding bit or fall
>>>>>> outside a
>>>>>> +     fields size for all fields in the union.  */
>>>>>> +      field = TYPE_FIELDS (arg_type);
>>>>>> +      while (field)
>>>>>> +    {
>>>>>> +      uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
>>>>>> +        = {0U, 0U, 0U, 0U};
>>>>>> +      int last_used_bit_t = *last_used_bit;
>>>>>> +      regno_t = *regno;
>>>>>> +      field_t = TREE_TYPE (field);
>>>>>> +
>>>>>> +      /* If the field's type is either a record or a union make
>>>>>> sure to
>>>>>> +         compute their padding bits too.  */
>>>>>> +      if (RECORD_OR_UNION_TYPE_P (field_t))
>>>>>> +        not_to_clear_reg_mask
>>>>>> +          |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
>>>>>> +                        &padding_bits_to_clear_t[0],
>>>>>> +                        starting_bit, &last_used_bit_t);
>>>>>> +      else
>>>>>> +        {
>>>>>> +          field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
>>>>>> +          regno_t = (field_size / 32) + *regno;
>>>>>> +          last_used_bit_t = (starting_bit + field_size) % 32;
>>>>>> +        }
>>>>>> +
>>>>>> +      for (i = *regno; i < regno_t; i++)
>>>>>> +        {
>>>>>> +          /* For all but the last register used by this field only
>>>>>> keep
>>>>>> the
>>>>>> +         padding bits that were padding bits in this field.  */
>>>>>> +          padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
>>>>>> +        }
>>>>>> +
>>>>>> +        /* For the last register, keep all padding bits that were
>>>>>> padding
>>>>>> +           bits in this field and any padding bits that are still
>>>>>> valid
>>>>>> +           as padding bits but fall outside of this field's size.  */
>>>>>> +        mask = (UINT32_MAX - ((uint32_t) 1 << last_used_bit_t)) + 1;
>>>>>> +        padding_bits_to_clear_res[regno_t]
>>>>>> +          &= padding_bits_to_clear_t[regno_t] | mask;
>>>>>> +
>>>>>> +      /* Update the maximum size of the fields in terms of registers
>>>>>> used
>>>>>> +         ('max_reg') and the 'last_used_bit' in said register.  */
>>>>>> +      if (max_reg < regno_t)
>>>>>> +        {
>>>>>> +          max_reg = regno_t;
>>>>>> +          max_bit = last_used_bit_t;
>>>>>> +        }
>>>>>> +      else if (max_reg == regno_t && max_bit < last_used_bit_t)
>>>>>> +        max_bit = last_used_bit_t;
>>>>>> +
>>>>>> +      field = TREE_CHAIN (field);
>>>>>> +    }
>>>>>> +
>>>>>> +      /* Update the current padding_bits_to_clear using the
>>>>>> intersection of the
>>>>>> +     padding bits of all the fields.  */
>>>>>> +      for (i=*regno; i < max_reg; i++)
>>>>>> +    padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
>>>>>> +
>>>>>>
>>>>>> watch the spacing in the 'for' definition.
>>>>>>
>>>>>>     +      /* Do not keep trailing padding bits, we do not know yet
>>>>>> whether
>>>>>> this
>>>>>> +     is the end of the argument.  */
>>>>>> +      mask = ((uint32_t) 1 << max_bit) - 1;
>>>>>> +      padding_bits_to_clear[max_reg]
>>>>>> +    |= padding_bits_to_clear_res[max_reg] & mask;
>>>>>> +
>>>>>> +      *regno = max_reg;
>>>>>> +      *last_used_bit = max_bit;
>>>>>> +    }
>>>>>> +  else
>>>>>> +    /* This function should only be used for structs and unions.  */
>>>>>> +    gcc_unreachable ();
>>>>>> +
>>>>>> +  return not_to_clear_reg_mask;
>>>>>> +}
>>>>>> +
>>>>>> +/* In the context of ARMv8-M Security Extensions, this function is
>>>>>> used
>>>>>> for both
>>>>>> +   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to
>>>>>> compute what
>>>>>> +   registers are used when returning or passing arguments, which is
>>>>>> then
>>>>>> +   returned as a mask.  It will also compute a mask to indicate
>>>>>> padding/unused
>>>>>> +   bits for each of these registers, and passes this through the
>>>>>> +   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is
>>>>>> passed in
>>>>>> +   ARG_TYPE, the rtl representation of the argument is passed in
>>>>>> ARG_RTX and
>>>>>> +   the starting register used to pass this argument or return
>>>>>> value is
>>>>>> passed
>>>>>> +   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to
>>>>>> compute these
>>>>>> +   for struct and union types.  */
>>>>>> +
>>>>>> +static unsigned HOST_WIDE_INT
>>>>>> +compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
>>>>>> +                 uint32_t * padding_bits_to_clear)
>>>>>> +
>>>>>> +{
>>>>>> +  int last_used_bit = 0;
>>>>>> +  unsigned HOST_WIDE_INT not_to_clear_mask;
>>>>>> +
>>>>>> +  if (RECORD_OR_UNION_TYPE_P (arg_type))
>>>>>> +    {
>>>>>> +      not_to_clear_mask
>>>>>> +    = comp_not_to_clear_mask_str_un (arg_type, &regno,
>>>>>> +                     padding_bits_to_clear, 0,
>>>>>> +                     &last_used_bit);
>>>>>> +
>>>>>> +
>>>>>> +      /* If the 'last_used_bit' is not zero, that means we are still
>>>>>> using a
>>>>>> +     part of the last 'regno'.  In such cases we must clear the
>>>>>> trailing
>>>>>> +     bits.  Otherwise we are not using regno and we should mark it
>>>>>> as to
>>>>>> +     clear.  */
>>>>>> +      if (last_used_bit != 0)
>>>>>> +    *(padding_bits_to_clear + regno)
>>>>>> +      |= UINT32_MAX - ((uint32_t) 1 << last_used_bit) + 1;
>>>>>>
>>>>>> padding_bits_to_clear[regno] |= ...
>>>>>>
>>>>>> +      else
>>>>>> +    not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
>>>>>> +    }
>>>>>> +  else
>>>>>> +    {
>>>>>> +      not_to_clear_mask = 0;
>>>>>> +      /* We are not dealing with structs nor unions.  So these
>>>>>> arguments may be
>>>>>> +     passed in floating point registers too.  In some cases a
>>>>>> BLKmode is
>>>>>> +     used when returning or passing arguments in multiple VFP
>>>>>> registers.  */
>>>>>> +      if (GET_MODE (arg_rtx) == BLKmode)
>>>>>> +    {
>>>>>> +      int i, arg_regs;
>>>>>> +      rtx reg;
>>>>>> +
>>>>>> +      /* This should really only occur when dealing with the
>>>>>> hard-float
>>>>>> +         ABI.  */
>>>>>> +      gcc_assert (TARGET_HARD_FLOAT_ABI);
>>>>>> +
>>>>>> +      for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
>>>>>> +        {
>>>>>> +          reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
>>>>>> +          gcc_assert (REG_P (reg));
>>>>>> +
>>>>>> +          not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
>>>>>> +
>>>>>> +          /* If we are dealing with DF mode, make sure we don't
>>>>>> +         clear either of the registers it addresses.  */
>>>>>> +          arg_regs = ARM_NUM_REGS (GET_MODE (reg));
>>>>>>
>>>>>> Better assert here that you're indeed dealing with DFmode and/or you
>>>>>> have 2 registers.
>>>>>>
>>>>> The current code actually works for larger modes too. I don't think
>>>>> code
>>>>> will ever be generated with larger types, but why assert if it works
>>>>> anyway?
>>>> ok, no need to assert here then.
>>>> I suppose it doesn't add much if the code handles the other modes fine.
>>>>
>>>> Kyrill
>>>>
>>> Hi,
>>>
>>> Reworked comments. No change to ChangeLogs.
>>>
>>> Cheers,
>>> Andre
>>
>> +/* Clear caller saved registers not used to pass return values and leaked
>> +   condition flags before exiting a cmse_nonsecure_entry function.  */
>> +
>> +void
>> +cmse_nonsecure_entry_clear_before_return (void)
>> +{
>> +  uint64_t to_clear_mask[2];
>> +  uint32_t padding_bits_to_clear = 0;
>> +  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
>> +  int regno, maxregno = IP_REGNUM;
>> +  tree result_type;
>> +  rtx result_rtl;
>> +
>> +  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
>> +  to_clear_mask[0] |= (1ULL << IP_REGNUM);
>> +  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
>> +     registers.  We also check TARGET_HARD_FLOAT to make sure these are
>> +     present.  */
>> +  if (TARGET_HARD_FLOAT)
>> +    {
>> +      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
>> +      maxregno = LAST_VFP_REGNUM;
>> +
>> +      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
>> +      to_clear_mask[0] |= float_mask;
>> +
>> +      float_mask = (1ULL << (maxregno - 63)) - 1;
>> +      to_clear_mask[1] = float_mask;
>> +
>> +      /* Make sure we dont clear the two scratch registers used to
>> clear the
>> +     relevant FPSCR bits in output_return_instruction.  We have only
>> +     implemented the clearing of FP registers for Thumb-2, so we assert
>> +     here that VFP was not enabled for Thumb-1 ARMv8-M targets.  */
>> +      gcc_assert (arm_arch_thumb2);
>>
>> I see this assert triggering when running the testsuite cmse.exp with
>> /-march=armv8-m.base/-mfloat-abi=softfp/-mfpu=fpv5-d16
>> from a toolchain configured with "--with-cpu=cortex-a15
>> --with-float=hard --with-mode=thumb --with-fpu=neon-vfpv4".
>> I think some more validation needs to happen to reject the attributes
>> for invalid configurations.
>>
>> Kyrill
>>
>>
>>
> Hi,
>
> So I believe the option is there to allow for interworking on targets
> that support 16bit Thumb (but not 32bit Thumb), using pragmas and
> compiling with -mfloat-abi=softfp. Yes, I agree it doesn't make sense to
> allow it for targets like ARMv6-M or ARMv8-M Baseline, but we can look
> at that separately.
>
> For now I changed the checks for clearing FP registers to check not only
> for 'TARGET_HARD_FLOAT' but also '!TARGET_THUMB1'.
>
> I suggest we re-evaluate the definition of 'TARGET_HARD_FLOAT' at a
> later point, either adding a '&& !TARGET_THUMB1' or change the comment
> above it. The comment reads 'Use hardware floating point instructions',
> which is wrong as we have seen from this exercise. I also got rid of the
> assert you were hitting, since given the changes it is impossible to hit
> it. I did add a test to the testsuite checking that we don't generate FP
> instructions when compiling with '-march=armv8-m.base -mfloat-abi=softfp'.
>
> Is this OK?
>
> Cheers,
> Andre
>
> *** gcc/ChangeLog ***
> 2016-10-28  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>          * config/arm/arm.c (output_return_instruction): Clear
>          registers.
>          (thumb2_expand_return): Likewise.
>          (thumb1_expand_epilogue): Likewise.
>          (thumb_exit): Likewise.
>          (arm_expand_epilogue): Likewise.
>          (cmse_nonsecure_entry_clear_before_return): New.
>          (comp_not_to_clear_mask_str_un): New.
>          (compute_not_to_clear_mask): New.
>          * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
>          * config/arm/thumb2.md (*thumb2_return): Duplicate pattern for
>          cmse_nonsecure_entry functions.
>
> *** gcc/testsuite/ChangeLog ***
> 2016-10-28  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>          * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
>          * gcc.target/arm/cmse/struct-1.c: New.
>          * gcc.target/arm/cmse/bitfield-1.c: New.
>          * gcc.target/arm/cmse/bitfield-2.c: New.
>          * gcc.target/arm/cmse/bitfield-3.c: New.
>          * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
> cleared.
>          * gcc.target/arm/cmse/baseline/softfp.c: New.
>          * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>          * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>          * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>          * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>          * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.

<Snip>

+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;

<....>

+  for (regno = 0; regno <= maxregno; regno++)
+    {

Use R0_REGNUM.

+      if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
+	continue;
+
+      if (IS_VFP_REGNUM (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)
+	      && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 1)))
+	    {
+	      emit_move_insn (gen_rtx_REG (DFmode, regno++),
+			      CONST1_RTX (DFmode));
+	      emit_use (gen_rtx_REG (DFmode, regno));

Put the regno++ on its own line.

+	    }
+	  else

<....>

diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index affcd832b72b7d358347e7370265be492866bb90..f5033ef802c085bd0ce479bc7026db96d9e25632 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1114,12 +1114,31 @@
  
  (define_insn "*thumb2_return"
    [(simple_return)]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
    "* return output_return_instruction (const_true_rtx, true, false, true);"
    [(set_attr "type" "branch")
     (set_attr "length" "4")]
  )
  
+(define_insn "*thumb2_return"
+  [(simple_return)]

I'd rather not have two patterns with the same name.
Call this *thumb2_cmse_entry_return or something

+  "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
+  "* return output_return_instruction (const_true_rtx, true, false, true);"
+  [(set_attr "type" "branch")
+   ; This is a return from a cmse_nonsecure_entry function so code will be
+   ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+   ; we adapt the length accordingly.
+   (set (attr "length")
+     (if_then_else (match_test "TARGET_HARD_FLOAT")
+      (const_int 12)
+      (const_int 8)))
+   ; We do not support predicate execution of returns from cmse_nonsecure_entry
+   ; functions because we need to clear the APSR.  Since predicable has to be
+   ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
+   ; functions.
+   (set_attr "predicable" "no")]
+)

Ok with those changes.
Thanks,
Kyrill

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

* Re: [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic
  2016-10-25 16:30     ` Andre Vieira (lists)
@ 2016-11-09 10:27       ` Kyrill Tkachov
  2016-11-09 14:53         ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-11-09 10:27 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

Hi Andre,

On 25/10/16 17:30, Andre Vieira (lists) wrote:
> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>> On 25/07/16 14:28, Andre Vieira (lists) wrote:
>>> This patch adds support ARMv8-M's Security Extension's
>>> cmse_nonsecure_caller intrinsic. This intrinsic is used to check whether
>>> an entry function was called from a non-secure state.
>>> See Section 5.4.3 of ARM®v8-M Security Extensions: Requirements on
>>> Development Tools
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html)
>>> for further details.
>>>
>>> The FIXME in config/arm/arm_cmse.h is for a diagnostic message that is
>>> suggested in the ARMv8-M Security Extensions document mentioned above,
>>> to diagnose the use of the cmse_nonsecure_caller intrinsic outside of
>>> functions with the 'cmse_nonsecure_entry' attribute.  Checking whether
>>> the intrinsic is called from within such functions can easily be done
>>> inside 'arm_expand_builtin'. However, making the warning point to the
>>> right location is more complicated.  The ARMv8-M Security Extensions
>>> specification does mention that such a diagnostic might become
>>> mandatory, so I might have to pick this up later, otherwise it is left
>>> as a potential extra feature.
>>>
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/arm-builtins.c (arm_builtins): Define
>>>          ARM_BUILTIN_CMSE_NONSECURE_CALLER.
>>>          (bdesc_2arg): Add line for cmse_nonsecure_caller.
>>>          (arm_expand_builtin): Handle cmse_nonsecure_caller.
>>>          * config/arm/arm_cmse.h (cmse_nonsecure_caller): New.
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse-1.c: Add test for
>>>          cmse_nonsecure_caller.
>>>
>> Added more documentation as requested.
>>
>> ---
>>
>> This patch adds support ARMv8-M's Security Extension's
>> cmse_nonsecure_caller intrinsic. This intrinsic is used to check whether
>> an entry function was called from a non-secure state.
>> See Section 5.4.3 of ARM®v8-M Security Extensions: Requirements on
>> Development Tools
>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html)
>> for further details.
>>
>> The FIXME in config/arm/arm_cmse.h is for a diagnostic message that is
>> suggested in the ARMv8-M Security Extensions document mentioned above,
>> to diagnose the use of the cmse_nonsecure_caller intrinsic outside of
>> functions with the 'cmse_nonsecure_entry' attribute.  Checking whether
>> the intrinsic is called from within such functions can easily be done
>> inside 'arm_expand_builtin'. However, making the warning point to the
>> right location is more complicated.  The ARMv8-M Security Extensions
>> specification does mention that such a diagnostic might become
>> mandatory, so I might have to pick this up later, otherwise it is left
>> as a potential extra feature.
>>
>>
>> *** gcc/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config/arm/arm-builtins.c (arm_builtins): Define
>>          ARM_BUILTIN_CMSE_NONSECURE_CALLER.
>>          (bdesc_2arg): Add line for cmse_nonsecure_caller.
>>          (arm_expand_builtin): Handle cmse_nonsecure_caller.
>>          * config/arm/arm_cmse.h (cmse_nonsecure_caller): New.
>>          * doc/extend.texi (ARM ARMv8-M Security Extensions): New intrinsic.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * gcc.target/arm/cmse/cmse-1.c: Add test for
>>          cmse_nonsecure_caller.
>>
> Hi,
>
> Rebased previous patch on top of trunk as requested. No changes to
> ChangeLog.
>
> Cheers,
> Andre

@@ -1832,6 +1834,17 @@ arm_init_builtins (void)
  	= add_builtin_function ("__builtin_arm_stfscr", ftype_set_fpscr,
  				ARM_BUILTIN_SET_FPSCR, BUILT_IN_MD, NULL, NULL_TREE);
      }
+
+  if (arm_arch_cmse)
+    {
+      tree ftype_cmse_nonsecure_caller
+	= build_function_ty

Should this be use_cmse ?
This looks ok to me otherwise.
I believe patch [6/7] is the only one needing approval after this...

Kyrill

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

* Re: [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic
  2016-11-09 10:27       ` Kyrill Tkachov
@ 2016-11-09 14:53         ` Andre Vieira (lists)
  2016-11-30 12:06           ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-11-09 14:53 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches

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

On 09/11/16 10:26, Kyrill Tkachov wrote:
> 
> @@ -1832,6 +1834,17 @@ arm_init_builtins (void)
>      = add_builtin_function ("__builtin_arm_stfscr", ftype_set_fpscr,
>                  ARM_BUILTIN_SET_FPSCR, BUILT_IN_MD, NULL, NULL_TREE);
>      }
> +
> +  if (arm_arch_cmse)
> +    {
> +      tree ftype_cmse_nonsecure_caller
> +    = build_function_ty
> 
> Should this be use_cmse ?
> This looks ok to me otherwise.
> I believe patch [6/7] is the only one needing approval after this...
> 
> Kyrill

Hi,

Yeah it should indeed be 'use_cmse'. Here is the reworked version, no
changes to ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff7 --]
[-- Type: text/plain, Size: 4017 bytes --]

diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index e73043db6db69fa64bb1e72cf71a36d7169062db..232d2de52106324e9f22b535a1b02cb95a2294b7 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -528,6 +528,8 @@ enum arm_builtins
   ARM_BUILTIN_GET_FPSCR,
   ARM_BUILTIN_SET_FPSCR,
 
+  ARM_BUILTIN_CMSE_NONSECURE_CALLER,
+
 #undef CRYPTO1
 #undef CRYPTO2
 #undef CRYPTO3
@@ -1832,6 +1834,17 @@ arm_init_builtins (void)
 	= add_builtin_function ("__builtin_arm_stfscr", ftype_set_fpscr,
 				ARM_BUILTIN_SET_FPSCR, BUILT_IN_MD, NULL, NULL_TREE);
     }
+
+  if (use_cmse)
+    {
+      tree ftype_cmse_nonsecure_caller
+	= build_function_type_list (unsigned_type_node, NULL);
+      arm_builtin_decls[ARM_BUILTIN_CMSE_NONSECURE_CALLER]
+	= add_builtin_function ("__builtin_arm_cmse_nonsecure_caller",
+				ftype_cmse_nonsecure_caller,
+				ARM_BUILTIN_CMSE_NONSECURE_CALLER, BUILT_IN_MD,
+				NULL, NULL_TREE);
+    }
 }
 
 /* Return the ARM builtin for CODE.  */
@@ -2452,6 +2465,12 @@ arm_expand_builtin (tree exp,
       emit_insn (pat);
       return target;
 
+    case ARM_BUILTIN_CMSE_NONSECURE_CALLER:
+      target = gen_reg_rtx (SImode);
+      op0 = arm_return_addr (0, NULL_RTX);
+      emit_insn (gen_addsi3 (target, op0, const1_rtx));
+      return target;
+
     case ARM_BUILTIN_TEXTRMSB:
     case ARM_BUILTIN_TEXTRMUB:
     case ARM_BUILTIN_TEXTRMSH:
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
index 894343bb835b61e09c14668d45aa43a8693fd011..82b58b1c4f4a12ba6062e2cc2632653788d0eeb7 100644
--- a/gcc/config/arm/arm_cmse.h
+++ b/gcc/config/arm/arm_cmse.h
@@ -163,6 +163,13 @@ __attribute__ ((__always_inline__))
 cmse_TTAT (void *__p)
 __CMSE_TT_ASM (at)
 
+/* FIXME: diagnose use outside cmse_nonsecure_entry functions.  */
+__extension__ static __inline int __attribute__ ((__always_inline__))
+cmse_nonsecure_caller (void)
+{
+  return __builtin_arm_cmse_nonsecure_caller ();
+}
+
 #define CMSE_AU_NONSECURE	2
 #define CMSE_MPU_NONSECURE	16
 #define CMSE_NONSECURE		18
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 462e6c71e20791b35f02adabfc97b9b013fd296a..88f6e014c3def8e6a2d2452df5d4937a4f0dd1ef 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12625,6 +12625,7 @@ cmse_address_info_t cmse_TTAT_fptr (FPTR)
 void * cmse_check_address_range (void *, size_t, int)
 typeof(p) cmse_nsfptr_create (FPTR p)
 intptr_t cmse_is_nsfptr (FPTR)
+int cmse_nonsecure_caller (void)
 @end smallexample
 
 @node AVR Built-in Functions
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index d5b9a2d9d59569de170da814ae660e9fb2b943e7..ddcf12a30a6c1806969d239c448da81ccf49532e 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -65,3 +65,32 @@ int foo (char * p)
 /* { dg-final { scan-assembler-times "ttat " 2 } } */
 /* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
 /* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
+
+typedef int (*int_ret_funcptr_t) (void);
+typedef int __attribute__ ((cmse_nonsecure_call)) (*int_ret_nsfuncptr_t) (void);
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return cmse_nonsecure_caller ();
+}
+
+int __attribute__ ((cmse_nonsecure_entry))
+qux (int_ret_funcptr_t int_ret_funcptr)
+{
+  int_ret_nsfuncptr_t int_ret_nsfunc_ptr;
+
+  if (cmse_is_nsfptr (int_ret_funcptr))
+    {
+      int_ret_nsfunc_ptr = cmse_nsfptr_create (int_ret_funcptr);
+      return int_ret_nsfunc_ptr ();
+    }
+  return 0;
+}
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "\tcmse_nonsecure_caller" } } */
+/* { dg-final { scan-rtl-dump "and.*reg.*const_int 1" expand } } */
+/* { dg-final { scan-assembler "bic" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */

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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-10-27 10:01       ` Andre Vieira (lists)
@ 2016-11-09 14:54         ` Andre Vieira (lists)
  2016-11-11 11:52           ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-11-09 14:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 27/10/16 11:01, Andre Vieira (lists) wrote:
> On 25/10/16 17:30, Andre Vieira (lists) wrote:
>> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>>> On 25/07/16 14:26, Andre Vieira (lists) wrote:
>>>> This patch extends support for the ARMv8-M Security Extensions
>>>> 'cmse_nonsecure_call' to use a new library function
>>>> '__gnu_cmse_nonsecure_call'. This library function is responsible for
>>>> (without using r0-r3 or d0-d7):
>>>> 1) saving and clearing all callee-saved registers using the secure stack
>>>> 2) clearing the LSB of the address passed in r4 and using blxns to
>>>> 'jump' to it
>>>> 3) clearing ASPR, including the 'ge bits' if DSP is enabled
>>>> 4) clearing FPSCR if using non-soft float-abi
>>>> 5) restoring callee-saved registers.
>>>>
>>>> The decisions whether to include DSP 'ge bits' clearing and floating
>>>> point registers (single/double precision) all depends on the multilib used.
>>>>
>>>> See Section 5.5 of ARM®v8-M Security Extensions
>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>
>>>> *** gcc/ChangeLog ***
>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>         * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>>>>         (cmse_nonsecure_call_clear_caller_saved): New.
>>>>         (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>>>>         * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>>>>         * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>>>>         (call_value): Likewise.
>>>>         (nonsecure_call_internal): New.
>>>>         (nonsecure_call_value_internal): New.
>>>>         * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>>>>         (*nonsecure_call_value_reg_thumb1_v5): New.
>>>>         * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>>>>         (*nonsecure_call_value_reg_thumb2): New.
>>>>         * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
>>>>
>>>> *** libgcc/ChangeLog ***
>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>         * config/arm/cmse_nonsecure_call.S: New.
>>>> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
>>>>
>>>>
>>>> *** gcc/testsuite/ChangeLog ***
>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>         * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>>>>         * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>>>>         * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>>>>         * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>>>>         * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>>>>         * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>>>>         * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>>>>         * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>>>>         * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>>>>         * gcc.target/arm/cmse/baseline/cmse-11.c: New.
>>>> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>>>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>>>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
>>>>
>>>
>>> Updated this patch to correctly clear only the cumulative
>>> exception-status (0-4,7) and the condition code bits (28-31) of the FPSCR.
>>>
>>> ----
>>>
>>> This patch extends support for the ARMv8-M Security Extensions
>>> 'cmse_nonsecure_call' to use a new library function
>>> '__gnu_cmse_nonsecure_call'. This library function is responsible for
>>> (without using r0-r3 or d0-d7):
>>> 1) saving and clearing all callee-saved registers using the secure stack
>>> 2) clearing the LSB of the address passed in r4 and using blxns to
>>> 'jump' to it
>>> 3) clearing ASPR, including the 'ge bits' if DSP is enabled
>>> 4) clearing the cumulative exception-status (0-4, 7) and the condition
>>> bits (28-31) of the FPSCR if using non-soft float-abi
>>> 5) restoring callee-saved registers.
>>>
>>> The decisions whether to include DSP 'ge bits' clearing and floating
>>> point registers (single/double precision) all depends on the multilib used.
>>>
>>> See Section 5.5 of ARM®v8-M Security Extensions
>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>         * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>>>         (cmse_nonsecure_call_clear_caller_saved): New.
>>>         (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>>>         * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>>>         * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>>>         (call_value): Likewise.
>>>         (nonsecure_call_internal): New.
>>>         (nonsecure_call_value_internal): New.
>>>         * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>>>         (*nonsecure_call_value_reg_thumb1_v5): New.
>>>         * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>>>         (*nonsecure_call_value_reg_thumb2): New.
>>>         * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
>>>
>>> *** libgcc/ChangeLog ***
>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>         * config/arm/cmse_nonsecure_call.S: New.
>>> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
>>>
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>         * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>>>         * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>>>         * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>>>         * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>>>         * gcc.target/arm/cmse/baseline/cmse-11.c: New.
>>> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>>>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
>>>
>> Hi,
>>
>> Rebased previous patch on top of trunk as requested. No changes to
>> ChangeLog.
>>
>> Cheers,
>> Andre
>>
> 
> Hi,
> 
> Reworked the testcase for compiling without -mcmse to catch the warning
> added in 5/7. Also took the opportunity to improve the code in the
> cmse_nonsecure_call library wrapper.
> 
> Cheers,
> Andre
> 

Hi,

Fixed an issue when returning from cmse_nonsecure_call's. The ARMv8-M
Mainline variant was missing a branch back and changed the Baseline
variant to use bx, rather than blx when returning. I also noticed a
sub-optimal sequence for thumb-1 and changed it.

Cheers,
Andre

[-- Attachment #2: diff6 --]
[-- Type: text/plain, Size: 81853 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index a9b8326c2770c1f9a9787743cb5faa549e6b7d02..2660bc3ba89c34b17911680c4e25eb2f6c0745fb 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -135,6 +135,7 @@ extern int arm_const_double_inline_cost (rtx);
 extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
+bool detect_cmse_nonsecure_call (tree);
 extern const char *output_call (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9e5656eeb13992c6d7837d21c9e049e264c7b9c0..6a47d3af41ba02b5dcba5f2e7411380e3f0343ee 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17850,6 +17850,197 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Saves callee saved registers, clears callee saved registers and caller saved
+   registers not used to pass arguments before a cmse_nonsecure_call.  And
+   restores the callee saved registers after.  */
+
+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  uint64_t to_clear_mask, float_mask;
+	  rtx_insn *seq;
+	  rtx pat, call, unspec, reg, cleared_reg, tmp;
+	  unsigned int regno, maxregno;
+	  rtx address;
+	  CUMULATIVE_ARGS args_so_far_v;
+	  cumulative_args_t args_so_far;
+	  tree arg_type, fntype;
+	  bool using_r4, first_param = true;
+	  function_args_iterator args_iter;
+	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
+	  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
+
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  if (!CALL_P (insn))
+	    continue;
+
+	  pat = PATTERN (insn);
+	  gcc_assert (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 0);
+	  call = XVECEXP (pat, 0, 0);
+
+	  /* Get the real call RTX if the insn sets a value, ie. returns.  */
+	  if (GET_CODE (call) == SET)
+	      call = SET_SRC (call);
+
+	  /* Check if it is a cmse_nonsecure_call.  */
+	  unspec = XEXP (call, 0);
+	  if (GET_CODE (unspec) != UNSPEC
+	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
+	    continue;
+
+	  /* Determine the caller-saved registers we need to clear.  */
+	  to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
+	  maxregno = NUM_ARG_REGS - 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
+	     lazy store and loads which clear both caller- and callee-saved
+	     registers.  */
+	  if (TARGET_HARD_FLOAT_ABI)
+	    {
+	      float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
+	      float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
+	      to_clear_mask |= float_mask;
+	      maxregno = D7_VFP_REGNUM;
+	    }
+
+	  /* Make sure the register used to hold the function address is not
+	     cleared.  */
+	  address = RTVEC_ELT (XVEC (unspec, 0), 0);
+	  gcc_assert (MEM_P (address));
+	  gcc_assert (REG_P (XEXP (address, 0)));
+	  to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+
+	  /* Set basic block of call insn so that df rescan is performed on
+	     insns inserted here.  */
+	  set_block_for_insn (insn, bb);
+	  df_set_flags (DF_DEFER_INSN_RESCAN);
+	  start_sequence ();
+
+	  /* Make sure the scheduler doesn't schedule other insns beyond
+	     here.  */
+	  emit_insn (gen_blockage ());
+
+	  /* Walk through all arguments and clear registers appropriately.
+	  */
+	  fntype = TREE_TYPE (MEM_EXPR (address));
+	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
+				    NULL_TREE);
+	  args_so_far = pack_cumulative_args (&args_so_far_v);
+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask &=
+		~compute_not_to_clear_mask (arg_type, arg_rtx,
+					      REGNO (arg_rtx),
+					      padding_bits_to_clear_ptr);
+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = 0; regno < NUM_ARG_REGS; regno++)
+	    {
+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = 0; regno <= maxregno; regno++)
+	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST1_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST1_RTX (SFmode));
+		}
+	      else
+		emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+	    }
+
+	  seq = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (seq, insn);
+
+	}
+    }
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -18150,6 +18341,8 @@ arm_reorg (void)
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
+  if (use_cmse)
+    cmse_nonsecure_call_clear_caller_saved ();
   if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
@@ -18522,6 +18715,23 @@ vfp_emit_fstmd (int base_reg, int count)
   return count * 8;
 }
 
+/* Returns true if -mcmse has been passed and the function pointed to by 'addr'
+   has the cmse_nonsecure_call attribute and returns false otherwise.  */
+
+bool
+detect_cmse_nonsecure_call (tree addr)
+{
+  if (!addr)
+    return FALSE;
+
+  tree fntype = TREE_TYPE (addr);
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_call",
+				    TYPE_ATTRIBUTES (fntype)))
+    return TRUE;
+  return FALSE;
+}
+
+
 /* Emit a call instruction with pattern PAT.  ADDR is the address of
    the call target.  */
 
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 8393f65bcf4c9c3e61b91e5adcd5f59ff7c6ec3f..3e65a43d39fb20061ee531d58fd21fbbc9cd1bde 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -8024,6 +8024,7 @@
   "
   {
     rtx callee, pat;
+    tree addr = MEM_EXPR (operands[0]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[2] == NULL_RTX)
@@ -8038,8 +8039,17 @@
 	: !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_internal (operands[0], operands[1], operands[2]);
-    arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_internal (operands[0], operands[1],
+					   operands[2]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_internal (operands[0], operands[1], operands[2]);
+	arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+      }
     DONE;
   }"
 )
@@ -8050,6 +8060,24 @@
 	      (use (match_operand 2 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_internal"
+  [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand" "")]
+			       UNSPEC_NONSECURE_MEM)
+		    (match_operand 1 "general_operand" ""))
+	      (use (match_operand 2 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[0] = replace_equiv_address (operands[0], tmp);
+  }")
+
 (define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
@@ -8085,6 +8113,7 @@
   "
   {
     rtx pat, callee;
+    tree addr = MEM_EXPR (operands[1]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
@@ -8099,9 +8128,18 @@
 	: !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_value_internal (operands[0], operands[1],
-				   operands[2], operands[3]);
-    arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_value_internal (operands[0], operands[1],
+						 operands[2], operands[3]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_value_internal (operands[0], operands[1],
+				       operands[2], operands[3]);
+	arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+      }
     DONE;
   }"
 )
@@ -8113,6 +8151,25 @@
 	      (use (match_operand 3 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_value_internal"
+  [(parallel [(set (match_operand       0 "" "")
+		   (call (unspec:SI [(match_operand 1 "memory_operand" "")]
+				    UNSPEC_NONSECURE_MEM)
+			 (match_operand 2 "general_operand" "")))
+	      (use (match_operand 3 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[1] = replace_equiv_address (operands[1], tmp);
+  }")
+
 (define_insn "*call_value_reg_armv5"
   [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 433fc79ae5810a4d3eb45d1ba80872a39e157e14..63a400fbfd8015cbd5a70252e24beacde4a5354d 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1705,6 +1705,19 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb1_v5"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_reg_thumb1"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
 	 (match_operand 1 "" ""))
@@ -1737,6 +1750,21 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb1_v5"
+  [(set (match_operand 0 "" "")
+	(call (unspec:SI
+	       [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+	       UNSPEC_NONSECURE_MEM)
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB1 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb1"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index f5033ef802c085bd0ce479bc7026db96d9e25632..8618dc31b44f2a7f0e3b0cc60fd226859e7545ae 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -580,6 +580,19 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
@@ -591,6 +604,21 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+	(call
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "register_operand" "l*r"))]
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index bee8795f007accc623c82b73c41a8619ebc29209..1aa39e8e0b9ddf17bb535c4d82959e569d3c9fd5 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -84,6 +84,8 @@
   UNSPEC_VRINTA         ; Represent a float to integral float rounding
                         ; towards nearest, ties away from zero.
   UNSPEC_PROBE_STACK    ; Probe stack memory reference
+  UNSPEC_NONSECURE_MEM	; Represent non-secure memory in ARMv8-M with
+			; security extension
 ])
 
 (define_c_enum "unspec" [
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6c1386c06edbdb58e76fa5e612c918010c507f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51ce2d42c051aeda8b06ad97086f2563a5fc47d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e9104b546a7693fcb2399622e828b1197eac1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 1023" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "movt\tr4, 32767" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d8941bbfeebd59744c43f10c842816b36ec9915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ffbb718d34d5bb8f10e1f3c0505c7dc393c670c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a6141829237823b8734de045a590a1917fa60b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #1799" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..642f4e0346b5186c78645780b45fe9c838848d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #7939" } } */
+/* { dg-final { scan-assembler "movt\tr4, 15" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, 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/baseline/cmse-11.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
new file mode 100644
index 0000000000000000000000000000000000000000..3007409ad88b9d2312ece4d55f3695787a1aa566
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+
+int
+foo (int a)
+{
+  return bar (bar (a + 1));
+}
+
+/* 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 "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\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/baseline/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2b931be5912b421f8427535ded3298883bec639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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 "movs\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmovs\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmovs\tr2, r4\n\tmovs\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/baseline/cmse-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..95da045690ae170a101949134482e821f27fe3aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* Remember dont clear r0 and r1, because we are passing the double parameter
+ * for bar in them.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, 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/baseline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff18e839b02c19c2c77769b18ef5ee1cfacf0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8063" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2e024b7f0776381f511077af91bd1ee5632ff12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
index 1d97f0e1a37209bd129ffe96ce92a86bc2e0d5d1..9e81e30c891bbc1f9d2d1d68d03bacad9ce65fe1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -2,11 +2,19 @@
 /* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
 
 
+void __attribute__ ((cmse_nonsecure_call)) (*bar) (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+typedef void __attribute__ ((cmse_nonsecure_call)) baz (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+
 int __attribute__ ((cmse_nonsecure_entry))
-foo (int a)
+foo (int a, baz b)
 { /* { dg-warning "attribute ignored without -mcmse option" } */
+  bar (a);
+  b (a);
   return a + 1;
 }
 
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler-not "blxns" } } */
+/* { dg-final { scan-assembler-not "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 38f18414c2fefec56161e6ac3f7291b03a3b29a3..66a8b7da005f7dfeffbded61b02fd6a7473a1dcf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -50,6 +50,8 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
+	    "" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
 	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b1396d52e742a1710ed5ad33fbeb559d866f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d029044aa9aa1d412c28ee5d18a8e3d0be36546
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..005515ab9cb85c201a2a8b2f6417d73ceeacbc60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dd218e62fdee2a6af819079ba1ea1909185d076
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { 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/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..c833bcb0ae978572fad46780bc180f61ccb14345
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cdb8c44b19c811f3a7b4fbce102a6c768f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e139ba61af57f06cff5a9d121c97bbf41e170bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { 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/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..285fa854b3d61c4d856e9be863ee73a87f1b11a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f56aaf2a97e740a77473cab245614b6fa696c04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..749f8a7278cb4ea9fd4462887ce7f37b57f83248
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad5068aac263f1c2edb17b8707fc9d1c0af6959
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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\.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/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..b18259eaef6da1933ef2d58d63b97d4bb4e450f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..182ddf9540374f30ae3694259f1edb62161455e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd262c89085eb0dc8737ad7955c3a12531492b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..e33568400ef830abaa019b5c2727a9f3b5d5704b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..024a12e0a414730eb1cbebfca8574d548238ab28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb195eb58d59fe9ea5ed74af79646199c61bcdae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..22ed3f8af882f96da49919c60fc6f4cd74dfc54b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634065e7cb64a5069cbb3c9be4b8cf9177f5e29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..04f8466cc112c03ee5a05e6e5223d2c66a033bbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffe94de85417b81f9dcb366eb1b40dc1661c91b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc846cd7a51303ec00f8f512a54cd697fbd0682
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d0f136ef171111c1cca6cd24c4f46b9fcb7fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/libgcc/config/arm/cmse_nonsecure_call.S b/libgcc/config/arm/cmse_nonsecure_call.S
new file mode 100644
index 0000000000000000000000000000000000000000..866da761d6c0983f6ff6458ec0523960ae9a5ea5
--- /dev/null
+++ b/libgcc/config/arm/cmse_nonsecure_call.S
@@ -0,0 +1,133 @@
+/* CMSE wrapper function used to save, clear and restore callee saved registers
+   for cmse_nonsecure_call's.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+.syntax unified
+.thumb
+.global __gnu_cmse_nonsecure_call
+__gnu_cmse_nonsecure_call:
+#if defined(__ARM_ARCH_8M_MAIN__)
+push	    {r5-r11,lr}
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+
+/* Save and clear callee-saved registers only if we are dealing with hard float
+   ABI.  The unused caller-saved registers have already been cleared by GCC
+   generated code.  */
+#ifdef __ARM_PCS_VFP
+vpush.f64   {d8-d15}
+#if __ARM_FP & 0x04
+mov	    r5, #0
+mov	    r6, #0
+vmov	    s16, s17, r5, r6
+vmov	    s18, s19, r5, r6
+vmov	    s20, s21, r5, r6
+vmov	    s22, s23, r5, r6
+vmov	    s24, s25, r5, r6
+vmov	    s26, s27, r5, r6
+vmov	    s28, s29, r5, r6
+vmov	    s30, s31, r5, r6
+#elif __ARM_FP & 0x08
+vmov.f64    d8, #0.00000
+vmov.f64    d9, #0.00000
+vmov.f64    d10, #0.00000
+vmov.f64    d11, #0.00000
+vmov.f64    d12, #0.00000
+vmov.f64    d13, #0.00000
+vmov.f64    d14, #0.00000
+vmov.f64    d15, #0.00000
+#else
+#error "Half precision implementation not supported."
+#endif
+/* Clear the cumulative exception-status bits (0-4,7) and the
+   condition code bits (28-31) of the FPSCR.  */
+vmrs	    r5, fpscr
+movw	    r6, #65376
+movt	    r6, #4095
+ands	    r5, r6
+vmsr	    fpscr, r5
+
+/* We are not dealing with hard float ABI, so we can safely use the vlstm and
+   vlldm instructions without needing to preserve the registers used for
+   argument passing.  */
+#else
+sub	    sp, sp, #0x88 /* Reserve stack space to save all floating point
+			     registers, including FPSCR.  */
+vlstm	    sp		  /* Lazy store and clearance of d0-d16 and FPSCR.  */
+#endif /* __ARM_PCS_VFP */
+
+/* Make sure to clear the 'GE' bits of the APSR register if 32-bit SIMD
+   instructions are available.  */
+#if defined(__ARM_FEATURE_SIMD32)
+msr	    APSR_nzcvqg, r4
+#else
+msr	    APSR_nzcvq, r4
+#endif
+
+mov	    r5, r4
+mov	    r6, r4
+blxns	    r4
+
+#ifdef __ARM_PCS_VFP
+vpop.f64    {d8-d15}
+#else
+vlldm	    sp		  /* Lazy restore of d0-d16 and FPSCR.  */
+add	    sp, sp, #0x88 /* Free space used to save floating point registers.  */
+#endif /* __ARM_PCS_VFP */
+
+pop	    {r5-r11, pc}
+
+#elif defined (__ARM_ARCH_8M_BASE__)
+push	    {r5-r7, lr}
+mov	    r5, r8
+mov	    r6, r9
+mov	    r7, r10
+push	    {r5-r7}
+mov	    r5, r11
+push	    {r5}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+msr	    APSR_nzcvq, r4
+blxns	    r4
+pop	    {r5}
+mov	    r11, r5
+pop	    {r5-r7}
+mov	    r10, r7
+mov	    r9, r6
+mov	    r8, r5
+pop	    {r5-r7, pc}
+
+#else
+#error "This should only be used for armv8-m base- and mainline."
+#endif
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 5618143bfd0f02b170db3f9e4c0a15cecb403cec..9e85ac06b146feaa14ab83374a0156737b870310 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -12,4 +12,6 @@ libgcc-objects += cmse.o cmse_nonsecure_call.o
 
 cmse.o: $(srcdir)/config/arm/cmse.c
 	$(gcc_compile) -c $(CMSE_OPTS) $<
+cmse_nonsecure_call.o: $(srcdir)/config/arm/cmse_nonsecure_call.S
+		       $(gcc_compile) -c $<
 endif

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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-11-09 14:54         ` Andre Vieira (lists)
@ 2016-11-11 11:52           ` Kyrill Tkachov
  2016-11-11 16:15             ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-11-11 11:52 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 09/11/16 14:53, Andre Vieira (lists) wrote:
> On 27/10/16 11:01, Andre Vieira (lists) wrote:
>> On 25/10/16 17:30, Andre Vieira (lists) wrote:
>>> On 24/08/16 12:01, Andre Vieira (lists) wrote:
>>>> On 25/07/16 14:26, Andre Vieira (lists) wrote:
>>>>> This patch extends support for the ARMv8-M Security Extensions
>>>>> 'cmse_nonsecure_call' to use a new library function
>>>>> '__gnu_cmse_nonsecure_call'. This library function is responsible for
>>>>> (without using r0-r3 or d0-d7):
>>>>> 1) saving and clearing all callee-saved registers using the secure stack
>>>>> 2) clearing the LSB of the address passed in r4 and using blxns to
>>>>> 'jump' to it
>>>>> 3) clearing ASPR, including the 'ge bits' if DSP is enabled
>>>>> 4) clearing FPSCR if using non-soft float-abi
>>>>> 5) restoring callee-saved registers.
>>>>>
>>>>> The decisions whether to include DSP 'ge bits' clearing and floating
>>>>> point registers (single/double precision) all depends on the multilib used.
>>>>>
>>>>> See Section 5.5 of ARM®v8-M Security Extensions
>>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>>
>>>>> *** gcc/ChangeLog ***
>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>
>>>>>          * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>>>>>          (cmse_nonsecure_call_clear_caller_saved): New.
>>>>>          (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>>>>>          * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>>>>>          * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>>>>>          (call_value): Likewise.
>>>>>          (nonsecure_call_internal): New.
>>>>>          (nonsecure_call_value_internal): New.
>>>>>          * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>>>>>          (*nonsecure_call_value_reg_thumb1_v5): New.
>>>>>          * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>>>>>          (*nonsecure_call_value_reg_thumb2): New.
>>>>>          * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
>>>>>
>>>>> *** libgcc/ChangeLog ***
>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>
>>>>>          * config/arm/cmse_nonsecure_call.S: New.
>>>>> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
>>>>>
>>>>>
>>>>> *** gcc/testsuite/ChangeLog ***
>>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>>
>>>>>          * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>>>>>          * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>>>>>          * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>>>>>          * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>>>>>          * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>>>>>          * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>>>>>          * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>>>>>          * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>>>>>          * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>>>>>          * gcc.target/arm/cmse/baseline/cmse-11.c: New.
>>>>> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
>>>>> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>>>>>          * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>>>>>          * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
>>>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
>>>>>
>>>> Updated this patch to correctly clear only the cumulative
>>>> exception-status (0-4,7) and the condition code bits (28-31) of the FPSCR.
>>>>
>>>> ----
>>>>
>>>> This patch extends support for the ARMv8-M Security Extensions
>>>> 'cmse_nonsecure_call' to use a new library function
>>>> '__gnu_cmse_nonsecure_call'. This library function is responsible for
>>>> (without using r0-r3 or d0-d7):
>>>> 1) saving and clearing all callee-saved registers using the secure stack
>>>> 2) clearing the LSB of the address passed in r4 and using blxns to
>>>> 'jump' to it
>>>> 3) clearing ASPR, including the 'ge bits' if DSP is enabled
>>>> 4) clearing the cumulative exception-status (0-4, 7) and the condition
>>>> bits (28-31) of the FPSCR if using non-soft float-abi
>>>> 5) restoring callee-saved registers.
>>>>
>>>> The decisions whether to include DSP 'ge bits' clearing and floating
>>>> point registers (single/double precision) all depends on the multilib used.
>>>>
>>>> See Section 5.5 of ARM®v8-M Security Extensions
>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>
>>>> *** gcc/ChangeLog ***
>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>          * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>>>>          (cmse_nonsecure_call_clear_caller_saved): New.
>>>>          (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>>>>          * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>>>>          * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>>>>          (call_value): Likewise.
>>>>          (nonsecure_call_internal): New.
>>>>          (nonsecure_call_value_internal): New.
>>>>          * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>>>>          (*nonsecure_call_value_reg_thumb1_v5): New.
>>>>          * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>>>>          (*nonsecure_call_value_reg_thumb2): New.
>>>>          * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
>>>>
>>>> *** libgcc/ChangeLog ***
>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>          * config/arm/cmse_nonsecure_call.S: New.
>>>> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
>>>>
>>>>
>>>> *** gcc/testsuite/ChangeLog ***
>>>> 2016-07-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>          * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>>>>          * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>>>>          * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>>>>          * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>>>>          * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>>>>          * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>>>>          * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>>>>          * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>>>>          * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>>>>          * gcc.target/arm/cmse/baseline/cmse-11.c: New.
>>>> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>>>>          * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>>>>          * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
>>>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
>>>>
>>> Hi,
>>>
>>> Rebased previous patch on top of trunk as requested. No changes to
>>> ChangeLog.
>>>
>>> Cheers,
>>> Andre
>>>
>> Hi,
>>
>> Reworked the testcase for compiling without -mcmse to catch the warning
>> added in 5/7. Also took the opportunity to improve the code in the
>> cmse_nonsecure_call library wrapper.
>>
>> Cheers,
>> Andre
>>
> Hi,
>
> Fixed an issue when returning from cmse_nonsecure_call's. The ARMv8-M
> Mainline variant was missing a branch back and changed the Baseline
> variant to use bx, rather than blx when returning. I also noticed a
> sub-optimal sequence for thumb-1 and changed it.
>
> Cheers,
> Andre

+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+

  <...>

+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask &=
+		~compute_not_to_clear_mask (arg_type, arg_rtx,
+					      REGNO (arg_rtx),
+					      padding_bits_to_clear_ptr);

I believe the convention in GCC is to put the "&=" on the next line.

+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = 0; regno < NUM_ARG_REGS; regno++)
+	    {

Please use regno = R0_REGNUM.

+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = 0; regno <= maxregno; regno++)

Same here.

  +	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST1_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST1_RTX (SFmode));

Why are you writing 1.0 to clear the register? I think you want CONST0_RTX (DFmode)
and CONST0_RTX (SFmode).

Also, in this function when you iterate from regno = 0 up to some number, please use
regno = R0_REGNUM (minor nit).

Thanks,
Kyrill


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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-11-11 11:52           ` Kyrill Tkachov
@ 2016-11-11 16:15             ` Andre Vieira (lists)
  2016-11-11 16:19               ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-11-11 16:15 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches

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


> Why are you writing 1.0 to clear the register? I think you want
> CONST0_RTX (DFmode)
> and CONST0_RTX (SFmode).
> 
> Also, in this function when you iterate from regno = 0 up to some
> number, please use
> regno = R0_REGNUM (minor nit).
> 
> Thanks,
> Kyrill
> 
> 
Hi Kyrill,

So you got me thinking there. I couldn't quite remember why I had chosen
1.0 rather than 0 to clear the FP registers. I now know it is because
vmov (immediate) will not take 0.0, it does take 1.0. I made the other
changes you suggested and changed the vmovs in the library function
wrapper back to #1.0. I also removed the second register for the single
precision FP clearing, since the vmov from two general registers to two
single precision registers can take the same general register twice,
saving on a mov. There is a discrepancy there with the way I clear other
FP registers, there I do use 0, since I'd need two moves(or a move and a
shift) to encode 1.0 into a general purpose register, so I made a
conscious choice of performance over consistency there.

Again no changes to ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff6 --]
[-- Type: text/plain, Size: 81855 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index a9b8326c2770c1f9a9787743cb5faa549e6b7d02..2660bc3ba89c34b17911680c4e25eb2f6c0745fb 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -135,6 +135,7 @@ extern int arm_const_double_inline_cost (rtx);
 extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
+bool detect_cmse_nonsecure_call (tree);
 extern const char *output_call (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9e5656eeb13992c6d7837d21c9e049e264c7b9c0..9c4809af09b9d53e1c8a7aba3525a969f3b10a60 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17850,6 +17850,197 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Saves callee saved registers, clears callee saved registers and caller saved
+   registers not used to pass arguments before a cmse_nonsecure_call.  And
+   restores the callee saved registers after.  */
+
+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  uint64_t to_clear_mask, float_mask;
+	  rtx_insn *seq;
+	  rtx pat, call, unspec, reg, cleared_reg, tmp;
+	  unsigned int regno, maxregno;
+	  rtx address;
+	  CUMULATIVE_ARGS args_so_far_v;
+	  cumulative_args_t args_so_far;
+	  tree arg_type, fntype;
+	  bool using_r4, first_param = true;
+	  function_args_iterator args_iter;
+	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
+	  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
+
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  if (!CALL_P (insn))
+	    continue;
+
+	  pat = PATTERN (insn);
+	  gcc_assert (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 0);
+	  call = XVECEXP (pat, 0, 0);
+
+	  /* Get the real call RTX if the insn sets a value, ie. returns.  */
+	  if (GET_CODE (call) == SET)
+	      call = SET_SRC (call);
+
+	  /* Check if it is a cmse_nonsecure_call.  */
+	  unspec = XEXP (call, 0);
+	  if (GET_CODE (unspec) != UNSPEC
+	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
+	    continue;
+
+	  /* Determine the caller-saved registers we need to clear.  */
+	  to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
+	  maxregno = NUM_ARG_REGS - 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
+	     lazy store and loads which clear both caller- and callee-saved
+	     registers.  */
+	  if (TARGET_HARD_FLOAT_ABI)
+	    {
+	      float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
+	      float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
+	      to_clear_mask |= float_mask;
+	      maxregno = D7_VFP_REGNUM;
+	    }
+
+	  /* Make sure the register used to hold the function address is not
+	     cleared.  */
+	  address = RTVEC_ELT (XVEC (unspec, 0), 0);
+	  gcc_assert (MEM_P (address));
+	  gcc_assert (REG_P (XEXP (address, 0)));
+	  to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+
+	  /* Set basic block of call insn so that df rescan is performed on
+	     insns inserted here.  */
+	  set_block_for_insn (insn, bb);
+	  df_set_flags (DF_DEFER_INSN_RESCAN);
+	  start_sequence ();
+
+	  /* Make sure the scheduler doesn't schedule other insns beyond
+	     here.  */
+	  emit_insn (gen_blockage ());
+
+	  /* Walk through all arguments and clear registers appropriately.
+	  */
+	  fntype = TREE_TYPE (MEM_EXPR (address));
+	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
+				    NULL_TREE);
+	  args_so_far = pack_cumulative_args (&args_so_far_v);
+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask
+		&= ~compute_not_to_clear_mask (arg_type, arg_rtx,
+					       REGNO (arg_rtx),
+					       padding_bits_to_clear_ptr);
+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = R0_REGNUM; regno < NUM_ARG_REGS; regno++)
+	    {
+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = R0_REGNUM; regno <= maxregno; regno++)
+	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST1_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST1_RTX (SFmode));
+		}
+	      else
+		emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+	    }
+
+	  seq = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (seq, insn);
+
+	}
+    }
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -18150,6 +18341,8 @@ arm_reorg (void)
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
+  if (use_cmse)
+    cmse_nonsecure_call_clear_caller_saved ();
   if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
@@ -18522,6 +18715,23 @@ vfp_emit_fstmd (int base_reg, int count)
   return count * 8;
 }
 
+/* Returns true if -mcmse has been passed and the function pointed to by 'addr'
+   has the cmse_nonsecure_call attribute and returns false otherwise.  */
+
+bool
+detect_cmse_nonsecure_call (tree addr)
+{
+  if (!addr)
+    return FALSE;
+
+  tree fntype = TREE_TYPE (addr);
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_call",
+				    TYPE_ATTRIBUTES (fntype)))
+    return TRUE;
+  return FALSE;
+}
+
+
 /* Emit a call instruction with pattern PAT.  ADDR is the address of
    the call target.  */
 
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 8393f65bcf4c9c3e61b91e5adcd5f59ff7c6ec3f..3e65a43d39fb20061ee531d58fd21fbbc9cd1bde 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -8024,6 +8024,7 @@
   "
   {
     rtx callee, pat;
+    tree addr = MEM_EXPR (operands[0]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[2] == NULL_RTX)
@@ -8038,8 +8039,17 @@
 	: !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_internal (operands[0], operands[1], operands[2]);
-    arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_internal (operands[0], operands[1],
+					   operands[2]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_internal (operands[0], operands[1], operands[2]);
+	arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+      }
     DONE;
   }"
 )
@@ -8050,6 +8060,24 @@
 	      (use (match_operand 2 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_internal"
+  [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand" "")]
+			       UNSPEC_NONSECURE_MEM)
+		    (match_operand 1 "general_operand" ""))
+	      (use (match_operand 2 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[0] = replace_equiv_address (operands[0], tmp);
+  }")
+
 (define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
@@ -8085,6 +8113,7 @@
   "
   {
     rtx pat, callee;
+    tree addr = MEM_EXPR (operands[1]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
@@ -8099,9 +8128,18 @@
 	: !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_value_internal (operands[0], operands[1],
-				   operands[2], operands[3]);
-    arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_value_internal (operands[0], operands[1],
+						 operands[2], operands[3]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_value_internal (operands[0], operands[1],
+				       operands[2], operands[3]);
+	arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+      }
     DONE;
   }"
 )
@@ -8113,6 +8151,25 @@
 	      (use (match_operand 3 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_value_internal"
+  [(parallel [(set (match_operand       0 "" "")
+		   (call (unspec:SI [(match_operand 1 "memory_operand" "")]
+				    UNSPEC_NONSECURE_MEM)
+			 (match_operand 2 "general_operand" "")))
+	      (use (match_operand 3 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[1] = replace_equiv_address (operands[1], tmp);
+  }")
+
 (define_insn "*call_value_reg_armv5"
   [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 433fc79ae5810a4d3eb45d1ba80872a39e157e14..63a400fbfd8015cbd5a70252e24beacde4a5354d 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1705,6 +1705,19 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb1_v5"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_reg_thumb1"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
 	 (match_operand 1 "" ""))
@@ -1737,6 +1750,21 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb1_v5"
+  [(set (match_operand 0 "" "")
+	(call (unspec:SI
+	       [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+	       UNSPEC_NONSECURE_MEM)
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB1 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb1"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index f5033ef802c085bd0ce479bc7026db96d9e25632..8618dc31b44f2a7f0e3b0cc60fd226859e7545ae 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -580,6 +580,19 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
@@ -591,6 +604,21 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+	(call
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "register_operand" "l*r"))]
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index bee8795f007accc623c82b73c41a8619ebc29209..1aa39e8e0b9ddf17bb535c4d82959e569d3c9fd5 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -84,6 +84,8 @@
   UNSPEC_VRINTA         ; Represent a float to integral float rounding
                         ; towards nearest, ties away from zero.
   UNSPEC_PROBE_STACK    ; Probe stack memory reference
+  UNSPEC_NONSECURE_MEM	; Represent non-secure memory in ARMv8-M with
+			; security extension
 ])
 
 (define_c_enum "unspec" [
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6c1386c06edbdb58e76fa5e612c918010c507f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51ce2d42c051aeda8b06ad97086f2563a5fc47d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e9104b546a7693fcb2399622e828b1197eac1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 1023" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "movt\tr4, 32767" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d8941bbfeebd59744c43f10c842816b36ec9915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ffbb718d34d5bb8f10e1f3c0505c7dc393c670c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a6141829237823b8734de045a590a1917fa60b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #1799" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..642f4e0346b5186c78645780b45fe9c838848d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #7939" } } */
+/* { dg-final { scan-assembler "movt\tr4, 15" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, 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/baseline/cmse-11.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
new file mode 100644
index 0000000000000000000000000000000000000000..3007409ad88b9d2312ece4d55f3695787a1aa566
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+
+int
+foo (int a)
+{
+  return bar (bar (a + 1));
+}
+
+/* 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 "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\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/baseline/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2b931be5912b421f8427535ded3298883bec639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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 "movs\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmovs\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmovs\tr2, r4\n\tmovs\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/baseline/cmse-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..95da045690ae170a101949134482e821f27fe3aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* Remember dont clear r0 and r1, because we are passing the double parameter
+ * for bar in them.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, 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/baseline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff18e839b02c19c2c77769b18ef5ee1cfacf0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8063" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2e024b7f0776381f511077af91bd1ee5632ff12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
index 1d97f0e1a37209bd129ffe96ce92a86bc2e0d5d1..9e81e30c891bbc1f9d2d1d68d03bacad9ce65fe1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -2,11 +2,19 @@
 /* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
 
 
+void __attribute__ ((cmse_nonsecure_call)) (*bar) (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+typedef void __attribute__ ((cmse_nonsecure_call)) baz (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+
 int __attribute__ ((cmse_nonsecure_entry))
-foo (int a)
+foo (int a, baz b)
 { /* { dg-warning "attribute ignored without -mcmse option" } */
+  bar (a);
+  b (a);
   return a + 1;
 }
 
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler-not "blxns" } } */
+/* { dg-final { scan-assembler-not "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 38f18414c2fefec56161e6ac3f7291b03a3b29a3..66a8b7da005f7dfeffbded61b02fd6a7473a1dcf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -50,6 +50,8 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
+	    "" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
 	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b1396d52e742a1710ed5ad33fbeb559d866f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d029044aa9aa1d412c28ee5d18a8e3d0be36546
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..005515ab9cb85c201a2a8b2f6417d73ceeacbc60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dd218e62fdee2a6af819079ba1ea1909185d076
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { 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/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..c833bcb0ae978572fad46780bc180f61ccb14345
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cdb8c44b19c811f3a7b4fbce102a6c768f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e139ba61af57f06cff5a9d121c97bbf41e170bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { 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/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..285fa854b3d61c4d856e9be863ee73a87f1b11a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f56aaf2a97e740a77473cab245614b6fa696c04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..749f8a7278cb4ea9fd4462887ce7f37b57f83248
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad5068aac263f1c2edb17b8707fc9d1c0af6959
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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\.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/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..b18259eaef6da1933ef2d58d63b97d4bb4e450f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..182ddf9540374f30ae3694259f1edb62161455e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd262c89085eb0dc8737ad7955c3a12531492b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..e33568400ef830abaa019b5c2727a9f3b5d5704b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..024a12e0a414730eb1cbebfca8574d548238ab28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb195eb58d59fe9ea5ed74af79646199c61bcdae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..22ed3f8af882f96da49919c60fc6f4cd74dfc54b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634065e7cb64a5069cbb3c9be4b8cf9177f5e29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..04f8466cc112c03ee5a05e6e5223d2c66a033bbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffe94de85417b81f9dcb366eb1b40dc1661c91b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc846cd7a51303ec00f8f512a54cd697fbd0682
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d0f136ef171111c1cca6cd24c4f46b9fcb7fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/libgcc/config/arm/cmse_nonsecure_call.S b/libgcc/config/arm/cmse_nonsecure_call.S
new file mode 100644
index 0000000000000000000000000000000000000000..fcde968508bb11114596e3e7dc73963e4067c7d9
--- /dev/null
+++ b/libgcc/config/arm/cmse_nonsecure_call.S
@@ -0,0 +1,132 @@
+/* CMSE wrapper function used to save, clear and restore callee saved registers
+   for cmse_nonsecure_call's.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+.syntax unified
+.thumb
+.global __gnu_cmse_nonsecure_call
+__gnu_cmse_nonsecure_call:
+#if defined(__ARM_ARCH_8M_MAIN__)
+push	    {r5-r11,lr}
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+
+/* Save and clear callee-saved registers only if we are dealing with hard float
+   ABI.  The unused caller-saved registers have already been cleared by GCC
+   generated code.  */
+#ifdef __ARM_PCS_VFP
+vpush.f64   {d8-d15}
+#if __ARM_FP & 0x04
+mov	    r5, #0
+vmov	    s16, s17, r5, r5
+vmov	    s18, s19, r5, r5
+vmov	    s20, s21, r5, r5
+vmov	    s22, s23, r5, r5
+vmov	    s24, s25, r5, r5
+vmov	    s26, s27, r5, r5
+vmov	    s28, s29, r5, r5
+vmov	    s30, s31, r5, r5
+#elif __ARM_FP & 0x08
+vmov.f64    d8, #1.00000
+vmov.f64    d9, #1.00000
+vmov.f64    d10, #1.00000
+vmov.f64    d11, #1.00000
+vmov.f64    d12, #1.00000
+vmov.f64    d13, #1.00000
+vmov.f64    d14, #1.00000
+vmov.f64    d15, #1.00000
+#else
+#error "Half precision implementation not supported."
+#endif
+/* Clear the cumulative exception-status bits (0-4,7) and the
+   condition code bits (28-31) of the FPSCR.  */
+vmrs	    r5, fpscr
+movw	    r6, #65376
+movt	    r6, #4095
+ands	    r5, r6
+vmsr	    fpscr, r5
+
+/* We are not dealing with hard float ABI, so we can safely use the vlstm and
+   vlldm instructions without needing to preserve the registers used for
+   argument passing.  */
+#else
+sub	    sp, sp, #0x88 /* Reserve stack space to save all floating point
+			     registers, including FPSCR.  */
+vlstm	    sp		  /* Lazy store and clearance of d0-d16 and FPSCR.  */
+#endif /* __ARM_PCS_VFP */
+
+/* Make sure to clear the 'GE' bits of the APSR register if 32-bit SIMD
+   instructions are available.  */
+#if defined(__ARM_FEATURE_SIMD32)
+msr	    APSR_nzcvqg, r4
+#else
+msr	    APSR_nzcvq, r4
+#endif
+
+mov	    r5, r4
+mov	    r6, r4
+blxns	    r4
+
+#ifdef __ARM_PCS_VFP
+vpop.f64    {d8-d15}
+#else
+vlldm	    sp		  /* Lazy restore of d0-d16 and FPSCR.  */
+add	    sp, sp, #0x88 /* Free space used to save floating point registers.  */
+#endif /* __ARM_PCS_VFP */
+
+pop	    {r5-r11, pc}
+
+#elif defined (__ARM_ARCH_8M_BASE__)
+push	    {r5-r7, lr}
+mov	    r5, r8
+mov	    r6, r9
+mov	    r7, r10
+push	    {r5-r7}
+mov	    r5, r11
+push	    {r5}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+msr	    APSR_nzcvq, r4
+blxns	    r4
+pop	    {r5}
+mov	    r11, r5
+pop	    {r5-r7}
+mov	    r10, r7
+mov	    r9, r6
+mov	    r8, r5
+pop	    {r5-r7, pc}
+
+#else
+#error "This should only be used for armv8-m base- and mainline."
+#endif
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 5618143bfd0f02b170db3f9e4c0a15cecb403cec..9e85ac06b146feaa14ab83374a0156737b870310 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -12,4 +12,6 @@ libgcc-objects += cmse.o cmse_nonsecure_call.o
 
 cmse.o: $(srcdir)/config/arm/cmse.c
 	$(gcc_compile) -c $(CMSE_OPTS) $<
+cmse_nonsecure_call.o: $(srcdir)/config/arm/cmse_nonsecure_call.S
+		       $(gcc_compile) -c $<
 endif

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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-11-11 16:19               ` Kyrill Tkachov
@ 2016-11-11 16:19                 ` Kyrill Tkachov
  2016-11-23 11:54                   ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-11-11 16:19 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches; +Cc: Ramana Radhakrishnan, Richard Earnshaw

And CC'ing Ramana and Richard this time...

On 11/11/16 16:18, Kyrill Tkachov wrote:
>
> On 11/11/16 16:15, Andre Vieira (lists) wrote:
>>> Why are you writing 1.0 to clear the register? I think you want
>>> CONST0_RTX (DFmode)
>>> and CONST0_RTX (SFmode).
>>>
>>> Also, in this function when you iterate from regno = 0 up to some
>>> number, please use
>>> regno = R0_REGNUM (minor nit).
>>>
>>> Thanks,
>>> Kyrill
>>>
>>>
>> Hi Kyrill,
>>
>> So you got me thinking there. I couldn't quite remember why I had chosen
>> 1.0 rather than 0 to clear the FP registers. I now know it is because
>> vmov (immediate) will not take 0.0, it does take 1.0.
>
> Ah, you're right (I checked it too).
>
>>   I made the other
>> changes you suggested and changed the vmovs in the library function
>> wrapper back to #1.0. I also removed the second register for the single
>> precision FP clearing, since the vmov from two general registers to two
>> single precision registers can take the same general register twice,
>> saving on a mov. There is a discrepancy there with the way I clear other
>> FP registers, there I do use 0, since I'd need two moves(or a move and a
>> shift) to encode 1.0 into a general purpose register, so I made a
>> conscious choice of performance over consistency there.
>
> Hmm, I'll defer to Ramana or Richard on whether we should keep consistent between SP and DP
> in libgcc/config/arm/cmse_nonsecure_call.S.
> Otherwise the patch looks good to me.
> Until this patch is approved by an arm maintainer can you please do a bootstrap and regtest
> on an arm-none-linux-gnueabihf target of all the patches in the series.
>
> Thanks,
> Kyrill
>> Again no changes to ChangeLog.
>>
>> Cheers,
>> Andre
>

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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-11-11 16:15             ` Andre Vieira (lists)
@ 2016-11-11 16:19               ` Kyrill Tkachov
  2016-11-11 16:19                 ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-11-11 16:19 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 11/11/16 16:15, Andre Vieira (lists) wrote:
>> Why are you writing 1.0 to clear the register? I think you want
>> CONST0_RTX (DFmode)
>> and CONST0_RTX (SFmode).
>>
>> Also, in this function when you iterate from regno = 0 up to some
>> number, please use
>> regno = R0_REGNUM (minor nit).
>>
>> Thanks,
>> Kyrill
>>
>>
> Hi Kyrill,
>
> So you got me thinking there. I couldn't quite remember why I had chosen
> 1.0 rather than 0 to clear the FP registers. I now know it is because
> vmov (immediate) will not take 0.0, it does take 1.0.

Ah, you're right (I checked it too).

>   I made the other
> changes you suggested and changed the vmovs in the library function
> wrapper back to #1.0. I also removed the second register for the single
> precision FP clearing, since the vmov from two general registers to two
> single precision registers can take the same general register twice,
> saving on a mov. There is a discrepancy there with the way I clear other
> FP registers, there I do use 0, since I'd need two moves(or a move and a
> shift) to encode 1.0 into a general purpose register, so I made a
> conscious choice of performance over consistency there.

Hmm, I'll defer to Ramana or Richard on whether we should keep consistent between SP and DP
in libgcc/config/arm/cmse_nonsecure_call.S.
Otherwise the patch looks good to me.
Until this patch is approved by an arm maintainer can you please do a bootstrap and regtest
on an arm-none-linux-gnueabihf target of all the patches in the series.

Thanks,
Kyrill
> Again no changes to ChangeLog.
>
> Cheers,
> Andre

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-11-08 12:16                   ` Kyrill Tkachov
@ 2016-11-23 11:52                     ` Andre Vieira (lists)
  2016-11-30 15:32                       ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-11-23 11:52 UTC (permalink / raw)
  To: Kyrill Tkachov, gcc-patches; +Cc: Kyrill Tkachov, Ramana Radhakrishnan

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

Hi,

After some extra testing I realized there was an issue with the way we
were clearing registers when returning from a cmse_nonsecure_entry
function for ARMv8-M.Baseline.  This patch fixes that and changes the
testcase to catch the issue.

The problem was I was always using LR to clear the registers, however,
due to the way the Thumb-1 backend works, we can't guarantee LR will
contain the address to which we will be returning at the time of
clearing. Instead we use r0 to clear r1-r3 and IP. If the function does
not use r0 to return a value, we clear r0 with 0 before using it to
clear everything else. As for LR, we move the value of the register used
to return into it prior to returning.

This satisfies the requirements of not leaking secure information since
all registers hold either:
- values to return
- 0
- return address

No changes to ChangeLog.

Cheers,
Andre

[-- Attachment #2: diff4 --]
[-- Type: text/plain, Size: 41223 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index fdbdd423236e7388802bc4bd568f260d95485bbe..0b93ece84b3ebab3c36beeb170a245c29453215d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17499,6 +17499,279 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
   return;
 }
 
+/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for structs
+   and unions in the context of ARMv8-M Security Extensions.  It is used as a
+   helper function for both 'cmse_nonsecure_call' and 'cmse_nonsecure_entry'
+   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to either one
+   or four masks, depending on whether it is being computed for a
+   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
+   respectively.  The tree for the type of the argument or a field within an
+   argument is passed in ARG_TYPE, the current register this argument or field
+   starts in is kept in the pointer REGNO and updated accordingly, the bit this
+   argument or field starts at is passed in STARTING_BIT and the last used bit
+   is kept in LAST_USED_BIT which is also updated accordingly.  */
+
+static unsigned HOST_WIDE_INT
+comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
+			       uint32_t * padding_bits_to_clear,
+			       unsigned starting_bit, int * last_used_bit)
+
+{
+  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
+
+  if (TREE_CODE (arg_type) == RECORD_TYPE)
+    {
+      unsigned current_bit = starting_bit;
+      tree field;
+      long int offset, size;
+
+
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  /* The offset within a structure is always an offset from
+	     the start of that structure.  Make sure we take that into the
+	     calculation of the register based offset that we use here.  */
+	  offset = starting_bit;
+	  offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
+	  offset %= 32;
+
+	  /* This is the actual size of the field, for bitfields this is the
+	     bitfield width and not the container size.  */
+	  size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+
+	  if (*last_used_bit != offset)
+	    {
+	      if (offset < *last_used_bit)
+		{
+		  /* This field's offset is before the 'last_used_bit', that
+		     means this field goes on the next register.  So we need to
+		     pad the rest of the current register and increase the
+		     register number.  */
+		  uint32_t mask;
+		  mask  = ((uint32_t)-1) - ((uint32_t) 1 << *last_used_bit);
+		  mask++;
+
+		  padding_bits_to_clear[*regno] |= mask;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      else
+		{
+		  /* Otherwise we pad the bits between the last field's end and
+		     the start of the new field.  */
+		  uint32_t mask;
+
+		  mask = ((uint32_t)-1) >> (32 - offset);
+		  mask -= ((uint32_t) 1 << *last_used_bit) - 1;
+		  padding_bits_to_clear[*regno] |= mask;
+		}
+	      current_bit = offset;
+	    }
+
+	  /* Calculate further padding bits for inner structs/unions too.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	    {
+	      *last_used_bit = current_bit;
+	      not_to_clear_reg_mask
+		|= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
+						  padding_bits_to_clear, offset,
+						  last_used_bit);
+	    }
+	  else
+	    {
+	      /* Update 'current_bit' with this field's size.  If the
+		 'current_bit' lies in a subsequent register, update 'regno' and
+		 reset 'current_bit' to point to the current bit in that new
+		 register.  */
+	      current_bit += size;
+	      while (current_bit >= 32)
+		{
+		  current_bit-=32;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      *last_used_bit = current_bit;
+	    }
+
+	  field = TREE_CHAIN (field);
+	}
+      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+    }
+  else if (TREE_CODE (arg_type) == UNION_TYPE)
+    {
+      tree field, field_t;
+      int i, regno_t, field_size;
+      int max_reg = -1;
+      int max_bit = -1;
+      uint32_t mask;
+      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
+	= {-1, -1, -1, -1};
+
+      /* To compute the padding bits in a union we only consider bits as
+	 padding bits if they are always either a padding bit or fall outside a
+	 fields size for all fields in the union.  */
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
+	    = {0U, 0U, 0U, 0U};
+	  int last_used_bit_t = *last_used_bit;
+	  regno_t = *regno;
+	  field_t = TREE_TYPE (field);
+
+	  /* If the field's type is either a record or a union make sure to
+	     compute their padding bits too.  */
+	  if (RECORD_OR_UNION_TYPE_P (field_t))
+	    not_to_clear_reg_mask
+	      |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
+						&padding_bits_to_clear_t[0],
+						starting_bit, &last_used_bit_t);
+	  else
+	    {
+	      field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+	      regno_t = (field_size / 32) + *regno;
+	      last_used_bit_t = (starting_bit + field_size) % 32;
+	    }
+
+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (((uint32_t) -1) - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;
+
+	  /* Update the maximum size of the fields in terms of registers used
+	     ('max_reg') and the 'last_used_bit' in said register.  */
+	  if (max_reg < regno_t)
+	    {
+	      max_reg = regno_t;
+	      max_bit = last_used_bit_t;
+	    }
+	  else if (max_reg == regno_t && max_bit < last_used_bit_t)
+	    max_bit = last_used_bit_t;
+
+	  field = TREE_CHAIN (field);
+	}
+
+      /* Update the current padding_bits_to_clear using the intersection of the
+	 padding bits of all the fields.  */
+      for (i=*regno; i < max_reg; i++)
+	padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+
+      /* Do not keep trailing padding bits, we do not know yet whether this
+	 is the end of the argument.  */
+      mask = ((uint32_t) 1 << max_bit) - 1;
+      padding_bits_to_clear[max_reg]
+	|= padding_bits_to_clear_res[max_reg] & mask;
+
+      *regno = max_reg;
+      *last_used_bit = max_bit;
+    }
+  else
+    /* This function should only be used for structs and unions.  */
+    gcc_unreachable ();
+
+  return not_to_clear_reg_mask;
+}
+
+/* In the context of ARMv8-M Security Extensions, this function is used for both
+   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to compute what
+   registers are used when returning or passing arguments, which is then
+   returned as a mask.  It will also compute a mask to indicate padding/unused
+   bits for each of these registers, and passes this through the
+   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is passed in
+   ARG_TYPE, the rtl representation of the argument is passed in ARG_RTX and
+   the starting register used to pass this argument or return value is passed
+   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to compute these
+   for struct and union types.  */
+
+static unsigned HOST_WIDE_INT
+compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
+			     uint32_t * padding_bits_to_clear)
+
+{
+  int last_used_bit = 0;
+  unsigned HOST_WIDE_INT not_to_clear_mask;
+
+  if (RECORD_OR_UNION_TYPE_P (arg_type))
+    {
+      not_to_clear_mask
+	= comp_not_to_clear_mask_str_un (arg_type, &regno,
+					 padding_bits_to_clear, 0,
+					 &last_used_bit);
+
+
+      /* If the 'last_used_bit' is not zero, that means we are still using a
+	 part of the last 'regno'.  In such cases we must clear the trailing
+	 bits.  Otherwise we are not using regno and we should mark it as to
+	 clear.  */
+      if (last_used_bit != 0)
+	padding_bits_to_clear[regno]
+	  |= ((uint32_t)-1) - ((uint32_t) 1 << last_used_bit) + 1;
+      else
+	not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
+    }
+  else
+    {
+      not_to_clear_mask = 0;
+      /* We are not dealing with structs nor unions.  So these arguments may be
+	 passed in floating point registers too.  In some cases a BLKmode is
+	 used when returning or passing arguments in multiple VFP registers.  */
+      if (GET_MODE (arg_rtx) == BLKmode)
+	{
+	  int i, arg_regs;
+	  rtx reg;
+
+	  /* This should really only occur when dealing with the hard-float
+	     ABI.  */
+	  gcc_assert (TARGET_HARD_FLOAT_ABI);
+
+	  for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
+	    {
+	      reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
+	      gcc_assert (REG_P (reg));
+
+	      not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
+
+	      /* If we are dealing with DF mode, make sure we don't
+		 clear either of the registers it addresses.  */
+	      arg_regs = ARM_NUM_REGS (GET_MODE (reg));
+	      if (arg_regs > 1)
+		{
+		  unsigned HOST_WIDE_INT mask;
+		  mask = HOST_WIDE_INT_1U << (REGNO (reg) + arg_regs);
+		  mask -= HOST_WIDE_INT_1U << REGNO (reg);
+		  not_to_clear_mask |= mask;
+		}
+	    }
+	}
+      else
+	{
+	  /* Otherwise we can rely on the MODE to determine how many registers
+	     are being used by this argument.  */
+	  int arg_regs = ARM_NUM_REGS (GET_MODE (arg_rtx));
+	  not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	  if (arg_regs > 1)
+	    {
+	      unsigned HOST_WIDE_INT
+	      mask = HOST_WIDE_INT_1U << (REGNO (arg_rtx) + arg_regs);
+	      mask -= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	      not_to_clear_mask |= mask;
+	    }
+	}
+    }
+
+  return not_to_clear_mask;
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -19920,7 +20193,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
-	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    {
+	      /* 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);
+	      if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+		{
+		  /* 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");
+		  output_asm_insn (instr, & operand);
+		}
+	      snprintf (instr, sizeof (instr), "bxns\t%%|lr");
+	    }
 	  /* Use bx if it's available.  */
 	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
@@ -24187,7 +24495,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
-	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	{
+	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+		       reg_containing_return_addr);
+	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	}
       else
 	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
@@ -24423,7 +24735,18 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
   /* Return to caller.  */
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
-    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    {
+      /* This is for the cases where LR is not being used to contain the return
+         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'.  */
+      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);
+      asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    }
   else
     asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
@@ -25285,6 +25608,148 @@ thumb1_expand_prologue (void)
     cfun->machine->lr_save_eliminated = 0;
 }
 
+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check that TARGET_HARD_FLOAT and !TARGET_THUMB1 hold
+     to make sure the instructions used to clear them are present.  */
+  if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      maxregno = LAST_VFP_REGNUM;
+
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask[0] |= float_mask;
+
+      float_mask = (1ULL << (maxregno - 63)) - 1;
+      to_clear_mask[1] = float_mask;
+
+      /* 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));
+      to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+      emit_use (gen_rtx_REG (SImode, 4));
+      to_clear_mask[0] &= ~(1ULL << 4);
+    }
+
+  /* If the user has defined registers to be caller saved, these are no longer
+     restored by the function before returning and must thus be cleared for
+     security purposes.  */
+  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+    {
+      /* We do not touch registers that can be used to pass arguments as per
+	 the AAPCS, since these should never be made callee-saved by user
+	 options.  */
+      if (IN_RANGE (regno, FIRST_VFP_REGNUM, D7_VFP_REGNUM))
+	continue;
+      if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
+	continue;
+      if (call_used_regs[regno])
+	to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+    }
+
+  /* Make sure we do not clear the registers used to return the result in.  */
+  result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+  if (!VOID_TYPE_P (result_type))
+    {
+      result_rtl = arm_function_value (result_type, current_function_decl, 0);
+
+      /* No need to check that we return in registers, because we don't
+	 support returning on stack yet.  */
+      to_clear_mask[0]
+	&= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
+				       padding_bits_to_clear_ptr);
+    }
+
+  if (padding_bits_to_clear != 0)
+    {
+      rtx reg_rtx;
+      /* Padding bits to clear is not 0 so we know we are dealing with
+	 returning a composite type, which only uses r0.  Let's make sure that
+	 r1-r3 is cleared too, we will use r1 as a scratch register.  */
+      gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
+
+      reg_rtx = gen_rtx_REG (SImode, R1_REGNUM);
+
+      /* Fill the lower half of the negated padding_bits_to_clear.  */
+      emit_move_insn (reg_rtx,
+		      GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
+
+      /* Also fill the top half of the negated padding_bits_to_clear.  */
+      if (((~padding_bits_to_clear) >> 16) > 0)
+	emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
+						      GEN_INT (16),
+						      GEN_INT (16)),
+				GEN_INT ((~padding_bits_to_clear) >> 16)));
+
+      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, R0_REGNUM),
+			   gen_rtx_REG (SImode, R0_REGNUM),
+			   reg_rtx));
+    }
+
+  for (regno = R0_REGNUM; regno <= maxregno; regno++)
+    {
+      if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
+	continue;
+
+      if (IS_VFP_REGNUM (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)
+	      && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 1)))
+	    {
+	      emit_move_insn (gen_rtx_REG (DFmode, regno++),
+			      CONST1_RTX (DFmode));
+	      emit_use (gen_rtx_REG (DFmode, regno));
+	    }
+	  else
+	    {
+	      emit_move_insn (gen_rtx_REG (SFmode, regno),
+			      CONST1_RTX (SFmode));
+	      emit_use (gen_rtx_REG (SFmode, regno));
+	    }
+	}
+      else
+	{
+	  if (TARGET_THUMB1)
+	    {
+	      if (regno == R0_REGNUM)
+		emit_move_insn (gen_rtx_REG (SImode, regno),
+				const0_rtx);
+	      else
+		/* R0 has either been cleared before, see code above, or it
+		   holds a return value, either way it is not secret
+		   information.  */
+		emit_move_insn (gen_rtx_REG (SImode, regno),
+				gen_rtx_REG (SImode, R0_REGNUM));
+	      emit_use (gen_rtx_REG (SImode, regno));
+	    }
+	  else
+	    {
+	      emit_move_insn (gen_rtx_REG (SImode, regno),
+			      gen_rtx_REG (SImode, LR_REGNUM));
+	      emit_use (gen_rtx_REG (SImode, regno));
+	    }
+	}
+    }
+}
+
 /* Generate pattern *pop_multiple_with_stack_update_and_return if single
    POP instruction can be generated.  LR should be replaced by PC.  All
    the checks required are already done by  USE_RETURN_INSN ().  Hence,
@@ -25334,6 +25799,8 @@ thumb2_expand_return (bool simple_return)
     }
   else
     {
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	cmse_nonsecure_entry_clear_before_return ();
       emit_jump_insn (simple_return_rtx);
     }
 }
@@ -25392,6 +25859,10 @@ thumb1_expand_epilogue (void)
 
   if (! df_regs_ever_live_p (LR_REGNUM))
     emit_use (gen_rtx_REG (SImode, LR_REGNUM));
+
+  /* Clear all caller-saved regs that are not used to return.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    cmse_nonsecure_entry_clear_before_return ();
 }
 
 /* Epilogue code for APCS frame.  */
@@ -25826,6 +26297,14 @@ 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 (!really_return)
     return;
 
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index cd98de7dcb40de483a9f93c0674bd216f4b0c56a..433fc79ae5810a4d3eb45d1ba80872a39e157e14 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1843,8 +1843,13 @@
   "*
     return thumb1_unexpanded_epilogue ();
   "
-  ; Length is absolute worst case
-  [(set_attr "length" "44")
+  ; Length is absolute worst case, when using CMSE and if this is an entry
+  ; function an extra 4 (MSR) bytes will be added.
+  [(set (attr "length")
+	(if_then_else
+	 (match_test "IS_CMSE_ENTRY (arm_current_func_type ())")
+	 (const_int 48)
+	 (const_int 44)))
    (set_attr "type" "block")
    ;; We don't clobber the conditions, but the potential length of this
    ;; operation is sufficient to make conditionalizing the sequence
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index affcd832b72b7d358347e7370265be492866bb90..f5033ef802c085bd0ce479bc7026db96d9e25632 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1114,12 +1114,31 @@
 
 (define_insn "*thumb2_return"
   [(simple_return)]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
   "* return output_return_instruction (const_true_rtx, true, false, true);"
   [(set_attr "type" "branch")
    (set_attr "length" "4")]
 )
 
+(define_insn "*thumb2_return"
+  [(simple_return)]
+  "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
+  "* return output_return_instruction (const_true_rtx, true, false, true);"
+  [(set_attr "type" "branch")
+   ; This is a return from a cmse_nonsecure_entry function so code will be
+   ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+   ; we adapt the length accordingly.
+   (set (attr "length")
+     (if_then_else (match_test "TARGET_HARD_FLOAT")
+      (const_int 12)
+      (const_int 8)))
+   ; We do not support predicate execution of returns from cmse_nonsecure_entry
+   ; functions because we need to clear the APSR.  Since predicable has to be
+   ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
+   ; functions.
+   (set_attr "predicable" "no")]
+)
+
 (define_insn_and_split "thumb2_eh_return"
   [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
 		    VUNSPEC_EH_RETURN)
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..814502d4e5d5ef87e920977b912f69f83cdde256
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "movs\tr1, r0" } } */
+/* { dg-final { scan-assembler "movs\tr2, r0" } } */
+/* { dg-final { scan-assembler "movs\tr3, r0" } } */
+/* { dg-final { scan-assembler "mov\tip, r0" } } */
+/* { dg-final { scan-assembler "mov\tlr, r0" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq," } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c
new file mode 100644
index 0000000000000000000000000000000000000000..0069fcdaebfd9caea02751856039a3aaefd3ffab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse -mfloat-abi=softfp" } */
+
+double __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+double
+foo (double a)
+{
+  return bar (1.0f, 2.0) + a;
+}
+
+float __attribute__ ((cmse_nonsecure_entry))
+baz (float a, double b)
+{
+  return (float) bar (a, b);
+}
+
+/* Make sure we are not using FP instructions, since ARMv8-M Baseline does not
+   support such instructions.  */
+/* { dg-final { scan-assembler-not "vmov" } } */
+/* { dg-final { scan-assembler-not "vmsr" } } */
+/* { dg-final { scan-assembler-not "vmrs" } } */
+
+/* Just double checking that we are still doing cmse though.  */
+/* { dg-final { scan-assembler-not "vmrs" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..fccc51d5c82f7955ee4cb8256c1dd38f9ff2670d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned short  a : 6;
+  unsigned char	  b : 3;
+  unsigned char	  c;
+  unsigned short  d : 8;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 63u;
+  t.b = 7u;
+  t.c = 255u;
+  t.d = 255u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 63u
+      || t.b != 7u
+      || t.c != 255u
+      || t.d != 255u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6aee3c4c022d50baec8ab16443130897540e703
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a : 7;
+  signed char b : 3;
+  short	      c : 11;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -64;
+  t.b = -4 ;
+  t.c = -1024;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -64
+      || t.b != -4
+      || t.c != -1024)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..285a2b92f64c1913ef585b8daa4d27c6da0a3d2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a;
+  signed char b : 2;
+  short		: 1;
+  signed char c : 3;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -32768;
+  t.b = -2;
+  t.c = -4;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -32768
+      || t.b != -2
+      || t.c != -4)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index f797dba1901720e04249d61078c1cbf2a3e436a9..38f18414c2fefec56161e6ac3f7291b03a3b29a3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -43,6 +43,26 @@ set LTO_TORTURE_OPTIONS ""
 gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
 	"" $DEFAULT_CFLAGS
 
+if {[check_effective_target_arm_arch_v8m_base_ok]} then {
+    # Baseline only
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/baseline/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
+if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    # Mainline -mfloat-abi=soft
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
+	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
 set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
 set dg-do-what-default ${saved-dg-do-what-default}
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..88dec2762812614ee986ee1a023c0acce8f94c91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..29f60baf5212f9fa2e4436fe40c6abe4ac671254
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7229ea8eb2da1da264f58f8518daf303d1bdeda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..7734d77dc3812e6a158ea1f6b067930846fffccb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..6addaa1a4eda8e2930d5fe72c94697bcf6e604e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { 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
new file mode 100644
index 0000000000000000000000000000000000000000..2d366a944df692f29ab44e3ee4d33c777b126223
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 255u;
+  t.b = 32767u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 255u || t.b != 32767u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
+

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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-11-11 16:19                 ` Kyrill Tkachov
@ 2016-11-23 11:54                   ` Andre Vieira (lists)
  2016-12-02 13:36                     ` Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-11-23 11:54 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov, Ramana Radhakrishnan, Richard Earnshaw

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

On 11/11/16 16:19, Kyrill Tkachov wrote:
> And CC'ing Ramana and Richard this time...
> 

Hi,

After some extra testing I found that the sibcall optimization was not
disabled for calls to function pointers with the cmse_nonsecure_call
attribute, causing the clearing and call to the function wrapper to be
skipped. This would result in an illegal branch into secure memory and
would HardFault.

Added a test.

Is this OK?

Cheers,
Andre

*** gcc/ChangeLog ***
2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (detect_cmse_nonsecure_call): New.
        (cmse_nonsecure_call_clear_caller_saved): New.
        (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
        (arm_function_ok_for_sibcall): Disable sibcalls for
cmse_nonsecure_call.
        * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
        * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
        (call_value): Likewise.
        (nonsecure_call_internal): New.
        (nonsecure_call_value_internal): New.
        * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
        (*nonsecure_call_value_reg_thumb1_v5): New.
        * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
        (*nonsecure_call_value_reg_thumb2): New.
        * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.

*** libgcc/ChangeLog ***
2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/cmse_nonsecure_call.S: New.
	* config/arm/t-arm: Compile cmse_nonsecure_call.S


*** gcc/testsuite/ChangeLog ***
2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
        * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
        * gcc.target/arm/cmse/cmse-14.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
        * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
        * gcc.target/arm/cmse/baseline/cmse-11.c: New.
	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
        * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
        * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.

[-- Attachment #2: diff6 --]
[-- Type: text/plain, Size: 83083 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index a9b8326c2770c1f9a9787743cb5faa549e6b7d02..2660bc3ba89c34b17911680c4e25eb2f6c0745fb 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -135,6 +135,7 @@ extern int arm_const_double_inline_cost (rtx);
 extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
+bool detect_cmse_nonsecure_call (tree);
 extern const char *output_call (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index b85003c41e15038c6612cd21ef3a7b3dae9ae8dd..39d6e8010eab69bb642127d4045c89430d836ab2 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -7021,6 +7021,15 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
     return false;
 
+  /* We do not allow ARMv8-M non-secure calls to be turned into sibling calls,
+     this would complicate matters for later code generation.  */
+  if (TREE_CODE (exp) == CALL_EXPR)
+    {
+      tree fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (exp)));
+      if (lookup_attribute ("cmse_nonsecure_call", TYPE_ATTRIBUTES (fntype)))
+	return false;
+    }
+
   if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
     {
       /* Check that the return value locations are the same.  For
@@ -17850,6 +17859,197 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Saves callee saved registers, clears callee saved registers and caller saved
+   registers not used to pass arguments before a cmse_nonsecure_call.  And
+   restores the callee saved registers after.  */
+
+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  uint64_t to_clear_mask, float_mask;
+	  rtx_insn *seq;
+	  rtx pat, call, unspec, reg, cleared_reg, tmp;
+	  unsigned int regno, maxregno;
+	  rtx address;
+	  CUMULATIVE_ARGS args_so_far_v;
+	  cumulative_args_t args_so_far;
+	  tree arg_type, fntype;
+	  bool using_r4, first_param = true;
+	  function_args_iterator args_iter;
+	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
+	  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
+
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  if (!CALL_P (insn))
+	    continue;
+
+	  pat = PATTERN (insn);
+	  gcc_assert (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 0);
+	  call = XVECEXP (pat, 0, 0);
+
+	  /* Get the real call RTX if the insn sets a value, ie. returns.  */
+	  if (GET_CODE (call) == SET)
+	      call = SET_SRC (call);
+
+	  /* Check if it is a cmse_nonsecure_call.  */
+	  unspec = XEXP (call, 0);
+	  if (GET_CODE (unspec) != UNSPEC
+	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
+	    continue;
+
+	  /* Determine the caller-saved registers we need to clear.  */
+	  to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
+	  maxregno = NUM_ARG_REGS - 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
+	     lazy store and loads which clear both caller- and callee-saved
+	     registers.  */
+	  if (TARGET_HARD_FLOAT_ABI)
+	    {
+	      float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
+	      float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
+	      to_clear_mask |= float_mask;
+	      maxregno = D7_VFP_REGNUM;
+	    }
+
+	  /* Make sure the register used to hold the function address is not
+	     cleared.  */
+	  address = RTVEC_ELT (XVEC (unspec, 0), 0);
+	  gcc_assert (MEM_P (address));
+	  gcc_assert (REG_P (XEXP (address, 0)));
+	  to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+
+	  /* Set basic block of call insn so that df rescan is performed on
+	     insns inserted here.  */
+	  set_block_for_insn (insn, bb);
+	  df_set_flags (DF_DEFER_INSN_RESCAN);
+	  start_sequence ();
+
+	  /* Make sure the scheduler doesn't schedule other insns beyond
+	     here.  */
+	  emit_insn (gen_blockage ());
+
+	  /* Walk through all arguments and clear registers appropriately.
+	  */
+	  fntype = TREE_TYPE (MEM_EXPR (address));
+	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
+				    NULL_TREE);
+	  args_so_far = pack_cumulative_args (&args_so_far_v);
+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask
+		&= ~compute_not_to_clear_mask (arg_type, arg_rtx,
+					       REGNO (arg_rtx),
+					       padding_bits_to_clear_ptr);
+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = R0_REGNUM; regno < NUM_ARG_REGS; regno++)
+	    {
+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = R0_REGNUM; regno <= maxregno; regno++)
+	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST1_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST1_RTX (SFmode));
+		}
+	      else
+		emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+	    }
+
+	  seq = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (seq, insn);
+
+	}
+    }
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -18150,6 +18350,8 @@ arm_reorg (void)
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
+  if (use_cmse)
+    cmse_nonsecure_call_clear_caller_saved ();
   if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
@@ -18522,6 +18724,23 @@ vfp_emit_fstmd (int base_reg, int count)
   return count * 8;
 }
 
+/* Returns true if -mcmse has been passed and the function pointed to by 'addr'
+   has the cmse_nonsecure_call attribute and returns false otherwise.  */
+
+bool
+detect_cmse_nonsecure_call (tree addr)
+{
+  if (!addr)
+    return FALSE;
+
+  tree fntype = TREE_TYPE (addr);
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_call",
+				    TYPE_ATTRIBUTES (fntype)))
+    return TRUE;
+  return FALSE;
+}
+
+
 /* Emit a call instruction with pattern PAT.  ADDR is the address of
    the call target.  */
 
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 8393f65bcf4c9c3e61b91e5adcd5f59ff7c6ec3f..3e65a43d39fb20061ee531d58fd21fbbc9cd1bde 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -8024,6 +8024,7 @@
   "
   {
     rtx callee, pat;
+    tree addr = MEM_EXPR (operands[0]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[2] == NULL_RTX)
@@ -8038,8 +8039,17 @@
 	: !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_internal (operands[0], operands[1], operands[2]);
-    arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_internal (operands[0], operands[1],
+					   operands[2]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_internal (operands[0], operands[1], operands[2]);
+	arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+      }
     DONE;
   }"
 )
@@ -8050,6 +8060,24 @@
 	      (use (match_operand 2 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_internal"
+  [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand" "")]
+			       UNSPEC_NONSECURE_MEM)
+		    (match_operand 1 "general_operand" ""))
+	      (use (match_operand 2 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[0] = replace_equiv_address (operands[0], tmp);
+  }")
+
 (define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
@@ -8085,6 +8113,7 @@
   "
   {
     rtx pat, callee;
+    tree addr = MEM_EXPR (operands[1]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
@@ -8099,9 +8128,18 @@
 	: !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_value_internal (operands[0], operands[1],
-				   operands[2], operands[3]);
-    arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_value_internal (operands[0], operands[1],
+						 operands[2], operands[3]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_value_internal (operands[0], operands[1],
+				       operands[2], operands[3]);
+	arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+      }
     DONE;
   }"
 )
@@ -8113,6 +8151,25 @@
 	      (use (match_operand 3 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_value_internal"
+  [(parallel [(set (match_operand       0 "" "")
+		   (call (unspec:SI [(match_operand 1 "memory_operand" "")]
+				    UNSPEC_NONSECURE_MEM)
+			 (match_operand 2 "general_operand" "")))
+	      (use (match_operand 3 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[1] = replace_equiv_address (operands[1], tmp);
+  }")
+
 (define_insn "*call_value_reg_armv5"
   [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 433fc79ae5810a4d3eb45d1ba80872a39e157e14..63a400fbfd8015cbd5a70252e24beacde4a5354d 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1705,6 +1705,19 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb1_v5"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_reg_thumb1"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
 	 (match_operand 1 "" ""))
@@ -1737,6 +1750,21 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb1_v5"
+  [(set (match_operand 0 "" "")
+	(call (unspec:SI
+	       [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+	       UNSPEC_NONSECURE_MEM)
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB1 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb1"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index f5033ef802c085bd0ce479bc7026db96d9e25632..8618dc31b44f2a7f0e3b0cc60fd226859e7545ae 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -580,6 +580,19 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
@@ -591,6 +604,21 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+	(call
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "register_operand" "l*r"))]
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index bee8795f007accc623c82b73c41a8619ebc29209..1aa39e8e0b9ddf17bb535c4d82959e569d3c9fd5 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -84,6 +84,8 @@
   UNSPEC_VRINTA         ; Represent a float to integral float rounding
                         ; towards nearest, ties away from zero.
   UNSPEC_PROBE_STACK    ; Probe stack memory reference
+  UNSPEC_NONSECURE_MEM	; Represent non-secure memory in ARMv8-M with
+			; security extension
 ])
 
 (define_c_enum "unspec" [
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6c1386c06edbdb58e76fa5e612c918010c507f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51ce2d42c051aeda8b06ad97086f2563a5fc47d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e9104b546a7693fcb2399622e828b1197eac1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 1023" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "movt\tr4, 32767" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d8941bbfeebd59744c43f10c842816b36ec9915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ffbb718d34d5bb8f10e1f3c0505c7dc393c670c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a6141829237823b8734de045a590a1917fa60b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #1799" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..642f4e0346b5186c78645780b45fe9c838848d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #7939" } } */
+/* { dg-final { scan-assembler "movt\tr4, 15" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, 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/baseline/cmse-11.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
new file mode 100644
index 0000000000000000000000000000000000000000..3007409ad88b9d2312ece4d55f3695787a1aa566
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+
+int
+foo (int a)
+{
+  return bar (bar (a + 1));
+}
+
+/* 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 "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\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/baseline/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2b931be5912b421f8427535ded3298883bec639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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 "movs\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmovs\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmovs\tr2, r4\n\tmovs\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/baseline/cmse-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..95da045690ae170a101949134482e821f27fe3aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* Remember dont clear r0 and r1, because we are passing the double parameter
+ * for bar in them.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, 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/baseline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff18e839b02c19c2c77769b18ef5ee1cfacf0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8063" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2e024b7f0776381f511077af91bd1ee5632ff12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
new file mode 100644
index 0000000000000000000000000000000000000000..701e9ee7e318a07278099548f9b7042a1fde1204
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int foo (void)
+{
+  return bar ();
+}
+
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler-not "b\[^ y\n\]*\\s+bar" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
index 1d97f0e1a37209bd129ffe96ce92a86bc2e0d5d1..9e81e30c891bbc1f9d2d1d68d03bacad9ce65fe1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -2,11 +2,19 @@
 /* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
 
 
+void __attribute__ ((cmse_nonsecure_call)) (*bar) (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+typedef void __attribute__ ((cmse_nonsecure_call)) baz (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+
 int __attribute__ ((cmse_nonsecure_entry))
-foo (int a)
+foo (int a, baz b)
 { /* { dg-warning "attribute ignored without -mcmse option" } */
+  bar (a);
+  b (a);
   return a + 1;
 }
 
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler-not "blxns" } } */
+/* { dg-final { scan-assembler-not "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 38f18414c2fefec56161e6ac3f7291b03a3b29a3..66a8b7da005f7dfeffbded61b02fd6a7473a1dcf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -50,6 +50,8 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
+	    "" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
 	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b1396d52e742a1710ed5ad33fbeb559d866f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d029044aa9aa1d412c28ee5d18a8e3d0be36546
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..005515ab9cb85c201a2a8b2f6417d73ceeacbc60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dd218e62fdee2a6af819079ba1ea1909185d076
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { 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/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..c833bcb0ae978572fad46780bc180f61ccb14345
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cdb8c44b19c811f3a7b4fbce102a6c768f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e139ba61af57f06cff5a9d121c97bbf41e170bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { 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/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..285fa854b3d61c4d856e9be863ee73a87f1b11a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f56aaf2a97e740a77473cab245614b6fa696c04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..749f8a7278cb4ea9fd4462887ce7f37b57f83248
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad5068aac263f1c2edb17b8707fc9d1c0af6959
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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\.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/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..b18259eaef6da1933ef2d58d63b97d4bb4e450f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..182ddf9540374f30ae3694259f1edb62161455e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd262c89085eb0dc8737ad7955c3a12531492b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..e33568400ef830abaa019b5c2727a9f3b5d5704b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..024a12e0a414730eb1cbebfca8574d548238ab28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb195eb58d59fe9ea5ed74af79646199c61bcdae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..22ed3f8af882f96da49919c60fc6f4cd74dfc54b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634065e7cb64a5069cbb3c9be4b8cf9177f5e29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..04f8466cc112c03ee5a05e6e5223d2c66a033bbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffe94de85417b81f9dcb366eb1b40dc1661c91b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc846cd7a51303ec00f8f512a54cd697fbd0682
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d0f136ef171111c1cca6cd24c4f46b9fcb7fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/libgcc/config/arm/cmse_nonsecure_call.S b/libgcc/config/arm/cmse_nonsecure_call.S
new file mode 100644
index 0000000000000000000000000000000000000000..fcde968508bb11114596e3e7dc73963e4067c7d9
--- /dev/null
+++ b/libgcc/config/arm/cmse_nonsecure_call.S
@@ -0,0 +1,132 @@
+/* CMSE wrapper function used to save, clear and restore callee saved registers
+   for cmse_nonsecure_call's.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+.syntax unified
+.thumb
+.global __gnu_cmse_nonsecure_call
+__gnu_cmse_nonsecure_call:
+#if defined(__ARM_ARCH_8M_MAIN__)
+push	    {r5-r11,lr}
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+
+/* Save and clear callee-saved registers only if we are dealing with hard float
+   ABI.  The unused caller-saved registers have already been cleared by GCC
+   generated code.  */
+#ifdef __ARM_PCS_VFP
+vpush.f64   {d8-d15}
+#if __ARM_FP & 0x04
+mov	    r5, #0
+vmov	    s16, s17, r5, r5
+vmov	    s18, s19, r5, r5
+vmov	    s20, s21, r5, r5
+vmov	    s22, s23, r5, r5
+vmov	    s24, s25, r5, r5
+vmov	    s26, s27, r5, r5
+vmov	    s28, s29, r5, r5
+vmov	    s30, s31, r5, r5
+#elif __ARM_FP & 0x08
+vmov.f64    d8, #1.00000
+vmov.f64    d9, #1.00000
+vmov.f64    d10, #1.00000
+vmov.f64    d11, #1.00000
+vmov.f64    d12, #1.00000
+vmov.f64    d13, #1.00000
+vmov.f64    d14, #1.00000
+vmov.f64    d15, #1.00000
+#else
+#error "Half precision implementation not supported."
+#endif
+/* Clear the cumulative exception-status bits (0-4,7) and the
+   condition code bits (28-31) of the FPSCR.  */
+vmrs	    r5, fpscr
+movw	    r6, #65376
+movt	    r6, #4095
+ands	    r5, r6
+vmsr	    fpscr, r5
+
+/* We are not dealing with hard float ABI, so we can safely use the vlstm and
+   vlldm instructions without needing to preserve the registers used for
+   argument passing.  */
+#else
+sub	    sp, sp, #0x88 /* Reserve stack space to save all floating point
+			     registers, including FPSCR.  */
+vlstm	    sp		  /* Lazy store and clearance of d0-d16 and FPSCR.  */
+#endif /* __ARM_PCS_VFP */
+
+/* Make sure to clear the 'GE' bits of the APSR register if 32-bit SIMD
+   instructions are available.  */
+#if defined(__ARM_FEATURE_SIMD32)
+msr	    APSR_nzcvqg, r4
+#else
+msr	    APSR_nzcvq, r4
+#endif
+
+mov	    r5, r4
+mov	    r6, r4
+blxns	    r4
+
+#ifdef __ARM_PCS_VFP
+vpop.f64    {d8-d15}
+#else
+vlldm	    sp		  /* Lazy restore of d0-d16 and FPSCR.  */
+add	    sp, sp, #0x88 /* Free space used to save floating point registers.  */
+#endif /* __ARM_PCS_VFP */
+
+pop	    {r5-r11, pc}
+
+#elif defined (__ARM_ARCH_8M_BASE__)
+push	    {r5-r7, lr}
+mov	    r5, r8
+mov	    r6, r9
+mov	    r7, r10
+push	    {r5-r7}
+mov	    r5, r11
+push	    {r5}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+msr	    APSR_nzcvq, r4
+blxns	    r4
+pop	    {r5}
+mov	    r11, r5
+pop	    {r5-r7}
+mov	    r10, r7
+mov	    r9, r6
+mov	    r8, r5
+pop	    {r5-r7, pc}
+
+#else
+#error "This should only be used for armv8-m base- and mainline."
+#endif
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 5618143bfd0f02b170db3f9e4c0a15cecb403cec..9e85ac06b146feaa14ab83374a0156737b870310 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -12,4 +12,6 @@ libgcc-objects += cmse.o cmse_nonsecure_call.o
 
 cmse.o: $(srcdir)/config/arm/cmse.c
 	$(gcc_compile) -c $(CMSE_OPTS) $<
+cmse_nonsecure_call.o: $(srcdir)/config/arm/cmse_nonsecure_call.S
+		       $(gcc_compile) -c $<
 endif

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

* [PATCHv3 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
  2016-11-04  9:30       ` Kyrill Tkachov
@ 2016-11-30 12:05         ` Andre Vieira (lists)
  2016-11-30 17:22           ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-11-30 12:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

Hi,

I got a bug report against the old version of this patch and fixed it
here. This had to do with GCC optimizations sharing types with and
without the 'cmse_nonsecure_call' attribute.  The patch now no longer
sets the main variant, this didn't seem to do what I thought it did.
Instead the patch now creates distinct type copies for every declared
pointer that eventually points to the function type with the attribute,
it will also create a distinct copy for the function type itself.
Another change in this patch was to make 'arm_comp_type_attributes', the
ARM implementation of TARGET_COMP_TYPE_ATTRIBUTES, deny compatibility
between function types with the attribute and without.

I added a test case to test the issue solved with these changes.

*** gcc/ChangeLog ***
2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * config/arm/arm.c (gimplify.h): New include.
        (arm_handle_cmse_nonsecure_call): New.
        (arm_attribute_table): Added cmse_nonsecure_call.
        (arm_comp_type_attributes): Deny compatibility of function types
with
        without the cmse_nonsecure_call attribute.
        * doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.

*** gcc/testsuite/ChangeLog ***
2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * gcc.target/arm/cmse/cmse-3.c: Add tests.
        * gcc.target/arm/cmse/cmse-4.c: Add tests.
        * gcc.target/arm/cmse/cmse-15.c: New.


Cheers,
Andre

[-- Attachment #2: diff5 --]
[-- Type: text/plain, Size: 8879 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9509b0e25c19f35ed312efa1d86efc18a0db7674..d1160d5001830beea981df7454f09daf7fac2c5a 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -63,6 +63,7 @@
 #include "tm-constrs.h"
 #include "rtl-iter.h"
 #include "optabs-libfuncs.h"
+#include "gimplify.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -137,6 +138,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
 static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
+static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -348,6 +350,8 @@ static const struct attribute_spec arm_attribute_table[] =
   /* ARMv8-M Security Extensions support.  */
   { "cmse_nonsecure_entry", 0, 0, true, false, false,
     arm_handle_cmse_nonsecure_entry, false },
+  { "cmse_nonsecure_call", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_call, true },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -6753,6 +6757,78 @@ arm_handle_cmse_nonsecure_entry (tree *node, tree name,
   return NULL_TREE;
 }
 
+
+/* Called upon detection of the use of the cmse_nonsecure_call attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function type tree or otherwise issue a diagnostic.  The
+   reason we check this at declaration time is to only allow the use of the
+   attribute with declarations of function pointers and not function
+   declarations.  This function checks NODE is of the expected type and issues
+   diagnostics otherwise using NAME.  If it is not of the expected type
+   *NO_ADD_ATTRS will be set to true.  */
+
+static tree
+arm_handle_cmse_nonsecure_call (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree decl = NULL_TREE, fntype = NULL_TREE;
+  tree main_variant, type;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored without -mcmse option.",
+	       name);
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == TYPE_DECL)
+    {
+      decl = *node;
+      fntype = TREE_TYPE (decl);
+    }
+
+  while (fntype != NULL_TREE && TREE_CODE (fntype) == POINTER_TYPE)
+    fntype = TREE_TYPE (fntype);
+
+  if (!decl || TREE_CODE (fntype) != FUNCTION_TYPE)
+    {
+	warning (OPT_Wattributes, "%qE attribute only applies to base type of a "
+		 "function pointer", name);
+	*no_add_attrs = true;
+	return NULL_TREE;
+    }
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (NULL, name, fntype);
+
+  if (*no_add_attrs)
+    return NULL_TREE;
+
+  /* Prevent trees being shared among function types with and without
+     cmse_nonsecure_call attribute.  */
+  type = TREE_TYPE (decl);
+
+  type = build_distinct_type_copy (type);
+  TREE_TYPE (decl) = type;
+  fntype = type;
+
+  while (TREE_CODE (fntype) != FUNCTION_TYPE)
+    {
+      type = fntype;
+      fntype = TREE_TYPE (fntype);
+      fntype = build_distinct_type_copy (fntype);
+      TREE_TYPE (type) = fntype;
+    }
+
+  /* Construct a type attribute and add it to the function type.  */
+  tree attrs = tree_cons (get_identifier ("cmse_nonsecure_call"), NULL_TREE,
+			  TYPE_ATTRIBUTES (fntype));
+  TYPE_ATTRIBUTES (fntype) = attrs;
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
@@ -6793,6 +6869,14 @@ arm_comp_type_attributes (const_tree type1, const_tree type2)
   if (l1 != l2)
     return 0;
 
+  l1 = lookup_attribute ("cmse_nonsecure_call",
+			 TYPE_ATTRIBUTES (type1)) != NULL;
+  l2 = lookup_attribute ("cmse_nonsecure_call",
+			 TYPE_ATTRIBUTES (type2)) != NULL;
+
+  if (l1 != l2)
+    return 0;
+
   return 1;
 }
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index e8d9d90c0ac98a2b50aad60edf01e16dfa480db7..e8d8deefca87eacbdde6042fc1885c0d0a85a5b8 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12622,8 +12622,8 @@ Security Extensions: Requiremenets on Development Tools Engineering
 Specification, which can be found at
 @uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 
-As part of the Security Extensions GCC implements a new function attribute
-@code{cmse_nonsecure_entry}.
+As part of the Security Extensions GCC implements two new function attributes:
+@code{cmse_nonsecure_entry} and @code{cmse_nonsecure_call}.
 
 As part of the Security Extensions GCC implements the intrinsics below.  FPTR
 is used here to mean any function pointer type.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
new file mode 100644
index 0000000000000000000000000000000000000000..4e9ace1f3f33b8a8653797e29ca62eb3dd7ae918
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
@@ -0,0 +1,72 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*ns_foo) (void);
+int (*s_bar) (void);
+int __attribute__ ((cmse_nonsecure_call)) (**ns_foo2) (void);
+int (**s_bar2) (void);
+
+typedef int __attribute__ ((cmse_nonsecure_call)) ns_foo_t (void);
+typedef int s_bar_t (void);
+typedef int __attribute__ ((cmse_nonsecure_call)) (* ns_foo_ptr) (void);
+typedef int (*s_bar_ptr) (void);
+
+int nonsecure0 (ns_foo_t * ns_foo_p)
+{
+  return ns_foo_p ();
+}
+
+int nonsecure1 (ns_foo_t ** ns_foo_p)
+{
+  return (*ns_foo_p) ();
+}
+
+int nonsecure2 (ns_foo_ptr ns_foo_p)
+{
+  return ns_foo_p ();
+}
+int nonsecure3 (ns_foo_ptr * ns_foo_p)
+{
+  return (*ns_foo_p) ();
+}
+
+int secure0 (s_bar_t * s_bar_p)
+{
+  return s_bar_p ();
+}
+
+int secure1 (s_bar_t ** s_bar_p)
+{
+  return (*s_bar_p) ();
+}
+
+int secure2 (s_bar_ptr s_bar_p)
+{
+  return s_bar_p ();
+}
+
+int secure3 (s_bar_ptr * s_bar_p)
+{
+  return (*s_bar_p) ();
+}
+
+int nonsecure4 (void)
+{
+  return ns_foo ();
+}
+
+int nonsecure5 (void)
+{
+  return (*ns_foo2) ();
+}
+
+int secure4 (void)
+{
+  return s_bar ();
+}
+
+int secure5 (void)
+{
+  return (*s_bar2) ();
+}
+/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 6 } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
index 2c2920e1dc310106d83203eb51e1a68a275d0152..7f92a4c28b3333e4c8fdc256211f3ed74a383cd4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -35,3 +35,11 @@ norf (struct span2 a) {}
 
 void __attribute__ ((cmse_nonsecure_entry))
 foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) bar2 (long long a, int b, long long c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) baz2 (long long a, int b, struct span c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef struct span __attribute__ ((cmse_nonsecure_call)) qux2 (void); /* { dg-error "not available to functions that return value on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) norf2 (int a, ...); /* { dg-error "not available to functions with variable number of arguments" } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
index 6f930ab04a1097c64097a4e003296bbe85733319..d0999a4181ac022b115ae20cf3e1c8bf78f6becf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -19,9 +19,16 @@ baz (void)
   return qux ();
 }
 
+void __attribute__ ((cmse_nonsecure_call))
+quux (void) {} /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
+int __attribute__ ((cmse_nonsecure_call)) norf; /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
 /* { dg-final { scan-assembler-times "bxns" 2 } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
 /* { dg-final { scan-assembler "baz:" } } */
 /* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_quux:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_norf:" } } */

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

* Re: [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic
  2016-11-09 14:53         ` Andre Vieira (lists)
@ 2016-11-30 12:06           ` Andre Vieira (lists)
  2016-12-05 11:46             ` [arm-embedded][committed][PATCH 7/7] " Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-11-30 12:06 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

Hi,

I changed the testcase with this patch since the old testcase was
casting a function pointer to another function pointer and using that
pointer to call the function. This is undefined behavior. The new test
reflects a more sane use of the intrinsics.

Cheers,
Andre

[-- Attachment #2: diff7 --]
[-- Type: text/plain, Size: 4196 bytes --]

diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index 5ed38d1608cfbfbd1248d76705fcf675bc36c2b2..14444206814fb95268ba5ba008245513b0dc94f1 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -528,6 +528,8 @@ enum arm_builtins
   ARM_BUILTIN_GET_FPSCR,
   ARM_BUILTIN_SET_FPSCR,
 
+  ARM_BUILTIN_CMSE_NONSECURE_CALLER,
+
 #undef CRYPTO1
 #undef CRYPTO2
 #undef CRYPTO3
@@ -1833,6 +1835,17 @@ arm_init_builtins (void)
 	= add_builtin_function ("__builtin_arm_stfscr", ftype_set_fpscr,
 				ARM_BUILTIN_SET_FPSCR, BUILT_IN_MD, NULL, NULL_TREE);
     }
+
+  if (use_cmse)
+    {
+      tree ftype_cmse_nonsecure_caller
+	= build_function_type_list (unsigned_type_node, NULL);
+      arm_builtin_decls[ARM_BUILTIN_CMSE_NONSECURE_CALLER]
+	= add_builtin_function ("__builtin_arm_cmse_nonsecure_caller",
+				ftype_cmse_nonsecure_caller,
+				ARM_BUILTIN_CMSE_NONSECURE_CALLER, BUILT_IN_MD,
+				NULL, NULL_TREE);
+    }
 }
 
 /* Return the ARM builtin for CODE.  */
@@ -2453,6 +2466,12 @@ arm_expand_builtin (tree exp,
       emit_insn (pat);
       return target;
 
+    case ARM_BUILTIN_CMSE_NONSECURE_CALLER:
+      target = gen_reg_rtx (SImode);
+      op0 = arm_return_addr (0, NULL_RTX);
+      emit_insn (gen_addsi3 (target, op0, const1_rtx));
+      return target;
+
     case ARM_BUILTIN_TEXTRMSB:
     case ARM_BUILTIN_TEXTRMUB:
     case ARM_BUILTIN_TEXTRMSH:
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
index 894343bb835b61e09c14668d45aa43a8693fd011..82b58b1c4f4a12ba6062e2cc2632653788d0eeb7 100644
--- a/gcc/config/arm/arm_cmse.h
+++ b/gcc/config/arm/arm_cmse.h
@@ -163,6 +163,13 @@ __attribute__ ((__always_inline__))
 cmse_TTAT (void *__p)
 __CMSE_TT_ASM (at)
 
+/* FIXME: diagnose use outside cmse_nonsecure_entry functions.  */
+__extension__ static __inline int __attribute__ ((__always_inline__))
+cmse_nonsecure_caller (void)
+{
+  return __builtin_arm_cmse_nonsecure_caller ();
+}
+
 #define CMSE_AU_NONSECURE	2
 #define CMSE_MPU_NONSECURE	16
 #define CMSE_NONSECURE		18
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index e8d8deefca87eacbdde6042fc1885c0d0a85a5b8..587a30d7efc6b1f2653efe96ed233828ebeb570a 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12640,6 +12640,7 @@ cmse_address_info_t cmse_TTAT_fptr (FPTR)
 void * cmse_check_address_range (void *, size_t, int)
 typeof(p) cmse_nsfptr_create (FPTR p)
 intptr_t cmse_is_nsfptr (FPTR)
+int cmse_nonsecure_caller (void)
 @end smallexample
 
 @node AVR Built-in Functions
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index d5b9a2d9d59569de170da814ae660e9fb2b943e7..c13272eed683aa06db027cd4646e5fe67817212b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -65,3 +65,42 @@ int foo (char * p)
 /* { dg-final { scan-assembler-times "ttat " 2 } } */
 /* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
 /* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return cmse_nonsecure_caller ();
+}
+
+typedef int __attribute__ ((cmse_nonsecure_call)) (int_nsfunc_t) (void);
+
+int default_callback (void)
+{
+  return 0;
+}
+
+int_nsfunc_t * fp = (int_nsfunc_t *) default_callback;
+
+void __attribute__ ((cmse_nonsecure_entry))
+qux (int_nsfunc_t * callback)
+{
+  fp = cmse_nsfptr_create (callback);
+}
+
+int call_callback (void)
+{
+  if (cmse_is_nsfptr (fp))
+      return fp ();
+  else
+    return default_callback ();
+}
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler "qux:" } } */
+/* { dg-final { scan-assembler "__acle_se_qux:" } } */
+/* { dg-final { scan-assembler-not "\tcmse_nonsecure_caller" } } */
+/* { dg-final { scan-rtl-dump "and.*reg.*const_int 1" expand } } */
+/* { dg-final { scan-assembler "bic" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
+/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 1 } } */

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-11-23 11:52                     ` Andre Vieira (lists)
@ 2016-11-30 15:32                       ` Andre Vieira (lists)
  2016-11-30 17:22                         ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-11-30 15:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kyrill Tkachov

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

On 23/11/16 11:52, Andre Vieira (lists) wrote:
> Hi,
> 
> After some extra testing I realized there was an issue with the way we
> were clearing registers when returning from a cmse_nonsecure_entry
> function for ARMv8-M.Baseline.  This patch fixes that and changes the
> testcase to catch the issue.
> 
> The problem was I was always using LR to clear the registers, however,
> due to the way the Thumb-1 backend works, we can't guarantee LR will
> contain the address to which we will be returning at the time of
> clearing. Instead we use r0 to clear r1-r3 and IP. If the function does
> not use r0 to return a value, we clear r0 with 0 before using it to
> clear everything else. As for LR, we move the value of the register used
> to return into it prior to returning.
> 
> This satisfies the requirements of not leaking secure information since
> all registers hold either:
> - values to return
> - 0
> - return address
> 
> No changes to ChangeLog.
> 
> Cheers,
> Andre
> 
Hi,

So I seemed to have forgotten to address two of your comments earlier,
done in this version.

To reiterate:
After some extra testing I realized there was an issue with the way we
were clearing registers when returning from a cmse_nonsecure_entry
function for ARMv8-M Baseline.  This patch fixes that and changes the
testcase to catch the issue.

The problem was I was always using LR to clear the registers, however,
due to the way the Thumb-1 backend works, we can't guarantee LR will
contain the address to which we will be returning at the time of
clearing. Instead we use r0 to clear r1-r3 and IP. If the function does
not use r0 to return a value, we clear r0 with 0 before using it to
clear everything else. As for LR, we move the value of the register used
to return into it prior to returning.

This satisfies the requirements of not leaking secure information since
all registers hold either:
- values to return
- 0
- return address

*** gcc/ChangeLog ***
2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
             Thomas Preud'homme  <thomas.preudhomme@arm.com>

         * config/arm/arm.c (output_return_instruction): Clear
         registers.
         (thumb2_expand_return): Likewise.
         (thumb1_expand_epilogue): Likewise.
         (thumb_exit): Likewise.
         (arm_expand_epilogue): Likewise.
         (cmse_nonsecure_entry_clear_before_return): New.
         (comp_not_to_clear_mask_str_un): New.
         (compute_not_to_clear_mask): New.
         * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
         * config/arm/thumb2.md (*thumb2_cmse_entry_return): Duplicate
         thumb2_return pattern for cmse_nonsecure_entry functions.

*** gcc/testsuite/ChangeLog ***
2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
             Thomas Preud'homme  <thomas.preudhomme@arm.com>

         * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
         * gcc.target/arm/cmse/struct-1.c: New.
         * gcc.target/arm/cmse/bitfield-1.c: New.
         * gcc.target/arm/cmse/bitfield-2.c: New.
         * gcc.target/arm/cmse/bitfield-3.c: New.
         * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
cleared.
         * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
         * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
         * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
         * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
         * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.

Cheers,
Andre

[-- Attachment #2: diff4 --]
[-- Type: text/plain, Size: 41249 bytes --]

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index db7e0c842fff1b0aee5059e3ea4813059caa8d03..6a9db85aa879e1c5547908dcc9f036ee37de489e 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -16297,6 +16297,279 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
   return;
 }
 
+/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for structs
+   and unions in the context of ARMv8-M Security Extensions.  It is used as a
+   helper function for both 'cmse_nonsecure_call' and 'cmse_nonsecure_entry'
+   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to either one
+   or four masks, depending on whether it is being computed for a
+   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
+   respectively.  The tree for the type of the argument or a field within an
+   argument is passed in ARG_TYPE, the current register this argument or field
+   starts in is kept in the pointer REGNO and updated accordingly, the bit this
+   argument or field starts at is passed in STARTING_BIT and the last used bit
+   is kept in LAST_USED_BIT which is also updated accordingly.  */
+
+static unsigned HOST_WIDE_INT
+comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
+			       uint32_t * padding_bits_to_clear,
+			       unsigned starting_bit, int * last_used_bit)
+
+{
+  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
+
+  if (TREE_CODE (arg_type) == RECORD_TYPE)
+    {
+      unsigned current_bit = starting_bit;
+      tree field;
+      long int offset, size;
+
+
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  /* The offset within a structure is always an offset from
+	     the start of that structure.  Make sure we take that into the
+	     calculation of the register based offset that we use here.  */
+	  offset = starting_bit;
+	  offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
+	  offset %= 32;
+
+	  /* This is the actual size of the field, for bitfields this is the
+	     bitfield width and not the container size.  */
+	  size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+
+	  if (*last_used_bit != offset)
+	    {
+	      if (offset < *last_used_bit)
+		{
+		  /* This field's offset is before the 'last_used_bit', that
+		     means this field goes on the next register.  So we need to
+		     pad the rest of the current register and increase the
+		     register number.  */
+		  uint32_t mask;
+		  mask  = ((uint32_t)-1) - ((uint32_t) 1 << *last_used_bit);
+		  mask++;
+
+		  padding_bits_to_clear[*regno] |= mask;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      else
+		{
+		  /* Otherwise we pad the bits between the last field's end and
+		     the start of the new field.  */
+		  uint32_t mask;
+
+		  mask = ((uint32_t)-1) >> (32 - offset);
+		  mask -= ((uint32_t) 1 << *last_used_bit) - 1;
+		  padding_bits_to_clear[*regno] |= mask;
+		}
+	      current_bit = offset;
+	    }
+
+	  /* Calculate further padding bits for inner structs/unions too.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	    {
+	      *last_used_bit = current_bit;
+	      not_to_clear_reg_mask
+		|= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
+						  padding_bits_to_clear, offset,
+						  last_used_bit);
+	    }
+	  else
+	    {
+	      /* Update 'current_bit' with this field's size.  If the
+		 'current_bit' lies in a subsequent register, update 'regno' and
+		 reset 'current_bit' to point to the current bit in that new
+		 register.  */
+	      current_bit += size;
+	      while (current_bit >= 32)
+		{
+		  current_bit-=32;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      *last_used_bit = current_bit;
+	    }
+
+	  field = TREE_CHAIN (field);
+	}
+      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+    }
+  else if (TREE_CODE (arg_type) == UNION_TYPE)
+    {
+      tree field, field_t;
+      int i, regno_t, field_size;
+      int max_reg = -1;
+      int max_bit = -1;
+      uint32_t mask;
+      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
+	= {-1, -1, -1, -1};
+
+      /* To compute the padding bits in a union we only consider bits as
+	 padding bits if they are always either a padding bit or fall outside a
+	 fields size for all fields in the union.  */
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
+	    = {0U, 0U, 0U, 0U};
+	  int last_used_bit_t = *last_used_bit;
+	  regno_t = *regno;
+	  field_t = TREE_TYPE (field);
+
+	  /* If the field's type is either a record or a union make sure to
+	     compute their padding bits too.  */
+	  if (RECORD_OR_UNION_TYPE_P (field_t))
+	    not_to_clear_reg_mask
+	      |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
+						&padding_bits_to_clear_t[0],
+						starting_bit, &last_used_bit_t);
+	  else
+	    {
+	      field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+	      regno_t = (field_size / 32) + *regno;
+	      last_used_bit_t = (starting_bit + field_size) % 32;
+	    }
+
+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (((uint32_t) -1) - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;
+
+	  /* Update the maximum size of the fields in terms of registers used
+	     ('max_reg') and the 'last_used_bit' in said register.  */
+	  if (max_reg < regno_t)
+	    {
+	      max_reg = regno_t;
+	      max_bit = last_used_bit_t;
+	    }
+	  else if (max_reg == regno_t && max_bit < last_used_bit_t)
+	    max_bit = last_used_bit_t;
+
+	  field = TREE_CHAIN (field);
+	}
+
+      /* Update the current padding_bits_to_clear using the intersection of the
+	 padding bits of all the fields.  */
+      for (i=*regno; i < max_reg; i++)
+	padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+
+      /* Do not keep trailing padding bits, we do not know yet whether this
+	 is the end of the argument.  */
+      mask = ((uint32_t) 1 << max_bit) - 1;
+      padding_bits_to_clear[max_reg]
+	|= padding_bits_to_clear_res[max_reg] & mask;
+
+      *regno = max_reg;
+      *last_used_bit = max_bit;
+    }
+  else
+    /* This function should only be used for structs and unions.  */
+    gcc_unreachable ();
+
+  return not_to_clear_reg_mask;
+}
+
+/* In the context of ARMv8-M Security Extensions, this function is used for both
+   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to compute what
+   registers are used when returning or passing arguments, which is then
+   returned as a mask.  It will also compute a mask to indicate padding/unused
+   bits for each of these registers, and passes this through the
+   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is passed in
+   ARG_TYPE, the rtl representation of the argument is passed in ARG_RTX and
+   the starting register used to pass this argument or return value is passed
+   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to compute these
+   for struct and union types.  */
+
+static unsigned HOST_WIDE_INT
+compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
+			     uint32_t * padding_bits_to_clear)
+
+{
+  int last_used_bit = 0;
+  unsigned HOST_WIDE_INT not_to_clear_mask;
+
+  if (RECORD_OR_UNION_TYPE_P (arg_type))
+    {
+      not_to_clear_mask
+	= comp_not_to_clear_mask_str_un (arg_type, &regno,
+					 padding_bits_to_clear, 0,
+					 &last_used_bit);
+
+
+      /* If the 'last_used_bit' is not zero, that means we are still using a
+	 part of the last 'regno'.  In such cases we must clear the trailing
+	 bits.  Otherwise we are not using regno and we should mark it as to
+	 clear.  */
+      if (last_used_bit != 0)
+	padding_bits_to_clear[regno]
+	  |= ((uint32_t)-1) - ((uint32_t) 1 << last_used_bit) + 1;
+      else
+	not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
+    }
+  else
+    {
+      not_to_clear_mask = 0;
+      /* We are not dealing with structs nor unions.  So these arguments may be
+	 passed in floating point registers too.  In some cases a BLKmode is
+	 used when returning or passing arguments in multiple VFP registers.  */
+      if (GET_MODE (arg_rtx) == BLKmode)
+	{
+	  int i, arg_regs;
+	  rtx reg;
+
+	  /* This should really only occur when dealing with the hard-float
+	     ABI.  */
+	  gcc_assert (TARGET_HARD_FLOAT_ABI);
+
+	  for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
+	    {
+	      reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
+	      gcc_assert (REG_P (reg));
+
+	      not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
+
+	      /* If we are dealing with DF mode, make sure we don't
+		 clear either of the registers it addresses.  */
+	      arg_regs = ARM_NUM_REGS (GET_MODE (reg));
+	      if (arg_regs > 1)
+		{
+		  unsigned HOST_WIDE_INT mask;
+		  mask = HOST_WIDE_INT_1U << (REGNO (reg) + arg_regs);
+		  mask -= HOST_WIDE_INT_1U << REGNO (reg);
+		  not_to_clear_mask |= mask;
+		}
+	    }
+	}
+      else
+	{
+	  /* Otherwise we can rely on the MODE to determine how many registers
+	     are being used by this argument.  */
+	  int arg_regs = ARM_NUM_REGS (GET_MODE (arg_rtx));
+	  not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	  if (arg_regs > 1)
+	    {
+	      unsigned HOST_WIDE_INT
+	      mask = HOST_WIDE_INT_1U << (REGNO (arg_rtx) + arg_regs);
+	      mask -= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	      not_to_clear_mask |= mask;
+	    }
+	}
+    }
+
+  return not_to_clear_mask;
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -18720,7 +18993,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
-	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    {
+	      /* 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);
+	      if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+		{
+		  /* 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");
+		  output_asm_insn (instr, & operand);
+		}
+	      snprintf (instr, sizeof (instr), "bxns\t%%|lr");
+	    }
 	  /* Use bx if it's available.  */
 	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
@@ -23027,7 +23335,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
-	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	{
+	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+		       reg_containing_return_addr);
+	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	}
       else
 	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
@@ -23263,7 +23575,18 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
   /* Return to caller.  */
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
-    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    {
+      /* This is for the cases where LR is not being used to contain the return
+         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'.  */
+      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);
+      asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    }
   else
     asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
@@ -24130,6 +24453,149 @@ thumb1_expand_prologue (void)
     cfun->machine->lr_save_eliminated = 0;
 }
 
+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check that TARGET_HARD_FLOAT and !TARGET_THUMB1 hold
+     to make sure the instructions used to clear them are present.  */
+  if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      maxregno = LAST_VFP_REGNUM;
+
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask[0] |= float_mask;
+
+      float_mask = (1ULL << (maxregno - 63)) - 1;
+      to_clear_mask[1] = float_mask;
+
+      /* 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));
+      to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+      emit_use (gen_rtx_REG (SImode, 4));
+      to_clear_mask[0] &= ~(1ULL << 4);
+    }
+
+  /* If the user has defined registers to be caller saved, these are no longer
+     restored by the function before returning and must thus be cleared for
+     security purposes.  */
+  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+    {
+      /* We do not touch registers that can be used to pass arguments as per
+	 the AAPCS, since these should never be made callee-saved by user
+	 options.  */
+      if (IN_RANGE (regno, FIRST_VFP_REGNUM, D7_VFP_REGNUM))
+	continue;
+      if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
+	continue;
+      if (call_used_regs[regno])
+	to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+    }
+
+  /* Make sure we do not clear the registers used to return the result in.  */
+  result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+  if (!VOID_TYPE_P (result_type))
+    {
+      result_rtl = arm_function_value (result_type, current_function_decl, 0);
+
+      /* No need to check that we return in registers, because we don't
+	 support returning on stack yet.  */
+      to_clear_mask[0]
+	&= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
+				       padding_bits_to_clear_ptr);
+    }
+
+  if (padding_bits_to_clear != 0)
+    {
+      rtx reg_rtx;
+      /* Padding bits to clear is not 0 so we know we are dealing with
+	 returning a composite type, which only uses r0.  Let's make sure that
+	 r1-r3 is cleared too, we will use r1 as a scratch register.  */
+      gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
+
+      reg_rtx = gen_rtx_REG (SImode, R1_REGNUM);
+
+      /* Fill the lower half of the negated padding_bits_to_clear.  */
+      emit_move_insn (reg_rtx,
+		      GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
+
+      /* Also fill the top half of the negated padding_bits_to_clear.  */
+      if (((~padding_bits_to_clear) >> 16) > 0)
+	emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
+						      GEN_INT (16),
+						      GEN_INT (16)),
+				GEN_INT ((~padding_bits_to_clear) >> 16)));
+
+      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, R0_REGNUM),
+			   gen_rtx_REG (SImode, R0_REGNUM),
+			   reg_rtx));
+    }
+
+  for (regno = R0_REGNUM; regno <= maxregno; regno++)
+    {
+      if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
+	continue;
+
+      if (IS_VFP_REGNUM (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)
+	      && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 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
+	{
+	  if (TARGET_THUMB1)
+	    {
+	      if (regno == R0_REGNUM)
+		emit_move_insn (gen_rtx_REG (SImode, regno),
+				const0_rtx);
+	      else
+		/* R0 has either been cleared before, see code above, or it
+		   holds a return value, either way it is not secret
+		   information.  */
+		emit_move_insn (gen_rtx_REG (SImode, regno),
+				gen_rtx_REG (SImode, R0_REGNUM));
+	      emit_use (gen_rtx_REG (SImode, regno));
+	    }
+	  else
+	    {
+	      emit_move_insn (gen_rtx_REG (SImode, regno),
+			      gen_rtx_REG (SImode, LR_REGNUM));
+	      emit_use (gen_rtx_REG (SImode, regno));
+	    }
+	}
+    }
+}
+
 /* Generate pattern *pop_multiple_with_stack_update_and_return if single
    POP instruction can be generated.  LR should be replaced by PC.  All
    the checks required are already done by  USE_RETURN_INSN ().  Hence,
@@ -24179,6 +24645,8 @@ thumb2_expand_return (bool simple_return)
     }
   else
     {
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	cmse_nonsecure_entry_clear_before_return ();
       emit_jump_insn (simple_return_rtx);
     }
 }
@@ -24237,6 +24705,10 @@ thumb1_expand_epilogue (void)
 
   if (! df_regs_ever_live_p (LR_REGNUM))
     emit_use (gen_rtx_REG (SImode, LR_REGNUM));
+
+  /* Clear all caller-saved regs that are not used to return.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    cmse_nonsecure_entry_clear_before_return ();
 }
 
 /* Epilogue code for APCS frame.  */
@@ -24671,6 +25143,14 @@ 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 (!really_return)
     return;
 
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 5f0dffba89145321351331db821bdeaa0df54b10..73a738195d5b35fe9b2a153d1270c26cbaad12e4 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1869,8 +1869,13 @@
   "*
     return thumb1_unexpanded_epilogue ();
   "
-  ; Length is absolute worst case
-  [(set_attr "length" "44")
+  ; Length is absolute worst case, when using CMSE and if this is an entry
+  ; function an extra 4 (MSR) bytes will be added.
+  [(set (attr "length")
+	(if_then_else
+	 (match_test "IS_CMSE_ENTRY (arm_current_func_type ())")
+	 (const_int 48)
+	 (const_int 44)))
    (set_attr "type" "block")
    ;; We don't clobber the conditions, but the potential length of this
    ;; operation is sufficient to make conditionalizing the sequence
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index affcd832b72b7d358347e7370265be492866bb90..9029a2fcfa8c865df9473eab7f807589a5a244e5 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1114,12 +1114,31 @@
 
 (define_insn "*thumb2_return"
   [(simple_return)]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
   "* return output_return_instruction (const_true_rtx, true, false, true);"
   [(set_attr "type" "branch")
    (set_attr "length" "4")]
 )
 
+(define_insn "*thumb2_cmse_entry_return"
+  [(simple_return)]
+  "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
+  "* return output_return_instruction (const_true_rtx, true, false, true);"
+  [(set_attr "type" "branch")
+   ; This is a return from a cmse_nonsecure_entry function so code will be
+   ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+   ; we adapt the length accordingly.
+   (set (attr "length")
+     (if_then_else (match_test "TARGET_HARD_FLOAT")
+      (const_int 12)
+      (const_int 8)))
+   ; We do not support predicate execution of returns from cmse_nonsecure_entry
+   ; functions because we need to clear the APSR.  Since predicable has to be
+   ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
+   ; functions.
+   (set_attr "predicable" "no")]
+)
+
 (define_insn_and_split "thumb2_eh_return"
   [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
 		    VUNSPEC_EH_RETURN)
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..814502d4e5d5ef87e920977b912f69f83cdde256
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "movs\tr1, r0" } } */
+/* { dg-final { scan-assembler "movs\tr2, r0" } } */
+/* { dg-final { scan-assembler "movs\tr3, r0" } } */
+/* { dg-final { scan-assembler "mov\tip, r0" } } */
+/* { dg-final { scan-assembler "mov\tlr, r0" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq," } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c
new file mode 100644
index 0000000000000000000000000000000000000000..0069fcdaebfd9caea02751856039a3aaefd3ffab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse -mfloat-abi=softfp" } */
+
+double __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+double
+foo (double a)
+{
+  return bar (1.0f, 2.0) + a;
+}
+
+float __attribute__ ((cmse_nonsecure_entry))
+baz (float a, double b)
+{
+  return (float) bar (a, b);
+}
+
+/* Make sure we are not using FP instructions, since ARMv8-M Baseline does not
+   support such instructions.  */
+/* { dg-final { scan-assembler-not "vmov" } } */
+/* { dg-final { scan-assembler-not "vmsr" } } */
+/* { dg-final { scan-assembler-not "vmrs" } } */
+
+/* Just double checking that we are still doing cmse though.  */
+/* { dg-final { scan-assembler-not "vmrs" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..fccc51d5c82f7955ee4cb8256c1dd38f9ff2670d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned short  a : 6;
+  unsigned char	  b : 3;
+  unsigned char	  c;
+  unsigned short  d : 8;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 63u;
+  t.b = 7u;
+  t.c = 255u;
+  t.d = 255u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 63u
+      || t.b != 7u
+      || t.c != 255u
+      || t.d != 255u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6aee3c4c022d50baec8ab16443130897540e703
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a : 7;
+  signed char b : 3;
+  short	      c : 11;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -64;
+  t.b = -4 ;
+  t.c = -1024;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -64
+      || t.b != -4
+      || t.c != -1024)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..285a2b92f64c1913ef585b8daa4d27c6da0a3d2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a;
+  signed char b : 2;
+  short		: 1;
+  signed char c : 3;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -32768;
+  t.b = -2;
+  t.c = -4;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -32768
+      || t.b != -2
+      || t.c != -4)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index f797dba1901720e04249d61078c1cbf2a3e436a9..38f18414c2fefec56161e6ac3f7291b03a3b29a3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -43,6 +43,26 @@ set LTO_TORTURE_OPTIONS ""
 gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
 	"" $DEFAULT_CFLAGS
 
+if {[check_effective_target_arm_arch_v8m_base_ok]} then {
+    # Baseline only
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/baseline/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
+if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    # Mainline -mfloat-abi=soft
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
+	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
 set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
 set dg-do-what-default ${saved-dg-do-what-default}
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..88dec2762812614ee986ee1a023c0acce8f94c91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..29f60baf5212f9fa2e4436fe40c6abe4ac671254
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7229ea8eb2da1da264f58f8518daf303d1bdeda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..7734d77dc3812e6a158ea1f6b067930846fffccb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..6addaa1a4eda8e2930d5fe72c94697bcf6e604e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { 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
new file mode 100644
index 0000000000000000000000000000000000000000..2d366a944df692f29ab44e3ee4d33c777b126223
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 255u;
+  t.b = 32767u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 255u || t.b != 32767u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
+

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

* Re: [PATCHv3 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
  2016-11-30 12:05         ` [PATCHv3 " Andre Vieira (lists)
@ 2016-11-30 17:22           ` Kyrill Tkachov
  2016-12-05 11:38             ` [PATCHv3 5/7, GCC[arm-embedded][committed][PATCH 5/7] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute, " Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-11-30 17:22 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 30/11/16 12:05, Andre Vieira (lists) wrote:
> Hi,
>
> I got a bug report against the old version of this patch and fixed it
> here. This had to do with GCC optimizations sharing types with and
> without the 'cmse_nonsecure_call' attribute.  The patch now no longer
> sets the main variant, this didn't seem to do what I thought it did.
> Instead the patch now creates distinct type copies for every declared
> pointer that eventually points to the function type with the attribute,
> it will also create a distinct copy for the function type itself.
> Another change in this patch was to make 'arm_comp_type_attributes', the
> ARM implementation of TARGET_COMP_TYPE_ATTRIBUTES, deny compatibility
> between function types with the attribute and without.
>
> I added a test case to test the issue solved with these changes.

Ok.
Thanks,
Kyrill

> *** gcc/ChangeLog ***
> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>          * config/arm/arm.c (gimplify.h): New include.
>          (arm_handle_cmse_nonsecure_call): New.
>          (arm_attribute_table): Added cmse_nonsecure_call.
>          (arm_comp_type_attributes): Deny compatibility of function types
> with
>          without the cmse_nonsecure_call attribute.
>          * doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.
>
> *** gcc/testsuite/ChangeLog ***
> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>          * gcc.target/arm/cmse/cmse-3.c: Add tests.
>          * gcc.target/arm/cmse/cmse-4.c: Add tests.
>          * gcc.target/arm/cmse/cmse-15.c: New.
>
>
> Cheers,
> Andre

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

* Re: [PATCHv2 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-11-30 15:32                       ` Andre Vieira (lists)
@ 2016-11-30 17:22                         ` Kyrill Tkachov
  2016-12-05 11:36                           ` [arm-embedded][committed][PATCH 4/7] " Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-11-30 17:22 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches


On 30/11/16 15:32, Andre Vieira (lists) wrote:
> On 23/11/16 11:52, Andre Vieira (lists) wrote:
>> Hi,
>>
>> After some extra testing I realized there was an issue with the way we
>> were clearing registers when returning from a cmse_nonsecure_entry
>> function for ARMv8-M.Baseline.  This patch fixes that and changes the
>> testcase to catch the issue.
>>
>> The problem was I was always using LR to clear the registers, however,
>> due to the way the Thumb-1 backend works, we can't guarantee LR will
>> contain the address to which we will be returning at the time of
>> clearing. Instead we use r0 to clear r1-r3 and IP. If the function does
>> not use r0 to return a value, we clear r0 with 0 before using it to
>> clear everything else. As for LR, we move the value of the register used
>> to return into it prior to returning.
>>
>> This satisfies the requirements of not leaking secure information since
>> all registers hold either:
>> - values to return
>> - 0
>> - return address
>>
>> No changes to ChangeLog.
>>
>> Cheers,
>> Andre
>>
> Hi,
>
> So I seemed to have forgotten to address two of your comments earlier,
> done in this version.
>
> To reiterate:
> After some extra testing I realized there was an issue with the way we
> were clearing registers when returning from a cmse_nonsecure_entry
> function for ARMv8-M Baseline.  This patch fixes that and changes the
> testcase to catch the issue.
>
> The problem was I was always using LR to clear the registers, however,
> due to the way the Thumb-1 backend works, we can't guarantee LR will
> contain the address to which we will be returning at the time of
> clearing. Instead we use r0 to clear r1-r3 and IP. If the function does
> not use r0 to return a value, we clear r0 with 0 before using it to
> clear everything else. As for LR, we move the value of the register used
> to return into it prior to returning.
>
> This satisfies the requirements of not leaking secure information since
> all registers hold either:
> - values to return
> - 0
> - return address
>
> *** gcc/ChangeLog ***
> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>           * config/arm/arm.c (output_return_instruction): Clear
>           registers.
>           (thumb2_expand_return): Likewise.
>           (thumb1_expand_epilogue): Likewise.
>           (thumb_exit): Likewise.
>           (arm_expand_epilogue): Likewise.
>           (cmse_nonsecure_entry_clear_before_return): New.
>           (comp_not_to_clear_mask_str_un): New.
>           (compute_not_to_clear_mask): New.
>           * config/arm/thumb1.md (*epilogue_insns): Change length attribute.
>           * config/arm/thumb2.md (*thumb2_cmse_entry_return): Duplicate
>           thumb2_return pattern for cmse_nonsecure_entry functions.
>
> *** gcc/testsuite/ChangeLog ***
> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>
>           * gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
>           * gcc.target/arm/cmse/struct-1.c: New.
>           * gcc.target/arm/cmse/bitfield-1.c: New.
>           * gcc.target/arm/cmse/bitfield-2.c: New.
>           * gcc.target/arm/cmse/bitfield-3.c: New.
>           * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers are
> cleared.
>           * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>           * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>           * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>           * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>           * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.

Ok, thanks for addressing the issues.
Kyrill

> Cheers,
> Andre

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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-11-23 11:54                   ` Andre Vieira (lists)
@ 2016-12-02 13:36                     ` Andre Vieira (lists)
  2016-12-02 13:42                       ` Kyrill Tkachov
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-12-02 13:36 UTC (permalink / raw)
  To: gcc-patches

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

On 23/11/16 11:53, Andre Vieira (lists) wrote:
> On 11/11/16 16:19, Kyrill Tkachov wrote:
>> And CC'ing Ramana and Richard this time...
>>
> 
> Hi,
> 
> After some extra testing I found that the sibcall optimization was not
> disabled for calls to function pointers with the cmse_nonsecure_call
> attribute, causing the clearing and call to the function wrapper to be
> skipped. This would result in an illegal branch into secure memory and
> would HardFault.
> 
> Added a test.
> 
> Is this OK?
> 
> Cheers,
> Andre
> 
> *** gcc/ChangeLog ***
> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>         (cmse_nonsecure_call_clear_caller_saved): New.
>         (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>         (arm_function_ok_for_sibcall): Disable sibcalls for
> cmse_nonsecure_call.
>         * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>         * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>         (call_value): Likewise.
>         (nonsecure_call_internal): New.
>         (nonsecure_call_value_internal): New.
>         * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>         (*nonsecure_call_value_reg_thumb1_v5): New.
>         * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>         (*nonsecure_call_value_reg_thumb2): New.
>         * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
> 
> *** libgcc/ChangeLog ***
> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * config/arm/cmse_nonsecure_call.S: New.
> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
> 
> 
> *** gcc/testsuite/ChangeLog ***
> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>             Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>         * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>         * gcc.target/arm/cmse/cmse-14.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>         * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>         * gcc.target/arm/cmse/baseline/cmse-11.c: New.
> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>         * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
> 
Hi,

To make the clearing of registers consistent between single and double
precision I decided to clear all FP registers with 0. The callee-saved
registers, saved, cleared and restored in the library wrapper we can do
this without much penalty to performance. The caller-saved registers are
compiler generated and currently generate a 'vldr' instruction, per
cleared (sp or dp) register. This is far from optimal, but it works and
it is "safer". I have some ideas to improve this, for instance using
r0-r1 to clear the FP registers, since they will either contain the
address of the callback function or an argument value, either way they
will never contain secret information. I will address this at a later time.

Changed the tests to reflect these changes. No changes to the ChangeLog.

Is this OK?

Cheers,
Andre


[-- Attachment #2: diff6 --]
[-- Type: text/plain, Size: 82903 bytes --]

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 634a5de05472d562972d9ad84b5858691715714c..05d73ab2271d28ce8d6d49199341d4365f0a2bcb 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -137,6 +137,7 @@ extern int arm_const_double_inline_cost (rtx);
 extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
+bool detect_cmse_nonsecure_call (tree);
 extern const char *output_call (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index a6b07b295e3ca6679b1edd988fcf01929b0e06f3..f1df3a0971010375c116041e38153f96b24e7aae 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -7000,6 +7000,15 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
     return false;
 
+  /* We do not allow ARMv8-M non-secure calls to be turned into sibling calls,
+     this would complicate matters for later code generation.  */
+  if (TREE_CODE (exp) == CALL_EXPR)
+    {
+      tree fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (exp)));
+      if (lookup_attribute ("cmse_nonsecure_call", TYPE_ATTRIBUTES (fntype)))
+	return false;
+    }
+
   if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
     {
       /* Check that the return value locations are the same.  For
@@ -16654,6 +16663,197 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Saves callee saved registers, clears callee saved registers and caller saved
+   registers not used to pass arguments before a cmse_nonsecure_call.  And
+   restores the callee saved registers after.  */
+
+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  uint64_t to_clear_mask, float_mask;
+	  rtx_insn *seq;
+	  rtx pat, call, unspec, reg, cleared_reg, tmp;
+	  unsigned int regno, maxregno;
+	  rtx address;
+	  CUMULATIVE_ARGS args_so_far_v;
+	  cumulative_args_t args_so_far;
+	  tree arg_type, fntype;
+	  bool using_r4, first_param = true;
+	  function_args_iterator args_iter;
+	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
+	  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
+
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  if (!CALL_P (insn))
+	    continue;
+
+	  pat = PATTERN (insn);
+	  gcc_assert (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 0);
+	  call = XVECEXP (pat, 0, 0);
+
+	  /* Get the real call RTX if the insn sets a value, ie. returns.  */
+	  if (GET_CODE (call) == SET)
+	      call = SET_SRC (call);
+
+	  /* Check if it is a cmse_nonsecure_call.  */
+	  unspec = XEXP (call, 0);
+	  if (GET_CODE (unspec) != UNSPEC
+	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
+	    continue;
+
+	  /* Determine the caller-saved registers we need to clear.  */
+	  to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
+	  maxregno = NUM_ARG_REGS - 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
+	     lazy store and loads which clear both caller- and callee-saved
+	     registers.  */
+	  if (TARGET_HARD_FLOAT_ABI)
+	    {
+	      float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
+	      float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
+	      to_clear_mask |= float_mask;
+	      maxregno = D7_VFP_REGNUM;
+	    }
+
+	  /* Make sure the register used to hold the function address is not
+	     cleared.  */
+	  address = RTVEC_ELT (XVEC (unspec, 0), 0);
+	  gcc_assert (MEM_P (address));
+	  gcc_assert (REG_P (XEXP (address, 0)));
+	  to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+
+	  /* Set basic block of call insn so that df rescan is performed on
+	     insns inserted here.  */
+	  set_block_for_insn (insn, bb);
+	  df_set_flags (DF_DEFER_INSN_RESCAN);
+	  start_sequence ();
+
+	  /* Make sure the scheduler doesn't schedule other insns beyond
+	     here.  */
+	  emit_insn (gen_blockage ());
+
+	  /* Walk through all arguments and clear registers appropriately.
+	  */
+	  fntype = TREE_TYPE (MEM_EXPR (address));
+	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
+				    NULL_TREE);
+	  args_so_far = pack_cumulative_args (&args_so_far_v);
+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask
+		&= ~compute_not_to_clear_mask (arg_type, arg_rtx,
+					       REGNO (arg_rtx),
+					       padding_bits_to_clear_ptr);
+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = R0_REGNUM; regno < NUM_ARG_REGS; regno++)
+	    {
+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = R0_REGNUM; regno <= maxregno; regno++)
+	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST0_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST0_RTX (SFmode));
+		}
+	      else
+		emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+	    }
+
+	  seq = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (seq, insn);
+
+	}
+    }
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -16954,6 +17154,8 @@ arm_reorg (void)
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
+  if (use_cmse)
+    cmse_nonsecure_call_clear_caller_saved ();
   if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
@@ -17326,6 +17528,23 @@ vfp_emit_fstmd (int base_reg, int count)
   return count * 8;
 }
 
+/* Returns true if -mcmse has been passed and the function pointed to by 'addr'
+   has the cmse_nonsecure_call attribute and returns false otherwise.  */
+
+bool
+detect_cmse_nonsecure_call (tree addr)
+{
+  if (!addr)
+    return FALSE;
+
+  tree fntype = TREE_TYPE (addr);
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_call",
+				    TYPE_ATTRIBUTES (fntype)))
+    return TRUE;
+  return FALSE;
+}
+
+
 /* Emit a call instruction with pattern PAT.  ADDR is the address of
    the call target.  */
 
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 5523baf5099cb7c35a6ad3c8a39e5c31efd32f17..d561a4b5d1be9a7bd159f51b50ec736bd89f8fd1 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -8052,6 +8052,7 @@
   "
   {
     rtx callee, pat;
+    tree addr = MEM_EXPR (operands[0]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[2] == NULL_RTX)
@@ -8066,8 +8067,17 @@
 	: !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_internal (operands[0], operands[1], operands[2]);
-    arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_internal (operands[0], operands[1],
+					   operands[2]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_internal (operands[0], operands[1], operands[2]);
+	arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+      }
     DONE;
   }"
 )
@@ -8078,6 +8088,24 @@
 	      (use (match_operand 2 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_internal"
+  [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand" "")]
+			       UNSPEC_NONSECURE_MEM)
+		    (match_operand 1 "general_operand" ""))
+	      (use (match_operand 2 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[0] = replace_equiv_address (operands[0], tmp);
+  }")
+
 (define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
@@ -8113,6 +8141,7 @@
   "
   {
     rtx pat, callee;
+    tree addr = MEM_EXPR (operands[1]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
@@ -8127,9 +8156,18 @@
 	: !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_value_internal (operands[0], operands[1],
-				   operands[2], operands[3]);
-    arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_value_internal (operands[0], operands[1],
+						 operands[2], operands[3]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_value_internal (operands[0], operands[1],
+				       operands[2], operands[3]);
+	arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+      }
     DONE;
   }"
 )
@@ -8141,6 +8179,25 @@
 	      (use (match_operand 3 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_value_internal"
+  [(parallel [(set (match_operand       0 "" "")
+		   (call (unspec:SI [(match_operand 1 "memory_operand" "")]
+				    UNSPEC_NONSECURE_MEM)
+			 (match_operand 2 "general_operand" "")))
+	      (use (match_operand 3 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[1] = replace_equiv_address (operands[1], tmp);
+  }")
+
 (define_insn "*call_value_reg_armv5"
   [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 73a738195d5b35fe9b2a153d1270c26cbaad12e4..f9e934fab015c5b8bda344a5a2ca0341912080a8 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1731,6 +1731,19 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb1_v5"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_reg_thumb1"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
 	 (match_operand 1 "" ""))
@@ -1763,6 +1776,21 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb1_v5"
+  [(set (match_operand 0 "" "")
+	(call (unspec:SI
+	       [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+	       UNSPEC_NONSECURE_MEM)
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB1 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb1"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index 9029a2fcfa8c865df9473eab7f807589a5a244e5..9b078a5c6a7ebd2ea7d1c39d9b6a80ce7b69a7dc 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -580,6 +580,19 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
@@ -591,6 +604,21 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+	(call
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "register_operand" "l*r"))]
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index bee8795f007accc623c82b73c41a8619ebc29209..1aa39e8e0b9ddf17bb535c4d82959e569d3c9fd5 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -84,6 +84,8 @@
   UNSPEC_VRINTA         ; Represent a float to integral float rounding
                         ; towards nearest, ties away from zero.
   UNSPEC_PROBE_STACK    ; Probe stack memory reference
+  UNSPEC_NONSECURE_MEM	; Represent non-secure memory in ARMv8-M with
+			; security extension
 ])
 
 (define_c_enum "unspec" [
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6c1386c06edbdb58e76fa5e612c918010c507f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51ce2d42c051aeda8b06ad97086f2563a5fc47d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e9104b546a7693fcb2399622e828b1197eac1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 1023" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "movt\tr4, 32767" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d8941bbfeebd59744c43f10c842816b36ec9915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ffbb718d34d5bb8f10e1f3c0505c7dc393c670c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a6141829237823b8734de045a590a1917fa60b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #1799" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..642f4e0346b5186c78645780b45fe9c838848d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #7939" } } */
+/* { dg-final { scan-assembler "movt\tr4, 15" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, 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/baseline/cmse-11.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
new file mode 100644
index 0000000000000000000000000000000000000000..3007409ad88b9d2312ece4d55f3695787a1aa566
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+
+int
+foo (int a)
+{
+  return bar (bar (a + 1));
+}
+
+/* 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 "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\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/baseline/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2b931be5912b421f8427535ded3298883bec639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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 "movs\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmovs\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmovs\tr2, r4\n\tmovs\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/baseline/cmse-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..95da045690ae170a101949134482e821f27fe3aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* Remember dont clear r0 and r1, because we are passing the double parameter
+ * for bar in them.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, 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/baseline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff18e839b02c19c2c77769b18ef5ee1cfacf0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8063" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2e024b7f0776381f511077af91bd1ee5632ff12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
new file mode 100644
index 0000000000000000000000000000000000000000..701e9ee7e318a07278099548f9b7042a1fde1204
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int foo (void)
+{
+  return bar ();
+}
+
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler-not "b\[^ y\n\]*\\s+bar" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
index 1d97f0e1a37209bd129ffe96ce92a86bc2e0d5d1..9e81e30c891bbc1f9d2d1d68d03bacad9ce65fe1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -2,11 +2,19 @@
 /* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
 
 
+void __attribute__ ((cmse_nonsecure_call)) (*bar) (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+typedef void __attribute__ ((cmse_nonsecure_call)) baz (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+
 int __attribute__ ((cmse_nonsecure_entry))
-foo (int a)
+foo (int a, baz b)
 { /* { dg-warning "attribute ignored without -mcmse option" } */
+  bar (a);
+  b (a);
   return a + 1;
 }
 
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler-not "blxns" } } */
+/* { dg-final { scan-assembler-not "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 38f18414c2fefec56161e6ac3f7291b03a3b29a3..66a8b7da005f7dfeffbded61b02fd6a7473a1dcf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -50,6 +50,8 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
+	    "" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
 	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b1396d52e742a1710ed5ad33fbeb559d866f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d029044aa9aa1d412c28ee5d18a8e3d0be36546
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..005515ab9cb85c201a2a8b2f6417d73ceeacbc60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dd218e62fdee2a6af819079ba1ea1909185d076
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { 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/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..c833bcb0ae978572fad46780bc180f61ccb14345
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cdb8c44b19c811f3a7b4fbce102a6c768f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e139ba61af57f06cff5a9d121c97bbf41e170bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { 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/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..d90ad811fc13c9b5cde1c9bf394e490255429ff2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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 "vldr\.32\ts0, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts1, .L" } } */
+/* { dg-final { scan-assembler-not "vldr\.32\ts2, .L" } } */
+/* { dg-final { scan-assembler-not "vldr\.32\ts3, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts4, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts5, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts6, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts7, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts8, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts9, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts10, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts11, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts12, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts13, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts14, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts15, .L" } } */
+
+/* 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-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..c047cd51c9480fc30e411bf7814769d32ccfe79e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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 "vldr\.32\ts0, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts1, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts2, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts3, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts4, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts5, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts6, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts7, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts8, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts9, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts10, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts11, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts12, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts13, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts14, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts15, .L" } } */
+
+/* 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/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..20d2d4a8fb13f89103a5d97b9b533caa37520b76
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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 "vldr\.32\ts0, .L" } } */
+/* { dg-final { scan-assembler-not "vldr\.32\ts1, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts2, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts3, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts4, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts5, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts6, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts7, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts8, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts9, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts10, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts11, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts12, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts13, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts14, .L" } } */
+/* { dg-final { scan-assembler "vldr\.32\ts15, .L" } } */
+
+/* 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-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..0af586a7fd18de879301c5bba9eccbe1ab0c4e33
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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 "vldr\.32\ts1, .L" } } */
+/* { dg-final { scan-assembler-not "vldr\.64\td0, .L" } } */
+/* { dg-final { scan-assembler-not "vldr\.32\ts0, .L" } } */
+/* { dg-final { scan-assembler-not "vldr\.64\td1, .L" } } */
+/* { dg-final { scan-assembler-not "vldr\.32\ts2, .L" } } */
+/* { dg-final { scan-assembler-not "vldr\.32\ts3, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td2, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td3, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td4, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td5, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td6, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td7, .L" } } */
+
+/* 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-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..a5c64fb06edd6927e0eb3b1f4e6d314274668a7a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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 "vldr\.64\td0, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td1, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td2, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td3, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td4, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td5, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td6, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td7, .L" } } */
+
+/* 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/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..5e041b17b0e4bad779b147c204cf8178c8798b80
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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 "vldr\.64\td0, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td1, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td2, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td3, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td4, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td5, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td6, .L" } } */
+/* { dg-final { scan-assembler "vldr\.64\td7, .L" } } */
+
+/* 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-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd262c89085eb0dc8737ad7955c3a12531492b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..e33568400ef830abaa019b5c2727a9f3b5d5704b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..024a12e0a414730eb1cbebfca8574d548238ab28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb195eb58d59fe9ea5ed74af79646199c61bcdae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..22ed3f8af882f96da49919c60fc6f4cd74dfc54b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634065e7cb64a5069cbb3c9be4b8cf9177f5e29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..04f8466cc112c03ee5a05e6e5223d2c66a033bbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffe94de85417b81f9dcb366eb1b40dc1661c91b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc846cd7a51303ec00f8f512a54cd697fbd0682
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d0f136ef171111c1cca6cd24c4f46b9fcb7fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/libgcc/config/arm/cmse_nonsecure_call.S b/libgcc/config/arm/cmse_nonsecure_call.S
new file mode 100644
index 0000000000000000000000000000000000000000..68b6a1cb5005d9ebb284a062443bc310d7e7db53
--- /dev/null
+++ b/libgcc/config/arm/cmse_nonsecure_call.S
@@ -0,0 +1,131 @@
+/* CMSE wrapper function used to save, clear and restore callee saved registers
+   for cmse_nonsecure_call's.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+.syntax unified
+.thumb
+.global __gnu_cmse_nonsecure_call
+__gnu_cmse_nonsecure_call:
+#if defined(__ARM_ARCH_8M_MAIN__)
+push	    {r5-r11,lr}
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+
+/* Save and clear callee-saved registers only if we are dealing with hard float
+   ABI.  The unused caller-saved registers have already been cleared by GCC
+   generated code.  */
+#ifdef __ARM_PCS_VFP
+vpush.f64   {d8-d15}
+mov	    r5, #0
+vmov	    d8, r5, r5
+#if __ARM_FP & 0x04
+vmov	    s18, s19, r5, r5
+vmov	    s20, s21, r5, r5
+vmov	    s22, s23, r5, r5
+vmov	    s24, s25, r5, r5
+vmov	    s26, s27, r5, r5
+vmov	    s28, s29, r5, r5
+vmov	    s30, s31, r5, r5
+#elif __ARM_FP & 0x08
+vmov.f64    d9, d8
+vmov.f64    d10, d8
+vmov.f64    d11, d8
+vmov.f64    d12, d8
+vmov.f64    d13, d8
+vmov.f64    d14, d8
+vmov.f64    d15, d8
+#else
+#error "Half precision implementation not supported."
+#endif
+/* Clear the cumulative exception-status bits (0-4,7) and the
+   condition code bits (28-31) of the FPSCR.  */
+vmrs	    r5, fpscr
+movw	    r6, #65376
+movt	    r6, #4095
+ands	    r5, r6
+vmsr	    fpscr, r5
+
+/* We are not dealing with hard float ABI, so we can safely use the vlstm and
+   vlldm instructions without needing to preserve the registers used for
+   argument passing.  */
+#else
+sub	    sp, sp, #0x88 /* Reserve stack space to save all floating point
+			     registers, including FPSCR.  */
+vlstm	    sp		  /* Lazy store and clearance of d0-d16 and FPSCR.  */
+#endif /* __ARM_PCS_VFP */
+
+/* Make sure to clear the 'GE' bits of the APSR register if 32-bit SIMD
+   instructions are available.  */
+#if defined(__ARM_FEATURE_SIMD32)
+msr	    APSR_nzcvqg, r4
+#else
+msr	    APSR_nzcvq, r4
+#endif
+
+mov	    r5, r4
+mov	    r6, r4
+blxns	    r4
+
+#ifdef __ARM_PCS_VFP
+vpop.f64    {d8-d15}
+#else
+vlldm	    sp		  /* Lazy restore of d0-d16 and FPSCR.  */
+add	    sp, sp, #0x88 /* Free space used to save floating point registers.  */
+#endif /* __ARM_PCS_VFP */
+
+pop	    {r5-r11, pc}
+
+#elif defined (__ARM_ARCH_8M_BASE__)
+push	    {r5-r7, lr}
+mov	    r5, r8
+mov	    r6, r9
+mov	    r7, r10
+push	    {r5-r7}
+mov	    r5, r11
+push	    {r5}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+msr	    APSR_nzcvq, r4
+blxns	    r4
+pop	    {r5}
+mov	    r11, r5
+pop	    {r5-r7}
+mov	    r10, r7
+mov	    r9, r6
+mov	    r8, r5
+pop	    {r5-r7, pc}
+
+#else
+#error "This should only be used for armv8-m base- and mainline."
+#endif
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 5618143bfd0f02b170db3f9e4c0a15cecb403cec..9e85ac06b146feaa14ab83374a0156737b870310 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -12,4 +12,6 @@ libgcc-objects += cmse.o cmse_nonsecure_call.o
 
 cmse.o: $(srcdir)/config/arm/cmse.c
 	$(gcc_compile) -c $(CMSE_OPTS) $<
+cmse_nonsecure_call.o: $(srcdir)/config/arm/cmse_nonsecure_call.S
+		       $(gcc_compile) -c $<
 endif

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

* Re: [PATCHv2 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-12-02 13:36                     ` Andre Vieira (lists)
@ 2016-12-02 13:42                       ` Kyrill Tkachov
  2016-12-05 11:44                         ` [arm-embedded][committed][PATCH 6/7] " Andre Vieira (lists)
  0 siblings, 1 reply; 72+ messages in thread
From: Kyrill Tkachov @ 2016-12-02 13:42 UTC (permalink / raw)
  To: Andre Vieira (lists), gcc-patches

Hi Andre,

On 02/12/16 13:36, Andre Vieira (lists) wrote:
> On 23/11/16 11:53, Andre Vieira (lists) wrote:
>> On 11/11/16 16:19, Kyrill Tkachov wrote:
>>> And CC'ing Ramana and Richard this time...
>>>
>> Hi,
>>
>> After some extra testing I found that the sibcall optimization was not
>> disabled for calls to function pointers with the cmse_nonsecure_call
>> attribute, causing the clearing and call to the function wrapper to be
>> skipped. This would result in an illegal branch into secure memory and
>> would HardFault.
>>
>> Added a test.
>>
>> Is this OK?
>>
>> Cheers,
>> Andre
>>
>> *** gcc/ChangeLog ***
>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>>          (cmse_nonsecure_call_clear_caller_saved): New.
>>          (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>>          (arm_function_ok_for_sibcall): Disable sibcalls for
>> cmse_nonsecure_call.
>>          * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>>          * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>>          (call_value): Likewise.
>>          (nonsecure_call_internal): New.
>>          (nonsecure_call_value_internal): New.
>>          * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>>          (*nonsecure_call_value_reg_thumb1_v5): New.
>>          * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>>          (*nonsecure_call_value_reg_thumb2): New.
>>          * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
>>
>> *** libgcc/ChangeLog ***
>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config/arm/cmse_nonsecure_call.S: New.
>> 	* config/arm/t-arm: Compile cmse_nonsecure_call.S
>>
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>>          * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>>          * gcc.target/arm/cmse/cmse-14.c: New.
>>          * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>>          * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>>          * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>>          * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>>          * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>>          * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>>          * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>>          * gcc.target/arm/cmse/baseline/cmse-11.c: New.
>> 	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
>>          * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>>          * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
>> 	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
>>
> Hi,
>
> To make the clearing of registers consistent between single and double
> precision I decided to clear all FP registers with 0. The callee-saved
> registers, saved, cleared and restored in the library wrapper we can do
> this without much penalty to performance. The caller-saved registers are
> compiler generated and currently generate a 'vldr' instruction, per
> cleared (sp or dp) register. This is far from optimal, but it works and
> it is "safer". I have some ideas to improve this, for instance using
> r0-r1 to clear the FP registers, since they will either contain the
> address of the callback function or an argument value, either way they
> will never contain secret information. I will address this at a later time.
>
> Changed the tests to reflect these changes. No changes to the ChangeLog.
>
> Is this OK?

Thanks, I much prefer the consistency.
This is ok.
I believe all patches in this series have been approved now, so you can go ahead and commit them.
Please keep an eye out for fallout over the next week.

Kyrill

> Cheers,
> Andre
>

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

* [arm-embedded][committed][PATCH 1/7] Add support for ARMv8-M's Secure Extensions flag and intrinsics
  2016-10-27 10:01             ` Kyrill Tkachov
@ 2016-12-05 11:27               ` Andre Vieira (lists)
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-12-05 11:27 UTC (permalink / raw)
  To: gcc-patches

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

On 27/10/16 11:01, Kyrill Tkachov wrote:
> 
> On 27/10/16 10:53, Andre Vieira (lists) wrote:
>> On 26/10/16 14:00, Kyrill Tkachov wrote:
>>> On 26/10/16 10:12, Kyrill Tkachov wrote:
>>>> Hi Andre, thanks for resending them.
>>>>
>>>> On 25/10/16 17:26, Andre Vieira (lists) wrote:
>>>>> On 24/08/16 12:00, Andre Vieira (lists) wrote:
>>>>>> On 25/07/16 14:19, Andre Vieira (lists) wrote:
>>>>>>> This patch adds the support of the '-mcmse' option to enable
>>>>>>> ARMv8-M's
>>>>>>> Security Extensions and supports the following intrinsics:
>>>>>>> cmse_TT
>>>>>>> cmse_TT_fptr
>>>>>>> cmse_TTT
>>>>>>> cmse_TTT_fptr
>>>>>>> cmse_TTA
>>>>>>> cmse_TTA_fptr
>>>>>>> cmse_TTAT
>>>>>>> cmse_TTAT_fptr
>>>>>>> cmse_check_address_range
>>>>>>> cmse_check_pointed_object
>>>>>>> cmse_is_nsfptr
>>>>>>> cmse_nsfptr_create
>>>>>>>
>>>>>>> It also defines the mandatory cmse_address_info struct and the
>>>>>>> __ARM_FEATURE_CMSE macro.
>>>>>>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>>>>>>> Extensions: Requirements on Development Tools
>>>>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> *** gcc/ChangeLog ***
>>>>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>>>
>>>>>>>           * config.gcc (extra_headers): Added arm_cmse.h.
>>>>>>>           * config/arm/arm-arches.def (ARM_ARCH):
>>>>>>>           (armv8-m): Add FL2_CMSE.
>>>>>>>           (armv8-m.main): Likewise.
>>>>>>>           (armv8-m.main+dsp): Likewise.
>>>>>>>           * config/arm/arm-c.c
>>>>>>>           (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>>>>>>           * config/arm/arm-protos.h
>>>>>>>           (arm_is_constant_pool_ref): Define FL2_CMSE.
>>>>>>>           * config/arm.c (arm_arch_cmse): New.
>>>>>>>           (arm_option_override): New error for unsupported cmse
>>>>>>> target.
>>>>>>>           * config/arm/arm.h (arm_arch_cmse): New.
>>>>>>>           * config/arm/arm.opt (mcmse): New.
>>>>>>>           * doc/invoke.texi (ARM Options): Add -mcmse.
>>>>>>>           * config/arm/arm_cmse.h: New file.
>>>>>>>
>>>>>>> *** libgcc/ChangeLog ***
>>>>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>>>
>>>>>>>           * config/arm/cmse.c: Likewise.
>>>>>>>           * config/arm/t-arm (HAVE_CMSE): New.
>>>>>>>
>>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>>> 2016-07-25  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>>>
>>>>>>>           * gcc.target/arm/cmse/cmse.exp: New.
>>>>>>>           * gcc.target/arm/cmse/cmse-1.c: New.
>>>>>>>           * gcc.target/arm/cmse/cmse-12.c: New.
>>>>>>>           * lib/target-supports.exp
>>>>>>>           (check_effective_target_arm_cmse_ok): New.
>>>
>>> Just remembered, new effective target checks should be documented in
>>> sourcebuild.texi
>>> Kyrill
>>>
>>>>>> Added more documentation as requested.
>>>>>>
>>>>>> This patch adds the support of the '-mcmse' option to enable
>>>>>> ARMv8-M's
>>>>>> Security Extensions and supports the following intrinsics:
>>>>>> cmse_TT
>>>>>> cmse_TT_fptr
>>>>>> cmse_TTT
>>>>>> cmse_TTT_fptr
>>>>>> cmse_TTA
>>>>>> cmse_TTA_fptr
>>>>>> cmse_TTAT
>>>>>> cmse_TTAT_fptr
>>>>>> cmse_check_address_range
>>>>>> cmse_check_pointed_object
>>>>>> cmse_is_nsfptr
>>>>>> cmse_nsfptr_create
>>>>>>
>>>>>> It also defines the mandatory cmse_address_info struct and the
>>>>>> __ARM_FEATURE_CMSE macro.
>>>>>> See Chapter 4, Sections 5.2, 5.3 and 5.6 of ARM®v8-M Security
>>>>>> Extensions: Requirements on Development Tools
>>>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>>>
>>>>>>
>>>>>>
>>>>>> *** gcc/ChangeLog ***
>>>>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>>
>>>>>>           * config.gcc (extra_headers): Added arm_cmse.h.
>>>>>>           * config/arm/arm-arches.def (ARM_ARCH):
>>>>>>           (armv8-m): Add FL2_CMSE.
>>>>>>           (armv8-m.main): Likewise.
>>>>>>           (armv8-m.main+dsp): Likewise.
>>>>>>           * config/arm/arm-c.c
>>>>>>           (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>>>>>           * config/arm/arm-protos.h
>>>>>>           (arm_is_constant_pool_ref): Define FL2_CMSE.
>>>>>>           * config/arm.c (arm_arch_cmse): New.
>>>>>>           (arm_option_override): New error for unsupported cmse
>>>>>> target.
>>>>>>           * config/arm/arm.h (arm_arch_cmse): New.
>>>>>>           * config/arm/arm.opt (mcmse): New.
>>>>>>           * doc/invoke.texi (ARM Options): Add -mcmse.
>>>>>>           * doc/extend.texi (ARM ARMv8-M Security Extensions): Add
>>>>>> section.
>>>>>>           * config/arm/arm_cmse.h: New file.
>>>>>>
>>>>>> *** libgcc/ChangeLog ***
>>>>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>>           * config/arm/cmse.c: Likewise.
>>>>>>           * config/arm/t-arm (HAVE_CMSE): New.
>>>>>>
>>>>>>
>>>>>> *** gcc/testsuite/ChangeLog ***
>>>>>> 2016-07-xx  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>>>>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>>>>>
>>>>>>           * gcc.target/arm/cmse/cmse.exp: New.
>>>>>>           * gcc.target/arm/cmse/cmse-1.c: New.
>>>>>>           * gcc.target/arm/cmse/cmse-12.c: New.
>>>>>>           * lib/target-supports.exp
>>>>>>           (check_effective_target_arm_cmse_ok): New.
>>>>>>
>>>>> Hi,
>>>>>
>>>>> Rebased previous patch on top of trunk as requested. No changes to
>>>>> ChangeLog.
>>>>>
>>>>> Cheers,
>>>>> Andre
>>>> diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
>>>> new file mode 100644
>>>> index
>>>> 0000000000000000000000000000000000000000..b4232937c6ae04754a6bbc513b143672a4be5530
>>>>
>>>>
>>>> --- /dev/null
>>>> +++ b/gcc/config/arm/arm_cmse.h
>>>>
>>>> <snip>
>>>>
>>>> +
>>>> +#if __ARM_FEATURE_CMSE & 2
>>>> +
>>>> +#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
>>>> +
>>>> +__extension__ static __inline __attribute__ ((__always_inline__))
>>>> +cmse_address_info_t
>>>> +__cmse_TTA_fptr (__cmse_fptr __p)
>>>> +__CMSE_TT_ASM (a)
>>>> +
>>>> +__extension__ static __inline __attribute__ ((__always_inline__))
>>>> +cmse_address_info_t
>>>> +cmse_TTA (void *__p)
>>>> +__CMSE_TT_ASM (a)
>>>> +
>>>> +#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
>>>> +
>>>> +__extension__ static __inline cmse_address_info_t
>>>> +__attribute__ ((__always_inline__))
>>>> +__cmse_TTAT_fptr (__cmse_fptr __p)
>>>> +__CMSE_TT_ASM (at)
>>>> +
>>>> +__extension__ static __inline cmse_address_info_t
>>>> +__attribute__ ((__always_inline__))
>>>> +cmse_TTAT (void *__p)
>>>> +__CMSE_TT_ASM (at)
>>>> +
>>>> +#define CMSE_AU_NONSECURE    2
>>>> +#define CMSE_MPU_NONSECURE    16
>>>> +#define CMSE_NONSECURE        18
>>>> +
>>>> +#endif /* __ARM_FEATURE_CMSE & 2 */
>>>> +
>>>> +#define CMSE_MPU_UNPRIV        4
>>>> +#define CMSE_MPU_READWRITE    1
>>>> +#define CMSE_MPU_READ        8
>>>> +
>>>> +__extension__ void *
>>>> +cmse_check_address_range (void *, size_t, int);
>>>> +
>>>> +#define cmse_check_pointed_object(p, f) \
>>>> +  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
>>>> +
>>>> +#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
>>>> +
>>>> +#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
>>>> +
>>>> +#endif /* __ARM_FEATURE_CMSE & 1 */
>>>>
>>>>  From my reading of the spec
>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf)
>>>>
>>>>
>>>> cmse_nsfptr_create and cmse_is_nsfptr should be defined if bit 1 of
>>>> __ARM_FEATURE_CMSE is set.
>>>> But in your patch they fall under the "#if __ARM_FEATURE_CMSE & 1"
>>>> check which checks bit 0.
>>>> They should be in the "__ARM_FEATURE_CMSE & 2" block. Please double
>>>> check the other defines against the SPEC to make sure they
>>>> match the feature bit in __ARM_FEATURE_CMSE.
>>>>
>>>> The patch is ok with that resolved if bootstrap and test on a normal
>>>> arm-none-linux-gnueabihf configuration
>>>> shows no problems.
>>>> Thanks,
>>>> Kyrill
>>>>
>> Hi,
>>
>> Reworked comments.
>>
>> Is this OK?
> 
> Yes, thanks.
> Please hold off committing until the whole series is approved.
> Kyrill
> 
>> Cheers,
>> Andre
>>
>> *** gcc/ChangeLog ***
>> 2016-10-27  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>           * config.gcc (extra_headers): Added arm_cmse.h.
>>           * config/arm/arm-arches.def (ARM_ARCH):
>>           (armv8-m): Add FL2_CMSE.
>>           (armv8-m.main): Likewise.
>>           (armv8-m.main+dsp): Likewise.
>>           * config/arm/arm-c.c
>>           (arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
>>           * config/arm/arm-protos.h
>>           (arm_is_constant_pool_ref): Define FL2_CMSE.
>>           * config/arm.c (arm_arch_cmse): New.
>>           (arm_option_override): New error for unsupported cmse target.
>>           * config/arm/arm.h (arm_arch_cmse): New.
>>           * config/arm/arm.opt (mcmse): New.
>>           * doc/invoke.texi (ARM Options): Add -mcmse.
>>           * config/arm/arm_cmse.h: New file.
>>           * doc/sourcebuild.texi (arm_cmse_ok): Add new effective target.
>>
>> *** libgcc/ChangeLog ***
>> 2016-10-27  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>           * config/arm/cmse.c: Likewise.
>>           * config/arm/t-arm (HAVE_CMSE): New.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-10-27  Andre Vieira <andre.simoesdiasvieira@arm.com>
>>               Thomas Preud'homme <thomas.preudhomme@arm.com>
>>
>>           * gcc.target/arm/cmse/cmse.exp: New.
>>           * gcc.target/arm/cmse/cmse-1.c: New.
>>           * gcc.target/arm/cmse/cmse-12.c: New.
>>           * lib/target-supports.exp
>>           (check_effective_target_arm_cmse_ok): New.
>>
> 

Hi,

Backported this to the embedded-6-branch in revision r243246.

Cheers,
Andre

gcc/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* config.gcc (extra_headers): Added arm_cmse.h.
	* config/arm/arm-arches.def (ARM_ARCH):
	(armv8-m): Add FL2_CMSE.
	(armv8-m.main): Likewise.
	(armv8-m.main+dsp): Likewise.
	* config/arm/arm-c.c
	(arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
	* config/arm/arm-flags.h: Define FL2_CMSE.
	* config/arm.c (arm_arch_cmse): New.
	(arm_option_override): New error for unsupported cmse target.
	* config/arm/arm.h (arm_arch_cmse): New.
	* config/arm/arm.opt (mcmse): New.
	* config/arm/arm_cmse.h: New file.
	* doc/invoke.texi (ARM Options): Add -mcmse.
	* doc/sourcebuild.texi (arm_cmse_ok): Add new effective target.
	* doc/extend.texi: Add ARMv8-M Security Extensions entry.

gcc/testsuite/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/cmse.exp: New.
	* gcc.target/arm/cmse/cmse-1.c: New.
	* gcc.target/arm/cmse/cmse-12.c: New.
	* lib/target-supports.exp
	(check_effective_target_arm_cmse_ok): New.

libgcc/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* config/arm/t-arm (HAVE_CMSE): New.
	* config/arm/cmse.c: New.

[-- Attachment #2: diff --]
[-- Type: text/plain, Size: 26567 bytes --]

diff --git a/gcc/ChangeLog.arm b/gcc/ChangeLog.arm
index d30cbcd8b5b6b6019b5f23d6e8d8b903ef7026c8..98704eb438dadd73cf793da5a7b8266b5e9ef267 100644
--- a/gcc/ChangeLog.arm
+++ b/gcc/ChangeLog.arm
@@ -1,3 +1,26 @@
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
+	* config.gcc (extra_headers): Added arm_cmse.h.
+	* config/arm/arm-arches.def (ARM_ARCH):
+	(armv8-m): Add FL2_CMSE.
+	(armv8-m.main): Likewise.
+	(armv8-m.main+dsp): Likewise.
+	* config/arm/arm-c.c
+	(arm_cpu_builtins): Added __ARM_FEATURE_CMSE macro.
+	* config/arm/arm-flags.h: Define FL2_CMSE.
+	* config/arm.c (arm_arch_cmse): New.
+	(arm_option_override): New error for unsupported cmse target.
+	* config/arm/arm.h (arm_arch_cmse): New.
+	* config/arm/arm.opt (mcmse): New.
+	* config/arm/arm_cmse.h: New file.
+	* doc/invoke.texi (ARM Options): Add -mcmse.
+	* doc/sourcebuild.texi (arm_cmse_ok): Add new effective target.
+	* doc/extend.texi: Add ARMv8-M Security Extensions entry.
+
 2016-11-22  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
 	Backport from mainline
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 9c29e50cb1d2e6c02a02c8554b5e880ef9e6ccc0..607b526dac650c6ab917b5b07e2de3e0c2ecc9a7 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -327,7 +327,7 @@ arc*-*-*)
 arm*-*-*)
 	cpu_type=arm
 	extra_objs="arm-builtins.o aarch-common.o"
-	extra_headers="mmintrin.h arm_neon.h arm_acle.h"
+	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_cmse.h"
 	target_type_format_char='%'
 	c_target_objs="arm-c.o"
 	cxx_target_objs="arm-c.o"
diff --git a/gcc/config/arm/arm-arches.def b/gcc/config/arm/arm-arches.def
index 59dac9a2304a92e9cac7c5ccdf1f0b655606fe15..1d2442970540948056c33f67288e1b4a281d7657 100644
--- a/gcc/config/arm/arm-arches.def
+++ b/gcc/config/arm/arm-arches.def
@@ -63,11 +63,11 @@ ARM_ARCH("armv8.1-a+crc",cortexa53, 8A,
 	  ARM_FSET_MAKE (FL_CO_PROC | FL_CRC32 | FL_FOR_ARCH8A,
 			 FL2_FOR_ARCH8_1A))
 ARM_ARCH("armv8-m.base", cortexm23, 8M_BASE,
-	 ARM_FSET_MAKE_CPU1 (			      FL_FOR_ARCH8M_BASE))
+	  ARM_FSET_MAKE (FL_FOR_ARCH8M_BASE, FL2_CMSE))
 ARM_ARCH("armv8-m.main", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC |	      FL_FOR_ARCH8M_MAIN))
+	  ARM_FSET_MAKE (FL_CO_PROC | FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("armv8-m.main+dsp", cortexm33, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN))
+	  ARM_FSET_MAKE (FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("iwmmxt",  iwmmxt,     5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT))
 ARM_ARCH("iwmmxt2", iwmmxt2,    5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT | FL_IWMMXT2))
 
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index 4fbdfc50d03507380e4fb59883923a81d9367489..c8ab1cb2377ebe7e8e96802f05142b33bb8008cb 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -76,6 +76,14 @@ arm_cpu_builtins (struct cpp_reader* pfile)
 
   def_or_undef_macro (pfile, "__ARM_32BIT_STATE", TARGET_32BIT);
 
+  if (arm_arch8 && !arm_arch_notm)
+    {
+      if (arm_arch_cmse && use_cmse)
+	builtin_define_with_int_value ("__ARM_FEATURE_CMSE", 3);
+      else
+	builtin_define ("__ARM_FEATURE_CMSE");
+    }
+
   if (TARGET_ARM_FEATURE_LDREX)
     builtin_define_with_int_value ("__ARM_FEATURE_LDREX",
 				   TARGET_ARM_FEATURE_LDREX);
diff --git a/gcc/config/arm/arm-flags.h b/gcc/config/arm/arm-flags.h
index 3feef51896a6de8c45f7e82aa252147f56b32b7a..d6709af5daab4d959990b2c6611bc3c1bc33a7f9 100644
--- a/gcc/config/arm/arm-flags.h
+++ b/gcc/config/arm/arm-flags.h
@@ -67,6 +67,7 @@
 #define FL_ARCH6KZ    (1U << 31)	/* ARMv6KZ architecture.  */
 
 #define FL2_ARCH8_1   (1U << 0)		/* Architecture 8.1.  */
+#define FL2_CMSE      (1U << 3)		/* ARMv8-M Security Extensions.  */
 
 /* Flags that only effect tuning, not available instructions.  */
 #define FL_TUNE		(FL_WBUF | FL_VFPV2 | FL_STRONG | FL_LDSCHED \
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 291d82d48c28d19c72aec569a05f2765c0809cdb..de9ad3e6a2df5103519ec16fcecdac8861a1cdfc 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -519,6 +519,9 @@ extern bool arm_disable_literal_pool;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 extern int arm_arch_crc;
 
+/* Nonzero if chip supports the ARMv8-M Security Extensions.  */
+extern int arm_arch_cmse;
+
 #ifndef TARGET_DEFAULT
 #define TARGET_DEFAULT  (MASK_APCS_FRAME)
 #endif
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index cc0bc7a669467ac7d0c1f9edcf70c4b0b8431690..7050f4897ddd9886d6c5377ca9c3e2764e2dff25 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -906,6 +906,9 @@ int arm_condexec_masklen = 0;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 int arm_arch_crc = 0;
 
+/* Nonzero if chip supports the ARMv8-M security extensions.  */
+int arm_arch_cmse = 0;
+
 /* Nonzero if the core has a very small, high-latency, multiply unit.  */
 int arm_m_profile_small_mul = 0;
 
@@ -3209,6 +3212,7 @@ arm_option_override (void)
   arm_arch_no_volatile_ce = ARM_FSET_HAS_CPU1 (insn_flags, FL_NO_VOLATILE_CE);
   arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0;
   arm_arch_crc = ARM_FSET_HAS_CPU1 (insn_flags, FL_CRC32);
+  arm_arch_cmse = ARM_FSET_HAS_CPU2 (insn_flags, FL2_CMSE);
   arm_m_profile_small_mul = ARM_FSET_HAS_CPU1 (insn_flags, FL_SMALLMUL);
 
   /* V5 code we generate is completely interworking capable, so we turn off
@@ -3462,6 +3466,9 @@ arm_option_override (void)
   if (target_slow_flash_data || target_pure_code)
     arm_disable_literal_pool = true;
 
+  if (use_cmse && !arm_arch_cmse)
+    error ("target CPU does not support ARMv8-M Security Extensions");
+
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index 35f047e2de1659c2b426cf42dbbdae5be62cbfef..5fb645df71b93960e8cda38c4b5b1d9d37df125c 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -109,6 +109,10 @@ mfloat-abi=
 Target RejectNegative Joined Enum(float_abi_type) Var(arm_float_abi) Init(TARGET_DEFAULT_FLOAT_ABI)
 Specify if floating point hardware should be used.
 
+mcmse
+Target RejectNegative Var(use_cmse)
+Specify that the compiler should target secure code as per ARMv8-M Security Extensions.
+
 Enum
 Name(float_abi_type) Type(enum float_abi_type)
 Known floating-point ABIs (for use with the -mfloat-abi= option):
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
new file mode 100644
index 0000000000000000000000000000000000000000..894343bb835b61e09c14668d45aa43a8693fd011
--- /dev/null
+++ b/gcc/config/arm/arm_cmse.h
@@ -0,0 +1,192 @@
+/* ARMv8-M Secure Extensions intrinsics include file.
+
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef _GCC_ARM_CMSE_H
+#define _GCC_ARM_CMSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __ARM_BIG_ENDIAN
+
+typedef union {
+  struct cmse_address_info {
+#if __ARM_FEATURE_CMSE & 2
+    unsigned idau_region:8;
+    unsigned idau_region_valid:1;
+    unsigned secure:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned nonsecure_read_ok:1;
+#else
+    unsigned :12;
+#endif
+    unsigned readwrite_ok:1;
+    unsigned read_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region:8;
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#else
+
+typedef union {
+  struct cmse_address_info {
+    unsigned mpu_region:8;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned read_ok:1;
+    unsigned readwrite_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned nonsecure_read_ok:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned secure:1;
+    unsigned idau_region_valid:1;
+    unsigned idau_region:8;
+#else
+    unsigned :12;
+#endif
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#endif /* __ARM_BIG_ENDIAN */
+
+#define cmse_TT_fptr(p) (__cmse_TT_fptr ((__cmse_fptr)(p)))
+
+typedef void (*__cmse_fptr)(void);
+
+#define __CMSE_TT_ASM(flags) \
+{ \
+  cmse_address_info_t __result; \
+   __asm__ ("tt" # flags " %0,%1" \
+	   : "=r"(__result) \
+	   : "r"(__p) \
+	   : "memory"); \
+  return __result; \
+}
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM ()
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT (void *__p)
+__CMSE_TT_ASM ()
+
+#define cmse_TTT_fptr(p) (__cmse_TTT_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TTT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (t)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT (void *__p)
+__CMSE_TT_ASM (t)
+
+#if __ARM_FEATURE_CMSE & 2
+
+#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+__cmse_TTA_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (a)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA (void *__p)
+__CMSE_TT_ASM (a)
+
+#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+__cmse_TTAT_fptr (__cmse_fptr __p)
+__CMSE_TT_ASM (at)
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT (void *__p)
+__CMSE_TT_ASM (at)
+
+#define CMSE_AU_NONSECURE	2
+#define CMSE_MPU_NONSECURE	16
+#define CMSE_NONSECURE		18
+
+#define cmse_nsfptr_create(p) ((typeof ((p))) ((intptr_t) (p) & ~1))
+
+#define cmse_is_nsfptr(p) (!((intptr_t) (p) & 1))
+
+#endif /* __ARM_FEATURE_CMSE & 2 */
+
+#define CMSE_MPU_UNPRIV		4
+#define CMSE_MPU_READWRITE	1
+#define CMSE_MPU_READ		8
+
+__extension__ void *
+cmse_check_address_range (void *, size_t, int);
+
+#define cmse_check_pointed_object(p, f) \
+  ((typeof ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
+
+#endif /* __ARM_FEATURE_CMSE & 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GCC_ARM_CMSE_H */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index ee2715d7ea62238f43eca099f04dbcb26a3af459..b582d5300d464ac3783c1fe60a73aca2527a9575 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -11416,6 +11416,7 @@ instructions, but allow the compiler to schedule those calls.
 * ARM iWMMXt Built-in Functions::
 * ARM C Language Extensions (ACLE)::
 * ARM Floating Point Status and Control Intrinsics::
+* ARM ARMv8-M Security Extensions::
 * AVR Built-in Functions::
 * Blackfin Built-in Functions::
 * FR-V Built-in Functions::
@@ -12260,6 +12261,31 @@ unsigned int __builtin_arm_get_fpscr ()
 void __builtin_arm_set_fpscr (unsigned int)
 @end smallexample
 
+@node ARM ARMv8-M Security Extensions
+@subsection ARM ARMv8-M Security Extensions
+
+GCC implements the ARMv8-M Security Extensions as described in the ARMv8-M
+Security Extensions: Requiremenets on Development Tools Engineering
+Specification, which can be found at
+@uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
+
+As part of the Security Extensions GCC implements the intrinsics below.  FPTR
+is used here to mean any function pointer type.
+
+@smallexample
+cmse_address_info_t cmse_TT (void *)
+cmse_address_info_t cmse_TT_fptr (FPTR)
+cmse_address_info_t cmse_TTT (void *)
+cmse_address_info_t cmse_TTT_fptr (FPTR)
+cmse_address_info_t cmse_TTA (void *)
+cmse_address_info_t cmse_TTA_fptr (FPTR)
+cmse_address_info_t cmse_TTAT (void *)
+cmse_address_info_t cmse_TTAT_fptr (FPTR)
+void * cmse_check_address_range (void *, size_t, int)
+typeof(p) cmse_nsfptr_create (FPTR p)
+intptr_t cmse_is_nsfptr (FPTR)
+@end smallexample
+
 @node AVR Built-in Functions
 @subsection AVR Built-in Functions
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 3112651f82790a2236042ed9a6791c78cf311d21..2f0ec8a6ced999fad5585bccf48f7534daa09189 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -633,7 +633,8 @@ Objective-C and Objective-C++ Dialects}.
 -mslow-flash-data @gol
 -masm-syntax-unified @gol
 -mrestrict-it @gol
--mpure-code}
+-mpure-code @gol
+-mcmse}
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol
@@ -14332,6 +14333,11 @@ Additionally, when compiling for ELF object format give all text sections the
 ELF processor-specific section attribute @code{SHF_ARM_PURECODE}.  This option
 is only available when generating non-pic code for ARMv7-M targets.
 
+@item -mcmse
+@opindex mcmse
+Generate secure code as per the "ARMv8-M Security Extensions: Requirements on
+Development Tools Engineering Specification", which can be found on
+@url{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 @end table
 
 @node AVR Options
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 74a679c64f4e575aecaa7dda93a19635a3595f6a..7f74d87b144be530a1f012819aed63519d7e2cbf 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -1609,6 +1609,10 @@ and @code{MOVT} instructions available.
 ARM target generates Thumb-1 code for @code{-mthumb} with
 @code{CBZ} and @code{CBNZ} instructions available.
 
+@item arm_cmse_ok
+ARM target supports ARMv8-M Security Extensions, enabled by the @code{-mcmse}
+option.
+
 @end table
 
 @subsubsection AArch64-specific attributes
diff --git a/gcc/testsuite/ChangeLog.arm b/gcc/testsuite/ChangeLog.arm
index 637ad1364c0cf2f4544f13c1b20521be804cc753..767b44aec61c90663ed7540e34c0e24da8c4835c 100644
--- a/gcc/testsuite/ChangeLog.arm
+++ b/gcc/testsuite/ChangeLog.arm
@@ -1,3 +1,15 @@
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
+	* gcc.target/arm/cmse/cmse.exp: New.
+	* gcc.target/arm/cmse/cmse-1.c: New.
+	* gcc.target/arm/cmse/cmse-12.c: New.
+	* lib/target-supports.exp
+	(check_effective_target_arm_cmse_ok): New.
+
 2016-11-22  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
 	Backport from mainline
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..d5b9a2d9d59569de170da814ae660e9fb2b943e7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mcmse -fdump-rtl-expand" }  */
+
+#include <arm_cmse.h>
+
+extern int a;
+extern int bar (void);
+
+int foo (char * p)
+{
+  cmse_address_info_t cait;
+
+  cait = cmse_TT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTA (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTA_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTAT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTAT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char), 0);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_READWRITE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV | CMSE_MPU_READ);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_AU_NONSECURE
+					 | CMSE_MPU_NONSECURE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  p = (char *) cmse_check_pointed_object (p, CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  return a;
+}
+/* { dg-final { scan-assembler-times "\ttt " 2 } } */
+/* { dg-final { scan-assembler-times "ttt " 2 } } */
+/* { dg-final { scan-assembler-times "tta " 2 } } */
+/* { dg-final { scan-assembler-times "ttat " 2 } } */
+/* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
+/* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
new file mode 100644
index 0000000000000000000000000000000000000000..87a2f1363a4e4bd817503e79e504980210e722c3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+#include <arm_cmse.h>
+
+char *
+foo (char * p)
+{
+  if (!cmse_is_nsfptr (p))
+    return cmse_nsfptr_create (p);
+}
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler-not "cmse_is_nsfptr" } } */
+/* { dg-final { scan-assembler-not "cmse_nsfptr_create" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
new file mode 100644
index 0000000000000000000000000000000000000000..f797dba1901720e04249d61078c1cbf2a3e436a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -0,0 +1,50 @@
+#   Copyright (C) 1997-2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite for ARMv8-M Security Extensions using the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Exit immediately if the target does not support -mcmse.
+if ![check_effective_target_arm_cmse_ok] then {
+    return
+}
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+set saved-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default "assemble"
+
+set saved-lto_torture_options ${LTO_TORTURE_OPTIONS}
+set LTO_TORTURE_OPTIONS ""
+
+# These are for both baseline and mainline.
+gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
+	"" $DEFAULT_CFLAGS
+
+set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 5fd027ccccc18fc4b0e0f50bca8380dafde3a271..a1d786b04466574b4f7ee19d4d6fa13464917d91 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -3397,6 +3397,19 @@ proc check_effective_target_arm_thumb1_cbz_ok {} {
     }
 }
 
+# Return 1 if this is an ARM target where ARMv8-M Security Extensions is
+# available.
+
+proc check_effective_target_arm_cmse_ok {} {
+    return [check_no_compiler_messages arm_cmse object {
+	int
+	foo (void)
+	{
+	  asm ("bxns r0");
+	}
+    } "-mcmse"];
+}
+
 # Return 1 if this compilation turns on string_ops_prefer_neon on.
 
 proc check_effective_target_arm_tune_string_ops_prefer_neon { } {
diff --git a/libgcc/ChangeLog.arm b/libgcc/ChangeLog.arm
index 0b6e290bdc8fdc3a7d995e0da18a38785afcc666..50b4ce5f0e8a32c51c7831291852caccad14e9c9 100644
--- a/libgcc/ChangeLog.arm
+++ b/libgcc/ChangeLog.arm
@@ -1,3 +1,12 @@
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
+	* config/arm/t-arm (HAVE_CMSE): New.
+	* config/arm/cmse.c: New.
+
 2016-07-12 Andre Vieira <andre.simoesdiasvieira@arm.com>
 
 	Backport from mainline
diff --git a/libgcc/config/arm/cmse.c b/libgcc/config/arm/cmse.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe3a22967c8536f2a8c05b58627f964d3fb1d345
--- /dev/null
+++ b/libgcc/config/arm/cmse.c
@@ -0,0 +1,108 @@
+/* ARMv8-M Security Extensions routines.
+   Copyright (C) 2015-2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <arm_cmse.h>
+
+/* ARM intrinsic function to perform a permission check on a given
+   address range.  See ACLE changes for ARMv8-M.  */
+
+void *
+cmse_check_address_range (void *p, size_t size, int flags)
+{
+  cmse_address_info_t permb, perme;
+  char *pb = (char *) p, *pe;
+
+  /* Check if the range wraps around.  */
+  if (UINTPTR_MAX - (uintptr_t) p < size)
+    return NULL;
+
+  /* Check if an unknown flag is present.  */
+  int known = CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE | CMSE_MPU_READ;
+  int known_secure_level = CMSE_MPU_UNPRIV;
+#if __ARM_FEATURE_CMSE & 2
+  known |= CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE;
+  known_secure_level |= CMSE_MPU_NONSECURE;
+#endif
+  if (flags & (~known))
+    return NULL;
+
+  /* Execute the right variant of the TT instructions.  */
+  pe = pb + size - 1;
+  const int singleCheck = (((uintptr_t) pb ^ (uintptr_t) pe) < 32);
+  switch (flags & known_secure_level)
+    {
+    case 0:
+      permb = cmse_TT (pb);
+      perme = singleCheck ? permb : cmse_TT (pe);
+      break;
+    case CMSE_MPU_UNPRIV:
+      permb = cmse_TTT (pb);
+      perme = singleCheck ? permb : cmse_TTT (pe);
+      break;
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_NONSECURE:
+      permb = cmse_TTA (pb);
+      perme = singleCheck ? permb : cmse_TTA (pe);
+      break;
+    case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+      permb = cmse_TTAT (pb);
+      perme = singleCheck ? permb : cmse_TTAT (pe);
+      break;
+#endif
+    default:
+      /* Invalid flag, eg.  CMSE_MPU_NONSECURE specified but
+	 __ARM_FEATURE_CMSE & 2 == 0.  */
+      return NULL;
+    }
+
+  /* Check that the range does not cross MPU, SAU, or IDAU boundaries.  */
+  if (permb.value != perme.value)
+    return NULL;
+
+  /* Check the permissions on the range.  */
+  switch (flags & (~known_secure_level))
+    {
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+    case		 CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_readwrite_ok	? p : NULL;
+    case CMSE_MPU_READ | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_read_ok	? p : NULL;
+    case CMSE_AU_NONSECURE:
+      return permb.flags.secure			? NULL : p;
+#endif
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE:
+    case		 CMSE_MPU_READWRITE:
+      return permb.flags.readwrite_ok		? p : NULL;
+    case CMSE_MPU_READ:
+      return permb.flags.read_ok		? p : NULL;
+    default:
+      return NULL;
+    }
+}
+
+
+#endif /* __ARM_FEATURE_CMSE & 1.  */
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 4e17e99b4a53bbafc0f1f8dddd02000f0e8f4f48..5618143bfd0f02b170db3f9e4c0a15cecb403cec 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -1,3 +1,15 @@
 LIB1ASMSRC = arm/lib1funcs.S
 LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
 	_thumb1_case_uhi _thumb1_case_si
+
+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),)
+CMSE_OPTS:=-mcmse
+endif
+
+ifdef HAVE_CMSE
+libgcc-objects += cmse.o cmse_nonsecure_call.o
+
+cmse.o: $(srcdir)/config/arm/cmse.c
+	$(gcc_compile) -c $(CMSE_OPTS) $<
+endif

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

* [arm-embedded][committed][PATCH 2/7] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute
  2016-10-27 10:19               ` Kyrill Tkachov
@ 2016-12-05 11:31                 ` Andre Vieira (lists)
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-12-05 11:31 UTC (permalink / raw)
  To: gcc-patches

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

On 27/10/16 11:19, Kyrill Tkachov wrote:
> 
> On 27/10/16 10:54, Andre Vieira (lists) wrote:
>> On 26/10/16 17:28, Kyrill Tkachov wrote:
>>> On 26/10/16 17:28, Andre Vieira (lists) wrote:
>>>> On 26/10/16 10:33, Kyrill Tkachov wrote:
>>>>> +static tree
>>>>> +arm_handle_cmse_nonsecure_entry (tree *node, tree name,
>>>>> +                 tree /* args */,
>>>>> +                 int /* flags */,
>>>>> +                 bool *no_add_attrs)
>>>>> +{
>>>>> +  tree fndecl;
>>>>> +
>>>>> +  if (!use_cmse)
>>>>> +    {
>>>>> +      *no_add_attrs = true;
>>>>> +      return NULL_TREE;
>>>>> +    }
>>>>>
>>>>> Do you also want to warn the user here that the attribute will be
>>>>> ignored?
>>>>> This looks ok to me otherwise.
>>>>>
>>>> Can easily do and might be more user friendly. How about
>>>> "<attribute_name> attribute ignored without -mcmse option."
>>> Yes, that's fine (without the full stop at the end)
>>> Kyrill
>>>
>>>> Cheers,
>>>> Andre
>>>>
>> Hi,
>>
>> Reworked comments. No change to ChangeLogs.
> 
> Ok.
> Thanks,
> Kyrill
> 
>> Cheers,
>> Andre
> 
Hi,

Backported this to the embedded-6-branch in revision r243248.

Cheers,
Andre

gcc/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
	(arm_attribute_table): Added cmse_nonsecure_entry
	(arm_compute_func_type): Handle cmse_nonsecure_entry.
	(cmse_func_args_or_return_in_stack): New.
	(arm_handle_cmse_nonsecure_entry): New.
	* config/arm/arm.h (ARM_FT_CMSE_ENTRY): New macro define.
	(IS_CMSE_ENTRY): Likewise.
	* doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.

gcc/testsuite/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

[-- Attachment #2: diff2 --]
[-- Type: text/plain, Size: 9952 bytes --]

diff --git a/gcc/ChangeLog.arm b/gcc/ChangeLog.arm
index 98704eb438dadd73cf793da5a7b8266b5e9ef267..c93007a6b814320f3a3fb283873e21347b4cd333 100644
--- a/gcc/ChangeLog.arm
+++ b/gcc/ChangeLog.arm
@@ -4,6 +4,21 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
+	(arm_attribute_table): Added cmse_nonsecure_entry
+	(arm_compute_func_type): Handle cmse_nonsecure_entry.
+	(cmse_func_args_or_return_in_stack): New.
+	(arm_handle_cmse_nonsecure_entry): New.
+	* config/arm/arm.h (ARM_FT_CMSE_ENTRY): New macro define.
+	(IS_CMSE_ENTRY): Likewise.
+	* doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* config.gcc (extra_headers): Added arm_cmse.h.
 	* config/arm/arm-arches.def (ARM_ARCH):
 	(armv8-m): Add FL2_CMSE.
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index de9ad3e6a2df5103519ec16fcecdac8861a1cdfc..4e5e477bd2ba4eaa30640d0fdb4336b56cb37391 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -1383,6 +1383,7 @@ enum reg_class
 #define ARM_FT_VOLATILE		(1 << 4) /* Does not return.  */
 #define ARM_FT_NESTED		(1 << 5) /* Embedded inside another func.  */
 #define ARM_FT_STACKALIGN	(1 << 6) /* Called with misaligned stack.  */
+#define ARM_FT_CMSE_ENTRY	(1 << 7) /* ARMv8-M non-secure entry function.  */
 
 /* Some macros to test these flags.  */
 #define ARM_FUNC_TYPE(t)	(t & ARM_FT_TYPE_MASK)
@@ -1391,6 +1392,7 @@ enum reg_class
 #define IS_NAKED(t)        	(t & ARM_FT_NAKED)
 #define IS_NESTED(t)       	(t & ARM_FT_NESTED)
 #define IS_STACKALIGN(t)       	(t & ARM_FT_STACKALIGN)
+#define IS_CMSE_ENTRY(t)	(t & ARM_FT_CMSE_ENTRY)
 
 
 /* Structure used to hold the function stack frame layout.  Offsets are
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 7050f4897ddd9886d6c5377ca9c3e2764e2dff25..6eafba774542fb4b20f7b72fd353621a54ca5bc6 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -136,6 +136,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
+static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -348,6 +349,9 @@ static const struct attribute_spec arm_attribute_table[] =
   { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute,
     false },
 #endif
+  /* ARMv8-M Security Extensions support.  */
+  { "cmse_nonsecure_entry", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_entry, false },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -3601,6 +3605,9 @@ arm_compute_func_type (void)
   else
     type |= arm_isr_value (TREE_VALUE (a));
 
+  if (lookup_attribute ("cmse_nonsecure_entry", attr))
+    type |= ARM_FT_CMSE_ENTRY;
+
   return type;
 }
 
@@ -6594,6 +6601,113 @@ arm_handle_notshared_attribute (tree *node,
 }
 #endif
 
+/* This function returns true if a function with declaration FNDECL and type
+   FNTYPE uses the stack to pass arguments or return variables and false
+   otherwise.  This is used for functions with the attributes
+   'cmse_nonsecure_call' or 'cmse_nonsecure_entry' and this function will issue
+   diagnostic messages if the stack is used.  NAME is the name of the attribute
+   used.  */
+
+static bool
+cmse_func_args_or_return_in_stack (tree fndecl, tree name, tree fntype)
+{
+  function_args_iterator args_iter;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
+  bool first_param = true;
+  tree arg_type, prev_arg_type = NULL_TREE, ret_type;
+
+  /* Error out if any argument is passed on the stack.  */
+  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX, fndecl);
+  args_so_far = pack_cumulative_args (&args_so_far_v);
+  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+    {
+      rtx arg_rtx;
+      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+      prev_arg_type = arg_type;
+      if (VOID_TYPE_P (arg_type))
+	continue;
+
+      if (!first_param)
+	arm_function_arg_advance (args_so_far, arg_mode, arg_type, true);
+      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type, true);
+      if (!arg_rtx
+	  || arm_arg_partial_bytes (args_so_far, arg_mode, arg_type, true))
+	{
+	  error ("%qE attribute not available to functions with arguments "
+		 "passed on the stack", name);
+	  return true;
+	}
+      first_param = false;
+    }
+
+  /* Error out for variadic functions since we cannot control how many
+     arguments will be passed and thus stack could be used.  stdarg_p () is not
+     used for the checking to avoid browsing arguments twice.  */
+  if (prev_arg_type != NULL_TREE && !VOID_TYPE_P (prev_arg_type))
+    {
+      error ("%qE attribute not available to functions with variable number "
+	     "of arguments", name);
+      return true;
+    }
+
+  /* Error out if return value is passed on the stack.  */
+  ret_type = TREE_TYPE (fntype);
+  if (arm_return_in_memory (ret_type, fntype))
+    {
+      error ("%qE attribute not available to functions that return value on "
+	     "the stack", name);
+      return true;
+    }
+  return false;
+}
+
+/* Called upon detection of the use of the cmse_nonsecure_entry attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function declaration tree or otherwise issue a warning.  */
+
+static tree
+arm_handle_cmse_nonsecure_entry (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree fndecl;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored without -mcmse option.",
+	       name);
+      return NULL_TREE;
+    }
+
+  /* Ignore attribute for function types.  */
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+	       name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  fndecl = *node;
+
+  /* Warn for static linkage functions.  */
+  if (!TREE_PUBLIC (fndecl))
+    {
+      warning (OPT_Wattributes, "%qE attribute has no effect on functions "
+	       "with static linkage", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (fndecl, name,
+						TREE_TYPE (fndecl));
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index b582d5300d464ac3783c1fe60a73aca2527a9575..1693c5968c608303159ac8b4a24744c0c57b7936 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12269,6 +12269,9 @@ Security Extensions: Requiremenets on Development Tools Engineering
 Specification, which can be found at
 @uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 
+As part of the Security Extensions GCC implements a new function attribute
+@code{cmse_nonsecure_entry}.
+
 As part of the Security Extensions GCC implements the intrinsics below.  FPTR
 is used here to mean any function pointer type.
 
diff --git a/gcc/testsuite/ChangeLog.arm b/gcc/testsuite/ChangeLog.arm
index 767b44aec61c90663ed7540e34c0e24da8c4835c..30afd4b0fa9b6f2859a3f0c84485b40487f602e9 100644
--- a/gcc/testsuite/ChangeLog.arm
+++ b/gcc/testsuite/ChangeLog.arm
@@ -4,6 +4,14 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* gcc.target/arm/cmse/cmse-3.c: New.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* gcc.target/arm/cmse/cmse.exp: New.
 	* gcc.target/arm/cmse/cmse-1.c: New.
 	* gcc.target/arm/cmse/cmse-12.c: New.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c2920e1dc310106d83203eb51e1a68a275d0152
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+struct span2 {
+  float a, b, c, d;
+};
+
+union test_union
+{
+  long long a;
+  int b;
+  struct span2 c;
+} test_union;
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (long long a, int b, long long c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+bar (long long a, int b, struct span c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+void __attribute__ ((cmse_nonsecure_entry))
+baz (int a, ...) {} /* { dg-error "not available to functions with variable number of arguments" } */
+
+struct span __attribute__ ((cmse_nonsecure_entry))
+qux (void) { /* { dg-error "not available to functions that return value on the stack" } */
+  struct span ret = {0, 0};
+  return ret;
+}
+
+void __attribute__ ((cmse_nonsecure_entry))
+norf (struct span2 a) {}
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */

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

* [arm-embedded][committed][PATCH 3/7] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return
  2016-10-27  9:55       ` Andre Vieira (lists)
@ 2016-12-05 11:34         ` Andre Vieira (lists)
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-12-05 11:34 UTC (permalink / raw)
  To: gcc-patches

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

On 27/10/16 10:55, Andre Vieira (lists) wrote:
> On 26/10/16 11:03, Kyrill Tkachov wrote:
>> Hi Andre,
>>
>> On 25/10/16 17:28, Andre Vieira (lists) wrote:
>>> On 25/07/16 14:23, Andre Vieira (lists) wrote:
>>>> This patch extends support for the ARMv8-M Security Extensions
>>>> 'cmse_nonsecure_entry' attribute in two ways:
>>>>
>>>> 1) Generate two labels for the function, the regular function name and
>>>> one with the function's name appended to '__acle_se_', this will trigger
>>>> the linker to create a secure gateway veneer for this entry function.
>>>> 2) Return from cmse_nonsecure_entry marked functions using bxns.
>>>>
>>>> See Section 5.4 of ARM®v8-M Security Extensions
>>>> (http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/index.html).
>>>>
>>>>
>>>>
>>>> *** gcc/ChangeLog ***
>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>          * config/arm/arm.c (use_return_insn): Change to return with 
>>>> bxns
>>>>          when cmse_nonsecure_entry.
>>>>          (output_return_instruction): Likewise.
>>>>          (arm_output_function_prologue): Likewise.
>>>>          (thumb_pop): Likewise.
>>>>          (thumb_exit): Likewise.
>>>>          (arm_function_ok_for_sibcall): Disable sibcall for entry
>>>> functions.
>>>>          (arm_asm_declare_function_name): New.
>>>>          * config/arm/arm-protos.h (arm_asm_declare_function_name): New.
>>>>          * config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
>>>>          use arm_asm_declare_function_name.
>>>>
>>>> *** gcc/testsuite/ChangeLog ***
>>>> 2016-07-25  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>          * gcc.target/arm/cmse/cmse-2.c: New.
>>>>          * gcc.target/arm/cmse/cmse-4.c: New.
>>>>
>>> Hi,
>>>
>>> Rebased previous patch on top of trunk as requested. No changes to
>>> ChangeLog.
>>>
>>> Cheers,
>>> Andre
>>
>> @@ -19919,6 +19932,42 @@ output_return_instruction (rtx operand, bool
>> really_return, bool reverse,
>>    return "";
>>  }
>>  
>> +/* Output in FILE asm statements needed to declare the NAME of the
>> function
>> +   defined by its DECL node.  */
>> +
>> +void
>> +arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
>> +{
>> +  size_t cmse_name_len;
>> +  char *cmse_name = 0;
>> +  char cmse_prefix[] = "__acle_se_";
>> +
>> +  if (use_cmse && lookup_attribute ("cmse_nonsecure_entry",
>> +                    DECL_ATTRIBUTES (decl)))
>> +    {
>> +      cmse_name_len = sizeof (cmse_prefix) + strlen (name);
>> +      cmse_name = XALLOCAVEC (char, cmse_name_len);
>> +      snprintf (cmse_name, cmse_name_len, "%s%s", cmse_prefix, name);
>> +      targetm.asm_out.globalize_label (file, cmse_name);
>> +    }
>> +
>>
>> I think this definitely warrants a quick comment explaining why you're
>> adding
>> __acle_se_ to the function label
>>
>>  
>>  /* Scan INSN just before assembler is output for it.
>> @@ -25247,6 +25301,12 @@ thumb2_expand_return (bool simple_return)
>>  
>>    if (!simple_return && saved_regs_mask)
>>      {
>> +      /* TODO: Verify that this path is never taken for
>> cmse_nonsecure_entry
>> +     functions or adapt code to handle according to ACLE.  This path
>> should
>> +     not be reachable for cmse_nonsecure_entry functions though we prefer
>> +     to guard it for now to ensure that future code changes do not
>> silently
>> +     change this behavior.  */
>>
>> I think you mean s/guard/assert/
>>
>>  +      gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
>>        if (num_regs == 1)
>>          {
>>            rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
>>
>> This is ok with those changes.
>> Thanks,
>> Kyrill
>>
> Hi,
> 
> Reworked comments. Also got rid of a redundant 'if (cmse_name)' in
> 'arm_asm_declare_function_name'. No change to ChangeLogs.
> 
> Cheers,
> Andre
> 
Hi,

Backported this to the embedded-6-branch in revision r<revision>.

Cheers,
Andre

gcc/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* config/arm/arm.c (use_return_insn): Change to return with  bxns
	when cmse_nonsecure_entry.
	(output_return_instruction): Likewise.
	(arm_output_function_prologue): Likewise.
	(thumb_pop): Likewise.
	(thumb_exit): Likewise.
	(thumb2_expand_return): Assert that entry functions always have simple
	returns.
	(arm_expand_epilogue): Handle entry functions.
	(arm_function_ok_for_sibcall): Disable sibcall for entry functions.
	(arm_asm_declare_function_name): New.
	* config/arm/arm-protos.h (arm_asm_declare_function_name): New.
	* config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
	use arm_asm_declare_function_name.

gcc/testsuite/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/cmse-4.c: New.
	* gcc.target/arm/cmse/cmse-9.c: New.
	* gcc.target/arm/cmse/cmse-10.c: New.



[-- Attachment #2: diff3 --]
[-- Type: text/plain, Size: 13128 bytes --]

diff --git a/gcc/ChangeLog.arm b/gcc/ChangeLog.arm
index c93007a6b814320f3a3fb283873e21347b4cd333..b443bd9a796b05a5ab26b0b72a6ad1c52b6cf8b8 100644
--- a/gcc/ChangeLog.arm
+++ b/gcc/ChangeLog.arm
@@ -4,6 +4,27 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* config/arm/arm.c (use_return_insn): Change to return with  bxns
+	when cmse_nonsecure_entry.
+	(output_return_instruction): Likewise.
+	(arm_output_function_prologue): Likewise.
+	(thumb_pop): Likewise.
+	(thumb_exit): Likewise.
+	(thumb2_expand_return): Assert that entry functions always have simple
+	returns.
+	(arm_expand_epilogue): Handle entry functions.
+	(arm_function_ok_for_sibcall): Disable sibcall for entry functions.
+	(arm_asm_declare_function_name): New.
+	* config/arm/arm-protos.h (arm_asm_declare_function_name): New.
+	* config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME): Redefine to
+	use arm_asm_declare_function_name.
+
+2016-12-05  Andre Vieira        <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* config/arm/arm.c (arm_handle_cmse_nonsecure_entry): New.
 	(arm_attribute_table): Added cmse_nonsecure_entry
 	(arm_compute_func_type): Handle cmse_nonsecure_entry.
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 8232b26a2e147a6ea20a39defae5ac7180adfc58..fb9e6f4c7f54f3f491381ba8e48ab14979bd0dc3 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -33,6 +33,7 @@ extern int arm_volatile_func (void);
 extern void arm_expand_prologue (void);
 extern void arm_expand_epilogue (bool);
 extern void arm_declare_function_name (FILE *, const char *, tree);
+extern void arm_asm_declare_function_name (FILE *, const char *, tree);
 extern void thumb2_expand_return (bool);
 extern const char *arm_strip_name_encoding (const char *);
 extern void arm_asm_output_labelref (FILE *, const char *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 6eafba774542fb4b20f7b72fd353621a54ca5bc6..97502c74588439960c5dff39168020e02f8444f2 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3834,6 +3834,11 @@ use_return_insn (int iscond, rtx sibling)
 	return 0;
     }
 
+  /* 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))
+    return 0;
+
   /* If there are saved registers but the LR isn't saved, then we need
      two instructions for the return.  */
   if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
@@ -6866,6 +6871,11 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
   if (IS_INTERRUPT (func_type))
     return false;
 
+  /* ARMv8-M non-secure entry functions need to return with bxns which is only
+     generated for entry functions themselves.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    return false;
+
   if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
     {
       /* Check that the return value locations are the same.  For
@@ -19715,6 +19725,7 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	 (e.g. interworking) then we can load the return address
 	 directly into the PC.  Otherwise we must load it into LR.  */
       if (really_return
+	  && !IS_CMSE_ENTRY (func_type)
 	  && (IS_INTERRUPT (func_type) || !TARGET_INTERWORK))
 	return_reg = reg_names[PC_REGNUM];
       else
@@ -19855,8 +19866,10 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 	  break;
 
 	default:
+	  if (IS_CMSE_ENTRY (func_type))
+	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
 	  /* Use bx if it's available.  */
-	  if (arm_arch5 || arm_arch4t)
+	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
 	  else
 	    sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
@@ -19869,6 +19882,44 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
   return "";
 }
 
+/* Output in FILE asm statements needed to declare the NAME of the function
+   defined by its DECL node.  */
+
+void
+arm_asm_declare_function_name (FILE *file, const char *name, tree decl)
+{
+  size_t cmse_name_len;
+  char *cmse_name = 0;
+  char cmse_prefix[] = "__acle_se_";
+
+  /* When compiling with ARMv8-M Security Extensions enabled, we should print an
+     extra function label for each function with the 'cmse_nonsecure_entry'
+     attribute.  This extra function label should be prepended with
+     '__acle_se_', telling the linker that it needs to create secure gateway
+     veneers for this function.  */
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_entry",
+				    DECL_ATTRIBUTES (decl)))
+    {
+      cmse_name_len = sizeof (cmse_prefix) + strlen (name);
+      cmse_name = XALLOCAVEC (char, cmse_name_len);
+      snprintf (cmse_name, cmse_name_len, "%s%s", cmse_prefix, name);
+      targetm.asm_out.globalize_label (file, cmse_name);
+
+      ARM_DECLARE_FUNCTION_NAME (file, cmse_name, decl);
+      ASM_OUTPUT_TYPE_DIRECTIVE (file, cmse_name, "function");
+    }
+
+  ARM_DECLARE_FUNCTION_NAME (file, name, decl);
+  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
+  ASM_OUTPUT_LABEL (file, name);
+
+  if (cmse_name)
+    ASM_OUTPUT_LABEL (file, cmse_name);
+
+  ARM_OUTPUT_FN_UNWIND (file, TRUE);
+}
+
 /* Write the function name into the code section, directly preceding
    the function prologue.
 
@@ -19918,10 +19969,6 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
 {
   unsigned long func_type;
 
-  /* ??? Do we want to print some of the below anyway?  */
-  if (TARGET_THUMB1)
-    return;
-
   /* Sanity check.  */
   gcc_assert (!arm_ccfsm_state && !arm_target_insn);
 
@@ -19956,6 +20003,8 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
     asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
   if (IS_STACKALIGN (func_type))
     asm_fprintf (f, "\t%@ Stack Align: May be called with mis-aligned SP.\n");
+  if (IS_CMSE_ENTRY (func_type))
+    asm_fprintf (f, "\t%@ Non-secure entry function: called from non-secure code.\n");
 
   asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
 	       crtl->args.size,
@@ -24031,8 +24080,8 @@ thumb_pop (FILE *f, unsigned long mask)
   if (mask & (1 << PC_REGNUM))
     {
       /* Catch popping the PC.  */
-      if (TARGET_INTERWORK || TARGET_BACKTRACE
-	  || crtl->calls_eh_return)
+      if (TARGET_INTERWORK || TARGET_BACKTRACE || crtl->calls_eh_return
+	  || IS_CMSE_ENTRY (arm_current_func_type ()))
 	{
 	  /* The PC is never poped directly, instead
 	     it is popped into r3 and then BX is used.  */
@@ -24093,7 +24142,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
       if (crtl->calls_eh_return)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
-      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+      else
+	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
     }
   /* Otherwise if we are not supporting interworking and we have not created
@@ -24102,7 +24154,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
   else if (!TARGET_INTERWORK
 	   && !TARGET_BACKTRACE
 	   && !is_called_in_ARM_mode (current_function_decl)
-	   && !crtl->calls_eh_return)
+	   && !crtl->calls_eh_return
+	   && !IS_CMSE_ENTRY (arm_current_func_type ()))
     {
       asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
       return;
@@ -24325,7 +24378,10 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
     asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
   /* Return to caller.  */
-  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+  else
+    asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
 \f
 /* Scan INSN just before assembler is output for it.
@@ -25211,6 +25267,12 @@ thumb2_expand_return (bool simple_return)
 
   if (!simple_return && saved_regs_mask)
     {
+      /* TODO: Verify that this path is never taken for cmse_nonsecure_entry
+	 functions or adapt code to handle according to ACLE.  This path should
+	 not be reachable for cmse_nonsecure_entry functions though we prefer
+	 to assert it for now to ensure that future code changes do not silently
+	 change this behavior.  */
+      gcc_assert (!IS_CMSE_ENTRY (arm_current_func_type ()));
       if (num_regs == 1)
         {
           rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
@@ -25628,6 +25690,7 @@ arm_expand_epilogue (bool really_return)
 
       if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
           && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
+	  && !IS_CMSE_ENTRY (func_type)
           && !IS_STACKALIGN (func_type)
           && really_return
           && crtl->args.pretend_args_size == 0
diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h
index bc4eb86f1da5beabf32647637eb87a3fc17a6c6a..03931eee7390ab4d09522e7d8bea10449719ddba 100644
--- a/gcc/config/arm/elf.h
+++ b/gcc/config/arm/elf.h
@@ -75,16 +75,7 @@
 
 /* We might need a ARM specific header to function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_NAME
-#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)		\
-  do								\
-    {								\
-      ARM_DECLARE_FUNCTION_NAME (FILE, NAME, DECL);		\
-      ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function");	\
-      ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL));		\
-      ASM_OUTPUT_LABEL(FILE, NAME);				\
-      ARM_OUTPUT_FN_UNWIND (FILE, TRUE);			\
-    }								\
-  while (0)
+#define ASM_DECLARE_FUNCTION_NAME arm_asm_declare_function_name
 
 /* We might need an ARM specific trailer for function declarations.  */
 #undef  ASM_DECLARE_FUNCTION_SIZE
diff --git a/gcc/testsuite/ChangeLog.arm b/gcc/testsuite/ChangeLog.arm
index 30afd4b0fa9b6f2859a3f0c84485b40487f602e9..338ac2d0fbd6752ce5ca59557cea12e4996d607f 100644
--- a/gcc/testsuite/ChangeLog.arm
+++ b/gcc/testsuite/ChangeLog.arm
@@ -4,6 +4,16 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* gcc.target/arm/cmse/cmse-4.c: New.
+	* gcc.target/arm/cmse/cmse-9.c: New.
+	* gcc.target/arm/cmse/cmse-10.c: New.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* gcc.target/arm/cmse/cmse-3.c: New.
 
 2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a91ac39ee37ef20495e047b402d3f5edc60a613
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-10.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+void
+foo (void) {}
+
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f930ab04a1097c64097a4e003296bbe85733319
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" }  */
+
+struct span {
+  int a, b;
+};
+
+extern int qux (void);
+
+void __attribute__ ((cmse_nonsecure_entry))
+foo (void) {}
+
+static void __attribute__ ((cmse_nonsecure_entry))
+bar (void) {} /* { dg-warning "has no effect on functions with static linkage" } */
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return qux ();
+}
+
+/* { dg-final { scan-assembler-times "bxns" 2 } } */
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..1d97f0e1a37209bd129ffe96ce92a86bc2e0d5d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
+
+
+int __attribute__ ((cmse_nonsecure_entry))
+foo (int a)
+{ /* { dg-warning "attribute ignored without -mcmse option" } */
+  return a + 1;
+}
+
+/* { dg-final { scan-assembler "foo:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_foo:" } } */

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

* [arm-embedded][committed][PATCH 4/7] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers
  2016-11-30 17:22                         ` Kyrill Tkachov
@ 2016-12-05 11:36                           ` Andre Vieira (lists)
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-12-05 11:36 UTC (permalink / raw)
  To: gcc-patches

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

On 30/11/16 17:22, Kyrill Tkachov wrote:
> 
> On 30/11/16 15:32, Andre Vieira (lists) wrote:
>> On 23/11/16 11:52, Andre Vieira (lists) wrote:
>>> Hi,
>>>
>>> After some extra testing I realized there was an issue with the way we
>>> were clearing registers when returning from a cmse_nonsecure_entry
>>> function for ARMv8-M.Baseline.  This patch fixes that and changes the
>>> testcase to catch the issue.
>>>
>>> The problem was I was always using LR to clear the registers, however,
>>> due to the way the Thumb-1 backend works, we can't guarantee LR will
>>> contain the address to which we will be returning at the time of
>>> clearing. Instead we use r0 to clear r1-r3 and IP. If the function does
>>> not use r0 to return a value, we clear r0 with 0 before using it to
>>> clear everything else. As for LR, we move the value of the register used
>>> to return into it prior to returning.
>>>
>>> This satisfies the requirements of not leaking secure information since
>>> all registers hold either:
>>> - values to return
>>> - 0
>>> - return address
>>>
>>> No changes to ChangeLog.
>>>
>>> Cheers,
>>> Andre
>>>
>> Hi,
>>
>> So I seemed to have forgotten to address two of your comments earlier,
>> done in this version.
>>
>> To reiterate:
>> After some extra testing I realized there was an issue with the way we
>> were clearing registers when returning from a cmse_nonsecure_entry
>> function for ARMv8-M Baseline.  This patch fixes that and changes the
>> testcase to catch the issue.
>>
>> The problem was I was always using LR to clear the registers, however,
>> due to the way the Thumb-1 backend works, we can't guarantee LR will
>> contain the address to which we will be returning at the time of
>> clearing. Instead we use r0 to clear r1-r3 and IP. If the function does
>> not use r0 to return a value, we clear r0 with 0 before using it to
>> clear everything else. As for LR, we move the value of the register used
>> to return into it prior to returning.
>>
>> This satisfies the requirements of not leaking secure information since
>> all registers hold either:
>> - values to return
>> - 0
>> - return address
>>
>> *** gcc/ChangeLog ***
>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>           * config/arm/arm.c (output_return_instruction): Clear
>>           registers.
>>           (thumb2_expand_return): Likewise.
>>           (thumb1_expand_epilogue): Likewise.
>>           (thumb_exit): Likewise.
>>           (arm_expand_epilogue): Likewise.
>>           (cmse_nonsecure_entry_clear_before_return): New.
>>           (comp_not_to_clear_mask_str_un): New.
>>           (compute_not_to_clear_mask): New.
>>           * config/arm/thumb1.md (*epilogue_insns): Change length
>> attribute.
>>           * config/arm/thumb2.md (*thumb2_cmse_entry_return): Duplicate
>>           thumb2_return pattern for cmse_nonsecure_entry functions.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>               Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>           * gcc.target/arm/cmse/cmse.exp: Test different multilibs
>> separate.
>>           * gcc.target/arm/cmse/struct-1.c: New.
>>           * gcc.target/arm/cmse/bitfield-1.c: New.
>>           * gcc.target/arm/cmse/bitfield-2.c: New.
>>           * gcc.target/arm/cmse/bitfield-3.c: New.
>>           * gcc.target/arm/cmse/baseline/cmse-2.c: Test that registers
>> are
>> cleared.
>>           * gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
>>           * gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
>>           * gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
>>           * gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
>>           * gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
> 
> Ok, thanks for addressing the issues.
> Kyrill
> 
>> Cheers,
>> Andre
> 
Hi,

Backported this to the embedded-6-branch in revision r243250.

Cheers,
Andre

gcc/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* config/arm/arm.c (output_return_instruction): Clear
	registers.
	(thumb2_expand_return): Likewise.
	(thumb1_expand_epilogue): Likewise.
	(thumb_exit): Likewise.
	(arm_expand_epilogue): Likewise.
	(cmse_nonsecure_entry_clear_before_return): New.
	(comp_not_to_clear_mask_str_un): New.
	(compute_not_to_clear_mask): New.
	* config/arm/thumb1.md (*epilogue_insns): Change length attribute.
	* config/arm/thumb2.md (*thumb2_return): Disable for
	cmse_nonsecure_entry functions.
	(*thumb2_cmse_entry_return): Duplicate thumb2_return pattern for
	cmse_nonsecure_entry functions.

gcc/testsuite/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
	* gcc.target/arm/cmse/struct-1.c: New.
	* gcc.target/arm/cmse/bitfield-1.c: New.
	* gcc.target/arm/cmse/bitfield-2.c: New.
	* gcc.target/arm/cmse/bitfield-3.c: New.
	* gcc.target/arm/cmse/baseline/cmse-2.c: New.
	* gcc.target/arm/cmse/baseline/softfp.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.

[-- Attachment #2: diff4 --]
[-- Type: text/plain, Size: 43815 bytes --]

diff --git a/gcc/ChangeLog.arm b/gcc/ChangeLog.arm
index b443bd9a796b05a5ab26b0b72a6ad1c52b6cf8b8..3085e1c93270cb7ab9fcee5dbe70ec6ada763026 100644
--- a/gcc/ChangeLog.arm
+++ b/gcc/ChangeLog.arm
@@ -4,6 +4,27 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* config/arm/arm.c (output_return_instruction): Clear
+	registers.
+	(thumb2_expand_return): Likewise.
+	(thumb1_expand_epilogue): Likewise.
+	(thumb_exit): Likewise.
+	(arm_expand_epilogue): Likewise.
+	(cmse_nonsecure_entry_clear_before_return): New.
+	(comp_not_to_clear_mask_str_un): New.
+	(compute_not_to_clear_mask): New.
+	* config/arm/thumb1.md (*epilogue_insns): Change length attribute.
+	* config/arm/thumb2.md (*thumb2_return): Disable for
+	cmse_nonsecure_entry functions.
+	(*thumb2_cmse_entry_return): Duplicate thumb2_return pattern for
+	cmse_nonsecure_entry functions.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* config/arm/arm.c (use_return_insn): Change to return with  bxns
 	when cmse_nonsecure_entry.
 	(output_return_instruction): Likewise.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 97502c74588439960c5dff39168020e02f8444f2..b9a62b5e6bf06dcc218dfdb3111dc0803681acd2 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17431,6 +17431,279 @@ note_invalid_constants (rtx_insn *insn, HOST_WIDE_INT address, int do_pushes)
   return;
 }
 
+/* This function computes the clear mask and PADDING_BITS_TO_CLEAR for structs
+   and unions in the context of ARMv8-M Security Extensions.  It is used as a
+   helper function for both 'cmse_nonsecure_call' and 'cmse_nonsecure_entry'
+   functions.  The PADDING_BITS_TO_CLEAR pointer can be the base to either one
+   or four masks, depending on whether it is being computed for a
+   'cmse_nonsecure_entry' return value or a 'cmse_nonsecure_call' argument
+   respectively.  The tree for the type of the argument or a field within an
+   argument is passed in ARG_TYPE, the current register this argument or field
+   starts in is kept in the pointer REGNO and updated accordingly, the bit this
+   argument or field starts at is passed in STARTING_BIT and the last used bit
+   is kept in LAST_USED_BIT which is also updated accordingly.  */
+
+static unsigned HOST_WIDE_INT
+comp_not_to_clear_mask_str_un (tree arg_type, int * regno,
+			       uint32_t * padding_bits_to_clear,
+			       unsigned starting_bit, int * last_used_bit)
+
+{
+  unsigned HOST_WIDE_INT not_to_clear_reg_mask = 0;
+
+  if (TREE_CODE (arg_type) == RECORD_TYPE)
+    {
+      unsigned current_bit = starting_bit;
+      tree field;
+      long int offset, size;
+
+
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  /* The offset within a structure is always an offset from
+	     the start of that structure.  Make sure we take that into the
+	     calculation of the register based offset that we use here.  */
+	  offset = starting_bit;
+	  offset += TREE_INT_CST_ELT (DECL_FIELD_BIT_OFFSET (field), 0);
+	  offset %= 32;
+
+	  /* This is the actual size of the field, for bitfields this is the
+	     bitfield width and not the container size.  */
+	  size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+
+	  if (*last_used_bit != offset)
+	    {
+	      if (offset < *last_used_bit)
+		{
+		  /* This field's offset is before the 'last_used_bit', that
+		     means this field goes on the next register.  So we need to
+		     pad the rest of the current register and increase the
+		     register number.  */
+		  uint32_t mask;
+		  mask  = ((uint32_t)-1) - ((uint32_t) 1 << *last_used_bit);
+		  mask++;
+
+		  padding_bits_to_clear[*regno] |= mask;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      else
+		{
+		  /* Otherwise we pad the bits between the last field's end and
+		     the start of the new field.  */
+		  uint32_t mask;
+
+		  mask = ((uint32_t)-1) >> (32 - offset);
+		  mask -= ((uint32_t) 1 << *last_used_bit) - 1;
+		  padding_bits_to_clear[*regno] |= mask;
+		}
+	      current_bit = offset;
+	    }
+
+	  /* Calculate further padding bits for inner structs/unions too.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)))
+	    {
+	      *last_used_bit = current_bit;
+	      not_to_clear_reg_mask
+		|= comp_not_to_clear_mask_str_un (TREE_TYPE (field), regno,
+						  padding_bits_to_clear, offset,
+						  last_used_bit);
+	    }
+	  else
+	    {
+	      /* Update 'current_bit' with this field's size.  If the
+		 'current_bit' lies in a subsequent register, update 'regno' and
+		 reset 'current_bit' to point to the current bit in that new
+		 register.  */
+	      current_bit += size;
+	      while (current_bit >= 32)
+		{
+		  current_bit-=32;
+		  not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+		  (*regno)++;
+		}
+	      *last_used_bit = current_bit;
+	    }
+
+	  field = TREE_CHAIN (field);
+	}
+      not_to_clear_reg_mask |= HOST_WIDE_INT_1U << *regno;
+    }
+  else if (TREE_CODE (arg_type) == UNION_TYPE)
+    {
+      tree field, field_t;
+      int i, regno_t, field_size;
+      int max_reg = -1;
+      int max_bit = -1;
+      uint32_t mask;
+      uint32_t padding_bits_to_clear_res[NUM_ARG_REGS]
+	= {-1, -1, -1, -1};
+
+      /* To compute the padding bits in a union we only consider bits as
+	 padding bits if they are always either a padding bit or fall outside a
+	 fields size for all fields in the union.  */
+      field = TYPE_FIELDS (arg_type);
+      while (field)
+	{
+	  uint32_t padding_bits_to_clear_t[NUM_ARG_REGS]
+	    = {0U, 0U, 0U, 0U};
+	  int last_used_bit_t = *last_used_bit;
+	  regno_t = *regno;
+	  field_t = TREE_TYPE (field);
+
+	  /* If the field's type is either a record or a union make sure to
+	     compute their padding bits too.  */
+	  if (RECORD_OR_UNION_TYPE_P (field_t))
+	    not_to_clear_reg_mask
+	      |= comp_not_to_clear_mask_str_un (field_t, &regno_t,
+						&padding_bits_to_clear_t[0],
+						starting_bit, &last_used_bit_t);
+	  else
+	    {
+	      field_size = TREE_INT_CST_ELT (DECL_SIZE (field), 0);
+	      regno_t = (field_size / 32) + *regno;
+	      last_used_bit_t = (starting_bit + field_size) % 32;
+	    }
+
+	  for (i = *regno; i < regno_t; i++)
+	    {
+	      /* For all but the last register used by this field only keep the
+		 padding bits that were padding bits in this field.  */
+	      padding_bits_to_clear_res[i] &= padding_bits_to_clear_t[i];
+	    }
+
+	    /* For the last register, keep all padding bits that were padding
+	       bits in this field and any padding bits that are still valid
+	       as padding bits but fall outside of this field's size.  */
+	    mask = (((uint32_t) -1) - ((uint32_t) 1 << last_used_bit_t)) + 1;
+	    padding_bits_to_clear_res[regno_t]
+	      &= padding_bits_to_clear_t[regno_t] | mask;
+
+	  /* Update the maximum size of the fields in terms of registers used
+	     ('max_reg') and the 'last_used_bit' in said register.  */
+	  if (max_reg < regno_t)
+	    {
+	      max_reg = regno_t;
+	      max_bit = last_used_bit_t;
+	    }
+	  else if (max_reg == regno_t && max_bit < last_used_bit_t)
+	    max_bit = last_used_bit_t;
+
+	  field = TREE_CHAIN (field);
+	}
+
+      /* Update the current padding_bits_to_clear using the intersection of the
+	 padding bits of all the fields.  */
+      for (i=*regno; i < max_reg; i++)
+	padding_bits_to_clear[i] |= padding_bits_to_clear_res[i];
+
+      /* Do not keep trailing padding bits, we do not know yet whether this
+	 is the end of the argument.  */
+      mask = ((uint32_t) 1 << max_bit) - 1;
+      padding_bits_to_clear[max_reg]
+	|= padding_bits_to_clear_res[max_reg] & mask;
+
+      *regno = max_reg;
+      *last_used_bit = max_bit;
+    }
+  else
+    /* This function should only be used for structs and unions.  */
+    gcc_unreachable ();
+
+  return not_to_clear_reg_mask;
+}
+
+/* In the context of ARMv8-M Security Extensions, this function is used for both
+   'cmse_nonsecure_call' and 'cmse_nonsecure_entry' functions to compute what
+   registers are used when returning or passing arguments, which is then
+   returned as a mask.  It will also compute a mask to indicate padding/unused
+   bits for each of these registers, and passes this through the
+   PADDING_BITS_TO_CLEAR pointer.  The tree of the argument type is passed in
+   ARG_TYPE, the rtl representation of the argument is passed in ARG_RTX and
+   the starting register used to pass this argument or return value is passed
+   in REGNO.  It makes use of 'comp_not_to_clear_mask_str_un' to compute these
+   for struct and union types.  */
+
+static unsigned HOST_WIDE_INT
+compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
+			     uint32_t * padding_bits_to_clear)
+
+{
+  int last_used_bit = 0;
+  unsigned HOST_WIDE_INT not_to_clear_mask;
+
+  if (RECORD_OR_UNION_TYPE_P (arg_type))
+    {
+      not_to_clear_mask
+	= comp_not_to_clear_mask_str_un (arg_type, &regno,
+					 padding_bits_to_clear, 0,
+					 &last_used_bit);
+
+
+      /* If the 'last_used_bit' is not zero, that means we are still using a
+	 part of the last 'regno'.  In such cases we must clear the trailing
+	 bits.  Otherwise we are not using regno and we should mark it as to
+	 clear.  */
+      if (last_used_bit != 0)
+	padding_bits_to_clear[regno]
+	  |= ((uint32_t)-1) - ((uint32_t) 1 << last_used_bit) + 1;
+      else
+	not_to_clear_mask &= ~(HOST_WIDE_INT_1U << regno);
+    }
+  else
+    {
+      not_to_clear_mask = 0;
+      /* We are not dealing with structs nor unions.  So these arguments may be
+	 passed in floating point registers too.  In some cases a BLKmode is
+	 used when returning or passing arguments in multiple VFP registers.  */
+      if (GET_MODE (arg_rtx) == BLKmode)
+	{
+	  int i, arg_regs;
+	  rtx reg;
+
+	  /* This should really only occur when dealing with the hard-float
+	     ABI.  */
+	  gcc_assert (TARGET_HARD_FLOAT_ABI);
+
+	  for (i = 0; i < XVECLEN (arg_rtx, 0); i++)
+	    {
+	      reg = XEXP (XVECEXP (arg_rtx, 0, i), 0);
+	      gcc_assert (REG_P (reg));
+
+	      not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (reg);
+
+	      /* If we are dealing with DF mode, make sure we don't
+		 clear either of the registers it addresses.  */
+	      arg_regs = ARM_NUM_REGS (GET_MODE (reg));
+	      if (arg_regs > 1)
+		{
+		  unsigned HOST_WIDE_INT mask;
+		  mask = HOST_WIDE_INT_1U << (REGNO (reg) + arg_regs);
+		  mask -= HOST_WIDE_INT_1U << REGNO (reg);
+		  not_to_clear_mask |= mask;
+		}
+	    }
+	}
+      else
+	{
+	  /* Otherwise we can rely on the MODE to determine how many registers
+	     are being used by this argument.  */
+	  int arg_regs = ARM_NUM_REGS (GET_MODE (arg_rtx));
+	  not_to_clear_mask |= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	  if (arg_regs > 1)
+	    {
+	      unsigned HOST_WIDE_INT
+	      mask = HOST_WIDE_INT_1U << (REGNO (arg_rtx) + arg_regs);
+	      mask -= HOST_WIDE_INT_1U << REGNO (arg_rtx);
+	      not_to_clear_mask |= mask;
+	    }
+	}
+    }
+
+  return not_to_clear_mask;
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -19867,7 +20140,42 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
 
 	default:
 	  if (IS_CMSE_ENTRY (func_type))
-	    snprintf (instr, sizeof (instr), "bxns%s\t%%|lr", conditional);
+	    {
+	      /* 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);
+	      if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+		{
+		  /* 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");
+		  output_asm_insn (instr, & operand);
+		}
+	      snprintf (instr, sizeof (instr), "bxns\t%%|lr");
+	    }
 	  /* Use bx if it's available.  */
 	  else if (arm_arch5 || arm_arch4t)
 	    sprintf (instr, "bx%s\t%%|lr", conditional);
@@ -24143,7 +24451,11 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
       if (IS_CMSE_ENTRY (arm_current_func_type ()))
-	asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	{
+	  asm_fprintf (f, "\tmsr\tAPSR_nzcvq, %r\n",
+		       reg_containing_return_addr);
+	  asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+	}
       else
 	asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
       return;
@@ -24379,7 +24691,18 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
   /* Return to caller.  */
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
-    asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    {
+      /* This is for the cases where LR is not being used to contain the return
+         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'.  */
+      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);
+      asm_fprintf (f, "\tbxns\t%r\n", reg_containing_return_addr);
+    }
   else
     asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
@@ -25246,6 +25569,149 @@ thumb1_expand_prologue (void)
     cfun->machine->lr_save_eliminated = 0;
 }
 
+/* Clear caller saved registers not used to pass return values and leaked
+   condition flags before exiting a cmse_nonsecure_entry function.  */
+
+void
+cmse_nonsecure_entry_clear_before_return (void)
+{
+  uint64_t to_clear_mask[2];
+  uint32_t padding_bits_to_clear = 0;
+  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
+  int regno, maxregno = IP_REGNUM;
+  tree result_type;
+  rtx result_rtl;
+
+  to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
+  to_clear_mask[0] |= (1ULL << IP_REGNUM);
+
+  /* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
+     registers.  We also check that TARGET_HARD_FLOAT and !TARGET_THUMB1 hold
+     to make sure the instructions used to clear them are present.  */
+  if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+    {
+      uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
+      maxregno = LAST_VFP_REGNUM;
+
+      float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
+      to_clear_mask[0] |= float_mask;
+
+      float_mask = (1ULL << (maxregno - 63)) - 1;
+      to_clear_mask[1] = float_mask;
+
+      /* 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));
+      to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+      emit_use (gen_rtx_REG (SImode, 4));
+      to_clear_mask[0] &= ~(1ULL << 4);
+    }
+
+  /* If the user has defined registers to be caller saved, these are no longer
+     restored by the function before returning and must thus be cleared for
+     security purposes.  */
+  for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+    {
+      /* We do not touch registers that can be used to pass arguments as per
+	 the AAPCS, since these should never be made callee-saved by user
+	 options.  */
+      if (IN_RANGE (regno, FIRST_VFP_REGNUM, D7_VFP_REGNUM))
+	continue;
+      if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
+	continue;
+      if (call_used_regs[regno])
+	to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+    }
+
+  /* Make sure we do not clear the registers used to return the result in.  */
+  result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
+  if (!VOID_TYPE_P (result_type))
+    {
+      result_rtl = arm_function_value (result_type, current_function_decl, 0);
+
+      /* No need to check that we return in registers, because we don't
+	 support returning on stack yet.  */
+      to_clear_mask[0]
+	&= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
+				       padding_bits_to_clear_ptr);
+    }
+
+  if (padding_bits_to_clear != 0)
+    {
+      rtx reg_rtx;
+      /* Padding bits to clear is not 0 so we know we are dealing with
+	 returning a composite type, which only uses r0.  Let's make sure that
+	 r1-r3 is cleared too, we will use r1 as a scratch register.  */
+      gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
+
+      reg_rtx = gen_rtx_REG (SImode, R1_REGNUM);
+
+      /* Fill the lower half of the negated padding_bits_to_clear.  */
+      emit_move_insn (reg_rtx,
+		      GEN_INT ((((~padding_bits_to_clear) << 16u) >> 16u)));
+
+      /* Also fill the top half of the negated padding_bits_to_clear.  */
+      if (((~padding_bits_to_clear) >> 16) > 0)
+	emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg_rtx,
+						      GEN_INT (16),
+						      GEN_INT (16)),
+				GEN_INT ((~padding_bits_to_clear) >> 16)));
+
+      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, R0_REGNUM),
+			   gen_rtx_REG (SImode, R0_REGNUM),
+			   reg_rtx));
+    }
+
+  for (regno = R0_REGNUM; regno <= maxregno; regno++)
+    {
+      if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
+	continue;
+
+      if (IS_VFP_REGNUM (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)
+	      && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 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
+	{
+	  if (TARGET_THUMB1)
+	    {
+	      if (regno == R0_REGNUM)
+		emit_move_insn (gen_rtx_REG (SImode, regno),
+				const0_rtx);
+	      else
+		/* R0 has either been cleared before, see code above, or it
+		   holds a return value, either way it is not secret
+		   information.  */
+		emit_move_insn (gen_rtx_REG (SImode, regno),
+				gen_rtx_REG (SImode, R0_REGNUM));
+	      emit_use (gen_rtx_REG (SImode, regno));
+	    }
+	  else
+	    {
+	      emit_move_insn (gen_rtx_REG (SImode, regno),
+			      gen_rtx_REG (SImode, LR_REGNUM));
+	      emit_use (gen_rtx_REG (SImode, regno));
+	    }
+	}
+    }
+}
+
 /* Generate pattern *pop_multiple_with_stack_update_and_return if single
    POP instruction can be generated.  LR should be replaced by PC.  All
    the checks required are already done by  USE_RETURN_INSN ().  Hence,
@@ -25295,6 +25761,8 @@ thumb2_expand_return (bool simple_return)
     }
   else
     {
+      if (IS_CMSE_ENTRY (arm_current_func_type ()))
+	cmse_nonsecure_entry_clear_before_return ();
       emit_jump_insn (simple_return_rtx);
     }
 }
@@ -25353,6 +25821,10 @@ thumb1_expand_epilogue (void)
 
   if (! df_regs_ever_live_p (LR_REGNUM))
     emit_use (gen_rtx_REG (SImode, LR_REGNUM));
+
+  /* Clear all caller-saved regs that are not used to return.  */
+  if (IS_CMSE_ENTRY (arm_current_func_type ()))
+    cmse_nonsecure_entry_clear_before_return ();
 }
 
 /* Epilogue code for APCS frame.  */
@@ -25787,6 +26259,14 @@ 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 (!really_return)
     return;
 
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 51b5fb0766a32424efac06b1bad044462c664dd6..39bcae78c16885cbb616b10616a014e289796591 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1869,8 +1869,13 @@
   "*
     return thumb1_unexpanded_epilogue ();
   "
-  ; Length is absolute worst case
-  [(set_attr "length" "44")
+  ; Length is absolute worst case, when using CMSE and if this is an entry
+  ; function an extra 4 (MSR) bytes will be added.
+  [(set (attr "length")
+	(if_then_else
+	 (match_test "IS_CMSE_ENTRY (arm_current_func_type ())")
+	 (const_int 48)
+	 (const_int 44)))
    (set_attr "type" "block")
    ;; We don't clobber the conditions, but the potential length of this
    ;; operation is sufficient to make conditionalizing the sequence
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index ab08288413c3e64911e8d7a8199b9809e0282d8e..140e71e9ca9428459b9d7f8fc3459529f85ec836 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -1115,12 +1115,31 @@
 
 (define_insn "*thumb2_return"
   [(simple_return)]
-  "TARGET_THUMB2"
+  "TARGET_THUMB2 && !IS_CMSE_ENTRY (arm_current_func_type ())"
   "* return output_return_instruction (const_true_rtx, true, false, true);"
   [(set_attr "type" "branch")
    (set_attr "length" "4")]
 )
 
+(define_insn "*thumb2_cmse_entry_return"
+  [(simple_return)]
+  "TARGET_THUMB2 && IS_CMSE_ENTRY (arm_current_func_type ())"
+  "* return output_return_instruction (const_true_rtx, true, false, true);"
+  [(set_attr "type" "branch")
+   ; This is a return from a cmse_nonsecure_entry function so code will be
+   ; added to clear the APSR and potentially the FPSCR if VFP is available, so
+   ; we adapt the length accordingly.
+   (set (attr "length")
+     (if_then_else (match_test "TARGET_HARD_FLOAT")
+      (const_int 12)
+      (const_int 8)))
+   ; We do not support predicate execution of returns from cmse_nonsecure_entry
+   ; functions because we need to clear the APSR.  Since predicable has to be
+   ; a constant, we had to duplicate the thumb2_return pattern for CMSE entry
+   ; functions.
+   (set_attr "predicable" "no")]
+)
+
 (define_insn_and_split "thumb2_eh_return"
   [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
 		    VUNSPEC_EH_RETURN)
diff --git a/gcc/testsuite/ChangeLog.arm b/gcc/testsuite/ChangeLog.arm
index 338ac2d0fbd6752ce5ca59557cea12e4996d607f..8663dd3af961000adeda07640e0b1a12d8121bce 100644
--- a/gcc/testsuite/ChangeLog.arm
+++ b/gcc/testsuite/ChangeLog.arm
@@ -4,6 +4,25 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
+	* gcc.target/arm/cmse/struct-1.c: New.
+	* gcc.target/arm/cmse/bitfield-1.c: New.
+	* gcc.target/arm/cmse/bitfield-2.c: New.
+	* gcc.target/arm/cmse/bitfield-3.c: New.
+	* gcc.target/arm/cmse/baseline/cmse-2.c: New.
+	* gcc.target/arm/cmse/baseline/softfp.c: New.
+	* gcc.target/arm/cmse/mainline/soft/cmse-5.c: New.
+	* gcc.target/arm/cmse/mainline/hard/cmse-5.c: New.
+	* gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c: New.
+	* gcc.target/arm/cmse/mainline/softfp/cmse-5.c: New.
+	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c: New.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* gcc.target/arm/cmse/cmse-4.c: New.
 	* gcc.target/arm/cmse/cmse-9.c: New.
 	* gcc.target/arm/cmse/cmse-10.c: New.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..814502d4e5d5ef87e920977b912f69f83cdde256
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "movs\tr1, r0" } } */
+/* { dg-final { scan-assembler "movs\tr2, r0" } } */
+/* { dg-final { scan-assembler "movs\tr3, r0" } } */
+/* { dg-final { scan-assembler "mov\tip, r0" } } */
+/* { dg-final { scan-assembler "mov\tlr, r0" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq," } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c
new file mode 100644
index 0000000000000000000000000000000000000000..0069fcdaebfd9caea02751856039a3aaefd3ffab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/softfp.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse -mfloat-abi=softfp" } */
+
+double __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+double
+foo (double a)
+{
+  return bar (1.0f, 2.0) + a;
+}
+
+float __attribute__ ((cmse_nonsecure_entry))
+baz (float a, double b)
+{
+  return (float) bar (a, b);
+}
+
+/* Make sure we are not using FP instructions, since ARMv8-M Baseline does not
+   support such instructions.  */
+/* { dg-final { scan-assembler-not "vmov" } } */
+/* { dg-final { scan-assembler-not "vmsr" } } */
+/* { dg-final { scan-assembler-not "vmrs" } } */
+
+/* Just double checking that we are still doing cmse though.  */
+/* { dg-final { scan-assembler-not "vmrs" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..fccc51d5c82f7955ee4cb8256c1dd38f9ff2670d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned short  a : 6;
+  unsigned char	  b : 3;
+  unsigned char	  c;
+  unsigned short  d : 8;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 63u;
+  t.b = 7u;
+  t.c = 255u;
+  t.d = 255u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 63u
+      || t.b != 7u
+      || t.c != 255u
+      || t.d != 255u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e6aee3c4c022d50baec8ab16443130897540e703
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-2.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a : 7;
+  signed char b : 3;
+  short	      c : 11;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -64;
+  t.b = -4 ;
+  t.c = -1024;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -64
+      || t.b != -4
+      || t.c != -1024)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..285a2b92f64c1913ef585b8daa4d27c6da0a3d2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/bitfield-3.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  short	      a;
+  signed char b : 2;
+  short		: 1;
+  signed char c : 3;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = -32768;
+  t.b = -2;
+  t.c = -4;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != -32768
+      || t.b != -2
+      || t.c != -4)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index f797dba1901720e04249d61078c1cbf2a3e436a9..38f18414c2fefec56161e6ac3f7291b03a3b29a3 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -43,6 +43,26 @@ set LTO_TORTURE_OPTIONS ""
 gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
 	"" $DEFAULT_CFLAGS
 
+if {[check_effective_target_arm_arch_v8m_base_ok]} then {
+    # Baseline only
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/baseline/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
+if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    # Mainline -mfloat-abi=soft
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
+	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/softfp-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard/*.c]] \
+	    "" $DEFAULT_CFLAGS
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/hard-sp/*.c]] \
+	    "" $DEFAULT_CFLAGS
+}
+
 set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
 set dg-do-what-default ${saved-dg-do-what-default}
 
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..88dec2762812614ee986ee1a023c0acce8f94c91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-5.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..29f60baf5212f9fa2e4436fe40c6abe4ac671254
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7229ea8eb2da1da264f58f8518daf303d1bdeda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-5.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "bxns" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..7734d77dc3812e6a158ea1f6b067930846fffccb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-5.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { dg-final { scan-assembler "bxns" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..6addaa1a4eda8e2930d5fe72c94697bcf6e604e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-5.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+extern float bar (void);
+
+float __attribute__ ((cmse_nonsecure_entry))
+foo (void)
+{
+  return bar ();
+}
+/* { dg-final { scan-assembler "__acle_se_foo:" } } */
+/* { 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_arch_v8m_main_ok && { ! arm_dsp } } } } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvqg, lr" { target { arm_arch_v8m_main_ok && arm_dsp } } } } */
+/* { dg-final { scan-assembler "push\t{r4}" } } */
+/* { dg-final { scan-assembler "vmrs\tip, fpscr" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65376" } } */
+/* { dg-final { scan-assembler "movt\tr4, #4095" } } */
+/* { dg-final { scan-assembler "and\tip, r4" } } */
+/* { dg-final { scan-assembler "vmsr\tfpscr, ip" } } */
+/* { dg-final { scan-assembler "pop\t{r4}" } } */
+/* { dg-final { scan-assembler "mov\tip, lr" } } */
+/* { 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
new file mode 100644
index 0000000000000000000000000000000000000000..2d366a944df692f29ab44e3ee4d33c777b126223
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/struct-1.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "--save-temps -mcmse -Wl,--section-start,.gnu.sgstubs=0x20400000" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b;
+} test_st;
+
+test_st __attribute__ ((cmse_nonsecure_entry)) foo (void)
+{
+  test_st t;
+  t.a = 255u;
+  t.b = 32767u;
+  return t;
+}
+
+int
+main (void)
+{
+  test_st t;
+  t = foo ();
+  if (t.a != 255u || t.b != 32767u)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { 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 "bxns" } } */
+
+

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

* Re: [PATCHv3 5/7, GCC[arm-embedded][committed][PATCH 5/7] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute
  2016-11-30 17:22           ` Kyrill Tkachov
@ 2016-12-05 11:38             ` Andre Vieira (lists)
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-12-05 11:38 UTC (permalink / raw)
  To: gcc-patches

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

On 30/11/16 17:22, Kyrill Tkachov wrote:
> 
> On 30/11/16 12:05, Andre Vieira (lists) wrote:
>> Hi,
>>
>> I got a bug report against the old version of this patch and fixed it
>> here. This had to do with GCC optimizations sharing types with and
>> without the 'cmse_nonsecure_call' attribute.  The patch now no longer
>> sets the main variant, this didn't seem to do what I thought it did.
>> Instead the patch now creates distinct type copies for every declared
>> pointer that eventually points to the function type with the attribute,
>> it will also create a distinct copy for the function type itself.
>> Another change in this patch was to make 'arm_comp_type_attributes', the
>> ARM implementation of TARGET_COMP_TYPE_ATTRIBUTES, deny compatibility
>> between function types with the attribute and without.
>>
>> I added a test case to test the issue solved with these changes.
> 
> Ok.
> Thanks,
> Kyrill
> 
>> *** gcc/ChangeLog ***
>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * config/arm/arm.c (gimplify.h): New include.
>>          (arm_handle_cmse_nonsecure_call): New.
>>          (arm_attribute_table): Added cmse_nonsecure_call.
>>          (arm_comp_type_attributes): Deny compatibility of function types
>> with
>>          without the cmse_nonsecure_call attribute.
>>          * doc/extend.texi (ARM ARMv8-M Security Extensions): New
>> attribute.
>>
>> *** gcc/testsuite/ChangeLog ***
>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>
>>          * gcc.target/arm/cmse/cmse-3.c: Add tests.
>>          * gcc.target/arm/cmse/cmse-4.c: Add tests.
>>          * gcc.target/arm/cmse/cmse-15.c: New.
>>
>>
>> Cheers,
>> Andre
> 
Hi,

Backported this to the embedded-6-branch in revision r243251.

Cheers,
Andre

gcc/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* config/arm/arm.c (gimplify.h): New include.
	(arm_handle_cmse_nonsecure_call): New.
	(arm_attribute_table): Added cmse_nonsecure_call.
	(arm_comp_type_attributes): Deny compatibility of function types
	with without the cmse_nonsecure_call attribute.
	* doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.

gcc/testsuite/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/cmse-3.c: Add tests.
	* gcc.target/arm/cmse/cmse-4.c: Add tests.
	* gcc.target/arm/cmse/cmse-15.c: New.

[-- Attachment #2: diff5 --]
[-- Type: text/plain, Size: 10698 bytes --]

diff --git a/gcc/ChangeLog.arm b/gcc/ChangeLog.arm
index 3085e1c93270cb7ab9fcee5dbe70ec6ada763026..8459d1885f218a364a4396e458d001d015932266 100644
--- a/gcc/ChangeLog.arm
+++ b/gcc/ChangeLog.arm
@@ -4,6 +4,19 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* config/arm/arm.c (gimplify.h): New include.
+	(arm_handle_cmse_nonsecure_call): New.
+	(arm_attribute_table): Added cmse_nonsecure_call.
+	(arm_comp_type_attributes): Deny compatibility of function types
+	with without the cmse_nonsecure_call attribute.
+	* doc/extend.texi (ARM ARMv8-M Security Extensions): New attribute.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* config/arm/arm.c (output_return_instruction): Clear
 	registers.
 	(thumb2_expand_return): Likewise.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index b9a62b5e6bf06dcc218dfdb3111dc0803681acd2..bba2991f65e9f0b12d43a05ad023bfc2d0f97aff 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -62,6 +62,7 @@
 #include "builtins.h"
 #include "tm-constrs.h"
 #include "rtl-iter.h"
+#include "gimplify.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -137,6 +138,7 @@ static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
 static tree arm_handle_cmse_nonsecure_entry (tree *, tree, tree, int, bool *);
+static tree arm_handle_cmse_nonsecure_call (tree *, tree, tree, int, bool *);
 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
 static int arm_comp_type_attributes (const_tree, const_tree);
@@ -352,6 +354,8 @@ static const struct attribute_spec arm_attribute_table[] =
   /* ARMv8-M Security Extensions support.  */
   { "cmse_nonsecure_entry", 0, 0, true, false, false,
     arm_handle_cmse_nonsecure_entry, false },
+  { "cmse_nonsecure_call", 0, 0, true, false, false,
+    arm_handle_cmse_nonsecure_call, true },
   { NULL,           0, 0, false, false, false, NULL, false }
 };
 \f
@@ -6713,6 +6717,78 @@ arm_handle_cmse_nonsecure_entry (tree *node, tree name,
   return NULL_TREE;
 }
 
+
+/* Called upon detection of the use of the cmse_nonsecure_call attribute, this
+   function will check whether the attribute is allowed here and will add the
+   attribute to the function type tree or otherwise issue a diagnostic.  The
+   reason we check this at declaration time is to only allow the use of the
+   attribute with declarations of function pointers and not function
+   declarations.  This function checks NODE is of the expected type and issues
+   diagnostics otherwise using NAME.  If it is not of the expected type
+   *NO_ADD_ATTRS will be set to true.  */
+
+static tree
+arm_handle_cmse_nonsecure_call (tree *node, tree name,
+				 tree /* args */,
+				 int /* flags */,
+				 bool *no_add_attrs)
+{
+  tree decl = NULL_TREE, fntype = NULL_TREE;
+  tree main_variant, type;
+
+  if (!use_cmse)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored without -mcmse option.",
+	       name);
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (*node) == VAR_DECL || TREE_CODE (*node) == TYPE_DECL)
+    {
+      decl = *node;
+      fntype = TREE_TYPE (decl);
+    }
+
+  while (fntype != NULL_TREE && TREE_CODE (fntype) == POINTER_TYPE)
+    fntype = TREE_TYPE (fntype);
+
+  if (!decl || TREE_CODE (fntype) != FUNCTION_TYPE)
+    {
+	warning (OPT_Wattributes, "%qE attribute only applies to base type of a "
+		 "function pointer", name);
+	*no_add_attrs = true;
+	return NULL_TREE;
+    }
+
+  *no_add_attrs |= cmse_func_args_or_return_in_stack (NULL, name, fntype);
+
+  if (*no_add_attrs)
+    return NULL_TREE;
+
+  /* Prevent trees being shared among function types with and without
+     cmse_nonsecure_call attribute.  */
+  type = TREE_TYPE (decl);
+
+  type = build_distinct_type_copy (type);
+  TREE_TYPE (decl) = type;
+  fntype = type;
+
+  while (TREE_CODE (fntype) != FUNCTION_TYPE)
+    {
+      type = fntype;
+      fntype = TREE_TYPE (fntype);
+      fntype = build_distinct_type_copy (fntype);
+      TREE_TYPE (type) = fntype;
+    }
+
+  /* Construct a type attribute and add it to the function type.  */
+  tree attrs = tree_cons (get_identifier ("cmse_nonsecure_call"), NULL_TREE,
+			  TYPE_ATTRIBUTES (fntype));
+  TYPE_ATTRIBUTES (fntype) = attrs;
+  return NULL_TREE;
+}
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
@@ -6753,6 +6829,14 @@ arm_comp_type_attributes (const_tree type1, const_tree type2)
   if (l1 != l2)
     return 0;
 
+  l1 = lookup_attribute ("cmse_nonsecure_call",
+			 TYPE_ATTRIBUTES (type1)) != NULL;
+  l2 = lookup_attribute ("cmse_nonsecure_call",
+			 TYPE_ATTRIBUTES (type2)) != NULL;
+
+  if (l1 != l2)
+    return 0;
+
   return 1;
 }
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 1693c5968c608303159ac8b4a24744c0c57b7936..50a2db184aa5c11865e0ebfc3881e54d2703774d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12269,8 +12269,8 @@ Security Extensions: Requiremenets on Development Tools Engineering
 Specification, which can be found at
 @uref{http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf}.
 
-As part of the Security Extensions GCC implements a new function attribute
-@code{cmse_nonsecure_entry}.
+As part of the Security Extensions GCC implements two new function attributes:
+@code{cmse_nonsecure_entry} and @code{cmse_nonsecure_call}.
 
 As part of the Security Extensions GCC implements the intrinsics below.  FPTR
 is used here to mean any function pointer type.
diff --git a/gcc/testsuite/ChangeLog.arm b/gcc/testsuite/ChangeLog.arm
index 8663dd3af961000adeda07640e0b1a12d8121bce..e8938adfc6a811130a54a5a8e3f291080d20ca46 100644
--- a/gcc/testsuite/ChangeLog.arm
+++ b/gcc/testsuite/ChangeLog.arm
@@ -4,6 +4,16 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* gcc.target/arm/cmse/cmse-3.c: Add tests.
+	* gcc.target/arm/cmse/cmse-4.c: Add tests.
+	* gcc.target/arm/cmse/cmse-15.c: New.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* gcc.target/arm/cmse/cmse.exp: Test different multilibs separate.
 	* gcc.target/arm/cmse/struct-1.c: New.
 	* gcc.target/arm/cmse/bitfield-1.c: New.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
new file mode 100644
index 0000000000000000000000000000000000000000..4e9ace1f3f33b8a8653797e29ca62eb3dd7ae918
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-15.c
@@ -0,0 +1,72 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*ns_foo) (void);
+int (*s_bar) (void);
+int __attribute__ ((cmse_nonsecure_call)) (**ns_foo2) (void);
+int (**s_bar2) (void);
+
+typedef int __attribute__ ((cmse_nonsecure_call)) ns_foo_t (void);
+typedef int s_bar_t (void);
+typedef int __attribute__ ((cmse_nonsecure_call)) (* ns_foo_ptr) (void);
+typedef int (*s_bar_ptr) (void);
+
+int nonsecure0 (ns_foo_t * ns_foo_p)
+{
+  return ns_foo_p ();
+}
+
+int nonsecure1 (ns_foo_t ** ns_foo_p)
+{
+  return (*ns_foo_p) ();
+}
+
+int nonsecure2 (ns_foo_ptr ns_foo_p)
+{
+  return ns_foo_p ();
+}
+int nonsecure3 (ns_foo_ptr * ns_foo_p)
+{
+  return (*ns_foo_p) ();
+}
+
+int secure0 (s_bar_t * s_bar_p)
+{
+  return s_bar_p ();
+}
+
+int secure1 (s_bar_t ** s_bar_p)
+{
+  return (*s_bar_p) ();
+}
+
+int secure2 (s_bar_ptr s_bar_p)
+{
+  return s_bar_p ();
+}
+
+int secure3 (s_bar_ptr * s_bar_p)
+{
+  return (*s_bar_p) ();
+}
+
+int nonsecure4 (void)
+{
+  return ns_foo ();
+}
+
+int nonsecure5 (void)
+{
+  return (*ns_foo2) ();
+}
+
+int secure4 (void)
+{
+  return s_bar ();
+}
+
+int secure5 (void)
+{
+  return (*s_bar2) ();
+}
+/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 6 } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
index 2c2920e1dc310106d83203eb51e1a68a275d0152..7f92a4c28b3333e4c8fdc256211f3ed74a383cd4 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-3.c
@@ -35,3 +35,11 @@ norf (struct span2 a) {}
 
 void __attribute__ ((cmse_nonsecure_entry))
 foo2 (long long a, int b, union test_union c) {} /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) bar2 (long long a, int b, long long c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) baz2 (long long a, int b, struct span c); /* { dg-error "not available to functions with arguments passed on the stack" } */
+
+typedef struct span __attribute__ ((cmse_nonsecure_call)) qux2 (void); /* { dg-error "not available to functions that return value on the stack" } */
+
+typedef void __attribute__ ((cmse_nonsecure_call)) norf2 (int a, ...); /* { dg-error "not available to functions with variable number of arguments" } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
index 6f930ab04a1097c64097a4e003296bbe85733319..d0999a4181ac022b115ae20cf3e1c8bf78f6becf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-4.c
@@ -19,9 +19,16 @@ baz (void)
   return qux ();
 }
 
+void __attribute__ ((cmse_nonsecure_call))
+quux (void) {} /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
+int __attribute__ ((cmse_nonsecure_call)) norf; /* { dg-warning "attribute only applies to base type of a function pointer" } */
+
 /* { dg-final { scan-assembler-times "bxns" 2 } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler "__acle_se_foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_bar:" } } */
 /* { dg-final { scan-assembler "baz:" } } */
 /* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_quux:" } } */
+/* { dg-final { scan-assembler-not "__acle_se_norf:" } } */

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

* [arm-embedded][committed][PATCH 6/7] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call
  2016-12-02 13:42                       ` Kyrill Tkachov
@ 2016-12-05 11:44                         ` Andre Vieira (lists)
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-12-05 11:44 UTC (permalink / raw)
  To: gcc-patches

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

On 02/12/16 13:41, Kyrill Tkachov wrote:
> Hi Andre,
> 
> On 02/12/16 13:36, Andre Vieira (lists) wrote:
>> On 23/11/16 11:53, Andre Vieira (lists) wrote:
>>> On 11/11/16 16:19, Kyrill Tkachov wrote:
>>>> And CC'ing Ramana and Richard this time...
>>>>
>>> Hi,
>>>
>>> After some extra testing I found that the sibcall optimization was not
>>> disabled for calls to function pointers with the cmse_nonsecure_call
>>> attribute, causing the clearing and call to the function wrapper to be
>>> skipped. This would result in an illegal branch into secure memory and
>>> would HardFault.
>>>
>>> Added a test.
>>>
>>> Is this OK?
>>>
>>> Cheers,
>>> Andre
>>>
>>> *** gcc/ChangeLog ***
>>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/arm.c (detect_cmse_nonsecure_call): New.
>>>          (cmse_nonsecure_call_clear_caller_saved): New.
>>>          (arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
>>>          (arm_function_ok_for_sibcall): Disable sibcalls for
>>> cmse_nonsecure_call.
>>>          * config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
>>>          * config/arm/arm.md (call): Handle cmse_nonsecure_entry.
>>>          (call_value): Likewise.
>>>          (nonsecure_call_internal): New.
>>>          (nonsecure_call_value_internal): New.
>>>          * config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
>>>          (*nonsecure_call_value_reg_thumb1_v5): New.
>>>          * config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
>>>          (*nonsecure_call_value_reg_thumb2): New.
>>>          * config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
>>>
>>> *** libgcc/ChangeLog ***
>>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * config/arm/cmse_nonsecure_call.S: New.
>>>     * config/arm/t-arm: Compile cmse_nonsecure_call.S
>>>
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-11-xx  Andre Vieira        <andre.simoesdiasvieira@arm.com>
>>>              Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>
>>>          * gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
>>>          * gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
>>>          * gcc.target/arm/cmse/cmse-14.c: New.
>>>          * gcc.target/arm/cmse/baseline/bitfield-4.c: New.
>>>          * gcc.target/arm/cmse/baseline/bitfield-5.c: New.
>>>          * gcc.target/arm/cmse/baseline/bitfield-6.c: New.
>>>          * gcc.target/arm/cmse/baseline/bitfield-7.c: New.
>>>          * gcc.target/arm/cmse/baseline/bitfield-8.c: New.
>>>          * gcc.target/arm/cmse/baseline/bitfield-9.c: New.
>>>          * gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
>>>          * gcc.target/arm/cmse/baseline/cmse-11.c: New.
>>>     * gcc.target/arm/cmse/baseline/cmse-13.c: New.
>>>     * gcc.target/arm/cmse/baseline/cmse-6.c: New.
>>>          * gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c: New.
>>>          * gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c: New.
>>>     * gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
>>>     * gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
>>>     * gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
>>>     * gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
>>>     * gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
>>>     * gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
>>>     * gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
>>>     * gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
>>>     * gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
>>>     * gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
>>>     * gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
>>>     * gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
>>>     * gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
>>>     * gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
>>>
>> Hi,
>>
>> To make the clearing of registers consistent between single and double
>> precision I decided to clear all FP registers with 0. The callee-saved
>> registers, saved, cleared and restored in the library wrapper we can do
>> this without much penalty to performance. The caller-saved registers are
>> compiler generated and currently generate a 'vldr' instruction, per
>> cleared (sp or dp) register. This is far from optimal, but it works and
>> it is "safer". I have some ideas to improve this, for instance using
>> r0-r1 to clear the FP registers, since they will either contain the
>> address of the callback function or an argument value, either way they
>> will never contain secret information. I will address this at a later
>> time.
>>
>> Changed the tests to reflect these changes. No changes to the ChangeLog.
>>
>> Is this OK?
> 
> Thanks, I much prefer the consistency.
> This is ok.
> I believe all patches in this series have been approved now, so you can
> go ahead and commit them.
> Please keep an eye out for fallout over the next week.
> 
> Kyrill
> 
>> Cheers,
>> Andre
>>
> 

Hi,

Backported this to the embedded-6-branch in revision r243252.

Cheers,
Andre

gcc/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* config/arm/arm.c (detect_cmse_nonsecure_call): New.
	(cmse_nonsecure_call_clear_caller_saved): New.
	(arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
	(arm_function_ok_for_sibcall): Disable sibcalls for
	cmse_nonsecure_call.
	* config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
	* config/arm/arm.md (call): Handle cmse_nonsecure_entry.
	(call_value): Likewise.
	(nonsecure_call_internal): New.
	(nonsecure_call_value_internal): New.
	* config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
	(*nonsecure_call_value_reg_thumb1_v5): New.
	* config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
	(*nonsecure_call_value_reg_thumb2): New.
	* config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.

gcc/testsuite/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
	* gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
	* gcc.target/arm/cmse/cmse-14.c: New.
	* gcc.target/arm/cmse/baseline/bitfield-4.c: New.
	* gcc.target/arm/cmse/baseline/bitfield-5.c: New.
	* gcc.target/arm/cmse/baseline/bitfield-6.c: New.
	* gcc.target/arm/cmse/baseline/bitfield-7.c: New.
	* gcc.target/arm/cmse/baseline/bitfield-8.c: New.
	* gcc.target/arm/cmse/baseline/bitfield-9.c: New.
	* gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
	* gcc.target/arm/cmse/baseline/cmse-11.c: New.
	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
	* gcc.target/arm/cmse/baseline/union-1.c: New.
	* gcc.target/arm/cmse/baseline/union-2.c: New.
	* gcc.target/arm/cmse/mainline/bitfield-4.c: New.
	* gcc.target/arm/cmse/mainline/bitfield-5.c: New.
	* gcc.target/arm/cmse/mainline/bitfield-6.c: New.
	* gcc.target/arm/cmse/mainline/bitfield-7.c: New.
	* gcc.target/arm/cmse/mainline/bitfield-8.c: New.
	* gcc.target/arm/cmse/mainline/bitfield-9.c: New.
	* gcc.target/arm/cmse/mainline/bitfield-and-union-1.c: New.
	* gcc.target/arm/cmse/mainline/union-1.c: New.
	* gcc.target/arm/cmse/mainline/union-2.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.

libgcc/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* config/arm/cmse_nonsecure_call.S: New.
	* config/arm/t-arm: Compile cmse_nonsecure_call.S

[-- Attachment #2: diff6 --]
[-- Type: text/plain, Size: 87851 bytes --]

diff --git a/gcc/ChangeLog.arm b/gcc/ChangeLog.arm
index 8459d1885f218a364a4396e458d001d015932266..315ea8897096ec7890675e0c680f048e19d5dd5b 100644
--- a/gcc/ChangeLog.arm
+++ b/gcc/ChangeLog.arm
@@ -4,6 +4,28 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* config/arm/arm.c (detect_cmse_nonsecure_call): New.
+	(cmse_nonsecure_call_clear_caller_saved): New.
+	(arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
+	(arm_function_ok_for_sibcall): Disable sibcalls for
+	cmse_nonsecure_call.
+	* config/arm/arm-protos.h (detect_cmse_nonsecure_call): New.
+	* config/arm/arm.md (call): Handle cmse_nonsecure_entry.
+	(call_value): Likewise.
+	(nonsecure_call_internal): New.
+	(nonsecure_call_value_internal): New.
+	* config/arm/thumb1.md (*nonsecure_call_reg_thumb1_v5): New.
+	(*nonsecure_call_value_reg_thumb1_v5): New.
+	* config/arm/thumb2.md (*nonsecure_call_reg_thumb2): New.
+	(*nonsecure_call_value_reg_thumb2): New.
+	* config/arm/unspecs.md (UNSPEC_NONSECURE_MEM): New.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* config/arm/arm.c (gimplify.h): New include.
 	(arm_handle_cmse_nonsecure_call): New.
 	(arm_attribute_table): Added cmse_nonsecure_call.
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index fb9e6f4c7f54f3f491381ba8e48ab14979bd0dc3..05bd4aaa17794fdb236d78b51d817c2c782dbec5 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -133,6 +133,7 @@ extern int arm_const_double_inline_cost (rtx);
 extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
+bool detect_cmse_nonsecure_call (tree);
 extern const char *output_call (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index bba2991f65e9f0b12d43a05ad023bfc2d0f97aff..7d37aae072f6e334f6bc73accf66047c23f28d0d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -6960,6 +6960,15 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
   if (IS_CMSE_ENTRY (arm_current_func_type ()))
     return false;
 
+  /* We do not allow ARMv8-M non-secure calls to be turned into sibling calls,
+     this would complicate matters for later code generation.  */
+  if (TREE_CODE (exp) == CALL_EXPR)
+    {
+      tree fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (exp)));
+      if (lookup_attribute ("cmse_nonsecure_call", TYPE_ATTRIBUTES (fntype)))
+	return false;
+    }
+
   if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
     {
       /* Check that the return value locations are the same.  For
@@ -17788,6 +17797,197 @@ compute_not_to_clear_mask (tree arg_type, rtx arg_rtx, int regno,
   return not_to_clear_mask;
 }
 
+/* Saves callee saved registers, clears callee saved registers and caller saved
+   registers not used to pass arguments before a cmse_nonsecure_call.  And
+   restores the callee saved registers after.  */
+
+static void
+cmse_nonsecure_call_clear_caller_saved (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  uint64_t to_clear_mask, float_mask;
+	  rtx_insn *seq;
+	  rtx pat, call, unspec, reg, cleared_reg, tmp;
+	  unsigned int regno, maxregno;
+	  rtx address;
+	  CUMULATIVE_ARGS args_so_far_v;
+	  cumulative_args_t args_so_far;
+	  tree arg_type, fntype;
+	  bool using_r4, first_param = true;
+	  function_args_iterator args_iter;
+	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
+	  uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear[0];
+
+	  if (!NONDEBUG_INSN_P (insn))
+	    continue;
+
+	  if (!CALL_P (insn))
+	    continue;
+
+	  pat = PATTERN (insn);
+	  gcc_assert (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 0);
+	  call = XVECEXP (pat, 0, 0);
+
+	  /* Get the real call RTX if the insn sets a value, ie. returns.  */
+	  if (GET_CODE (call) == SET)
+	      call = SET_SRC (call);
+
+	  /* Check if it is a cmse_nonsecure_call.  */
+	  unspec = XEXP (call, 0);
+	  if (GET_CODE (unspec) != UNSPEC
+	      || XINT (unspec, 1) != UNSPEC_NONSECURE_MEM)
+	    continue;
+
+	  /* Determine the caller-saved registers we need to clear.  */
+	  to_clear_mask = (1LL << (NUM_ARG_REGS)) - 1;
+	  maxregno = NUM_ARG_REGS - 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
+	     lazy store and loads which clear both caller- and callee-saved
+	     registers.  */
+	  if (TARGET_HARD_FLOAT_ABI)
+	    {
+	      float_mask = (1LL << (D7_VFP_REGNUM + 1)) - 1;
+	      float_mask &= ~((1LL << FIRST_VFP_REGNUM) - 1);
+	      to_clear_mask |= float_mask;
+	      maxregno = D7_VFP_REGNUM;
+	    }
+
+	  /* Make sure the register used to hold the function address is not
+	     cleared.  */
+	  address = RTVEC_ELT (XVEC (unspec, 0), 0);
+	  gcc_assert (MEM_P (address));
+	  gcc_assert (REG_P (XEXP (address, 0)));
+	  to_clear_mask &= ~(1LL << REGNO (XEXP (address, 0)));
+
+	  /* Set basic block of call insn so that df rescan is performed on
+	     insns inserted here.  */
+	  set_block_for_insn (insn, bb);
+	  df_set_flags (DF_DEFER_INSN_RESCAN);
+	  start_sequence ();
+
+	  /* Make sure the scheduler doesn't schedule other insns beyond
+	     here.  */
+	  emit_insn (gen_blockage ());
+
+	  /* Walk through all arguments and clear registers appropriately.
+	  */
+	  fntype = TREE_TYPE (MEM_EXPR (address));
+	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
+				    NULL_TREE);
+	  args_so_far = pack_cumulative_args (&args_so_far_v);
+	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	    {
+	      rtx arg_rtx;
+	      machine_mode arg_mode = TYPE_MODE (arg_type);
+
+	      if (VOID_TYPE_P (arg_type))
+		continue;
+
+	      if (!first_param)
+		arm_function_arg_advance (args_so_far, arg_mode, arg_type,
+					  true);
+
+	      arg_rtx = arm_function_arg (args_so_far, arg_mode, arg_type,
+					  true);
+	      gcc_assert (REG_P (arg_rtx));
+	      to_clear_mask
+		&= ~compute_not_to_clear_mask (arg_type, arg_rtx,
+					       REGNO (arg_rtx),
+					       padding_bits_to_clear_ptr);
+
+	      first_param = false;
+	    }
+
+	  /* Clear padding bits where needed.  */
+	  cleared_reg = XEXP (address, 0);
+	  reg = gen_rtx_REG (SImode, IP_REGNUM);
+	  using_r4 = false;
+	  for (regno = R0_REGNUM; regno < NUM_ARG_REGS; regno++)
+	    {
+	      if (padding_bits_to_clear[regno] == 0)
+		continue;
+
+	      /* If this is a Thumb-1 target copy the address of the function
+		 we are calling from 'r4' into 'ip' such that we can use r4 to
+		 clear the unused bits in the arguments.  */
+	      if (TARGET_THUMB1 && !using_r4)
+		{
+		  using_r4 =  true;
+		  reg = cleared_reg;
+		  emit_move_insn (gen_rtx_REG (SImode, IP_REGNUM),
+					  reg);
+		}
+
+	      tmp = GEN_INT ((((~padding_bits_to_clear[regno]) << 16u) >> 16u));
+	      emit_move_insn (reg, tmp);
+	      /* Also fill the top half of the negated
+		 padding_bits_to_clear.  */
+	      if (((~padding_bits_to_clear[regno]) >> 16) > 0)
+		{
+		  tmp = GEN_INT ((~padding_bits_to_clear[regno]) >> 16);
+		  emit_insn (gen_rtx_SET (gen_rtx_ZERO_EXTRACT (SImode, reg,
+								GEN_INT (16),
+								GEN_INT (16)),
+					  tmp));
+		}
+
+	      emit_insn (gen_andsi3 (gen_rtx_REG (SImode, regno),
+				     gen_rtx_REG (SImode, regno),
+				     reg));
+
+	    }
+	  if (using_r4)
+	    emit_move_insn (cleared_reg,
+			    gen_rtx_REG (SImode, IP_REGNUM));
+
+	  /* We use right shift and left shift to clear the LSB of the address
+	     we jump to instead of using bic, to avoid having to use an extra
+	     register on Thumb-1.  */
+	  tmp = gen_rtx_LSHIFTRT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+	  tmp = gen_rtx_ASHIFT (SImode, cleared_reg, const1_rtx);
+	  emit_insn (gen_rtx_SET (cleared_reg, tmp));
+
+	  /* Clearing all registers that leak before doing a non-secure
+	     call.  */
+	  for (regno = R0_REGNUM; regno <= maxregno; regno++)
+	    {
+	      if (!(to_clear_mask & (1LL << regno)))
+		continue;
+
+	      /* If regno is an even vfp register and its successor is also to
+		 be cleared, use vmov.  */
+	      if (IS_VFP_REGNUM (regno))
+		{
+		  if (TARGET_VFP_DOUBLE
+		      && VFP_REGNO_OK_FOR_DOUBLE (regno)
+		      && to_clear_mask & (1LL << (regno + 1)))
+		    emit_move_insn (gen_rtx_REG (DFmode, regno++),
+				    CONST0_RTX (DFmode));
+		  else
+		    emit_move_insn (gen_rtx_REG (SFmode, regno),
+				    CONST0_RTX (SFmode));
+		}
+	      else
+		emit_move_insn (gen_rtx_REG (SImode, regno), cleared_reg);
+	    }
+
+	  seq = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (seq, insn);
+
+	}
+    }
+}
+
 /* Rewrite move insn into subtract of 0 if the condition codes will
    be useful in next conditional jump insn.  */
 
@@ -18088,6 +18288,8 @@ arm_reorg (void)
   HOST_WIDE_INT address = 0;
   Mfix * fix;
 
+  if (use_cmse)
+    cmse_nonsecure_call_clear_caller_saved ();
   if (TARGET_THUMB1)
     thumb1_reorg ();
   else if (TARGET_THUMB2)
@@ -18460,6 +18662,23 @@ vfp_emit_fstmd (int base_reg, int count)
   return count * 8;
 }
 
+/* Returns true if -mcmse has been passed and the function pointed to by 'addr'
+   has the cmse_nonsecure_call attribute and returns false otherwise.  */
+
+bool
+detect_cmse_nonsecure_call (tree addr)
+{
+  if (!addr)
+    return FALSE;
+
+  tree fntype = TREE_TYPE (addr);
+  if (use_cmse && lookup_attribute ("cmse_nonsecure_call",
+				    TYPE_ATTRIBUTES (fntype)))
+    return TRUE;
+  return FALSE;
+}
+
+
 /* Emit a call instruction with pattern PAT.  ADDR is the address of
    the call target.  */
 
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 8819cb7345896ce845d3aac00e45e6d880fdc808..c8dc184cd154922b4fc881d138058f68dc9e8569 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -7640,6 +7640,7 @@
   "
   {
     rtx callee, pat;
+    tree addr = MEM_EXPR (operands[0]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[2] == NULL_RTX)
@@ -7654,8 +7655,17 @@
 	: !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_internal (operands[0], operands[1], operands[2]);
-    arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_internal (operands[0], operands[1],
+					   operands[2]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_internal (operands[0], operands[1], operands[2]);
+	arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
+      }
     DONE;
   }"
 )
@@ -7666,6 +7676,24 @@
 	      (use (match_operand 2 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_internal"
+  [(parallel [(call (unspec:SI [(match_operand 0 "memory_operand" "")]
+			       UNSPEC_NONSECURE_MEM)
+		    (match_operand 1 "general_operand" ""))
+	      (use (match_operand 2 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[0], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[0] = replace_equiv_address (operands[0], tmp);
+  }")
+
 (define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
@@ -7701,6 +7729,7 @@
   "
   {
     rtx pat, callee;
+    tree addr = MEM_EXPR (operands[1]);
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
@@ -7715,9 +7744,18 @@
 	: !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
 
-    pat = gen_call_value_internal (operands[0], operands[1],
-				   operands[2], operands[3]);
-    arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+    if (detect_cmse_nonsecure_call (addr))
+      {
+	pat = gen_nonsecure_call_value_internal (operands[0], operands[1],
+						 operands[2], operands[3]);
+	emit_call_insn (pat);
+      }
+    else
+      {
+	pat = gen_call_value_internal (operands[0], operands[1],
+				       operands[2], operands[3]);
+	arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
+      }
     DONE;
   }"
 )
@@ -7729,6 +7767,25 @@
 	      (use (match_operand 3 "" ""))
 	      (clobber (reg:SI LR_REGNUM))])])
 
+(define_expand "nonsecure_call_value_internal"
+  [(parallel [(set (match_operand       0 "" "")
+		   (call (unspec:SI [(match_operand 1 "memory_operand" "")]
+				    UNSPEC_NONSECURE_MEM)
+			 (match_operand 2 "general_operand" "")))
+	      (use (match_operand 3 "" ""))
+	      (clobber (reg:SI LR_REGNUM))
+	      (clobber (reg:SI 4))])]
+  "use_cmse"
+  "
+  {
+    rtx tmp;
+    tmp = copy_to_suggested_reg (XEXP (operands[1], 0),
+				 gen_rtx_REG (SImode, 4),
+				 SImode);
+
+    operands[1] = replace_equiv_address (operands[1], tmp);
+  }")
+
 (define_insn "*call_value_reg_armv5"
   [(set (match_operand 0 "" "")
         (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 39bcae78c16885cbb616b10616a014e289796591..af8a9f8e0a911fad2192b13df540de4f367ac586 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -1731,6 +1731,19 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb1_v5"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB1 && use_cmse && !SIBLING_CALL_P (insn)"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_reg_thumb1"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
 	 (match_operand 1 "" ""))
@@ -1763,6 +1776,21 @@
    (set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb1_v5"
+  [(set (match_operand 0 "" "")
+	(call (unspec:SI
+	       [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+	       UNSPEC_NONSECURE_MEM)
+	      (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB1 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb1"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index 140e71e9ca9428459b9d7f8fc3459529f85ec836..ad4fee1cdcdcccd2cdab92f7643af1f7f9f12438 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -581,6 +581,19 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_reg_thumb2"
+  [(call (unspec:SI [(mem:SI (match_operand:SI 0 "s_register_operand" "r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 0))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*call_value_reg_thumb2"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
@@ -592,6 +605,21 @@
   [(set_attr "type" "call")]
 )
 
+(define_insn "*nonsecure_call_value_reg_thumb2"
+  [(set (match_operand 0 "" "")
+	(call
+	 (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "l*r"))]
+		    UNSPEC_NONSECURE_MEM)
+	 (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))
+   (clobber (match_dup 1))]
+  "TARGET_THUMB2 && use_cmse"
+  "bl\t__gnu_cmse_nonsecure_call"
+  [(set_attr "length" "4")
+   (set_attr "type" "call")]
+)
+
 (define_insn "*thumb2_indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "register_operand" "l*r"))]
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 5744c62cf5ab3b3711fef2b442c62cd3eadf0793..c2f5e5b52cd84380c009af4077bd6effda923701 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -84,6 +84,8 @@
   UNSPEC_VRINTA         ; Represent a float to integral float rounding
                         ; towards nearest, ties away from zero.
   UNSPEC_PROBE_STACK    ; Probe stack memory reference
+  UNSPEC_NONSECURE_MEM	; Represent non-secure memory in ARMv8-M with
+			; security extension
 ])
 
 (define_c_enum "unspec" [
diff --git a/gcc/testsuite/ChangeLog.arm b/gcc/testsuite/ChangeLog.arm
index e8938adfc6a811130a54a5a8e3f291080d20ca46..70bbbb8a16c48153322311538d9f8d7e49f76248 100644
--- a/gcc/testsuite/ChangeLog.arm
+++ b/gcc/testsuite/ChangeLog.arm
@@ -4,6 +4,51 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
+	* gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
+	* gcc.target/arm/cmse/cmse-14.c: New.
+	* gcc.target/arm/cmse/baseline/bitfield-4.c: New.
+	* gcc.target/arm/cmse/baseline/bitfield-5.c: New.
+	* gcc.target/arm/cmse/baseline/bitfield-6.c: New.
+	* gcc.target/arm/cmse/baseline/bitfield-7.c: New.
+	* gcc.target/arm/cmse/baseline/bitfield-8.c: New.
+	* gcc.target/arm/cmse/baseline/bitfield-9.c: New.
+	* gcc.target/arm/cmse/baseline/bitfield-and-union-1.c: New.
+	* gcc.target/arm/cmse/baseline/cmse-11.c: New.
+	* gcc.target/arm/cmse/baseline/cmse-13.c: New.
+	* gcc.target/arm/cmse/baseline/cmse-6.c: New.
+	* gcc.target/arm/cmse/baseline/union-1.c: New.
+	* gcc.target/arm/cmse/baseline/union-2.c: New.
+	* gcc.target/arm/cmse/mainline/bitfield-4.c: New.
+	* gcc.target/arm/cmse/mainline/bitfield-5.c: New.
+	* gcc.target/arm/cmse/mainline/bitfield-6.c: New.
+	* gcc.target/arm/cmse/mainline/bitfield-7.c: New.
+	* gcc.target/arm/cmse/mainline/bitfield-8.c: New.
+	* gcc.target/arm/cmse/mainline/bitfield-9.c: New.
+	* gcc.target/arm/cmse/mainline/bitfield-and-union-1.c: New.
+	* gcc.target/arm/cmse/mainline/union-1.c: New.
+	* gcc.target/arm/cmse/mainline/union-2.c: New.
+	* gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c: New.
+	* gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c: New.
+	* gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c: New.
+	* gcc.target/arm/cmse/mainline/hard/cmse-13.c: New.
+	* gcc.target/arm/cmse/mainline/hard/cmse-7.c: New.
+	* gcc.target/arm/cmse/mainline/hard/cmse-8.c: New.
+	* gcc.target/arm/cmse/mainline/soft/cmse-13.c: New.
+	* gcc.target/arm/cmse/mainline/soft/cmse-7.c: New.
+	* gcc.target/arm/cmse/mainline/soft/cmse-8.c: New.
+	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c: New.
+	* gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c: New.
+	* gcc.target/arm/cmse/mainline/softfp/cmse-13.c: New.
+	* gcc.target/arm/cmse/mainline/softfp/cmse-7.c: New.
+	* gcc.target/arm/cmse/mainline/softfp/cmse-8.c: New.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* gcc.target/arm/cmse/cmse-3.c: Add tests.
 	* gcc.target/arm/cmse/cmse-4.c: Add tests.
 	* gcc.target/arm/cmse/cmse-15.c: New.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6c1386c06edbdb58e76fa5e612c918010c507f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-4.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d51ce2d42c051aeda8b06ad97086f2563a5fc47d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-5.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..77e9104b546a7693fcb2399622e828b1197eac1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-6.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 1023" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #3" } } */
+/* { dg-final { scan-assembler "movt\tr4, 32767" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d8941bbfeebd59744c43f10c842816b36ec9915
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-7.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ffbb718d34d5bb8f10e1f3c0505c7dc393c670c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-8.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #255" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a6141829237823b8734de045a590a1917fa60b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-9.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #1799" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..642f4e0346b5186c78645780b45fe9c838848d45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/bitfield-and-union-1.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #7939" } } */
+/* { dg-final { scan-assembler "movt\tr4, 15" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 2047" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr4, #1" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr3, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, 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/baseline/cmse-11.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
new file mode 100644
index 0000000000000000000000000000000000000000..3007409ad88b9d2312ece4d55f3695787a1aa566
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-11.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (int);
+
+int
+foo (int a)
+{
+  return bar (bar (a + 1));
+}
+
+/* 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 "movs\tr1, r4" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\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/baseline/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2b931be5912b421f8427535ded3298883bec639
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" } */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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 "movs\tr0, r4" } } */
+/* { dg-final { scan-assembler "\n\tmovs\tr1, r4" } } */
+/* { dg-final { scan-assembler-not "\n\tmovs\tr2, r4\n\tmovs\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/baseline/cmse-6.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..95da045690ae170a101949134482e821f27fe3aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/cmse-6.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_base_ok } */
+/* { dg-add-options arm_arch_v8m_base } */
+/* { dg-options "-mcmse" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* Remember dont clear r0 and r1, because we are passing the double parameter
+ * for bar in them.  */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, 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/baseline/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff18e839b02c19c2c77769b18ef5ee1cfacf0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8063" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr2, r4" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2e024b7f0776381f511077af91bd1ee5632ff12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/baseline/union-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mov\tip, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #8191" } } */
+/* { dg-final { scan-assembler "movt\tr4, 63" } } */
+/* { dg-final { scan-assembler "ands\tr0, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #511" } } */
+/* { dg-final { scan-assembler "movt\tr4, 65535" } } */
+/* { dg-final { scan-assembler "ands\tr1, r4" } } */
+/* { dg-final { scan-assembler "movw\tr4, #65535" } } */
+/* { dg-final { scan-assembler "movt\tr4, 31" } } */
+/* { dg-final { scan-assembler "ands\tr2, r4" } } */
+/* { dg-final { scan-assembler "mov\tr4, ip" } } */
+/* { dg-final { scan-assembler "lsrs\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "lsls\tr4, r4, #1" } } */
+/* { dg-final { scan-assembler "movs\tr3, r4" } } */
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
new file mode 100644
index 0000000000000000000000000000000000000000..701e9ee7e318a07278099548f9b7042a1fde1204
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-14.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int foo (void)
+{
+  return bar ();
+}
+
+/* { dg-final { scan-assembler "bl\t__gnu_cmse_nonsecure_call" } } */
+/* { dg-final { scan-assembler-not "b\[^ y\n\]*\\s+bar" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
index 1d97f0e1a37209bd129ffe96ce92a86bc2e0d5d1..9e81e30c891bbc1f9d2d1d68d03bacad9ce65fe1 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-9.c
@@ -2,11 +2,19 @@
 /* { dg-skip-if "Testing exclusion of -mcmse" { arm-*-* } { "-mcmse" } { "" } }  */
 
 
+void __attribute__ ((cmse_nonsecure_call)) (*bar) (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+typedef void __attribute__ ((cmse_nonsecure_call)) baz (int); /* { dg-warning "attribute ignored without -mcmse option" } */
+
 int __attribute__ ((cmse_nonsecure_entry))
-foo (int a)
+foo (int a, baz b)
 { /* { dg-warning "attribute ignored without -mcmse option" } */
+  bar (a);
+  b (a);
   return a + 1;
 }
 
+/* { dg-final { scan-assembler-not "bxns" } } */
+/* { dg-final { scan-assembler-not "blxns" } } */
+/* { dg-final { scan-assembler-not "bl\t__gnu_cmse_nonsecure_call" } } */
 /* { dg-final { scan-assembler "foo:" } } */
 /* { dg-final { scan-assembler-not "__acle_se_foo:" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
index 38f18414c2fefec56161e6ac3f7291b03a3b29a3..66a8b7da005f7dfeffbded61b02fd6a7473a1dcf 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -50,6 +50,8 @@ if {[check_effective_target_arm_arch_v8m_base_ok]} then {
 }
 
 if {[check_effective_target_arm_arch_v8m_main_ok]} then {
+    gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/*.c]] \
+	    "" $DEFAULT_CFLAGS
     # Mainline -mfloat-abi=soft
     gcc-dg-runtest [lsort [glob $srcdir/$subdir/mainline/soft/*.c]] \
 	    "-mfloat-abi=soft" $DEFAULT_CFLAGS
diff --git a/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b1396d52e742a1710ed5ad33fbeb559d866f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-4.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int b:5;
+  unsigned int c:11, :0, d:8;
+  struct { unsigned int ee:2; } e;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+extern void foo (test_st st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-5.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d029044aa9aa1d412c28ee5d18a8e3d0be36546
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-6.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
new file mode 100644
index 0000000000000000000000000000000000000000..005515ab9cb85c201a2a8b2f6417d73ceeacbc60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-6.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char a;
+  unsigned int	b : 3;
+  unsigned int	c : 14;
+  unsigned int	d : 1;
+  struct {
+      unsigned int    ee  : 2;
+      unsigned short  ff  : 15;
+  } e;
+  unsigned char	g : 1;
+  unsigned char	  : 4;
+  unsigned char	h : 3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..6dd218e62fdee2a6af819079ba1ea1909185d076
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-7.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned short  b :5;
+  unsigned char	  c;
+  unsigned short  d :11;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+
+/* { 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/bitfield-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..c833bcb0ae978572fad46780bc180f61ccb14345
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-8.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-9.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cdb8c44b19c811f3a7b4fbce102a6c768f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-9.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  char a:3;
+} test_st3;
+
+typedef struct
+{
+  char a:3;
+} test_st2;
+
+typedef struct
+{
+  test_st2 st2;
+  test_st3 st3;
+} test_st;
+
+typedef union
+{
+  test_st st;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st;
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st);
+
+int
+main (void)
+{
+  read_st r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+
+  f (r.st);
+  return 0;
+}
+
+/* { 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/bitfield-and-union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e139ba61af57f06cff5a9d121c97bbf41e170bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/bitfield-and-union-1.c
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned short a :11;
+} test_st_4;
+
+typedef union
+{
+  char	      a;
+  test_st_4 st4;
+}test_un_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef struct
+{
+  unsigned char	  a :3;
+  unsigned int	  b :13;
+  test_un_2	  un2;
+} test_st_2;
+
+typedef union
+{
+  test_st_2 st2;
+  test_st_3 st3;
+}test_un_1;
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned char	  c :4;
+  test_un_1	  un1;
+} test_st_1;
+
+typedef union
+{
+  test_st_1 st1;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_st_1;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_st_1);
+
+int
+main (void)
+{
+  read_st_1 r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+  r.values.v4 = 0xFFFFFFFF;
+
+  f (r.st1);
+  return 0;
+}
+
+/* { 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/hard-sp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..285fa854b3d61c4d856e9be863ee73a87f1b11a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-13.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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/hard-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f56aaf2a97e740a77473cab245614b6fa696c04
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-7.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..749f8a7278cb4ea9fd4462887ce7f37b57f83248
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard-sp/cmse-8.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/hard/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad5068aac263f1c2edb17b8707fc9d1c0af6959
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-13.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (3.0f, 2.0) + a + 1;
+}
+
+/* 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\.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/hard/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..b18259eaef6da1933ef2d58d63b97d4bb4e450f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/hard/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..182ddf9540374f30ae3694259f1edb62161455e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/hard/cmse-8.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=softfp } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=hard -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/soft/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd262c89085eb0dc8737ad7955c3a12531492b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-13.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/soft/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..e33568400ef830abaa019b5c2727a9f3b5d5704b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-7.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/soft/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..024a12e0a414730eb1cbebfca8574d548238ab28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/soft/cmse-8.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=hard" -mfloat-abi=softfp } {""} } */
+/* { dg-options "-mcmse -mfloat-abi=soft" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp-sp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..fb195eb58d59fe9ea5ed74af79646199c61bcdae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp-sp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..22ed3f8af882f96da49919c60fc6f4cd74dfc54b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp-sp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing double precision" {*-*-*} {"-mfpu=fpv[4-5]-d16"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-sp-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-13.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
new file mode 100644
index 0000000000000000000000000000000000000000..9634065e7cb64a5069cbb3c9be4b8cf9177f5e29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-13.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (float, double);
+
+int
+foo (int a)
+{
+  return bar (1.0f, 2.0) + a + 1;
+}
+
+/* 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/softfp/cmse-7.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
new file mode 100644
index 0000000000000000000000000000000000000000..04f8466cc112c03ee5a05e6e5223d2c66a033bbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-7.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (void);
+
+int
+foo (int a)
+{
+  return bar () + a + 1;
+}
+
+/* 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/softfp/cmse-8.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffe94de85417b81f9dcb366eb1b40dc1661c91b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/softfp/cmse-8.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arch_v8m_main_ok } */
+/* { dg-add-options arm_arch_v8m_main } */
+/* { dg-skip-if "Do not combine float-abi= hard | soft | softfp" {*-*-*} {"-mfloat-abi=soft" -mfloat-abi=hard } {""} } */
+/* { dg-skip-if "Skip these if testing single precision" {*-*-*} {"-mfpu=*-sp-*"} {""} } */
+/* { dg-options "-mcmse -mfloat-abi=softfp -mfpu=fpv5-d16" }  */
+
+int __attribute__ ((cmse_nonsecure_call)) (*bar) (double);
+
+int
+foo (int a)
+{
+  return bar (2.0) + a + 1;
+}
+
+/* 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/union-1.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fc846cd7a51303ec00f8f512a54cd697fbd0682
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/union-2.c b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..420d0f136ef171111c1cca6cd24c4f46b9fcb7fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/mainline/union-2.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-mcmse" } */
+
+typedef struct
+{
+  unsigned char	  a :2;
+  unsigned char	    :0;
+  unsigned short  b :5;
+  unsigned char	    :0;
+  unsigned short  c :3;
+  unsigned char	    :0;
+  unsigned int	  d :9;
+} test_st_1;
+
+typedef struct
+{
+  unsigned short  a :7;
+  unsigned char	    :0;
+  unsigned char	  b :1;
+  unsigned char	    :0;
+  unsigned short  c :6;
+} test_st_2;
+
+typedef struct
+{
+  unsigned char	  a;
+  unsigned int	    :0;
+  unsigned int	  b :1;
+  unsigned short    :0;
+  unsigned short  c;
+  unsigned int	    :0;
+  unsigned int	  d :21;
+} test_st_3;
+
+typedef union
+{
+  test_st_1 st_1;
+  test_st_2 st_2;
+  test_st_3 st_3;
+}test_un;
+
+typedef union
+{
+  test_un un;
+  struct
+    {
+      unsigned int v1;
+      unsigned int v2;
+      unsigned int v3;
+      unsigned int v4;
+    }values;
+} read_un;
+
+
+typedef void __attribute__ ((cmse_nonsecure_call)) (*foo_ns) (test_un);
+
+int
+main (void)
+{
+  read_un r;
+  foo_ns f;
+
+  f = (foo_ns) 0x200000;
+  r.values.v1 = 0xFFFFFFFF;
+  r.values.v2 = 0xFFFFFFFF;
+  r.values.v3 = 0xFFFFFFFF;
+
+  f (r.un);
+  return 0;
+}
+
+/* { 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/libgcc/ChangeLog.arm b/libgcc/ChangeLog.arm
index 50b4ce5f0e8a32c51c7831291852caccad14e9c9..481f85b4b926138c9d3a6580b94d3ecdd6c0fa14 100644
--- a/libgcc/ChangeLog.arm
+++ b/libgcc/ChangeLog.arm
@@ -4,6 +4,15 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* config/arm/cmse_nonsecure_call.S: New.
+	* config/arm/t-arm: Compile cmse_nonsecure_call.S
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* config/arm/t-arm (HAVE_CMSE): New.
 	* config/arm/cmse.c: New.
 
diff --git a/libgcc/config/arm/cmse_nonsecure_call.S b/libgcc/config/arm/cmse_nonsecure_call.S
new file mode 100644
index 0000000000000000000000000000000000000000..68b6a1cb5005d9ebb284a062443bc310d7e7db53
--- /dev/null
+++ b/libgcc/config/arm/cmse_nonsecure_call.S
@@ -0,0 +1,131 @@
+/* CMSE wrapper function used to save, clear and restore callee saved registers
+   for cmse_nonsecure_call's.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+.syntax unified
+.thumb
+.global __gnu_cmse_nonsecure_call
+__gnu_cmse_nonsecure_call:
+#if defined(__ARM_ARCH_8M_MAIN__)
+push	    {r5-r11,lr}
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+
+/* Save and clear callee-saved registers only if we are dealing with hard float
+   ABI.  The unused caller-saved registers have already been cleared by GCC
+   generated code.  */
+#ifdef __ARM_PCS_VFP
+vpush.f64   {d8-d15}
+mov	    r5, #0
+vmov	    d8, r5, r5
+#if __ARM_FP & 0x04
+vmov	    s18, s19, r5, r5
+vmov	    s20, s21, r5, r5
+vmov	    s22, s23, r5, r5
+vmov	    s24, s25, r5, r5
+vmov	    s26, s27, r5, r5
+vmov	    s28, s29, r5, r5
+vmov	    s30, s31, r5, r5
+#elif __ARM_FP & 0x08
+vmov.f64    d9, d8
+vmov.f64    d10, d8
+vmov.f64    d11, d8
+vmov.f64    d12, d8
+vmov.f64    d13, d8
+vmov.f64    d14, d8
+vmov.f64    d15, d8
+#else
+#error "Half precision implementation not supported."
+#endif
+/* Clear the cumulative exception-status bits (0-4,7) and the
+   condition code bits (28-31) of the FPSCR.  */
+vmrs	    r5, fpscr
+movw	    r6, #65376
+movt	    r6, #4095
+ands	    r5, r6
+vmsr	    fpscr, r5
+
+/* We are not dealing with hard float ABI, so we can safely use the vlstm and
+   vlldm instructions without needing to preserve the registers used for
+   argument passing.  */
+#else
+sub	    sp, sp, #0x88 /* Reserve stack space to save all floating point
+			     registers, including FPSCR.  */
+vlstm	    sp		  /* Lazy store and clearance of d0-d16 and FPSCR.  */
+#endif /* __ARM_PCS_VFP */
+
+/* Make sure to clear the 'GE' bits of the APSR register if 32-bit SIMD
+   instructions are available.  */
+#if defined(__ARM_FEATURE_SIMD32)
+msr	    APSR_nzcvqg, r4
+#else
+msr	    APSR_nzcvq, r4
+#endif
+
+mov	    r5, r4
+mov	    r6, r4
+blxns	    r4
+
+#ifdef __ARM_PCS_VFP
+vpop.f64    {d8-d15}
+#else
+vlldm	    sp		  /* Lazy restore of d0-d16 and FPSCR.  */
+add	    sp, sp, #0x88 /* Free space used to save floating point registers.  */
+#endif /* __ARM_PCS_VFP */
+
+pop	    {r5-r11, pc}
+
+#elif defined (__ARM_ARCH_8M_BASE__)
+push	    {r5-r7, lr}
+mov	    r5, r8
+mov	    r6, r9
+mov	    r7, r10
+push	    {r5-r7}
+mov	    r5, r11
+push	    {r5}
+mov	    r5, r4
+mov	    r6, r4
+mov	    r7, r4
+mov	    r8, r4
+mov	    r9, r4
+mov	    r10, r4
+mov	    r11, r4
+mov	    ip, r4
+msr	    APSR_nzcvq, r4
+blxns	    r4
+pop	    {r5}
+mov	    r11, r5
+pop	    {r5-r7}
+mov	    r10, r7
+mov	    r9, r6
+mov	    r8, r5
+pop	    {r5-r7, pc}
+
+#else
+#error "This should only be used for armv8-m base- and mainline."
+#endif
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 5618143bfd0f02b170db3f9e4c0a15cecb403cec..9e85ac06b146feaa14ab83374a0156737b870310 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -12,4 +12,6 @@ libgcc-objects += cmse.o cmse_nonsecure_call.o
 
 cmse.o: $(srcdir)/config/arm/cmse.c
 	$(gcc_compile) -c $(CMSE_OPTS) $<
+cmse_nonsecure_call.o: $(srcdir)/config/arm/cmse_nonsecure_call.S
+		       $(gcc_compile) -c $<
 endif

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

* [arm-embedded][committed][PATCH 7/7] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic
  2016-11-30 12:06           ` Andre Vieira (lists)
@ 2016-12-05 11:46             ` Andre Vieira (lists)
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Vieira (lists) @ 2016-12-05 11:46 UTC (permalink / raw)
  To: gcc-patches

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

On 30/11/16 12:06, Andre Vieira (lists) wrote:
> Hi,
> 
> I changed the testcase with this patch since the old testcase was
> casting a function pointer to another function pointer and using that
> pointer to call the function. This is undefined behavior. The new test
> reflects a more sane use of the intrinsics.
> 
> Cheers,
> Andre
> 
Hi,

Backported this to the embedded-6-branch in revision r243253.

Cheers,
Andre

gcc/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* config/arm/arm-builtins.c (arm_builtins): Define
	ARM_BUILTIN_CMSE_NONSECURE_CALLER.
	(bdesc_2arg): Add line for cmse_nonsecure_caller.
	(arm_init_builtins): Handle cmse_nonsecure_caller.
	(arm_expand_builtin): Likewise.
	* config/arm/arm_cmse.h (cmse_nonsecure_caller): New.

gcc/testsuite/ChangeLog.arm:
2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	Backport from mainline
	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
		    Thomas Preud'homme	<thomas.preudhomme@arm.com>

	* gcc.target/arm/cmse/cmse-1.c: Add test for
	cmse_nonsecure_caller.

[-- Attachment #2: diff7 --]
[-- Type: text/plain, Size: 5986 bytes --]

diff --git a/gcc/ChangeLog.arm b/gcc/ChangeLog.arm
index 315ea8897096ec7890675e0c680f048e19d5dd5b..800a4b60efe7fe5ba9077217b7eb1271e9e05180 100644
--- a/gcc/ChangeLog.arm
+++ b/gcc/ChangeLog.arm
@@ -4,6 +4,19 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* config/arm/arm-builtins.c (arm_builtins): Define
+	ARM_BUILTIN_CMSE_NONSECURE_CALLER.
+	(bdesc_2arg): Add line for cmse_nonsecure_caller.
+	(arm_init_builtins): Handle cmse_nonsecure_caller.
+	(arm_expand_builtin): Likewise.
+	* config/arm/arm_cmse.h (cmse_nonsecure_caller): New.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* config/arm/arm.c (detect_cmse_nonsecure_call): New.
 	(cmse_nonsecure_call_clear_caller_saved): New.
 	(arm_reorg): Use cmse_nonsecure_call_clear_caller_saved.
diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index 68b2839879f78e8d819444fbc11d2a91f8d6279a..ac56648706cd81a35fc32bde0bf3fc723387f5d5 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -515,6 +515,8 @@ enum arm_builtins
   ARM_BUILTIN_GET_FPSCR,
   ARM_BUILTIN_SET_FPSCR,
 
+  ARM_BUILTIN_CMSE_NONSECURE_CALLER,
+
 #undef CRYPTO1
 #undef CRYPTO2
 #undef CRYPTO3
@@ -1789,6 +1791,17 @@ arm_init_builtins (void)
 	= add_builtin_function ("__builtin_arm_stfscr", ftype_set_fpscr,
 				ARM_BUILTIN_SET_FPSCR, BUILT_IN_MD, NULL, NULL_TREE);
     }
+
+  if (use_cmse)
+    {
+      tree ftype_cmse_nonsecure_caller
+	= build_function_type_list (unsigned_type_node, NULL);
+      arm_builtin_decls[ARM_BUILTIN_CMSE_NONSECURE_CALLER]
+	= add_builtin_function ("__builtin_arm_cmse_nonsecure_caller",
+				ftype_cmse_nonsecure_caller,
+				ARM_BUILTIN_CMSE_NONSECURE_CALLER, BUILT_IN_MD,
+				NULL, NULL_TREE);
+    }
 }
 
 /* Return the ARM builtin for CODE.  */
@@ -2368,6 +2381,12 @@ arm_expand_builtin (tree exp,
       emit_insn (pat);
       return target;
 
+    case ARM_BUILTIN_CMSE_NONSECURE_CALLER:
+      target = gen_reg_rtx (SImode);
+      op0 = arm_return_addr (0, NULL_RTX);
+      emit_insn (gen_addsi3 (target, op0, const1_rtx));
+      return target;
+
     case ARM_BUILTIN_TEXTRMSB:
     case ARM_BUILTIN_TEXTRMUB:
     case ARM_BUILTIN_TEXTRMSH:
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
index 894343bb835b61e09c14668d45aa43a8693fd011..82b58b1c4f4a12ba6062e2cc2632653788d0eeb7 100644
--- a/gcc/config/arm/arm_cmse.h
+++ b/gcc/config/arm/arm_cmse.h
@@ -163,6 +163,13 @@ __attribute__ ((__always_inline__))
 cmse_TTAT (void *__p)
 __CMSE_TT_ASM (at)
 
+/* FIXME: diagnose use outside cmse_nonsecure_entry functions.  */
+__extension__ static __inline int __attribute__ ((__always_inline__))
+cmse_nonsecure_caller (void)
+{
+  return __builtin_arm_cmse_nonsecure_caller ();
+}
+
 #define CMSE_AU_NONSECURE	2
 #define CMSE_MPU_NONSECURE	16
 #define CMSE_NONSECURE		18
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 50a2db184aa5c11865e0ebfc3881e54d2703774d..44d9b48fcd2ffd8a3b127261be8088d1ab67002e 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -12287,6 +12287,7 @@ cmse_address_info_t cmse_TTAT_fptr (FPTR)
 void * cmse_check_address_range (void *, size_t, int)
 typeof(p) cmse_nsfptr_create (FPTR p)
 intptr_t cmse_is_nsfptr (FPTR)
+int cmse_nonsecure_caller (void)
 @end smallexample
 
 @node AVR Built-in Functions
diff --git a/gcc/testsuite/ChangeLog.arm b/gcc/testsuite/ChangeLog.arm
index 70bbbb8a16c48153322311538d9f8d7e49f76248..17dbfe0675bc9c8d01b3af4360ee7327bd719eda 100644
--- a/gcc/testsuite/ChangeLog.arm
+++ b/gcc/testsuite/ChangeLog.arm
@@ -4,6 +4,15 @@
 	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
 
+	* gcc.target/arm/cmse/cmse-1.c: Add test for
+	cmse_nonsecure_caller.
+
+2016-12-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+	Backport from mainline
+	2016-12-02  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+		    Thomas Preud'homme	<thomas.preudhomme@arm.com>
+
 	* gcc.target/arm/cmse/cmse.exp: Run tests in mainline dir.
 	* gcc.target/arm/cmse/cmse-9.c: Added some extra tests.
 	* gcc.target/arm/cmse/cmse-14.c: New.
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
index d5b9a2d9d59569de170da814ae660e9fb2b943e7..c13272eed683aa06db027cd4646e5fe67817212b 100644
--- a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -65,3 +65,42 @@ int foo (char * p)
 /* { dg-final { scan-assembler-times "ttat " 2 } } */
 /* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
 /* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
+
+int __attribute__ ((cmse_nonsecure_entry))
+baz (void)
+{
+  return cmse_nonsecure_caller ();
+}
+
+typedef int __attribute__ ((cmse_nonsecure_call)) (int_nsfunc_t) (void);
+
+int default_callback (void)
+{
+  return 0;
+}
+
+int_nsfunc_t * fp = (int_nsfunc_t *) default_callback;
+
+void __attribute__ ((cmse_nonsecure_entry))
+qux (int_nsfunc_t * callback)
+{
+  fp = cmse_nsfptr_create (callback);
+}
+
+int call_callback (void)
+{
+  if (cmse_is_nsfptr (fp))
+      return fp ();
+  else
+    return default_callback ();
+}
+/* { dg-final { scan-assembler "baz:" } } */
+/* { dg-final { scan-assembler "__acle_se_baz:" } } */
+/* { dg-final { scan-assembler "qux:" } } */
+/* { dg-final { scan-assembler "__acle_se_qux:" } } */
+/* { dg-final { scan-assembler-not "\tcmse_nonsecure_caller" } } */
+/* { dg-final { scan-rtl-dump "and.*reg.*const_int 1" expand } } */
+/* { dg-final { scan-assembler "bic" } } */
+/* { dg-final { scan-assembler "push\t\{r4, r5, r6" } } */
+/* { dg-final { scan-assembler "msr\tAPSR_nzcvq" } } */
+/* { dg-final { scan-assembler-times "bl\\s+__gnu_cmse_nonsecure_call" 1 } } */

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

end of thread, other threads:[~2016-12-05 11:46 UTC | newest]

Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-25 13:17 [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Andre Vieira (lists)
2016-07-25 13:20 ` [PATCH 1/7, GCC, ARM, V8M] Add support for ARMv8-M's Secure Extensions flag and intrinsics Andre Vieira (lists)
2016-08-24 11:00   ` [PATCHv2 " Andre Vieira (lists)
2016-10-25 16:26     ` Andre Vieira (lists)
2016-10-26  9:13       ` Kyrill Tkachov
2016-10-26 13:00         ` Kyrill Tkachov
2016-10-27  9:54           ` Andre Vieira (lists)
2016-10-27 10:01             ` Kyrill Tkachov
2016-12-05 11:27               ` [arm-embedded][committed][PATCH 1/7] " Andre Vieira (lists)
2016-07-25 13:21 ` [PATCH 2/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_entry attribute Andre Vieira (lists)
2016-08-24 11:01   ` [PATCHv2 " Andre Vieira (lists)
2016-10-25 16:28     ` Andre Vieira (lists)
2016-10-26  9:33       ` Kyrill Tkachov
2016-10-26 16:28         ` Andre Vieira (lists)
2016-10-26 16:28           ` Kyrill Tkachov
2016-10-27  9:54             ` Andre Vieira (lists)
2016-10-27 10:19               ` Kyrill Tkachov
2016-12-05 11:31                 ` [arm-embedded][committed][PATCH 2/7] " Andre Vieira (lists)
2016-07-25 13:23 ` [PATCH 3/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: __acle_se label and bxns return Andre Vieira (lists)
2016-10-25 16:29   ` Andre Vieira (lists)
2016-10-26 10:03     ` Kyrill Tkachov
2016-10-27  9:55       ` Andre Vieira (lists)
2016-12-05 11:34         ` [arm-embedded][committed][PATCH 3/7] " Andre Vieira (lists)
2016-07-25 13:24 ` [PATCH 4/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_entry: clear registers Andre Vieira (lists)
2016-08-24 11:01   ` [PATCHv2 " Andre Vieira (lists)
2016-10-25 16:29     ` Andre Vieira (lists)
2016-10-26 12:51       ` Kyrill Tkachov
2016-10-26 16:26         ` Andre Vieira (lists)
2016-10-26 16:30           ` Kyrill Tkachov
2016-10-27 10:00             ` Andre Vieira (lists)
2016-10-27 10:44               ` Kyrill Tkachov
2016-10-28 16:08                 ` Andre Vieira (lists)
2016-11-08 12:16                   ` Kyrill Tkachov
2016-11-23 11:52                     ` Andre Vieira (lists)
2016-11-30 15:32                       ` Andre Vieira (lists)
2016-11-30 17:22                         ` Kyrill Tkachov
2016-12-05 11:36                           ` [arm-embedded][committed][PATCH 4/7] " Andre Vieira (lists)
2016-10-26 14:14       ` [PATCHv2 4/7, GCC, ARM, V8M] " Kyrill Tkachov
2016-07-25 13:25 ` [PATCH 5/7, GCC, ARM, V8M] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute Andre Vieira (lists)
2016-08-24 11:01   ` [PATCHv2 " Andre Vieira (lists)
2016-10-25 16:29     ` Andre Vieira (lists)
2016-10-27 10:00       ` Andre Vieira (lists)
2016-11-04  9:30       ` Kyrill Tkachov
2016-11-30 12:05         ` [PATCHv3 " Andre Vieira (lists)
2016-11-30 17:22           ` Kyrill Tkachov
2016-12-05 11:38             ` [PATCHv3 5/7, GCC[arm-embedded][committed][PATCH 5/7] Handling ARMv8-M Security Extension's cmse_nonsecure_call attribute, " Andre Vieira (lists)
2016-07-25 13:26 ` [PATCH 6/7, GCC, ARM, V8M] ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call Andre Vieira (lists)
2016-08-24 11:02   ` [PATCHv2 " Andre Vieira (lists)
2016-10-25 16:30     ` Andre Vieira (lists)
2016-10-27 10:01       ` Andre Vieira (lists)
2016-11-09 14:54         ` Andre Vieira (lists)
2016-11-11 11:52           ` Kyrill Tkachov
2016-11-11 16:15             ` Andre Vieira (lists)
2016-11-11 16:19               ` Kyrill Tkachov
2016-11-11 16:19                 ` Kyrill Tkachov
2016-11-23 11:54                   ` Andre Vieira (lists)
2016-12-02 13:36                     ` Andre Vieira (lists)
2016-12-02 13:42                       ` Kyrill Tkachov
2016-12-05 11:44                         ` [arm-embedded][committed][PATCH 6/7] " Andre Vieira (lists)
2016-07-25 13:29 ` [PATCH 7/7, GCC, ARM, V8M] Added support for ARMV8-M Security Extension cmse_nonsecure_caller intrinsic Andre Vieira (lists)
2016-08-24 11:02   ` Andre Vieira (lists)
2016-10-25 16:30     ` Andre Vieira (lists)
2016-11-09 10:27       ` Kyrill Tkachov
2016-11-09 14:53         ` Andre Vieira (lists)
2016-11-30 12:06           ` Andre Vieira (lists)
2016-12-05 11:46             ` [arm-embedded][committed][PATCH 7/7] " Andre Vieira (lists)
2016-08-08  4:20 ` [PATCH 0/7, GCC, V8M] ARMv8-M Security Extensions Sandra Loosemore
2016-08-09 12:01   ` Andre Vieira (lists)
2016-08-09 16:47     ` Sandra Loosemore
2016-08-10  8:09       ` Andre Vieira (lists)
2016-08-24 11:02         ` Andre Vieira (lists)
2016-10-24 16:14           ` 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).