[ARM] PR target/70830: Avoid POP-{reglist}^ when returning from interrupt handlers
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>
Thu, 12 May 2016 09:56:46 +0000 (09:56 +0000)
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>
Thu, 12 May 2016 09:56:46 +0000 (09:56 +0000)
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
gcc/config/arm/arm.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/interrupt-1.c
gcc/testsuite/gcc.target/arm/interrupt-2.c
gcc/testsuite/gcc.target/arm/pr70830.c [new file with mode: 0644]

index e47a12b00ec7504139de87e4e4b8d6a52c84dfb8..23a486928f41725d847dc36d801941278e0c2f30 100644 (file)
@@ -1,3 +1,12 @@
+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>
 
        * config/i386/i386.md (isa): Add x64_avx512dq, enable if
index 71b51439dc7ba5be67671e9fb4c3f18040cce58f..58b04322d187ea26c45f499a6822c5af8641a905 100644 (file)
@@ -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);
 
index f4f2390bfc18e4a3b44a5813f6c80f945bf5c33a..41e5d51d8a972d180eff68f8273b8bfb7dd7fcc7 100644 (file)
@@ -1,3 +1,12 @@
+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>
 
        * gcc.target/i386/avx512bw-vpextr-1.c: New test.
index debbaf78cc84d17e3c43fbd9185f7d6b3fe5d88f..fe94877cead7501dd73f2eba92feff395de9df2f 100644 (file)
@@ -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}\\^" } } */
index 92f8630e016b869dc6bc1b3dabaa6b14fd2cf776..289eca0f6406bb73b029b9307cdcca6e047bcfb2 100644 (file)
@@ -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 (file)
index 0000000..cad903b
--- /dev/null
@@ -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}\\^" } } */