diff mbox

[AARCH64] Fix for branch offsets over 1 MiB

Message ID 55DC375D.8060904@arm.com
State New
Headers show

Commit Message

Andre Vieira (lists) Aug. 25, 2015, 9:37 a.m. UTC
Conditional branches have a maximum range of [-1048576, 1048572]. Any 
destination further away can not be reached by these.
To be able to have conditional branches in very large functions, we 
invert the condition and change the destination to jump over an 
unconditional branch to the original, far away, destination.

gcc/ChangeLog:
2015-08-07  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): Idem.
         (*tb<optab><mode>1): Idem.
         (*cb<optab><mode>1): Idem.
         * config/aarch64/iterators.md (inv_cb): New code attribute.
         (inv_tb): Idem.
         * config/aarch64/aarch64.c (aarch64_gen_far_branch): New.
         * config/aarch64/aarch64-protos.h (aarch64_gen_far_branch): New.

gcc/testsuite/ChangeLog:
2015-08-07  Andre Vieira  <andre.simoesdiasvieira@arm.com>

         * gcc.target/aarch64/long-branch.c: New test.

Comments

Andrew Pinski Aug. 25, 2015, 9:50 a.m. UTC | #1
On Tue, Aug 25, 2015 at 5:37 PM, Andre Vieira
<Andre.SimoesDiasVieira@arm.com> wrote:
> Conditional branches have a maximum range of [-1048576, 1048572]. Any
> destination further away can not be reached by these.
> To be able to have conditional branches in very large functions, we invert
> the condition and change the destination to jump over an unconditional
> branch to the original, far away, destination.
>
> gcc/ChangeLog:
> 2015-08-07  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): Idem.
>         (*tb<optab><mode>1): Idem.
>         (*cb<optab><mode>1): Idem.
>         * config/aarch64/iterators.md (inv_cb): New code attribute.
>         (inv_tb): Idem.
>         * config/aarch64/aarch64.c (aarch64_gen_far_branch): New.
>         * config/aarch64/aarch64-protos.h (aarch64_gen_far_branch): New.
>
> gcc/testsuite/ChangeLog:
> 2015-08-07  Andre Vieira  <andre.simoesdiasvieira@arm.com>
>
>         * gcc.target/aarch64/long-branch.c: New test.

Just a few comments about the testcase.  You could improve the size
(on disk) of the testcase by using the preprocessor some more:
Something like:
#define CASE_ENTRY2 (x) CASE_ENTRY ((x)) CASE_ENTRY ((x)+1)
#define CASE_ENTRY4 (x) CASE_ENTRY2 ((x)) CASE_ENTRY2 ((x)+2+1)
#define CASE_ENTRY8 (x) CASE_ENTRY4 ((x)) CASE_ENTRY4 ((x)+4+1)
#define CASE_ENTRY16 (x) CASE_ENTRY8 ((x)) CASE_ENTRY8 ((x)+8+1)
#define CASE_ENTRY32 (x) CASE_ENTRY16 ((x)) CASE_ENTRY16 ((x)+16)
#define CASE_ENTRY64 (x) CASE_ENTRY32 ((x)) CASE_ENTRY32 ((x)+32+1)
#define CASE_ENTRY128 (x) CASE_ENTRY64 ((x)) CASE_ENTRY16 ((x)+64+1)
#define CASE_ENTRY256 (x) CASE_ENTRY128 ((x)) CASE_ENTRY128 ((x)+128+1)

And then use
CASE_ENTRY256 (1)

You can do the same trick to reduce the size of CASE_ENTRY too.

