aarch64.md (*condjump): Handle functions > 1 MiB.
authorThomas Preud'homme <thopre01@gcc.gnu.org>
Thu, 27 Aug 2015 10:08:54 +0000 (10:08 +0000)
committerThomas Preud'homme <thopre01@gcc.gnu.org>
Thu, 27 Aug 2015 10:08:54 +0000 (10:08 +0000)
2015-08-27  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
            Andre Vieira  <andre.simoesdiasvieira@arm.com>

    gcc/
    * config/aarch64/aarch64.md (*condjump): Handle functions > 1 MiB.
    (*cb<optab><mode>1): Likewise.
    (*tb<optab><mode>1): Likewise.
    (*cb<optab><mode>1): Likewise.
    * config/aarch64/iterators.md (inv_cb): New code attribute.
    (inv_tb): Likewise.
    * config/aarch64/aarch64.c (aarch64_gen_far_branch): New.
    * config/aarch64/aarch64-protos.h (aarch64_gen_far_branch): New.

    gcc/testsuite/
    * gcc.target/aarch64/long_branch_1.c: New test.

From-SVN: r227253

gcc/ChangeLog
gcc/config/aarch64/aarch64-protos.h
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/aarch64.md
gcc/config/aarch64/iterators.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/long_branch_1.c [new file with mode: 0644]

index cbc5c46684c6e5af168d8ccdbe4ab32ccdf3a785..ad56ed16b12de5abaf8c32396874b91e56b5a458 100644 (file)
@@ -1,3 +1,15 @@
+2015-08-27  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
+           Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+       * config/aarch64/aarch64.md (*condjump): Handle functions > 1 MiB.
+       (*cb<optab><mode>1): Likewise.
+       (*tb<optab><mode>1): Likewise.
+       (*cb<optab><mode>1): Likewise.
+       * config/aarch64/iterators.md (inv_cb): New code attribute.
+       (inv_tb): Likewise.
+       * config/aarch64/aarch64.c (aarch64_gen_far_branch): New.
+       * config/aarch64/aarch64-protos.h (aarch64_gen_far_branch): New.
+
 2015-08-27  Richard Biener  <rguenther@suse.de>
 
        * ipa.c (cgraph_build_static_cdtor_1): Set DECL_IGNORED_P.
index 8fbc204123a7d0cc5f082aea721e0465c2233ea2..5dde59a185278aad78ffcc5e44a40059b0bd53bc 100644 (file)
@@ -330,6 +330,7 @@ unsigned aarch64_trampoline_size (void);
 void aarch64_asm_output_labelref (FILE *, const char *);
 void aarch64_cpu_cpp_builtins (cpp_reader *);
 void aarch64_elf_asm_named_section (const char *, unsigned, tree);
+const char * aarch64_gen_far_branch (rtx *, int, const char *, const char *);
 void aarch64_err_no_fpadvsimd (machine_mode, const char *);
 void aarch64_expand_epilogue (bool);
 void aarch64_expand_mov_immediate (rtx, rtx);
index c74bf84fc8bfb2b80167b676e17834e0d1ea77e6..b046dae315731ee29d7751e614e57bda834b7e15 100644 (file)
@@ -586,6 +586,29 @@ static const char * const aarch64_condition_codes[] =
   "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
 };
 
