[ARC] Automatic context save/restore for regular interrupts.
The AUX_IRQ_CTRL register controls the behavior of automated register save and restore or prologue and epilogue sequences during a non-fast interrupt entry and exit, and context save and restore instructions. A user passes to the compiler the configuration of the AUX_IRQ_CTRL register via mirq-ctrl-saved option. This option, specifies gneral-purposes registers that the processor saves/restores on interrupt entry and exit, and it is only valid for ARC EM and ARC HS cores. gcc/ 2017-05-09 Claudiu Zissulescu <claziss@synopsys.com> * config/arc/arc.c (irq_ctrl_saved): New variable. (ARC_AUTOBLINK_IRQ_P): Define. (ARC_AUTOFP_IRQ_P): Likewise. (ARC_AUTO_IRQ_P): Likewise. (irq_range): New function. (arc_must_save_register): Likewise. (arc_must_save_return_addr): Likewise. (arc_dwarf_emit_irq_save_regs): Likewise. (arc_override_options): Handle deferred options. (MUST_SAVE_REGISTER): Deleted, replaced by arc_must_save_register. (MUST_SAVE_RETURN_ADDR): Deleted, replaced by arc_must_save_return_addr. (arc_compute_frame_size): Handle automated save and restore of registers. (arc_expand_prologue): Likewise. (arc_expand_epilogue): Likewise. * config/arc/arc.md (stack_irq_dwarf): New unspec instruction. * config/arc/arc.opt (mirq-ctrl-saved): New option. * doc/invoke.texi (mirq-ctrl-saved): Document option. testsuite/ 2017-05-09 Claudiu Zissulescu <claziss@synopsys.com> * gcc.target/arc/interrupt-5.c: Newfile. * gcc.target/arc/interrupt-6.c: Likewise. * gcc.target/arc/interrupt-7.c: Likewise. * gcc.target/arc/interrupt-8.c: Likewise. * gcc.target/arc/interrupt-9.c: Likewise. From-SVN: r247795
This commit is contained in:
parent
019bd543a9
commit
4145318390
11 changed files with 451 additions and 32 deletions
22
ChangeLog
22
ChangeLog
|
@ -1,3 +1,25 @@
|
|||
2017-05-09 Claudiu Zissulescu <claziss@synopsys.com>
|
||||
|
||||
* config/arc/arc.c (irq_ctrl_saved): New variable.
|
||||
(ARC_AUTOBLINK_IRQ_P): Define.
|
||||
(ARC_AUTOFP_IRQ_P): Likewise.
|
||||
(ARC_AUTO_IRQ_P): Likewise.
|
||||
(irq_range): New function.
|
||||
(arc_must_save_register): Likewise.
|
||||
(arc_must_save_return_addr): Likewise.
|
||||
(arc_dwarf_emit_irq_save_regs): Likewise.
|
||||
(arc_override_options): Handle deferred options.
|
||||
(MUST_SAVE_REGISTER): Deleted, replaced by arc_must_save_register.
|
||||
(MUST_SAVE_RETURN_ADDR): Deleted, replaced by
|
||||
arc_must_save_return_addr.
|
||||
(arc_compute_frame_size): Handle automated save and restore of
|
||||
registers.
|
||||
(arc_expand_prologue): Likewise.
|
||||
(arc_expand_epilogue): Likewise.
|
||||
* config/arc/arc.md (stack_irq_dwarf): New unspec instruction.
|
||||
* config/arc/arc.opt (mirq-ctrl-saved): New option.
|
||||
* doc/invoke.texi (mirq-ctrl-saved): Document option.
|
||||
|
||||
2017-04-19 Thomas Koenig <tkoenig@gcc.gnu.org>
|
||||
Tobias Burnus <tobias.burnus@physik.fu-berlin.de>
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "builtins.h"
|
||||
#include "rtl-iter.h"
|
||||
#include "alias.h"
|
||||
#include "opts.h"
|
||||
|
||||
/* Which cpu we're compiling for (ARC600, ARC601, ARC700). */
|
||||
static char arc_cpu_name[10] = "";
|
||||
|
@ -111,6 +112,29 @@ struct GTY (()) arc_ccfsm
|
|||
int target_label;
|
||||
};
|
||||
|
||||
/* Status of the IRQ_CTRL_AUX register. */
|
||||
typedef struct irq_ctrl_saved_t
|
||||
{
|
||||
/* Last register number used by IRQ_CTRL_SAVED aux_reg. */
|
||||
short irq_save_last_reg;
|
||||
/* True if BLINK is automatically saved. */
|
||||
bool irq_save_blink;
|
||||
/* True if LPCOUNT is automatically saved. */
|
||||
bool irq_save_lpcount;
|
||||
} irq_ctrl_saved_t;
|
||||
static irq_ctrl_saved_t irq_ctrl_saved;
|
||||
|
||||
#define ARC_AUTOBLINK_IRQ_P(FNTYPE) \
|
||||
(ARC_INTERRUPT_P (FNTYPE) && irq_ctrl_saved.irq_save_blink)
|
||||
|
||||
#define ARC_AUTOFP_IRQ_P(FNTYPE) \
|
||||
(ARC_INTERRUPT_P (FNTYPE) && (irq_ctrl_saved.irq_save_last_reg > 26))
|
||||
|
||||
#define ARC_AUTO_IRQ_P(FNTYPE) \
|
||||
(ARC_INTERRUPT_P (FNTYPE) \
|
||||
&& (irq_ctrl_saved.irq_save_blink \
|
||||
|| (irq_ctrl_saved.irq_save_last_reg >= 0)))
|
||||
|
||||
#define arc_ccfsm_current cfun->machine->ccfsm_current
|
||||
|
||||
#define ARC_CCFSM_BRANCH_DELETED_P(STATE) \
|
||||
|
@ -806,11 +830,110 @@ arc_init (void)
|
|||
}
|
||||
}
|
||||
|
||||
/* Parse -mirq-ctrl-saved=RegisterRange, blink, lp_copunt. The
|
||||
register range is specified as two registers separated by a dash.
|
||||
It always starts with r0, and its upper limit is fp register.
|
||||
blink and lp_count registers are optional. */
|
||||
|
||||
static void
|
||||
irq_range (const char *cstr)
|
||||
{
|
||||
int i, first, last, blink, lpcount, xreg;
|
||||
char *str, *dash, *comma;
|
||||
|
||||
i = strlen (cstr);
|
||||
str = (char *) alloca (i + 1);
|
||||
memcpy (str, cstr, i + 1);
|
||||
blink = -1;
|
||||
lpcount = -1;
|
||||
|
||||
dash = strchr (str, '-');
|
||||
if (!dash)
|
||||
{
|
||||
warning (0, "value of -mirq-ctrl-saved must have form R0-REGx");
|
||||
return;
|
||||
}
|
||||
*dash = '\0';
|
||||
|
||||
comma = strchr (dash + 1, ',');
|
||||
if (comma)
|
||||
*comma = '\0';
|
||||
|
||||
first = decode_reg_name (str);
|
||||
if (first != 0)
|
||||
{
|
||||
warning (0, "first register must be R0");
|
||||
return;
|
||||
}
|
||||
|
||||
/* At this moment we do not have the register names initialized
|
||||
accordingly. */
|
||||
if (!strcmp (dash + 1, "ilink"))
|
||||
last = 29;
|
||||
else
|
||||
last = decode_reg_name (dash + 1);
|
||||
|
||||
if (last < 0)
|
||||
{
|
||||
warning (0, "unknown register name: %s", dash + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(last & 0x01))
|
||||
{
|
||||
warning (0, "last register name %s must be an odd register", dash + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
*dash = '-';
|
||||
|
||||
if (first > last)
|
||||
{
|
||||
warning (0, "%s-%s is an empty range", str, dash + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
while (comma)
|
||||
{
|
||||
*comma = ',';
|
||||
str = comma + 1;
|
||||
|
||||
comma = strchr (str, ',');
|
||||
if (comma)
|
||||
*comma = '\0';
|
||||
|
||||
xreg = decode_reg_name (str);
|
||||
switch (xreg)
|
||||
{
|
||||
case 31:
|
||||
blink = 31;
|
||||
break;
|
||||
|
||||
case 60:
|
||||
lpcount = 60;
|
||||
break;
|
||||
|
||||
default:
|
||||
warning (0, "unknown register name: %s", str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
irq_ctrl_saved.irq_save_last_reg = last;
|
||||
irq_ctrl_saved.irq_save_blink = (blink == 31) || (last == 31);
|
||||
irq_ctrl_saved.irq_save_lpcount = (lpcount == 60);
|
||||
}
|
||||
|
||||
/* Check ARC options, generate derived target attributes. */
|
||||
|
||||
static void
|
||||
arc_override_options (void)
|
||||
{
|
||||
unsigned int i;
|
||||
cl_deferred_option *opt;
|
||||
vec<cl_deferred_option> *vopt
|
||||
= (vec<cl_deferred_option> *) arc_deferred_options;
|
||||
|
||||
if (arc_cpu == PROCESSOR_NONE)
|
||||
arc_cpu = TARGET_CPU_DEFAULT;
|
||||
|
||||
|
@ -839,6 +962,28 @@ arc_override_options (void)
|
|||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
irq_ctrl_saved.irq_save_last_reg = -1;
|
||||
irq_ctrl_saved.irq_save_blink = false;
|
||||
irq_ctrl_saved.irq_save_lpcount = false;
|
||||
|
||||
/* Handle the deferred options. */
|
||||
if (vopt)
|
||||
FOR_EACH_VEC_ELT (*vopt, i, opt)
|
||||
{
|
||||
switch (opt->opt_index)
|
||||
{
|
||||
case OPT_mirq_ctrl_saved_:
|
||||
if (TARGET_V2)
|
||||
irq_range (opt->arg);
|
||||
else
|
||||
warning (0, "option -mirq-ctrl-saved valid only for ARC v2 processors");
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
/* Set cpu flags accordingly to architecture/selected cpu. The cpu
|
||||
specific flags are set in arc-common.c. The architecture forces
|
||||
the default hardware configurations in, regardless what command
|
||||
|
@ -2235,14 +2380,52 @@ arc_compute_function_type (struct function *fun)
|
|||
FIXME: This will not be needed if we used some arbitrary register
|
||||
instead of r26.
|
||||
*/
|
||||
#define MUST_SAVE_REGISTER(regno, interrupt_p) \
|
||||
(((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \
|
||||
&& (df_regs_ever_live_p (regno) && (!call_used_regs[regno] || interrupt_p))) \
|
||||
|| (flag_pic && crtl->uses_pic_offset_table \
|
||||
&& regno == PIC_OFFSET_TABLE_REGNUM) )
|
||||
|
||||
#define MUST_SAVE_RETURN_ADDR \
|
||||
(cfun->machine->frame_info.save_return_addr)
|
||||
static bool
|
||||
arc_must_save_register (int regno, struct function *func)
|
||||
{
|
||||
enum arc_function_type fn_type = arc_compute_function_type (func);
|
||||
bool irq_auto_save_p = ((irq_ctrl_saved.irq_save_last_reg >= regno)
|
||||
&& ARC_INTERRUPT_P (fn_type));
|
||||
|
||||
if ((regno) != RETURN_ADDR_REGNUM
|
||||
&& (regno) != FRAME_POINTER_REGNUM
|
||||
&& df_regs_ever_live_p (regno)
|
||||
&& (!call_used_regs[regno]
|
||||
|| ARC_INTERRUPT_P (fn_type))
|
||||
/* Do not emit code for auto saved regs. */
|
||||
&& !irq_auto_save_p)
|
||||
return true;
|
||||
|
||||
if (flag_pic && crtl->uses_pic_offset_table
|
||||
&& regno == PIC_OFFSET_TABLE_REGNUM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if the return address must be saved in the current function,
|
||||
otherwise return false. */
|
||||
|
||||
static bool
|
||||
arc_must_save_return_addr (struct function *func)
|
||||
{
|
||||
if (func->machine->frame_info.save_return_addr)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Helper function to wrap FRAME_POINTER_NEEDED. We do this as
|
||||
FRAME_POINTER_NEEDED will not be true until the IRA (Integrated
|
||||
Register Allocator) pass, while we want to get the frame size
|
||||
correct earlier than the IRA pass. */
|
||||
static bool
|
||||
arc_frame_pointer_needed (void)
|
||||
{
|
||||
return (frame_pointer_needed);
|
||||
}
|
||||
|
||||
|
||||
/* Return non-zero if there are registers to be saved or loaded using
|
||||
millicode thunks. We can only use consecutive sequences starting
|
||||
|
@ -2286,8 +2469,6 @@ arc_compute_frame_size (int size) /* size = # of var. bytes allocated. */
|
|||
unsigned int total_size, var_size, args_size, pretend_size, extra_size;
|
||||
unsigned int reg_size, reg_offset;
|
||||
unsigned int gmask;
|
||||
enum arc_function_type fn_type;
|
||||
int interrupt_p;
|
||||
struct arc_frame_info *frame_info = &cfun->machine->frame_info;
|
||||
|
||||
size = ARC_STACK_ALIGN (size);
|
||||
|
@ -2306,15 +2487,13 @@ arc_compute_frame_size (int size) /* size = # of var. bytes allocated. */
|
|||
|
||||
reg_size = 0;
|
||||
gmask = 0;
|
||||
fn_type = arc_compute_function_type (cfun);
|
||||
interrupt_p = ARC_INTERRUPT_P (fn_type);
|
||||
|
||||
for (regno = 0; regno <= 31; regno++)
|
||||
{
|
||||
if (MUST_SAVE_REGISTER (regno, interrupt_p))
|
||||
if (arc_must_save_register (regno, cfun))
|
||||
{
|
||||
reg_size += UNITS_PER_WORD;
|
||||
gmask |= 1 << regno;
|
||||
gmask |= 1L << regno;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2330,9 +2509,9 @@ arc_compute_frame_size (int size) /* size = # of var. bytes allocated. */
|
|||
}
|
||||
|
||||
extra_size = 0;
|
||||
if (MUST_SAVE_RETURN_ADDR)
|
||||
if (arc_must_save_return_addr (cfun))
|
||||
extra_size = 4;
|
||||
if (frame_pointer_needed)
|
||||
if (arc_frame_pointer_needed ())
|
||||
extra_size += 4;
|
||||
|
||||
/* 5) Space for variable arguments passed in registers */
|
||||
|
@ -2357,7 +2536,7 @@ arc_compute_frame_size (int size) /* size = # of var. bytes allocated. */
|
|||
Frame: pretend_size <blink> reg_size <fp> var_size args_size <--sp
|
||||
*/
|
||||
reg_offset = (total_size - (pretend_size + reg_size + extra_size)
|
||||
+ (frame_pointer_needed ? 4 : 0));
|
||||
+ (arc_frame_pointer_needed () ? 4 : 0));
|
||||
|
||||
/* Save computed information. */
|
||||
frame_info->total_size = total_size;
|
||||
|
@ -2548,6 +2727,77 @@ arc_save_restore (rtx base_reg,
|
|||
int arc_return_address_regs[4]
|
||||
= {0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM};
|
||||
|
||||
|
||||
/* Build dwarf information when the context is saved via AUX_IRQ_CTRL
|
||||
mechanism. */
|
||||
|
||||
static void
|
||||
arc_dwarf_emit_irq_save_regs (void)
|
||||
{
|
||||
rtx tmp, par, insn, reg;
|
||||
int i, offset, j;
|
||||
|
||||
par = gen_rtx_SEQUENCE (VOIDmode,
|
||||
rtvec_alloc (irq_ctrl_saved.irq_save_last_reg + 1
|
||||
+ irq_ctrl_saved.irq_save_blink
|
||||
+ irq_ctrl_saved.irq_save_lpcount
|
||||
+ 1));
|
||||
|
||||
/* Build the stack adjustment note for unwind info. */
|
||||
j = 0;
|
||||
offset = UNITS_PER_WORD * (irq_ctrl_saved.irq_save_last_reg + 1
|
||||
+ irq_ctrl_saved.irq_save_blink
|
||||
+ irq_ctrl_saved.irq_save_lpcount);
|
||||
tmp = plus_constant (Pmode, stack_pointer_rtx, -1 * offset);
|
||||
tmp = gen_rtx_SET (stack_pointer_rtx, tmp);
|
||||
RTX_FRAME_RELATED_P (tmp) = 1;
|
||||
XVECEXP (par, 0, j++) = tmp;
|
||||
|
||||
offset -= UNITS_PER_WORD;
|
||||
|
||||
/* 1st goes LP_COUNT. */
|
||||
if (irq_ctrl_saved.irq_save_lpcount)
|
||||
{
|
||||
reg = gen_rtx_REG (SImode, 60);
|
||||
tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
|
||||
tmp = gen_frame_mem (SImode, tmp);
|
||||
tmp = gen_rtx_SET (tmp, reg);
|
||||
RTX_FRAME_RELATED_P (tmp) = 1;
|
||||
XVECEXP (par, 0, j++) = tmp;
|
||||
offset -= UNITS_PER_WORD;
|
||||
}
|
||||
|
||||
/* 2nd goes BLINK. */
|
||||
if (irq_ctrl_saved.irq_save_blink)
|
||||
{
|
||||
reg = gen_rtx_REG (SImode, 31);
|
||||
tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
|
||||
tmp = gen_frame_mem (SImode, tmp);
|
||||
tmp = gen_rtx_SET (tmp, reg);
|
||||
RTX_FRAME_RELATED_P (tmp) = 1;
|
||||
XVECEXP (par, 0, j++) = tmp;
|
||||
offset -= UNITS_PER_WORD;
|
||||
}
|
||||
|
||||
/* Build the parallel of the remaining registers recorded as saved
|
||||
for unwind. */
|
||||
for (i = irq_ctrl_saved.irq_save_last_reg; i >= 0; i--)
|
||||
{
|
||||
reg = gen_rtx_REG (SImode, i);
|
||||
tmp = plus_constant (Pmode, stack_pointer_rtx, offset);
|
||||
tmp = gen_frame_mem (SImode, tmp);
|
||||
tmp = gen_rtx_SET (tmp, reg);
|
||||
RTX_FRAME_RELATED_P (tmp) = 1;
|
||||
XVECEXP (par, 0, j++) = tmp;
|
||||
offset -= UNITS_PER_WORD;
|
||||
}
|
||||
|
||||
/* Dummy insn used to anchor the dwarf info. */
|
||||
insn = emit_insn (gen_stack_irq_dwarf());
|
||||
add_reg_note (insn, REG_FRAME_RELATED_EXPR, par);
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
|
||||
/* Set up the stack and frame pointer (if desired) for the function. */
|
||||
|
||||
void
|
||||
|
@ -2561,6 +2811,7 @@ 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);
|
||||
|
||||
size = ARC_STACK_ALIGN (size);
|
||||
|
||||
|
@ -2588,16 +2839,25 @@ arc_expand_prologue (void)
|
|||
frame_size_to_allocate -= cfun->machine->frame_info.pretend_size;
|
||||
}
|
||||
|
||||
/* IRQ using automatic save mechanism will save the register before
|
||||
anything we do. */
|
||||
if (ARC_AUTO_IRQ_P (fn_type))
|
||||
{
|
||||
arc_dwarf_emit_irq_save_regs ();
|
||||
}
|
||||
|
||||
/* The home-grown ABI says link register is saved first. */
|
||||
if (MUST_SAVE_RETURN_ADDR)
|
||||
if (arc_must_save_return_addr (cfun)
|
||||
&& !ARC_AUTOBLINK_IRQ_P (fn_type))
|
||||
{
|
||||
rtx ra = gen_rtx_REG (SImode, RETURN_ADDR_REGNUM);
|
||||
rtx mem = gen_frame_mem (Pmode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx));
|
||||
rtx mem = gen_frame_mem (Pmode,
|
||||
gen_rtx_PRE_DEC (Pmode,
|
||||
stack_pointer_rtx));
|
||||
|
||||
frame_move_inc (mem, ra, stack_pointer_rtx, 0);
|
||||
frame_size_to_allocate -= UNITS_PER_WORD;
|
||||
|
||||
} /* MUST_SAVE_RETURN_ADDR */
|
||||
}
|
||||
|
||||
/* Save any needed call-saved regs (and call-used if this is an
|
||||
interrupt handler) for ARCompact ISA. */
|
||||
|
@ -2609,9 +2869,10 @@ arc_expand_prologue (void)
|
|||
frame_size_to_allocate -= cfun->machine->frame_info.reg_size;
|
||||
}
|
||||
|
||||
|
||||
/* Save frame pointer if needed. */
|
||||
if (frame_pointer_needed)
|
||||
/* Save frame pointer if needed. First save the FP on stack, if not
|
||||
autosaved. */
|
||||
if (arc_frame_pointer_needed ()
|
||||
&& !ARC_AUTOFP_IRQ_P (fn_type))
|
||||
{
|
||||
rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
|
||||
GEN_INT (-UNITS_PER_WORD + first_offset));
|
||||
|
@ -2621,6 +2882,11 @@ arc_expand_prologue (void)
|
|||
frame_move_inc (mem, frame_pointer_rtx, stack_pointer_rtx, 0);
|
||||
frame_size_to_allocate -= UNITS_PER_WORD;
|
||||
first_offset = 0;
|
||||
}
|
||||
|
||||
/* Emit mov fp,sp. */
|
||||
if (arc_frame_pointer_needed ())
|
||||
{
|
||||
frame_move (frame_pointer_rtx, stack_pointer_rtx);
|
||||
}
|
||||
|
||||
|
@ -2675,13 +2941,13 @@ arc_expand_epilogue (int sibcall_p)
|
|||
sp, but don't restore sp if we don't have to. */
|
||||
|
||||
if (!can_trust_sp_p)
|
||||
gcc_assert (frame_pointer_needed);
|
||||
gcc_assert (arc_frame_pointer_needed ());
|
||||
|
||||
/* Restore stack pointer to the beginning of saved register area for
|
||||
ARCompact ISA. */
|
||||
if (frame_size)
|
||||
{
|
||||
if (frame_pointer_needed)
|
||||
if (arc_frame_pointer_needed ())
|
||||
frame_move (stack_pointer_rtx, frame_pointer_rtx);
|
||||
else
|
||||
first_offset = frame_size;
|
||||
|
@ -2692,7 +2958,8 @@ arc_expand_epilogue (int sibcall_p)
|
|||
|
||||
|
||||
/* Restore any saved registers. */
|
||||
if (frame_pointer_needed)
|
||||
if (arc_frame_pointer_needed ()
|
||||
&& !ARC_AUTOFP_IRQ_P (fn_type))
|
||||
{
|
||||
rtx addr = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
|
||||
|
||||
|
@ -2730,14 +2997,15 @@ arc_expand_epilogue (int sibcall_p)
|
|||
: satisfies_constraint_C2a (GEN_INT (first_offset))))
|
||||
/* Also do this if we have both gprs and return
|
||||
address to restore, and they both would need a LIMM. */
|
||||
|| (MUST_SAVE_RETURN_ADDR
|
||||
&& !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2)
|
||||
&& cfun->machine->frame_info.gmask))
|
||||
|| (arc_must_save_return_addr (cfun)
|
||||
&& !SMALL_INT ((cfun->machine->frame_info.reg_size + first_offset) >> 2)
|
||||
&& cfun->machine->frame_info.gmask))
|
||||
{
|
||||
frame_stack_add (first_offset);
|
||||
first_offset = 0;
|
||||
}
|
||||
if (MUST_SAVE_RETURN_ADDR)
|
||||
if (arc_must_save_return_addr (cfun)
|
||||
&& !ARC_AUTOBLINK_IRQ_P (fn_type))
|
||||
{
|
||||
rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
|
||||
int ra_offs = cfun->machine->frame_info.reg_size + first_offset;
|
||||
|
@ -2802,7 +3070,6 @@ arc_expand_epilogue (int sibcall_p)
|
|||
& ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), 1, &first_offset);
|
||||
}
|
||||
|
||||
|
||||
/* The rest of this function does the following:
|
||||
ARCompact : handle epilogue_delay, restore sp (phase-2), return
|
||||
*/
|
||||
|
|
|
@ -6241,6 +6241,14 @@
|
|||
[(set (zero_extract:SI (match_dup 3) (match_dup 1) (match_dup 2))
|
||||
(zero_extract:SI (match_dup 0) (match_dup 1) (match_dup 2)))])
|
||||
|
||||
;; Dummy pattern used as a place holder for automatically saved
|
||||
;; registers.
|
||||
(define_insn "stack_irq_dwarf"
|
||||
[(unspec_volatile [(const_int 1)] VUNSPEC_ARC_STACK_IRQ)]
|
||||
""
|
||||
""
|
||||
[(set_attr "length" "0")])
|
||||
|
||||
;; include the arc-FPX instructions
|
||||
(include "fpx.md")
|
||||
|
||||
|
|
|
@ -486,3 +486,7 @@ Enable use of NPS400 xld/xst extension.
|
|||
munaligned-access
|
||||
Target Report Var(unaligned_access) Init(UNALIGNED_ACCESS_DEFAULT)
|
||||
Enable unaligned word and halfword accesses to packed data.
|
||||
|
||||
mirq-ctrl-saved=
|
||||
Target RejectNegative Joined Var(arc_deferred_options) Defer
|
||||
Specifies the registers that the processor saves on an interrupt entry and exit.
|
||||
|
|
|
@ -606,7 +606,7 @@ Objective-C and Objective-C++ Dialects}.
|
|||
-mnorm -mspfp -mspfp-compact -mspfp-fast -msimd -msoft-float -mswap @gol
|
||||
-mcrc -mdsp-packa -mdvbf -mlock -mmac-d16 -mmac-24 -mrtsc -mswape @gol
|
||||
-mtelephony -mxy -misize -mannotate-align -marclinux -marclinux_prof @gol
|
||||
-mlong-calls -mmedium-calls -msdata @gol
|
||||
-mlong-calls -mmedium-calls -msdata -mirq-ctrl-saved @gol
|
||||
-mvolatile-cache -mtp-regno=@var{regno} @gol
|
||||
-malign-call -mauto-modify-reg -mbbit-peephole -mno-brcc @gol
|
||||
-mcase-vector-pcrel -mcompact-casesi -mno-cond-exec -mearly-cbranchsi @gol
|
||||
|
@ -14547,6 +14547,15 @@ hardware extensions. Not available for ARC EM@.
|
|||
|
||||
@end table
|
||||
|
||||
@item -mirq-ctrl-saved=@var{register-range}, @var{blink}, @var{lp_count}
|
||||
@opindex mirq-ctrl-saved
|
||||
Specifies general-purposes registers that the processor automatically
|
||||
saves/restores on interrupt entry and exit. @var{register-range} is
|
||||
specified as two registers separated by a dash. The register range
|
||||
always starts with @code{r0}, the upper limit is @code{fp} register.
|
||||
@var{blink} and @var{lp_count} are optional. This option is only
|
||||
valid for ARC EM and ARC HS cores.
|
||||
|
||||
@end table
|
||||
|
||||
The following options are passed through to the assembler, and also
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2017-05-09 Claudiu Zissulescu <claziss@synopsys.com>
|
||||
|
||||
* gcc.target/arc/interrupt-5.c: Newfile.
|
||||
* gcc.target/arc/interrupt-6.c: Likewise.
|
||||
* gcc.target/arc/interrupt-7.c: Likewise.
|
||||
* gcc.target/arc/interrupt-8.c: Likewise.
|
||||
* gcc.target/arc/interrupt-9.c: Likewise.
|
||||
|
||||
2017-05-09 Richard Biener <rguenther@suse.de>
|
||||
|
||||
* gcc.dg/vect/vect-44.c: Add --param vect-max-peeling-for-alignment=0
|
||||
|
|
19
gcc/testsuite/gcc.target/arc/interrupt-5.c
Normal file
19
gcc/testsuite/gcc.target/arc/interrupt-5.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
|
||||
/* { dg-options "-O2 -mirq-ctrl-saved=r0-r3,blink" } */
|
||||
|
||||
/* Check if the registers R0-R3,blink are automatically saved. */
|
||||
|
||||
extern int bar (void *);
|
||||
|
||||
void __attribute__ ((interrupt("ilink")))
|
||||
foo(void)
|
||||
{
|
||||
bar (0);
|
||||
__asm__ volatile ( "" : : : "r0","r1","r2","r3");
|
||||
}
|
||||
/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "push_s blink" } } */
|
22
gcc/testsuite/gcc.target/arc/interrupt-6.c
Normal file
22
gcc/testsuite/gcc.target/arc/interrupt-6.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
|
||||
/* { dg-options "-O2 -mirq-ctrl-saved=r0-ilink" } */
|
||||
|
||||
#include <alloca.h>
|
||||
|
||||
/* Check if ilink is recognized. Check how FP and BLINK are saved.
|
||||
BLINK is saved last on the stack because the IRQ autosave will do
|
||||
first r0-ilink. To avoid this ABI exception, one needs to autosave
|
||||
always blink when using the IRQ autosave feature. */
|
||||
|
||||
extern int bar (void *);
|
||||
|
||||
void __attribute__ ((interrupt("ilink")))
|
||||
foo(void)
|
||||
{
|
||||
int *p = alloca (10);
|
||||
bar (p);
|
||||
}
|
||||
/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler "ld.*blink,\\\[sp\\\]" } } */
|
||||
/* { dg-final { scan-assembler "push_s.*blink" } } */
|
16
gcc/testsuite/gcc.target/arc/interrupt-7.c
Normal file
16
gcc/testsuite/gcc.target/arc/interrupt-7.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
|
||||
/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17,blink" } */
|
||||
|
||||
/* Check if the registers R0-R17,blink are automatically saved. */
|
||||
|
||||
void __attribute__ ((interrupt("ilink")))
|
||||
foo(void)
|
||||
{
|
||||
__asm__ volatile ( "" : : : "r13","r14","r15","r16");
|
||||
}
|
||||
/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "push_s blink" } } */
|
27
gcc/testsuite/gcc.target/arc/interrupt-8.c
Normal file
27
gcc/testsuite/gcc.target/arc/interrupt-8.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "Not available for ARCv1" { arc700 || arc6xx } } */
|
||||
/* { dg-options "-O2 -mirq-ctrl-saved=r0-r17" } */
|
||||
|
||||
/* Check if the registers R0-R17 are automatically saved. GP is saved
|
||||
by the compiler. */
|
||||
|
||||
int a;
|
||||
|
||||
void __attribute__ ((interrupt("ilink")))
|
||||
foo(void)
|
||||
{
|
||||
__asm__ volatile ( "" : : : "r0","r1","r2","r3");
|
||||
__asm__ volatile ( "" : : : "r13","r14","r15","r16");
|
||||
a++;
|
||||
}
|
||||
/* { dg-final { scan-assembler-not "st.*r13,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r14,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r15,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r16,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler "st.*gp,\\\[sp,-4\\\]" } } */
|
||||
/* { dg-final { scan-assembler "ld.*gp,\\\[sp\\\]" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r0,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r1,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r2,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler-not "st.*r3,\\\[sp" } } */
|
||||
/* { dg-final { scan-assembler "rtie" } } */
|
17
gcc/testsuite/gcc.target/arc/interrupt-9.c
Normal file
17
gcc/testsuite/gcc.target/arc/interrupt-9.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-require-effective-target archs }*/
|
||||
/* { dg-options "-O0 -mirq-ctrl-saved=r0-fp" } */
|
||||
|
||||
/* Check if we get the move operation between fp and sp. */
|
||||
|
||||
void __attribute__ ((interrupt("ilink")))
|
||||
handler1 (void)
|
||||
{
|
||||
asm (""
|
||||
:
|
||||
:
|
||||
: "r0", "r1", "r2", "r3", "r4",
|
||||
"r5", "r6", "r7", "r8", "r9");
|
||||
}
|
||||
/* { dg-final { scan-assembler "mov.*fp,sp" } } */
|
||||
/* { dg-final { scan-assembler-not ".*fp,\\\[sp" } } */
|
Loading…
Add table
Reference in a new issue