From 5acc47a40d13af51cd1709f0238c798a666bcd7b Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Thu, 12 May 2016 09:56:46 +0000 Subject: [PATCH] [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 --- gcc/ChangeLog | 9 +++++++++ gcc/config/arm/arm.c | 19 +++++++++++-------- gcc/testsuite/ChangeLog | 9 +++++++++ gcc/testsuite/gcc.target/arm/interrupt-1.c | 6 +++--- gcc/testsuite/gcc.target/arm/interrupt-2.c | 6 +++--- gcc/testsuite/gcc.target/arm/pr70830.c | 14 ++++++++++++++ 6 files changed, 49 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/pr70830.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e47a12b00ec..23a486928f4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2016-05-12 Kyrylo Tkachov + + 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 * config/i386/i386.md (isa): Add x64_avx512dq, enable if diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 71b51439dc7..58b04322d18 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -17755,6 +17755,7 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse, int num_saves = XVECLEN (operands[0], 0); unsigned int regno; unsigned int regno_base = REGNO (operands[1]); + bool interrupt_p = IS_INTERRUPT (arm_current_func_type ()); offset = 0; offset += update ? 1 : 0; @@ -17772,7 +17773,8 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse, } 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); } @@ -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. It's just a convention, their semantics are identical. */ if (regno_base == SP_REGNUM) - /* update is never true here, hence there is no need to handle - pop here. */ - sprintf (pattern, "ldmfd%s", conditional); - - if (update) + sprintf (pattern, "ldmfd%s\t", conditional); + else if (update) sprintf (pattern, "ldmia%s\t", conditional); else sprintf (pattern, "ldm%s\t", conditional); @@ -17811,7 +17810,7 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse, strcat (pattern, "}"); - if (IS_INTERRUPT (arm_current_func_type ()) && return_pc) + if (interrupt_p && return_pc) strcat (pattern, "^"); output_asm_insn (pattern, &cond); @@ -19622,8 +19621,12 @@ output_return_instruction (rtx operand, bool really_return, bool reverse, 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 - sprintf (instr, "pop%s\t{", conditional); + sprintf (instr, "pop%s\t{", conditional); p = instr + strlen (instr); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f4f2390bfc1..41e5d51d8a9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2016-05-12 Kyrylo Tkachov + + 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 * gcc.target/i386/avx512bw-vpextr-1.c: New test. diff --git a/gcc/testsuite/gcc.target/arm/interrupt-1.c b/gcc/testsuite/gcc.target/arm/interrupt-1.c index debbaf78cc8..fe94877cead 100644 --- a/gcc/testsuite/gcc.target/arm/interrupt-1.c +++ b/gcc/testsuite/gcc.target/arm/interrupt-1.c @@ -1,8 +1,8 @@ /* Verify that prologue and epilogue are correct for functions with __attribute__ ((interrupt)). */ -/* { dg-do compile } */ +/* { dg-do assemble } */ /* { dg-require-effective-target arm_nothumb } */ -/* { dg-options "-O0 -marm" } */ +/* { dg-options "-O0 -marm -save-temps" } */ /* This test is not valid when -mthumb. */ extern void bar (int); @@ -14,4 +14,4 @@ void foo () } /* { 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}\\^" } } */ diff --git a/gcc/testsuite/gcc.target/arm/interrupt-2.c b/gcc/testsuite/gcc.target/arm/interrupt-2.c index 92f8630e016..289eca0f640 100644 --- a/gcc/testsuite/gcc.target/arm/interrupt-2.c +++ b/gcc/testsuite/gcc.target/arm/interrupt-2.c @@ -1,8 +1,8 @@ /* Verify that prologue and epilogue are correct for functions with __attribute__ ((interrupt)). */ -/* { dg-do compile } */ +/* { dg-do assemble } */ /* { dg-require-effective-target arm_nothumb } */ -/* { dg-options "-O1 -marm" } */ +/* { dg-options "-O1 -marm -save-temps" } */ /* This test is not valid when -mthumb. */ extern void bar (int); @@ -16,4 +16,4 @@ void test() } /* { 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}\\^" } } */ diff --git a/gcc/testsuite/gcc.target/arm/pr70830.c b/gcc/testsuite/gcc.target/arm/pr70830.c new file mode 100644 index 00000000000..cad903b0cf2 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr70830.c @@ -0,0 +1,14 @@ +/* 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}\\^" } } */ -- 2.30.2