+/* Generate code to enable conditional branches in functions over 1 MiB.  */
+const char *
+aarch64_gen_far_branch (rtx * operands, int pos_label, const char * dest,
+                       const char * branch_format)
+{
+    rtx_code_label * tmp_label = gen_label_rtx ();
+    char label_buf[256];
+    char buffer[128];
+    ASM_GENERATE_INTERNAL_LABEL (label_buf, dest,
+                                CODE_LABEL_NUMBER (tmp_label));
+    const char *label_ptr = targetm.strip_name_encoding (label_buf);
+    rtx dest_label = operands[pos_label];
+    operands[pos_label] = tmp_label;
+
+    snprintf (buffer, sizeof (buffer), "%s%s", branch_format, label_ptr);
+    output_asm_insn (buffer, operands);
+
+    snprintf (buffer, sizeof (buffer), "b\t%%l%d\n%s:", pos_label, label_ptr);
+    operands[pos_label] = dest_label;
+    output_asm_insn (buffer, operands);
+    return "";
+}
+
 void
 aarch64_err_no_fpadvsimd (machine_mode mode, const char *msg)
 {
index c8511f0c88579a66f1aac803957509d70fb7f7bf..25229824fb510563bc36dd7f8c5f5bbf84db7ca8 100644 (file)
             (const_string "no")
        ] (const_string "yes")))
 
+;; Attribute that specifies whether we are dealing with a branch to a
+;; label that is far away, i.e. further away than the maximum/minimum
+;; representable in a signed 21-bits number.
+;; 0 :=: no
+;; 1 :=: yes
+(define_attr "far_branch" "" (const_int 0))
+
 ;; -------------------------------------------------------------------
 ;; Pipeline descriptions and scheduling
 ;; -------------------------------------------------------------------
                           (label_ref (match_operand 2 "" ""))
                           (pc)))]
   ""
-  "b%m0\\t%l2"
-  [(set_attr "type" "branch")]
+  {
+    if (get_attr_length (insn) == 8)
+      return aarch64_gen_far_branch (operands, 2, "Lbcond", "b%M0\\t");
+    else
+      return  "b%m0\\t%l2";
+  }
+  [(set_attr "type" "branch")
+   (set (attr "length")
+       (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -1048576))
+                          (lt (minus (match_dup 2) (pc)) (const_int 1048572)))
+                     (const_int 4)
+                     (const_int 8)))
+   (set (attr "far_branch")
+       (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -1048576))
+                          (lt (minus (match_dup 2) (pc)) (const_int 1048572)))
+                     (const_int 0)
+                     (const_int 1)))]
 )
 
 (define_expand "casesi"
                           (label_ref (match_operand 1 "" ""))
                           (pc)))]
   ""
-  "<cbz>\\t%<w>0, %l1"
-  [(set_attr "type" "branch")]
-
+  {
+    if (get_attr_length (insn) == 8)
+      return aarch64_gen_far_branch (operands, 1, "Lcb", "<inv_cb>\\t%<w>0, ");
+    else
+      return "<cbz>\\t%<w>0, %l1";
+  }
+  [(set_attr "type" "branch")
+   (set (attr "length")
+       (if_then_else (and (ge (minus (match_dup 1) (pc)) (const_int -1048576))
+                          (lt (minus (match_dup 1) (pc)) (const_int 1048572)))
+                     (const_int 4)
+                     (const_int 8)))
+   (set (attr "far_branch")
+       (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -1048576))
+                          (lt (minus (match_dup 2) (pc)) (const_int 1048572)))
+                     (const_int 0)
+                     (const_int 1)))]
 )
 
 (define_insn "*tb<optab><mode>1"
   {
     if (get_attr_length (insn) == 8)
       {
-       operands[1] = GEN_INT (HOST_WIDE_INT_1U << UINTVAL (operands[1]));
-       return "tst\t%<w>0, %1\;<bcond>\t%l2";
+       if (get_attr_far_branch (insn) == 1)
+         return aarch64_gen_far_branch (operands, 2, "Ltb",
+                                        "<inv_tb>\\t%<w>0, %1, ");
+       else
+         {
+           operands[1] = GEN_INT (HOST_WIDE_INT_1U << UINTVAL (operands[1]));
+           return "tst\t%<w>0, %1\;<bcond>\t%l2";
+         }
       }
     else
       return "<tbz>\t%<w>0, %1, %l2";
        (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -32768))
                           (lt (minus (match_dup 2) (pc)) (const_int 32764)))
                      (const_int 4)
