[PATCH] [ARC] Add support for naked functions.
gcc/ 2017-07-17 Claudiu Zissulescu <claziss@synopsys.com> Andrew Burgess <andrew.burgess@embecosm.com> * config/arc/arc-protos.h (arc_compute_function_type): Change prototype. (arc_return_address_register): New function. * config/arc/arc.c (arc_handle_fndecl_attribute): New function. (arc_handle_fndecl_attribute): Add naked attribute. (TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS): Define. (TARGET_WARN_FUNC_RETURN): Likewise. (arc_allocate_stack_slots_for_args): New function. (arc_warn_func_return): Likewise. (machine_function): Change type fn_type. (arc_compute_function_type): Consider new naked function type, change function return type. (arc_must_save_register): Adapt to handle new arc_compute_function_type's return type. (arc_expand_prologue): Likewise. (arc_expand_epilogue): Likewise. (arc_return_address_regs): Delete. (arc_return_address_register): New function. (arc_epilogue_uses): Use above function. * config/arc/arc.h (arc_return_address_regs): Delete prototype. (arc_function_type): Change encoding, add naked type. (ARC_INTERRUPT_P): Change to handle the new encoding. (ARC_FAST_INTERRUPT_P): Likewise. (ARC_NORMAL_P): Define. (ARC_NAKED_P): Likewise. (arc_compute_function_type): Delete prototype. * config/arc/arc.md (in_ret_delay_slot): Use arc_return_address_register function. (simple_return): Likewise. (p_return_i): Likewise. gcc/testsuite 2017-07-17 Claudiu Zissulescu <claziss@synopsys.com> Andrew Burgess <andrew.burgess@embecosm.com> * gcc.target/arc/naked-1.c: New file. * gcc.target/arc/naked-2.c: Likewise. Co-Authored-By: Andrew Burgess <andrew.burgess@embecosm.com> From-SVN: r250266
This commit is contained in:
parent
9ebce09858
commit
1825c61e15
8 changed files with 231 additions and 63 deletions
|
@ -1,3 +1,36 @@
|
|||
2017-07-17 Claudiu Zissulescu <claziss@synopsys.com>
|
||||
Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* config/arc/arc-protos.h (arc_compute_function_type): Change prototype.
|
||||
(arc_return_address_register): New function.
|
||||
* config/arc/arc.c (arc_handle_fndecl_attribute): New function.
|
||||
(arc_handle_fndecl_attribute): Add naked attribute.
|
||||
(TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS): Define.
|
||||
(TARGET_WARN_FUNC_RETURN): Likewise.
|
||||
(arc_allocate_stack_slots_for_args): New function.
|
||||
(arc_warn_func_return): Likewise.
|
||||
(machine_function): Change type fn_type.
|
||||
(arc_compute_function_type): Consider new naked function type,
|
||||
change function return type.
|
||||
(arc_must_save_register): Adapt to handle new
|
||||
arc_compute_function_type's return type.
|
||||
(arc_expand_prologue): Likewise.
|
||||
(arc_expand_epilogue): Likewise.
|
||||
(arc_return_address_regs): Delete.
|
||||
(arc_return_address_register): New function.
|
||||
(arc_epilogue_uses): Use above function.
|
||||
* config/arc/arc.h (arc_return_address_regs): Delete prototype.
|
||||
(arc_function_type): Change encoding, add naked type.
|
||||
(ARC_INTERRUPT_P): Change to handle the new encoding.
|
||||
(ARC_FAST_INTERRUPT_P): Likewise.
|
||||
(ARC_NORMAL_P): Define.
|
||||
(ARC_NAKED_P): Likewise.
|
||||
(arc_compute_function_type): Delete prototype.
|
||||
* config/arc/arc.md (in_ret_delay_slot): Use
|
||||
arc_return_address_register function.
|
||||
(simple_return): Likewise.
|
||||
(p_return_i): Likewise.
|
||||
|
||||
2017-07-17 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR tree-optimization/81428
|
||||
|
|
|
@ -45,13 +45,10 @@ extern void arc_expand_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
|
|||
extern void arc_split_compare_and_swap (rtx *);
|
||||
extern void arc_expand_compare_and_swap (rtx *);
|
||||
extern bool compact_memory_operand_p (rtx, machine_mode, bool, bool);
|
||||
extern int arc_return_address_register (unsigned int);
|
||||
extern unsigned int arc_compute_function_type (struct function *);
|
||||
#endif /* RTX_CODE */
|
||||
|
||||
#ifdef TREE_CODE
|
||||
extern enum arc_function_type arc_compute_function_type (struct function *);
|
||||
#endif /* TREE_CODE */
|
||||
|
||||
|
||||
extern unsigned int arc_compute_frame_size (int);
|
||||
extern bool arc_ccfsm_branch_deleted_p (void);
|
||||
extern void arc_ccfsm_record_branch_deleted (void);
|
||||
|
|
|
@ -211,6 +211,7 @@ static int rgf_banked_register_count;
|
|||
static int get_arc_condition_code (rtx);
|
||||
|
||||
static tree arc_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree arc_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
|
||||
|
||||
/* Initialized arc_attribute_table to NULL since arc doesnot have any
|
||||
machine specific supported attributes. */
|
||||
|
@ -229,6 +230,9 @@ const struct attribute_spec arc_attribute_table[] =
|
|||
/* And these functions are always known to reside within the 21 bit
|
||||
addressing range of blcc. */
|
||||
{ "short_call", 0, 0, false, true, true, NULL, false },
|
||||
/* Function which are not having the prologue and epilogue generated
|
||||
by the compiler. */
|
||||
{ "naked", 0, 0, true, false, false, arc_handle_fndecl_attribute, false },
|
||||
{ NULL, 0, 0, false, false, false, NULL, false }
|
||||
};
|
||||
static int arc_comp_type_attributes (const_tree, const_tree);
|
||||
|
@ -512,6 +516,12 @@ static void arc_finalize_pic (void);
|
|||
#define TARGET_DIFFERENT_ADDR_DISPLACEMENT_P hook_bool_void_true
|
||||
#define TARGET_SPILL_CLASS arc_spill_class
|
||||
|
||||
#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS
|
||||
#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS arc_allocate_stack_slots_for_args
|
||||
|
||||
#undef TARGET_WARN_FUNC_RETURN
|
||||
#define TARGET_WARN_FUNC_RETURN arc_warn_func_return
|
||||
|
||||
#include "target-def.h"
|
||||
|
||||
#undef TARGET_ASM_ALIGNED_HI_OP
|
||||
|
@ -1855,6 +1865,42 @@ arc_handle_interrupt_attribute (tree *, tree name, tree args, int,
|
|||
return NULL_TREE;
|
||||
}
|
||||
|
||||
static tree
|
||||
arc_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
|
||||
int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
|
||||
{
|
||||
if (TREE_CODE (*node) != FUNCTION_DECL)
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute only applies to functions",
|
||||
name);
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Implement `TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS' */
|
||||
|
||||
static bool
|
||||
arc_allocate_stack_slots_for_args (void)
|
||||
{
|
||||
/* Naked functions should not allocate stack slots for arguments. */
|
||||
unsigned int fn_type = arc_compute_function_type (cfun);
|
||||
|
||||
return !ARC_NAKED_P(fn_type);
|
||||
}
|
||||
|
||||
/* Implement `TARGET_WARN_FUNC_RETURN'. */
|
||||
|
||||
static bool
|
||||
arc_warn_func_return (tree decl)
|
||||
{
|
||||
struct function *func = DECL_STRUCT_FUNCTION (decl);
|
||||
unsigned int fn_type = arc_compute_function_type (func);
|
||||
|
||||
return !ARC_NAKED_P (fn_type);
|
||||
}
|
||||
|
||||
/* Return zero if TYPE1 and TYPE are incompatible, one if they are compatible,
|
||||
and two if they are nearly compatible (which causes a warning to be
|
||||
generated). */
|
||||
|
@ -2358,7 +2404,7 @@ struct GTY (()) arc_frame_info
|
|||
|
||||
typedef struct GTY (()) machine_function
|
||||
{
|
||||
enum arc_function_type fn_type;
|
||||
unsigned int fn_type;
|
||||
struct arc_frame_info frame_info;
|
||||
/* To keep track of unalignment caused by short insns. */
|
||||
int unalign;
|
||||
|
@ -2376,43 +2422,40 @@ typedef struct GTY (()) machine_function
|
|||
The result is cached. To reset the cache at the end of a function,
|
||||
call with DECL = NULL_TREE. */
|
||||
|
||||
enum arc_function_type
|
||||
unsigned int
|
||||
arc_compute_function_type (struct function *fun)
|
||||
{
|
||||
tree decl = fun->decl;
|
||||
tree a;
|
||||
enum arc_function_type fn_type = fun->machine->fn_type;
|
||||
tree attr, decl = fun->decl;
|
||||
unsigned int fn_type = fun->machine->fn_type;
|
||||
|
||||
if (fn_type != ARC_FUNCTION_UNKNOWN)
|
||||
return fn_type;
|
||||
|
||||
/* Assume we have a normal function (not an interrupt handler). */
|
||||
fn_type = ARC_FUNCTION_NORMAL;
|
||||
/* Check if it is a naked function. */
|
||||
if (lookup_attribute ("naked", DECL_ATTRIBUTES (decl)) != NULL_TREE)
|
||||
fn_type |= ARC_FUNCTION_NAKED;
|
||||
else
|
||||
fn_type |= ARC_FUNCTION_NORMAL;
|
||||
|
||||
/* Now see if this is an interrupt handler. */
|
||||
for (a = DECL_ATTRIBUTES (decl);
|
||||
a;
|
||||
a = TREE_CHAIN (a))
|
||||
attr = lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl));
|
||||
if (attr != NULL_TREE)
|
||||
{
|
||||
tree name = TREE_PURPOSE (a), args = TREE_VALUE (a);
|
||||
tree value, args = TREE_VALUE (attr);
|
||||
|
||||
if (name == get_identifier ("interrupt")
|
||||
&& list_length (args) == 1
|
||||
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
|
||||
{
|
||||
tree value = TREE_VALUE (args);
|
||||
gcc_assert (list_length (args) == 1);
|
||||
value = TREE_VALUE (args);
|
||||
gcc_assert (TREE_CODE (value) == STRING_CST);
|
||||
|
||||
if (!strcmp (TREE_STRING_POINTER (value), "ilink1")
|
||||
|| !strcmp (TREE_STRING_POINTER (value), "ilink"))
|
||||
fn_type = ARC_FUNCTION_ILINK1;
|
||||
else if (!strcmp (TREE_STRING_POINTER (value), "ilink2"))
|
||||
fn_type = ARC_FUNCTION_ILINK2;
|
||||
else if (!strcmp (TREE_STRING_POINTER (value), "firq"))
|
||||
fn_type = ARC_FUNCTION_FIRQ;
|
||||
else
|
||||
gcc_unreachable ();
|
||||
break;
|
||||
}
|
||||
if (!strcmp (TREE_STRING_POINTER (value), "ilink1")
|
||||
|| !strcmp (TREE_STRING_POINTER (value), "ilink"))
|
||||
fn_type |= ARC_FUNCTION_ILINK1;
|
||||
else if (!strcmp (TREE_STRING_POINTER (value), "ilink2"))
|
||||
fn_type |= ARC_FUNCTION_ILINK2;
|
||||
else if (!strcmp (TREE_STRING_POINTER (value), "firq"))
|
||||
fn_type |= ARC_FUNCTION_FIRQ;
|
||||
else
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
return fun->machine->fn_type = fn_type;
|
||||
|
@ -2433,7 +2476,7 @@ arc_compute_function_type (struct function *fun)
|
|||
static bool
|
||||
arc_must_save_register (int regno, struct function *func)
|
||||
{
|
||||
enum arc_function_type fn_type = arc_compute_function_type (func);
|
||||
unsigned int fn_type = arc_compute_function_type (func);
|
||||
bool irq_auto_save_p = ((irq_ctrl_saved.irq_save_last_reg >= regno)
|
||||
&& ARC_AUTO_IRQ_P (fn_type));
|
||||
bool firq_auto_save_p = ARC_FAST_INTERRUPT_P (fn_type);
|
||||
|
@ -2878,7 +2921,11 @@ arc_expand_prologue (void)
|
|||
Change the stack layout so that we rather store a high register with the
|
||||
PRE_MODIFY, thus enabling more short insn generation.) */
|
||||
int first_offset = 0;
|
||||
enum arc_function_type fn_type = arc_compute_function_type (cfun);
|
||||
unsigned int fn_type = arc_compute_function_type (cfun);
|
||||
|
||||
/* Naked functions don't have prologue. */
|
||||
if (ARC_NAKED_P (fn_type))
|
||||
return;
|
||||
|
||||
size = ARC_STACK_ALIGN (size);
|
||||
|
||||
|
@ -2989,7 +3036,7 @@ void
|
|||
arc_expand_epilogue (int sibcall_p)
|
||||
{
|
||||
int size = get_frame_size ();
|
||||
enum arc_function_type fn_type = arc_compute_function_type (cfun);
|
||||
unsigned int fn_type = arc_compute_function_type (cfun);
|
||||
|
||||
size = ARC_STACK_ALIGN (size);
|
||||
size = (!cfun->machine->frame_info.initialized
|
||||
|
@ -3005,6 +3052,10 @@ arc_expand_epilogue (int sibcall_p)
|
|||
int millicode_p = cfun->machine->frame_info.millicode_end_reg > 0;
|
||||
rtx insn;
|
||||
|
||||
/* Naked functions don't have epilogue. */
|
||||
if (ARC_NAKED_P (fn_type))
|
||||
return;
|
||||
|
||||
size_to_deallocate = size;
|
||||
|
||||
frame_size = size - (pretend_size +
|
||||
|
@ -9788,37 +9839,60 @@ arc_can_follow_jump (const rtx_insn *follower, const rtx_insn *followee)
|
|||
return true;
|
||||
}
|
||||
|
||||
int arc_return_address_regs[5] =
|
||||
{0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM, ILINK1_REGNUM};
|
||||
/* Return the register number of the register holding the return address
|
||||
for a function of type TYPE. */
|
||||
|
||||
/* Implement EPILOGUE__USES.
|
||||
int
|
||||
arc_return_address_register (unsigned int fn_type)
|
||||
{
|
||||
int regno = 0;
|
||||
|
||||
if (ARC_INTERRUPT_P (fn_type))
|
||||
{
|
||||
if (((fn_type & ARC_FUNCTION_ILINK1) | ARC_FUNCTION_FIRQ) != 0)
|
||||
regno = ILINK1_REGNUM;
|
||||
else if ((fn_type & ARC_FUNCTION_ILINK2) != 0)
|
||||
regno = ILINK2_REGNUM;
|
||||
else
|
||||
gcc_unreachable ();
|
||||
}
|
||||
else if (ARC_NORMAL_P (fn_type) || ARC_NAKED_P (fn_type))
|
||||
regno = RETURN_ADDR_REGNUM;
|
||||
|
||||
gcc_assert (regno != 0);
|
||||
return regno;
|
||||
}
|
||||
|
||||
/* Implement EPILOGUE_USES.
|
||||
Return true if REGNO should be added to the deemed uses of the epilogue.
|
||||
|
||||
We use the return address
|
||||
arc_return_address_regs[arc_compute_function_type (cfun)]. But
|
||||
also, we have to make sure all the register restore instructions
|
||||
are known to be live in interrupt functions, plus the blink
|
||||
register if it is clobbered by the isr. */
|
||||
We have to make sure all the register restore instructions are
|
||||
known to be live in interrupt functions, plus the blink register if
|
||||
it is clobbered by the isr. */
|
||||
|
||||
bool
|
||||
arc_epilogue_uses (int regno)
|
||||
{
|
||||
unsigned int fn_type;
|
||||
|
||||
if (regno == arc_tp_regno)
|
||||
return true;
|
||||
|
||||
fn_type = arc_compute_function_type (cfun);
|
||||
if (reload_completed)
|
||||
{
|
||||
if (ARC_INTERRUPT_P (cfun->machine->fn_type))
|
||||
{
|
||||
if (!fixed_regs[regno])
|
||||
return true;
|
||||
return ((regno == arc_return_address_regs[cfun->machine->fn_type])
|
||||
return ((regno == arc_return_address_register (fn_type))
|
||||
|| (regno == RETURN_ADDR_REGNUM));
|
||||
}
|
||||
else
|
||||
return regno == RETURN_ADDR_REGNUM;
|
||||
}
|
||||
else
|
||||
return regno == arc_return_address_regs[arc_compute_function_type (cfun)];
|
||||
return regno == arc_return_address_register (fn_type);
|
||||
}
|
||||
|
||||
/* Helper for EH_USES macro. */
|
||||
|
|
|
@ -1370,10 +1370,6 @@ do { \
|
|||
#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGNMENT) \
|
||||
arc_asm_output_aligned_decl_local (STREAM, DECL, NAME, SIZE, ALIGNMENT, 0)
|
||||
|
||||
/* To translate the return value of arc_function_type into a register number
|
||||
to jump through for function return. */
|
||||
extern int arc_return_address_regs[5];
|
||||
|
||||
/* Debugging information. */
|
||||
|
||||
/* Generate DBX and DWARF debugging information. */
|
||||
|
@ -1506,22 +1502,38 @@ extern struct rtx_def *arc_compare_op0, *arc_compare_op1;
|
|||
|
||||
/* ARC function types. */
|
||||
enum arc_function_type {
|
||||
ARC_FUNCTION_UNKNOWN, ARC_FUNCTION_NORMAL,
|
||||
/* No function should have the unknown type. This value is used to
|
||||
indicate the that function type has not yet been computed. */
|
||||
ARC_FUNCTION_UNKNOWN = 0,
|
||||
|
||||
/* The normal function type indicates that the function has the
|
||||
standard prologue and epilogue. */
|
||||
ARC_FUNCTION_NORMAL = 1 << 0,
|
||||
/* These are interrupt handlers. The name corresponds to the register
|
||||
name that contains the return address. */
|
||||
ARC_FUNCTION_ILINK1, ARC_FUNCTION_ILINK2,
|
||||
ARC_FUNCTION_ILINK1 = 1 << 1,
|
||||
ARC_FUNCTION_ILINK2 = 1 << 2,
|
||||
/* Fast interrupt is only available on ARCv2 processors. */
|
||||
ARC_FUNCTION_FIRQ
|
||||
ARC_FUNCTION_FIRQ = 1 << 3,
|
||||
/* The naked function type indicates that the function does not have
|
||||
prologue or epilogue, and that no stack frame is available. */
|
||||
ARC_FUNCTION_NAKED = 1 << 4
|
||||
};
|
||||
#define ARC_INTERRUPT_P(TYPE) \
|
||||
(((TYPE) == ARC_FUNCTION_ILINK1) || ((TYPE) == ARC_FUNCTION_ILINK2) \
|
||||
|| ((TYPE) == ARC_FUNCTION_FIRQ))
|
||||
|
||||
#define ARC_FAST_INTERRUPT_P(TYPE) ((TYPE) == ARC_FUNCTION_FIRQ)
|
||||
/* Check if a function is an interrupt function. */
|
||||
#define ARC_INTERRUPT_P(TYPE) \
|
||||
(((TYPE) & (ARC_FUNCTION_ILINK1 | ARC_FUNCTION_ILINK2 \
|
||||
| ARC_FUNCTION_FIRQ)) != 0)
|
||||
|
||||
/* Compute the type of a function from its DECL. Needed for EPILOGUE_USES. */
|
||||
struct function;
|
||||
extern enum arc_function_type arc_compute_function_type (struct function *);
|
||||
/* Check if a function is a fast interrupt function. */
|
||||
#define ARC_FAST_INTERRUPT_P(TYPE) (((TYPE) & ARC_FUNCTION_FIRQ) != 0)
|
||||
|
||||
/* Check if a function is normal, that is, has standard prologue and
|
||||
epilogue. */
|
||||
#define ARC_NORMAL_P(TYPE) (((TYPE) & ARC_FUNCTION_NORMAL) != 0)
|
||||
|
||||
/* Check if a function is naked. */
|
||||
#define ARC_NAKED_P(TYPE) (((TYPE) & ARC_FUNCTION_NAKED) != 0)
|
||||
|
||||
/* Called by crtstuff.c to make calls to function FUNCTION that are defined in
|
||||
SECTION_OP, and then to switch back to text section. */
|
||||
|
|
|
@ -505,8 +505,8 @@
|
|||
(cond [(eq_attr "in_delay_slot" "false")
|
||||
(const_string "no")
|
||||
(match_test "regno_clobbered_p
|
||||
(arc_return_address_regs
|
||||
[arc_compute_function_type (cfun)],
|
||||
(arc_return_address_register
|
||||
(arc_compute_function_type (cfun)),
|
||||
insn, SImode, 1)")
|
||||
(const_string "no")]
|
||||
(const_string "yes")))
|
||||
|
@ -4859,7 +4859,8 @@
|
|||
{
|
||||
rtx reg
|
||||
= gen_rtx_REG (Pmode,
|
||||
arc_return_address_regs[arc_compute_function_type (cfun)]);
|
||||
arc_return_address_register (arc_compute_function_type
|
||||
(cfun)));
|
||||
|
||||
if (TARGET_V2
|
||||
&& ARC_INTERRUPT_P (arc_compute_function_type (cfun)))
|
||||
|
@ -4908,7 +4909,8 @@
|
|||
xop[0] = operands[0];
|
||||
xop[1]
|
||||
= gen_rtx_REG (Pmode,
|
||||
arc_return_address_regs[arc_compute_function_type (cfun)]);
|
||||
arc_return_address_register (arc_compute_function_type
|
||||
(cfun)));
|
||||
|
||||
if (TARGET_PAD_RETURN)
|
||||
arc_pad_return ();
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2017-07-17 Claudiu Zissulescu <claziss@synopsys.com>
|
||||
Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* gcc.target/arc/naked-1.c: New file.
|
||||
* gcc.target/arc/naked-2.c: Likewise.
|
||||
|
||||
2017-07-17 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR tree-optimization/81428
|
||||
|
|
18
gcc/testsuite/gcc.target/arc/naked-1.c
Normal file
18
gcc/testsuite/gcc.target/arc/naked-1.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O0" } */
|
||||
/* Check that naked functions don't place arguments on the stack at
|
||||
optimisation level '-O0'. */
|
||||
extern void bar (int);
|
||||
|
||||
void __attribute__((naked))
|
||||
foo (int n, int m)
|
||||
{
|
||||
bar (n + m);
|
||||
}
|
||||
/* { dg-final { scan-assembler "\tbl @bar" } } */
|
||||
|
||||
/* Look for things that would appear in a non-naked function, but which
|
||||
should not appear in a naked function. */
|
||||
/* { dg-final { scan-assembler-not "\tj.* \\\[blink\\\]" } } */
|
||||
/* { dg-final { scan-assembler-not "\tst.* " } } */
|
||||
/* { dg-final { scan-assembler-not "\tmov fp,sp" } } */
|
26
gcc/testsuite/gcc.target/arc/naked-2.c
Normal file
26
gcc/testsuite/gcc.target/arc/naked-2.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O0" } */
|
||||
/* Check that naked functions don't place arguments on the stack at
|
||||
optimisation level '-O0'. */
|
||||
|
||||
#if defined(__HS__) || defined(__EM__)
|
||||
# define ILINK "ilink"
|
||||
#else
|
||||
# define ILINK "ilink1"
|
||||
#endif
|
||||
|
||||
extern void bar (int);
|
||||
|
||||
void __attribute__((naked, interrupt(ILINK)))
|
||||
foo (int n, int m)
|
||||
{
|
||||
bar (n + m);
|
||||
}
|
||||
/* { dg-final { scan-assembler "\tbl @bar" } } */
|
||||
|
||||
/* Look for things that would appear in a non-naked function, but which
|
||||
should not appear in a naked function. */
|
||||
/* { dg-final { scan-assembler-not "\trtie" } } */
|
||||
/* { dg-final { scan-assembler-not "j.*\[ilink1\]" } } */
|
||||
/* { dg-final { scan-assembler-not "\tst.* " } } */
|
||||
/* { dg-final { scan-assembler-not "\tmov fp,sp" } } */
|
Loading…
Add table
Reference in a new issue