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 <[email protected]>
>>>> Thomas Preud'homme <[email protected]>
>>>>
>>>> * 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 <[email protected]>
>>>> Thomas Preud'homme <[email protected]>
>>>>
>>>> * config/arm/cmse_nonsecure_call.S: New.
>>>> * config/arm/t-arm: Compile cmse_nonsecure_call.S
>>>>
>>>>
>>>> *** gcc/testsuite/ChangeLog ***
>>>> 2016-07-25 Andre Vieira <[email protected]>
>>>> Thomas Preud'homme <[email protected]>
>>>>
>>>> * 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 <[email protected]>
>>> Thomas Preud'homme <[email protected]>
>>>
>>> * 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 <[email protected]>
>>> Thomas Preud'homme <[email protected]>
>>>
>>> * config/arm/cmse_nonsecure_call.S: New.
>>> * config/arm/t-arm: Compile cmse_nonsecure_call.S
>>>
>>>
>>> *** gcc/testsuite/ChangeLog ***
>>> 2016-07-xx Andre Vieira <[email protected]>
>>> Thomas Preud'homme <[email protected]>
>>>
>>> * 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
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