-                     (const_int 8)))]
+                     (const_int 8)))
+   (set (attr "far_branch")
+       (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -1048576))
+                          (lt (minus (match_dup 2) (pc)) (const_int 1048572)))
+                     (const_int 0)
+                     (const_int 1)))]
+
 )
 
 (define_insn "*cb<optab><mode>1"
   {
     if (get_attr_length (insn) == 8)
       {
-       char buf[64];
-       uint64_t val = ((uint64_t ) 1)
-                       << (GET_MODE_SIZE (<MODE>mode) * BITS_PER_UNIT - 1);
-       sprintf (buf, "tst\t%%<w>0, %" PRId64, val);
-       output_asm_insn (buf, operands);
-       return "<bcond>\t%l1";
+       if (get_attr_far_branch (insn) == 1)
+         return aarch64_gen_far_branch (operands, 1, "Ltb",
+                                        "<inv_tb>\\t%<w>0, <sizem1>, ");
+       else
+         {
+           char buf[64];
+           uint64_t val = ((uint64_t) 1)
+               << (GET_MODE_SIZE (<MODE>mode) * BITS_PER_UNIT - 1);
+           sprintf (buf, "tst\t%%<w>0, %" PRId64, val);
+           output_asm_insn (buf, operands);
+           return "<bcond>\t%l1";
+         }
       }
     else
       return "<tbz>\t%<w>0, <sizem1>, %l1";
        (if_then_else (and (ge (minus (match_dup 1) (pc)) (const_int -32768))
                           (lt (minus (match_dup 1) (pc)) (const_int 32764)))
                      (const_int 4)
-                     (const_int 8)))]
+                     (const_int 8)))
+   (set (attr "far_branch")
+       (if_then_else (and (ge (minus (match_dup 1) (pc)) (const_int -1048576))
+                          (lt (minus (match_dup 1) (pc)) (const_int 1048572)))
+                     (const_int 0)
+                     (const_int 1)))]
 )
 
 ;; -------------------------------------------------------------------
index b8a45d1d6ed8bbcfcb9a2b37edd0e24ba171649f..475aa6e6d37c78a455e22e26990504b3d96a2f80 100644 (file)
 ;; Emit cbz/cbnz depending on comparison type.
 (define_code_attr cbz [(eq "cbz") (ne "cbnz") (lt "cbnz") (ge "cbz")])
 
+;; Emit inverted cbz/cbnz depending on comparison type.
+(define_code_attr inv_cb [(eq "cbnz") (ne "cbz") (lt "cbz") (ge "cbnz")])
+
 ;; Emit tbz/tbnz depending on comparison type.
 (define_code_attr tbz [(eq "tbz") (ne "tbnz") (lt "tbnz") (ge "tbz")])
 
