Commit 5acc47a4 by Kyrylo Tkachov Committed by Kyrylo Tkachov

[ARM] PR target/70830: Avoid POP-{reglist}^ when returning from interrupt handlers

	PR target/70830
	* config/arm/arm.c (arm_output_multireg_pop): Avoid POP instruction
	when popping the PC and within an interrupt handler routine.
	Add missing tab to output of "ldmfd".
	(output_return_instruction): Output LDMFD with SP update rather
	than POP when returning from interrupt handler.

	* gcc.target/arm/interrupt-1.c: Change dg-compile to dg-assemble.
	Add -save-temps to dg-options.
	Scan for ldmfd rather than pop instruction.
	* gcc.target/arm/interrupt-2.c: Likewise.
	* gcc.target/arm/pr70830.c: New test.

From-SVN: r236169
parent 3cd63842
2016-05-12 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
PR target/70830
* config/arm/arm.c (arm_output_multireg_pop): Avoid POP instruction
when popping the PC and within an interrupt handler routine.
Add missing tab to output of "ldmfd".
(output_return_instruction): Output LDMFD with SP update rather
than POP when returning from interrupt handler.
2016-05-12 Jakub Jelinek <jakub@redhat.com> 2016-05-12 Jakub Jelinek <jakub@redhat.com>
* config/i386/i386.md (isa): Add x64_avx512dq, enable if * config/i386/i386.md (isa): Add x64_avx512dq, enable if
......
...@@ -17755,6 +17755,7 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse, ...@@ -17755,6 +17755,7 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse,
int num_saves = XVECLEN (operands[0], 0); int num_saves = XVECLEN (operands[0], 0);
unsigned int regno; unsigned int regno;
unsigned int regno_base = REGNO (operands[1]); unsigned int regno_base = REGNO (operands[1]);
bool interrupt_p = IS_INTERRUPT (arm_current_func_type ());
offset = 0; offset = 0;
offset += update ? 1 : 0; offset += update ? 1 : 0;
...@@ -17772,7 +17773,8 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse, ...@@ -17772,7 +17773,8 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse,
} }
conditional = reverse ? "%?%D0" : "%?%d0"; conditional = reverse ? "%?%D0" : "%?%d0";
if ((regno_base == SP_REGNUM) && update) /* Can't use POP if returning from an interrupt. */
if ((regno_base == SP_REGNUM) && !(interrupt_p && return_pc))
{ {
sprintf (pattern, "pop%s\t{", conditional); sprintf (pattern, "pop%s\t{", conditional);
} }
...@@ -17781,11 +17783,8 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse, ...@@ -17781,11 +17783,8 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse,
/* Output ldmfd when the base register is SP, otherwise output ldmia. /* Output ldmfd when the base register is SP, otherwise output ldmia.
It's just a convention, their semantics are identical. */ It's just a convention, their semantics are identical. */
if (regno_base == SP_REGNUM) if (regno_base == SP_REGNUM)
/* update is never true here, hence there is no need to handle sprintf (pattern, "ldmfd%s\t", conditional);
pop here. */ else if (update)
sprintf (pattern, "ldmfd%s", conditional);
if (update)
sprintf (pattern, "ldmia%s\t", conditional); sprintf (pattern, "ldmia%s\t", conditional);
else else
sprintf (pattern, "ldm%s\t", conditional); sprintf (pattern, "ldm%s\t", conditional);
...@@ -17811,7 +17810,7 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse, ...@@ -17811,7 +17810,7 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse,
strcat (pattern, "}"); strcat (pattern, "}");
if (IS_INTERRUPT (arm_current_func_type ()) && return_pc) if (interrupt_p && return_pc)
strcat (pattern, "^"); strcat (pattern, "^");
output_asm_insn (pattern, &cond); output_asm_insn (pattern, &cond);
...@@ -19622,8 +19621,12 @@ output_return_instruction (rtx operand, bool really_return, bool reverse, ...@@ -19622,8 +19621,12 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
sprintf (instr, "ldmfd%s\t%%|sp, {", conditional); sprintf (instr, "ldmfd%s\t%%|sp, {", conditional);
} }
} }
/* For interrupt returns we have to use an LDM rather than
a POP so that we can use the exception return variant. */
else if (IS_INTERRUPT (func_type))
sprintf (instr, "ldmfd%s\t%%|sp!, {", conditional);
else else
sprintf (instr, "pop%s\t{", conditional); sprintf (instr, "pop%s\t{", conditional);
p = instr + strlen (instr); p = instr + strlen (instr);
......
2016-05-12 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
PR target/70830
* gcc.target/arm/interrupt-1.c: Change dg-compile to dg-assemble.
Add -save-temps to dg-options.
Scan for ldmfd rather than pop instruction.
* gcc.target/arm/interrupt-2.c: Likewise.
* gcc.target/arm/pr70830.c: New test.
2016-05-12 Jakub Jelinek <jakub@redhat.com> 2016-05-12 Jakub Jelinek <jakub@redhat.com>
* gcc.target/i386/avx512bw-vpextr-1.c: New test. * gcc.target/i386/avx512bw-vpextr-1.c: New test.
......
/* Verify that prologue and epilogue are correct for functions with /* Verify that prologue and epilogue are correct for functions with
__attribute__ ((interrupt)). */ __attribute__ ((interrupt)). */
/* { dg-do compile } */ /* { dg-do assemble } */
/* { dg-require-effective-target arm_nothumb } */ /* { dg-require-effective-target arm_nothumb } */
/* { dg-options "-O0 -marm" } */ /* { dg-options "-O0 -marm -save-temps" } */
/* This test is not valid when -mthumb. */ /* This test is not valid when -mthumb. */
extern void bar (int); extern void bar (int);
...@@ -14,4 +14,4 @@ void foo () ...@@ -14,4 +14,4 @@ void foo ()
} }
/* { dg-final { scan-assembler "push\t{r0, r1, r2, r3, r4, fp, ip, lr}" } } */ /* { dg-final { scan-assembler "push\t{r0, r1, r2, r3, r4, fp, ip, lr}" } } */
/* { dg-final { scan-assembler "pop\t{r0, r1, r2, r3, r4, fp, ip, pc}\\^" } } */ /* { dg-final { scan-assembler "ldmfd\tsp!, {r0, r1, r2, r3, r4, fp, ip, pc}\\^" } } */
/* Verify that prologue and epilogue are correct for functions with /* Verify that prologue and epilogue are correct for functions with
__attribute__ ((interrupt)). */ __attribute__ ((interrupt)). */
/* { dg-do compile } */ /* { dg-do assemble } */
/* { dg-require-effective-target arm_nothumb } */ /* { dg-require-effective-target arm_nothumb } */
/* { dg-options "-O1 -marm" } */ /* { dg-options "-O1 -marm -save-temps" } */
/* This test is not valid when -mthumb. */ /* This test is not valid when -mthumb. */
extern void bar (int); extern void bar (int);
...@@ -16,4 +16,4 @@ void test() ...@@ -16,4 +16,4 @@ void test()
} }
/* { dg-final { scan-assembler "push\t{r0, r1, r2, r3, r4, r5, ip, lr}" } } */ /* { dg-final { scan-assembler "push\t{r0, r1, r2, r3, r4, r5, ip, lr}" } } */
/* { dg-final { scan-assembler "pop\t{r0, r1, r2, r3, r4, r5, ip, pc}\\^" } } */ /* { dg-final { scan-assembler "ldmfd\tsp!, {r0, r1, r2, r3, r4, r5, ip, pc}\\^" } } */
/* PR target/70830. */
/* { dg-do assemble } */
/* { dg-require-effective-target arm_arm_ok } */
/* { dg-options "-Os -marm -save-temps" } */
/* This test is not valid when -mthumb. */
extern void prints (char *);
void __attribute__ ((interrupt ("IRQ"))) dm3730_IRQHandler(void)
{
prints("IRQ" );
}
/* { dg-final { scan-assembler "ldmfd\tsp!, {r0, r1, r2, r3, ip, pc}\\^" } } */
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