Thanks,
Andrew Pinski
Andrew Pinski Aug. 25, 2015, 9:52 a.m. UTC | #2
On Tue, Aug 25, 2015 at 5:50 PM, Andrew Pinski <pinskia@gmail.com> wrote:
> On Tue, Aug 25, 2015 at 5:37 PM, Andre Vieira
> <Andre.SimoesDiasVieira@arm.com> wrote:
>> Conditional branches have a maximum range of [-1048576, 1048572]. Any
>> destination further away can not be reached by these.
>> To be able to have conditional branches in very large functions, we invert
>> the condition and change the destination to jump over an unconditional
>> branch to the original, far away, destination.
>>
>> gcc/ChangeLog:
>> 2015-08-07  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): Idem.
>>         (*tb<optab><mode>1): Idem.
>>         (*cb<optab><mode>1): Idem.
>>         * config/aarch64/iterators.md (inv_cb): New code attribute.
>>         (inv_tb): Idem.
>>         * config/aarch64/aarch64.c (aarch64_gen_far_branch): New.
>>         * config/aarch64/aarch64-protos.h (aarch64_gen_far_branch): New.
>>
>> gcc/testsuite/ChangeLog:
>> 2015-08-07  Andre Vieira  <andre.simoesdiasvieira@arm.com>
>>
>>         * gcc.target/aarch64/long-branch.c: New test.
>
> Just a few comments about the testcase.  You could improve the size
> (on disk) of the testcase by using the preprocessor some more:
> Something like:
> #define CASE_ENTRY2 (x) CASE_ENTRY ((x)) CASE_ENTRY ((x)+1)
> #define CASE_ENTRY4 (x) CASE_ENTRY2 ((x)) CASE_ENTRY2 ((x)+2+1)
> #define CASE_ENTRY8 (x) CASE_ENTRY4 ((x)) CASE_ENTRY4 ((x)+4+1)
> #define CASE_ENTRY16 (x) CASE_ENTRY8 ((x)) CASE_ENTRY8 ((x)+8+1)
> #define CASE_ENTRY32 (x) CASE_ENTRY16 ((x)) CASE_ENTRY16 ((x)+16)
> #define CASE_ENTRY64 (x) CASE_ENTRY32 ((x)) CASE_ENTRY32 ((x)+32+1)
> #define CASE_ENTRY128 (x) CASE_ENTRY64 ((x)) CASE_ENTRY16 ((x)+64+1)
> #define CASE_ENTRY256 (x) CASE_ENTRY128 ((x)) CASE_ENTRY128 ((x)+128+1)


I do have an off by one error but you should get the idea.  Basically
instead of 200 lines, we only have 9 lines (log2(256) == 8).

Thanks,
Andrew

>
> And then use
> CASE_ENTRY256 (1)
>
> You can do the same trick to reduce the size of CASE_ENTRY too.
>
> Thanks,
> Andrew Pinski
diff mbox

Patch

From 9759c5a50c44b0421c7911014e63a6222dd9017d Mon Sep 17 00:00:00 2001
From: Andre Simoes Dias Vieira <andsim01@arm.com>
Date: Fri, 14 Aug 2015 10:21:57 +0100
Subject: [PATCH] fix for far branches

---
 gcc/config/aarch64/aarch64-protos.h            |   1 +
 gcc/config/aarch64/aarch64.c                   |  23 +
 gcc/config/aarch64/aarch64.md                  |  89 +++-
 gcc/config/aarch64/iterators.md                |   6 +
 gcc/testsuite/gcc.target/aarch64/long_branch.c | 565 +++++++++++++++++++++++++
 5 files changed, 669 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/long_branch.c

diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 32b5d0958a6e0b2356874736f858f007fe68cdda..87a26deb6a0dbf13e25275baeebec21a37a42f41 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -316,6 +316,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);
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 7159f5aca5df97f154b3e654f60af9136354f335..3b491a232d81892b6511bad84e4174d939fa1be7 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -587,6 +587,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)
 {
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 35255e91a95cdf20d52270470202f7499ba46bb2..74f6e3ec4bdcd076c2ad6d1431102aa50dfb5068 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -181,6 +181,13 @@ 
 	     (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
 ;; -------------------------------------------------------------------
@@ -308,8 +315,23 @@ 
 			   (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"
@@ -488,9 +510,23 @@ 
 			   (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"
@@ -506,8 +542,14 @@ 
   {
     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";
@@ -517,7 +559,13 @@ 
 	(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"
@@ -530,12 +578,18 @@ 
   {
     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";
@@ -545,7 +599,12 @@ 
 	(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)))]
 )
 
 ;; -------------------------------------------------------------------
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 5d7966d7adf49a1824ddc41cd34b04c6f179b09a..8b245c351f11960267d242892fcddb68b1542ddb 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -820,9 +820,15 @@ 
 ;; 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")
diff --git a/gcc/testsuite/gcc.target/aarch64/long_branch.c b/gcc/testsuite/gcc.target/aarch64/long_branch.c
new file mode 100644
index 0000000000000000000000000000000000000000..37aed8823d3a3634be2462d0c18a9301c59ec97d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/long_branch.c
@@ -0,0 +1,565 @@ 
+/* { 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 CASE_ENTRY(n) \
+  case n: \
+    sum = sum / (n + 1); \
+    sum = restore (sum, n + 1); \
+    if (sum == (n + addend)) \
+      break;\
+    sum = sum / (n + 2); \
+    sum = restore (sum, n + 2); \
+    sum = sum / (n + 3); \
+    sum = restore (sum, n + 3); \
+    sum = sum / (n + 4); \
+    sum = restore (sum, n + 4); \
+    sum = sum / (n + 5); \
+    sum = restore (sum, n + 5); \
+    sum = sum / (n + 6); \
+    sum = restore (sum, n + 6); \
+    sum = sum / (n + 7); \
+    sum = restore (sum, n + 7); \
+    sum = sum / (n + 8); \
+    sum = restore (sum, n + 8); \
+    sum = sum / (n + 9); \
+    sum = restore (sum, n + 9); \
+    sum = sum / (n + 10); \
+    sum = restore (sum, n + 10); \
+    sum = sum / (n + 11); \
+    sum = restore (sum, n + 11); \
+    sum = sum / (n + 12); \
+    sum = restore (sum, n + 12); \
+    sum = sum / (n + 13); \
+    sum = restore (sum, n + 13); \
+    sum = sum / (n + 14); \
+    sum = restore (sum, n + 14); \
+    sum = sum / (n + 15); \
+    sum = restore (sum, n + 15); \
+    sum = sum / (n + 16); \
+    sum = restore (sum, n + 16); \
+    sum = sum / (n + 17); \
+    sum = restore (sum, n + 17); \
+    sum = sum / (n + 18); \
+    sum = restore (sum, n + 18); \
+    sum = sum / (n + 19); \
+    sum = restore (sum, n + 19); \
+    sum = sum / (n + 20); \
+    sum = restore (sum, n + 20); \
+    sum = sum / (n + 21); \
+    sum = restore (sum, n + 21); \
+    sum = sum / (n + 22); \
+    sum = restore (sum, n + 22); \
+    sum = sum / (n + 23); \
+    sum = restore (sum, n + 23); \
+    sum = sum / (n + 24); \
+    sum = restore (sum, n + 24); \
+    sum = sum / (n + 25); \
+    sum = restore (sum, n + 25); \
+    sum = sum / (n + 26); \
+    sum = restore (sum, n + 26); \
+    sum = sum / (n + 27); \
+    sum = restore (sum, n + 27); \
+    sum = sum / (n + 28); \
+    sum = restore (sum, n + 28); \
+    sum = sum / (n + 29); \
+    sum = restore (sum, n + 29); \
+    sum = sum / (n + 30); \
+    sum = restore (sum, n + 30); \
+    sum = sum / (n + 31); \
+    sum = restore (sum, n + 31); \
+    sum = sum / (n + 32); \
+    sum = restore (sum, n + 32); \
+    sum = sum / (n + 33); \
+    sum = restore (sum, n + 33); \
+    sum = sum / (n + 34); \
+    sum = restore (sum, n + 34); \
+    sum = sum / (n + 35); \
+    sum = restore (sum, n + 35); \
+    sum = sum / (n + 36); \
+    sum = restore (sum, n + 36); \
+    sum = sum / (n + 37); \
+    sum = restore (sum, n + 37); \
+    sum = sum / (n + 38); \
+    sum = restore (sum, n + 38); \
+    sum = sum / (n + 39); \
+    sum = restore (sum, n + 39); \
+    sum = sum / (n + 40); \
+    sum = restore (sum, n + 40); \
+    sum = sum / (n + 41); \
+    sum = restore (sum, n + 41); \
+    sum = sum / (n + 42); \
+    sum = restore (sum, n + 42); \
+    sum = sum / (n + 43); \
+    sum = restore (sum, n + 43); \
+    sum = sum / (n + 44); \
+    sum = restore (sum, n + 44); \
+    sum = sum / (n + 45); \
+    sum = restore (sum, n + 45); \
+    sum = sum / (n + 46); \
+    sum = restore (sum, n + 46); \
+    sum = sum / (n + 47); \
+    sum = restore (sum, n + 47); \
+    sum = sum / (n + 48); \
+    sum = restore (sum, n + 48); \
+    sum = sum / (n + 49); \
+    sum = restore (sum, n + 49); \
+    sum = sum / (n + 50); \
+    sum = restore (sum, n + 50); \
+    sum = sum / (n + 51); \
+    sum = restore (sum, n + 51); \
+    sum = sum / (n + 52); \
+    sum = restore (sum, n + 52); \
+    sum = sum / (n + 53); \
+    sum = restore (sum, n + 53); \
+    sum = sum / (n + 54); \
+    sum = restore (sum, n + 54); \
+    sum = sum / (n + 55); \
+    sum = restore (sum, n + 55); \
+    sum = sum / (n + 56); \
+    sum = restore (sum, n + 56); \
+    sum = sum / (n + 57); \
+    sum = restore (sum, n + 57); \
+    sum = sum / (n + 58); \
+    sum = restore (sum, n + 58); \
+    sum = sum / (n + 59); \
+    sum = restore (sum, n + 59); \
+    sum = sum / (n + 60); \
+    sum = restore (sum, n + 60); \
+    sum = sum / (n + 61); \
+    sum = restore (sum, n + 61); \
+    sum = sum / (n + 62); \
+    sum = restore (sum, n + 62); \
+    sum = sum / (n + 63); \
+    sum = restore (sum, n + 63); \
+    sum = sum / (n + 64); \
+    sum = restore (sum, n + 64); \
+    sum = sum / (n + 65); \
+    sum = restore (sum, n + 65); \
+    sum = sum / (n + 66); \
+    sum = restore (sum, n + 66); \
+    sum = sum / (n + 67); \
+    sum = restore (sum, n + 67); \
+    sum = sum / (n + 68); \
+    sum = restore (sum, n + 68); \
+    sum = sum / (n + 69); \
+    sum = restore (sum, n + 69); \
+    sum = sum / (n + 70); \
+    sum = restore (sum, n + 70); \
+    sum = sum / (n + 71); \
+    sum = restore (sum, n + 71); \
+    sum = sum / (n + 72); \
+    sum = restore (sum, n + 72); \
+    sum = sum / (n + 73); \
+    sum = restore (sum, n + 73); \
+    sum = sum / (n + 74); \
+    sum = restore (sum, n + 74); \
+    sum = sum / (n + 75); \
+    sum = restore (sum, n + 75); \
+    sum = sum / (n + 76); \
+    sum = restore (sum, n + 76); \
+    sum = sum / (n + 77); \
+    sum = restore (sum, n + 77); \
+    sum = sum / (n + 78); \
+    sum = restore (sum, n + 78); \
+    sum = sum / (n + 79); \
+    sum = restore (sum, n + 79); \
+    sum = sum / (n + 80); \
+    sum = restore (sum, n + 80); \
+    sum = sum / (n + 81); \
+    sum = restore (sum, n + 81); \
+    sum = sum / (n + 82); \
+    sum = restore (sum, n + 82); \
+    sum = sum / (n + 83); \
+    sum = restore (sum, n + 83); \
+    sum = sum / (n + 84); \
+    sum = restore (sum, n + 84); \
+    sum = sum / (n + 85); \
+    sum = restore (sum, n + 85); \
+    sum = sum / (n + 86); \
+    sum = restore (sum, n + 86); \
+    sum = sum / (n + 87); \
+    sum = restore (sum, n + 87); \
+    sum = sum / (n + 88); \
+    sum = restore (sum, n + 88); \
+    sum = sum / (n + 89); \
+    sum = restore (sum, n + 89); \
+    sum = sum / (n + 90); \
+    sum = restore (sum, n + 90); \
+    sum = sum / (n + 91); \
+    sum = restore (sum, n + 91); \
+    sum = sum / (n + 92); \
+    sum = restore (sum, n + 92); \
+    sum = sum / (n + 93); \
+    sum = restore (sum, n + 93); \
+    sum = sum / (n + 94); \
+    sum = restore (sum, n + 94); \
+    sum = sum / (n + 95); \
+    sum = restore (sum, n + 95); \
+    sum = sum / (n + 96); \
+    sum = restore (sum, n + 96); \
+    sum = sum / (n + 97); \
+    sum = restore (sum, n + 97); \
+    sum = sum / (n + 98); \
+    sum = restore (sum, n + 98); \
+    sum = sum / (n + 99); \
+    sum = restore (sum, n + 99); \
+    sum = sum / (n + 100); \
+    sum = restore (sum, n + 100); \
+    sum = sum / (n + 101); \
+    sum = restore (sum, n + 101); \
+    sum = sum / (n + 102); \
+    sum = restore (sum, n + 102); \
+    sum = sum / (n + 103); \
+    sum = restore (sum, n + 103); \
+    sum = sum / (n + 104); \
+    sum = restore (sum, n + 104); \
+    sum = sum / (n + 105); \
+    sum = restore (sum, n + 105); \
+    sum = sum / (n + 106); \
+    sum = restore (sum, n + 106); \
+    sum = sum / (n + 107); \
+    sum = restore (sum, n + 107); \
+    sum = sum / (n + 108); \
+    sum = restore (sum, n + 108); \
+    sum = sum / (n + 109); \
+    sum = restore (sum, n + 109); \
+    sum = sum / (n + 110); \
+    sum = restore (sum, n + 110); \
+    sum = sum / (n + 111); \
+    sum = restore (sum, n + 111); \
+    sum = sum / (n + 112); \
+    sum = restore (sum, n + 112); \
+    sum = sum / (n + 113); \
+    sum = restore (sum, n + 113); \
+    sum = sum / (n + 114); \
+    sum = restore (sum, n + 114); \
+    sum = sum / (n + 115); \
+    sum = restore (sum, n + 115); \
+    sum = sum / (n + 116); \
+    sum = restore (sum, n + 116); \
+    sum = sum / (n + 117); \
+    sum = restore (sum, n + 117); \
+    sum = sum / (n + 118); \
+    sum = restore (sum, n + 118); \
+    sum = sum / (n + 119); \
+    sum = restore (sum, n + 119); \
+    sum = sum / (n + 120); \
+    sum = restore (sum, n + 120); \
+    sum = sum / (n + 121); \
+    sum = restore (sum, n + 121); \
+    sum = sum / (n + 122); \
+    sum = restore (sum, n + 122); \
+    sum = sum / (n + 123); \
+    sum = restore (sum, n + 123); \
+    sum = sum / (n + 124); \
+    sum = restore (sum, n + 124); \
+    sum = sum / (n + 125); \
+    sum = restore (sum, n + 125); \
+    sum = sum / (n + 126); \
+    sum = restore (sum, n + 126); \
+    sum = sum / (n + 127); \
+    sum = restore (sum, n + 127); \
+    sum = sum / (n + 128); \
+    sum = restore (sum, n + 128); \
+    sum = sum / (n + 129); \
+    sum = restore (sum, n + 129); \
+    sum = sum / (n + 130); \
+    sum = restore (sum, n + 130); \
+    sum = sum / (n + 131); \
+    sum = restore (sum, n + 131); \
+    sum = sum / (n + 132); \
+    sum = restore (sum, n + 132); \
+    sum = sum / (n + 133); \
+    sum = restore (sum, n + 133); \
+    sum = sum / (n + 134); \
+    sum = restore (sum, n + 134); \
+    sum = sum / (n + 135); \
+    sum = restore (sum, n + 135); \
+    sum = sum / (n + 136); \
+    sum = restore (sum, n + 136); \
+    sum = sum / (n + 137); \
+    sum = restore (sum, n + 137); \
+    sum = sum / (n + 138); \
+    sum = restore (sum, n + 138); \
+    sum = sum / (n + 139); \
+    sum = restore (sum, n + 139); \
+    sum = sum / (n + 140); \
+    sum = restore (sum, n + 140); \
+    sum = sum / (n + 141); \
+    sum = restore (sum, n + 141); \
+    sum = sum / (n + 142); \
+    sum = restore (sum, n + 142); \
+    sum = sum / (n + 143); \
+    sum = restore (sum, n + 143); \
+    sum = sum / (n + 144); \
+    sum = restore (sum, n + 144); \
+    sum = sum / (n + 145); \
+    sum = restore (sum, n + 145); \
+    sum = sum / (n + 146); \
+    sum = restore (sum, n + 146); \
+    sum = sum / (n + 147); \
+    sum = restore (sum, n + 147); \
+    sum = sum / (n + 148); \
+    sum = restore (sum, n + 148); \
+    sum = sum / (n + 149); \
+    sum = restore (sum, n + 149); \
+    sum = sum / (n + 150); \
+    sum = restore (sum, n + 150); \
+    break;
+
+__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_ENTRY (1)
+	  CASE_ENTRY (2)
+	  CASE_ENTRY (3)
+	  CASE_ENTRY (4)
+	  CASE_ENTRY (5)
+	  CASE_ENTRY (6)
+	  CASE_ENTRY (7)
+	  CASE_ENTRY (8)
+	  CASE_ENTRY (9)
+	  CASE_ENTRY (10)
+	  CASE_ENTRY (11)
+	  CASE_ENTRY (12)
+	  CASE_ENTRY (13)
+	  CASE_ENTRY (14)
+	  CASE_ENTRY (15)
+	  CASE_ENTRY (16)
+	  CASE_ENTRY (17)
+	  CASE_ENTRY (18)
+	  CASE_ENTRY (19)
+	  CASE_ENTRY (20)
+	  CASE_ENTRY (21)
+	  CASE_ENTRY (22)
+	  CASE_ENTRY (23)
+	  CASE_ENTRY (24)
+	  CASE_ENTRY (25)
+	  CASE_ENTRY (26)
+	  CASE_ENTRY (27)
+	  CASE_ENTRY (28)
+	  CASE_ENTRY (29)
+	  CASE_ENTRY (30)
+	  CASE_ENTRY (31)
+	  CASE_ENTRY (32)
+	  CASE_ENTRY (33)
+	  CASE_ENTRY (34)
+	  CASE_ENTRY (35)
+	  CASE_ENTRY (36)
+	  CASE_ENTRY (37)
+	  CASE_ENTRY (38)
+	  CASE_ENTRY (39)
+	  CASE_ENTRY (40)
+	  CASE_ENTRY (41)
+	  CASE_ENTRY (42)
+	  CASE_ENTRY (43)
+	  CASE_ENTRY (44)
+	  CASE_ENTRY (45)
+	  CASE_ENTRY (46)
+	  CASE_ENTRY (47)
+	  CASE_ENTRY (48)
+	  CASE_ENTRY (49)
+	  CASE_ENTRY (50)
+	  CASE_ENTRY (51)
+	  CASE_ENTRY (52)
+	  CASE_ENTRY (53)
+	  CASE_ENTRY (54)
+	  CASE_ENTRY (55)
+	  CASE_ENTRY (56)
+	  CASE_ENTRY (57)
+	  CASE_ENTRY (58)
+	  CASE_ENTRY (59)
+	  CASE_ENTRY (60)
+	  CASE_ENTRY (61)
+	  CASE_ENTRY (62)
+	  CASE_ENTRY (63)
+	  CASE_ENTRY (64)
+	  CASE_ENTRY (65)
+	  CASE_ENTRY (66)
+	  CASE_ENTRY (67)
+	  CASE_ENTRY (68)
+	  CASE_ENTRY (69)
+	  CASE_ENTRY (70)
+	  CASE_ENTRY (71)
+	  CASE_ENTRY (72)
+	  CASE_ENTRY (73)
+	  CASE_ENTRY (74)
+	  CASE_ENTRY (75)
+	  CASE_ENTRY (76)
+	  CASE_ENTRY (77)
+	  CASE_ENTRY (78)
+	  CASE_ENTRY (79)
+	  CASE_ENTRY (80)
+	  CASE_ENTRY (81)
+	  CASE_ENTRY (82)
+	  CASE_ENTRY (83)
+	  CASE_ENTRY (84)
+	  CASE_ENTRY (85)
+	  CASE_ENTRY (86)
+	  CASE_ENTRY (87)
+	  CASE_ENTRY (88)
+	  CASE_ENTRY (89)
+	  CASE_ENTRY (90)
+	  CASE_ENTRY (91)
+	  CASE_ENTRY (92)
+	  CASE_ENTRY (93)
+	  CASE_ENTRY (94)
+	  CASE_ENTRY (95)
+	  CASE_ENTRY (96)
+	  CASE_ENTRY (97)
+	  CASE_ENTRY (98)
+	  CASE_ENTRY (99)
+	  CASE_ENTRY (100)
+	  CASE_ENTRY (101)
+	  CASE_ENTRY (102)
+	  CASE_ENTRY (103)
+	  CASE_ENTRY (104)
+	  CASE_ENTRY (105)
+	  CASE_ENTRY (106)
+	  CASE_ENTRY (107)
+	  CASE_ENTRY (108)
+	  CASE_ENTRY (109)
+	  CASE_ENTRY (110)
+	  CASE_ENTRY (111)
+	  CASE_ENTRY (112)
+	  CASE_ENTRY (113)
+	  CASE_ENTRY (114)
+	  CASE_ENTRY (115)
+	  CASE_ENTRY (116)
+	  CASE_ENTRY (117)
+	  CASE_ENTRY (118)
+	  CASE_ENTRY (119)
+	  CASE_ENTRY (120)
+	  CASE_ENTRY (121)
+	  CASE_ENTRY (122)
+	  CASE_ENTRY (123)
+	  CASE_ENTRY (124)
+	  CASE_ENTRY (125)
+	  CASE_ENTRY (126)
+	  CASE_ENTRY (127)
+	  CASE_ENTRY (128)
+	  CASE_ENTRY (129)
+	  CASE_ENTRY (130)
+	  CASE_ENTRY (131)
+	  CASE_ENTRY (132)
+	  CASE_ENTRY (133)
+	  CASE_ENTRY (134)
+	  CASE_ENTRY (135)
+	  CASE_ENTRY (136)
+	  CASE_ENTRY (137)
+	  CASE_ENTRY (138)
+	  CASE_ENTRY (139)
+	  CASE_ENTRY (140)
+	  CASE_ENTRY (141)
+	  CASE_ENTRY (142)
+	  CASE_ENTRY (143)
+	  CASE_ENTRY (144)
+	  CASE_ENTRY (145)
+	  CASE_ENTRY (146)
+	  CASE_ENTRY (147)
+	  CASE_ENTRY (148)
+	  CASE_ENTRY (149)
+	  CASE_ENTRY (150)
+	  CASE_ENTRY (151)
+	  CASE_ENTRY (152)
+	  CASE_ENTRY (153)
+	  CASE_ENTRY (154)
+	  CASE_ENTRY (155)
+	  CASE_ENTRY (156)
+	  CASE_ENTRY (157)
+	  CASE_ENTRY (158)
+	  CASE_ENTRY (159)
+	  CASE_ENTRY (160)
+	  CASE_ENTRY (161)
+	  CASE_ENTRY (162)
+	  CASE_ENTRY (163)
+	  CASE_ENTRY (164)
+	  CASE_ENTRY (165)
+	  CASE_ENTRY (166)
+	  CASE_ENTRY (167)
+	  CASE_ENTRY (168)
+	  CASE_ENTRY (169)
+	  CASE_ENTRY (170)
+	  CASE_ENTRY (171)
+	  CASE_ENTRY (172)
+	  CASE_ENTRY (173)
+	  CASE_ENTRY (174)
+	  CASE_ENTRY (175)
+	  CASE_ENTRY (176)
+	  CASE_ENTRY (177)
+	  CASE_ENTRY (178)
+	  CASE_ENTRY (179)
+	  CASE_ENTRY (180)
+	  CASE_ENTRY (181)
+	  CASE_ENTRY (182)
+	  CASE_ENTRY (183)
+	  CASE_ENTRY (184)
+	  CASE_ENTRY (185)
+	  CASE_ENTRY (186)
+	  CASE_ENTRY (187)
+	  CASE_ENTRY (188)
+	  CASE_ENTRY (189)
+	  CASE_ENTRY (190)
+	  CASE_ENTRY (191)
+	  CASE_ENTRY (192)
+	  CASE_ENTRY (193)
+	  CASE_ENTRY (194)
+	  CASE_ENTRY (195)
+	  CASE_ENTRY (196)
+	  CASE_ENTRY (197)
+	  CASE_ENTRY (198)
+	  CASE_ENTRY (199)
+	  CASE_ENTRY (200)
+	}
+
+      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" } } */
-- 
1.9.1