+;; Emit inverted tbz/tbnz depending on comparison type.
+(define_code_attr inv_tb [(eq "tbnz") (ne "tbz") (lt "tbz") (ge "tbnz")])
+
 ;; Max/min attributes.
 (define_code_attr maxmin [(smax "max")
                          (smin "min")
index 15a2a438b997e71f340f0bc9513c5eb67e1c95a5..2abe06d8095389471c166ba6676e9ae6a1e79c35 100644 (file)
@@ -1,3 +1,7 @@
+2015-08-27  Andre Vieira  <andre.simoesdiasvieira@arm.com>
+
+       * gcc.target/aarch64/long_branch_1.c: New test.
+
 2015-08-27  Dominik Vogt  <vogt@linux.vnet.ibm.com>
 
        * gcc.target/s390/20150826-1.c: New test.
diff --git a/gcc/testsuite/gcc.target/aarch64/long_branch_1.c b/gcc/testsuite/gcc.target/aarch64/long_branch_1.c
new file mode 100644 (file)
index 0000000..46f500d
--- /dev/null
@@ -0,0 +1,91 @@
+/* { dg-do assemble } */
+/* { dg-timeout-factor 2.0 } */
+/* { dg-options "-O1 -fno-reorder-blocks -fno-tree-cselim --save-temps" } */
+
+
+__attribute__((noinline, noclone)) int
+restore (int a, int b)
+{
+  return a * b;
+}
+
+__attribute__((noinline, noclone)) void
+do_nothing (int *input)
+{
+  *input = restore (*input, 1);
+  return;
+}
+#define ENTRY_SUM(n, x) \
+    sum = sum / ((n) + (x)); \
+    sum = restore (sum, (n) + (x));
+
+#define ENTRY_SUM2(n, x) ENTRY_SUM ((n), (x)) ENTRY_SUM ((n), (x)+1)
+#define ENTRY_SUM4(n, x) ENTRY_SUM2 ((n), (x)) ENTRY_SUM2 ((n), (x)+2)
+#define ENTRY_SUM8(n, x) ENTRY_SUM4 ((n), (x)) ENTRY_SUM4 ((n), (x)+4)
+#define ENTRY_SUM16(n, x) ENTRY_SUM8 ((n), (x)) ENTRY_SUM8 ((n), (x)+8)
+#define ENTRY_SUM32(n, x) ENTRY_SUM16 ((n), (x)) ENTRY_SUM16 ((n), (x)+16)
+#define ENTRY_SUM64(n, x) ENTRY_SUM32 ((n), (x)) ENTRY_SUM32 ((n), (x)+32)
+#define ENTRY_SUM128(n, x) ENTRY_SUM64 ((n), (x)) ENTRY_SUM64 ((n), (x)+64)
+
+#define CASE_ENTRY(n) \
+  case n: \
+    sum = sum / (n + 1); \
+    sum = restore (sum, n + 1); \
+    if (sum == (n + addend)) \
+      break;\
+    ENTRY_SUM128 ((n), 2) \
+    ENTRY_SUM16 ((n), 130) \
+    break;
+
+#define CASE_ENTRY2(n) CASE_ENTRY ((n)) CASE_ENTRY ((n)+1)
+#define CASE_ENTRY4(n) CASE_ENTRY2 ((n)) CASE_ENTRY2 ((n)+2)
+#define CASE_ENTRY8(n) CASE_ENTRY4 ((n)) CASE_ENTRY4 ((n)+4)
+#define CASE_ENTRY16(n) CASE_ENTRY8 ((n)) CASE_ENTRY8 ((n)+8)
+#define CASE_ENTRY32(n) CASE_ENTRY16 ((n)) CASE_ENTRY16 ((n)+16)
+#define CASE_ENTRY64(n) CASE_ENTRY32 ((n)) CASE_ENTRY32 ((n)+32)
+#define CASE_ENTRY128(n) CASE_ENTRY64 ((n)) CASE_ENTRY64 ((n)+64)
+
+__attribute__((noinline, noclone)) long long
+test_and_branch (int selector, int addend, int cond)
+{
+  long long sum = selector + 1;
+
+  if (selector > 200)
+    {
+start0:
+      return sum - 1;
+start1:
+      return sum + 1;
+start2:
+      return sum;
+start3:
+      return sum - 2;
+    }
+  else
+    {
+      switch (selector)
+       {
+         CASE_ENTRY128 (1)
+         CASE_ENTRY64 (129)
+         CASE_ENTRY16 (193)
+       }
+
+      do_nothing ((int *)&sum);
+
+      if (cond == 0)
+       goto start0;
+      else if (cond < 0)
+       goto start1;
+      else if ((cond & 0x010) != 0)
+       goto start2;
+      else if (cond >= 14)
+       goto start3;
+
+    }
+
+  return -1;
+}
+
+/* { dg-final { scan-assembler "Lbcond" } } */
+/* { dg-final { scan-assembler "Lcb" } } */
+/* { dg-final { scan-assembler "Ltb" } } */