Commit c92e08e3 by Andre Vieira Committed by Andre Vieira

ARMv8-M Security Extension's cmse_nonsecure_call: use __gnu_cmse_nonsecure_call

    gcc/ChangeLog:
    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.

    libgcc/ChangeLog:
    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

    gcc/testsuite/ChangeLog:
    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.


Co-Authored-By: Thomas Preud'homme <thomas.preudhomme@arm.com>

From-SVN: r243192
parent 32ce1e4f
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-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.
......@@ -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 *);
......
......@@ -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. */
......
......@@ -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"))
......
......@@ -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"))
......
......@@ -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"))]
......
......@@ -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" [
......
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-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.
......
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
......@@ -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:" } } */
......@@ -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
......
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
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-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.
......
/* 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
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment