arm.c (thumb1_final_prescan_insn): Assert lr save for real far jump.
authorJoey Ye <joey.ye@arm.com>
Mon, 15 Apr 2013 07:41:27 +0000 (07:41 +0000)
committerJoey Ye <jye2@gcc.gnu.org>
Mon, 15 Apr 2013 07:41:27 +0000 (07:41 +0000)
2013-04-15  Joey Ye  <joey.ye@arm.com>

    * config/arm/arm.c (thumb1_final_prescan_insn): Assert lr save
    for real far jump.
    (thumb_far_jump_used_p): Count instruction size and set
    far_jump_used.

testsuite:
    * gcc.target/arm/thumb1-far-jump-1.c: New test.
    * gcc.target/arm/thumb1-far-jump-2.c: New test.

From-SVN: r197956

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/thumb1-far-jump-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/thumb1-far-jump-2.c [new file with mode: 0644]

index 370ccbb507a381b7bcfb213c06092f97eb788ce5..6d664610d2ec141974ee27b94aa7f03a136bbcb7 100644 (file)
@@ -1,3 +1,10 @@
+2013-04-15  Joey Ye  <joey.ye@arm.com>
+
+       * config/arm/arm.c (thumb1_final_prescan_insn): Assert lr save
+       for real far jump.
+       (thumb_far_jump_used_p): Count instruction size and set
+       far_jump_used.
+
 2013-04-14  Eric Botcazou  <ebotcazou@adacore.com>
 
        * reorg.c (fill_simple_delay_slots): Reindent block of code.
index 982487ec22a002c08e468708fd1b4fd242460ef1..e0667849c70d0ab6b5a44e54ff4ff6137a476ca2 100644 (file)
@@ -22713,6 +22713,11 @@ thumb1_final_prescan_insn (rtx insn)
       else if (conds != CONDS_NOCOND)
        cfun->machine->thumb1_cc_insn = NULL_RTX;
     }
+
+    /* Check if unexpected far jump is used.  */
+    if (cfun->machine->lr_save_eliminated
+        && get_attr_far_jump (insn) == FAR_JUMP_YES)
+      internal_error("Unexpected thumb1 far jump");
 }
 
 int
@@ -22738,6 +22743,8 @@ static int
 thumb_far_jump_used_p (void)
 {
   rtx insn;
+  bool far_jump = false;
+  unsigned int func_size = 0;
 
   /* This test is only important for leaf functions.  */
   /* assert (!leaf_function_p ()); */
@@ -22788,6 +22795,26 @@ thumb_far_jump_used_p (void)
     {
       if (JUMP_P (insn) && get_attr_far_jump (insn) == FAR_JUMP_YES)
        {
+         far_jump = true;
+       }
+      func_size += get_attr_length (insn);
+    }
+
+  /* Attribute far_jump will always be true for thumb1 before
+     shorten_branch pass.  So checking far_jump attribute before
+     shorten_branch isn't much useful.
+
+     Following heuristic tries to estimate more accruately if a far jump
+     may finally be used.  The heuristic is very conservative as there is
+     no chance to roll-back the decision of not to use far jump.
+
+     Thumb1 long branch offset is -2048 to 2046.  The worst case is each
+     2-byte insn is assiociated with a 4 byte constant pool.  Using
+     function size 2048/3 as the threshold is conservative enough.  */
+  if (far_jump)
+    {
+      if ((func_size * 3) >= 2048)
+        {
          /* Record the fact that we have decided that
             the function does use far jumps.  */
          cfun->machine->far_jump_used = 1;
index cdff281c9307d9ce043e67a143aaaa7fd4872f4b..c8d46d5bd630a1ce6c4f95208b3191550724e432 100644 (file)
@@ -1,3 +1,8 @@
+2013-04-15  Joey Ye  <joey.ye@arm.com>
+
+       * gcc.target/arm/thumb1-far-jump-1.c: New test.
+       * gcc.target/arm/thumb1-far-jump-2.c: New test.
+
 2013-04-14  Mikael Morin  <mikael@gcc.gnu.org>
 
        PR fortran/56816
diff --git a/gcc/testsuite/gcc.target/arm/thumb1-far-jump-1.c b/gcc/testsuite/gcc.target/arm/thumb1-far-jump-1.c
new file mode 100644 (file)
index 0000000..eb16d2f
--- /dev/null
@@ -0,0 +1,34 @@
+/* Check for thumb1 far jump. Shouldn't save lr for small leaf functions
+ * even with a branch in it.  */
+/* { dg-options "-Os" } */
+/* { dg-skip-if "" { ! { arm_thumb1 } } } */
+
+void f()
+{
+  for (;;);
+}
+
+volatile int g;
+void f2(int i)
+{
+  if (i) g=0;
+}
+
+void f3(int i)
+{
+  if (i) {
+    g=0;
+    g=1;
+    g=2;
+    g=3;
+    g=4;
+    g=5;
+    g=6;
+    g=7;
+    g=8;
+    g=9;
+  }
+}
+
+/* { dg-final { scan-assembler-not "push.*lr" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/thumb1-far-jump-2.c b/gcc/testsuite/gcc.target/arm/thumb1-far-jump-2.c
new file mode 100644 (file)
index 0000000..c6878f8
--- /dev/null
@@ -0,0 +1,57 @@
+/* Check for thumb1 far jump. This is the extreme case that far jump
+ * will be used with minimum number of instructions. By passing this case
+ * it means the heuristic of saving lr for far jump meets the most extreme
+ * requirement.  */
+/* { dg-options "-Os" } */
+/* { dg-skip-if "" { ! { arm_thumb1 } } } */
+
+volatile register r4 asm("r4");
+void f3(int i)
+{
+#define GO(n) \
+  extern volatile int g_##n; \
+  r4=(int)&g_##n;
+
+#define GO8(n) \
+  GO(n##_0) \
+  GO(n##_1) \
+  GO(n##_2) \
+  GO(n##_3) \
+  GO(n##_4) \
+  GO(n##_5) \
+  GO(n##_6) \
+  GO(n##_7)
+
+#define GO64(n) \
+  GO8(n##_0) \
+  GO8(n##_1) \
+  GO8(n##_2) \
+  GO8(n##_3) \
+  GO8(n##_4) \
+  GO8(n##_5) \
+  GO8(n##_6) \
+  GO8(n##_7) \
+
+#define GO498(n) \
+  GO64(n##_0) \
+  GO64(n##_1) \
+  GO64(n##_2) \
+  GO64(n##_3) \
+  GO64(n##_4) \
+  GO64(n##_5) \
+  GO64(n##_6) \
+  GO8(n##_0) \
+  GO8(n##_1) \
+  GO8(n##_2) \
+  GO8(n##_3) \
+  GO8(n##_4) \
+  GO8(n##_5) \
+  GO(n##_0) \
+  GO(n##_1) \
+
+  if (i) {
+    GO498(0);
+  }
+}
+
+/* { dg-final { scan-assembler "push.*lr" } } */