From patchwork Fri Sep 11 17:15:23 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Andre Vieira (lists)" X-Patchwork-Id: 516916 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4774A140180 for ; Sat, 12 Sep 2015 03:15:38 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=YYx/SVBh; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; q= dns; s=default; b=JXC+sh7CuwlvQ3NXzVdnRtfTcKF/QSt2ADbBzVauTVd5ac xuRHF3KUhNIlPS6+3dF3AfQVFU5UJQo81YNiio8UIg6QJ3kBhKWaZIHC40GT5d6H Hp1Ewlc5xT3mW1Eff3R1xxh00L9epcOFcq7STGJO2q4duy8JFz4sGmFqujTTY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; s= default; bh=IWmwU6B4cFnXoWE6oS2ko5MvH08=; b=YYx/SVBhmrY/heFVLV0B AddqcOhFThmolSv244wHYoaNFMadA0vrZj0GYHqQYJ7LOHweHljrn+utQ6DRqeUT PmwObCCd3CIyxzlPTqQAI/lbPD33xn2vQBUjnInGsOmCpWZy6YtiitOZkyVd7ycB M+5PKl8LQqImsDz/kpmu63E= Received: (qmail 108432 invoked by alias); 11 Sep 2015 17:15:31 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 108421 invoked by uid 89); 11 Sep 2015 17:15:31 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.4 required=5.0 tests=AWL, BAYES_50, KAM_ASCII_DIVIDERS, KAM_LOTSOFHASH, SPF_PASS autolearn=no version=3.3.2 X-HELO: eu-smtp-delivery-143.mimecast.com Received: from eu-smtp-delivery-143.mimecast.com (HELO eu-smtp-delivery-143.mimecast.com) (207.82.80.143) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 11 Sep 2015 17:15:27 +0000 Received: from cam-owa1.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by eu-smtp-1.mimecast.com with ESMTP id uk-mta-28-vFPaFiokSHeK6Z54t6qjPQ-1; Fri, 11 Sep 2015 18:15:23 +0100 Received: from [10.2.206.103] ([10.1.2.79]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Fri, 11 Sep 2015 18:15:23 +0100 Message-ID: <55F30C2B.4020506@arm.com> Date: Fri, 11 Sep 2015 18:15:23 +0100 From: Andre Vieira User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 MIME-Version: 1.0 To: GCC Patches Subject: [gcc-5-branch][PATCH][AARCH64]Fix for branch offsets over 1 MiB X-MC-Unique: vFPaFiokSHeK6Z54t6qjPQ-1 X-IsSubscribed: yes 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. This patch backports the fix from trunk to the gcc-5-branch. The original patch is at: https://gcc.gnu.org/ml/gcc-patches/2015-08/msg01493.html gcc/ChangeLog: 2015-09-09 Andre Vieira Backport from mainline: 2015-08-27 Ramana Radhakrishnan Andre Vieira * config/aarch64/aarch64.md (*condjump): Handle functions > 1 MiB. (*cb1): Likewise. (*tb1): Likewise. (*cb1): 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/ChangeLog: 2015-09-09 Andre Vieira Backport from mainline: 2015-08-27 Andre Vieira * gcc.target/aarch64/long_branch_1.c: New test. From 5b9f35c3a6dff67328e66e82f33ef3dc732ff5f7 Mon Sep 17 00:00:00 2001 From: Andre Simoes Dias Vieira Date: Tue, 8 Sep 2015 16:51:14 +0100 Subject: [PATCH] Backport 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_1.c | 91 ++++++++++++++++++++++++ 5 files changed, 195 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/long_branch_1.c diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 59c5824f894cf5dafe93a996180056696518feb4..8669694bfc33cc040baeab5aaddc7a0575071add 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -258,6 +258,7 @@ void aarch64_init_expanders (void); void aarch64_print_operand (FILE *, rtx, char); void aarch64_print_operand_address (FILE *, rtx); void aarch64_emit_call_insn (rtx); +const char * aarch64_gen_far_branch (rtx *, int, const char *, const char *); /* Initialize builtins for SIMD intrinsics. */ void init_aarch64_simd_builtins (void); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index cd20b48d7fd300ab496e67cae0d6e503ac305409..c2e4252cf689a4d7b28890743095536f3a390338 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1029,6 +1029,29 @@ aarch64_split_128bit_move_p (rtx dst, rtx src) /* Split a complex SIMD combine. */ +/* 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_split_simd_combine (rtx dst, rtx src1, rtx src2) { diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 4e7a6d19ac2ff8067912052697ca7a1fc403f910..c3c3beb75b4d4486d5b235e31b4db7bd213c7c7b 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -179,6 +179,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 ;; ------------------------------------------------------------------- @@ -306,8 +313,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" @@ -486,9 +508,23 @@ (label_ref (match_operand 1 "" "")) (pc)))] "" - "\\t%0, %l1" - [(set_attr "type" "branch")] - + { + if (get_attr_length (insn) == 8) + return aarch64_gen_far_branch (operands, 1, "Lcb", "\\t%0, "); + else + return "\\t%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 "*tb1" @@ -504,8 +540,14 @@ { if (get_attr_length (insn) == 8) { - operands[1] = GEN_INT (HOST_WIDE_INT_1U << UINTVAL (operands[1])); - return "tst\t%0, %1\;\t%l2"; + if (get_attr_far_branch (insn) == 1) + return aarch64_gen_far_branch (operands, 2, "Ltb", + "\\t%0, %1, "); + else + { + operands[1] = GEN_INT (HOST_WIDE_INT_1U << UINTVAL (operands[1])); + return "tst\t%0, %1\;\t%l2"; + } } else return "\t%0, %1, %l2"; @@ -515,7 +557,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 "*cb1" @@ -528,12 +576,18 @@ { if (get_attr_length (insn) == 8) { - char buf[64]; - uint64_t val = ((uint64_t ) 1) - << (GET_MODE_SIZE (mode) * BITS_PER_UNIT - 1); - sprintf (buf, "tst\t%%0, %"PRId64, val); - output_asm_insn (buf, operands); - return "\t%l1"; + if (get_attr_far_branch (insn) == 1) + return aarch64_gen_far_branch (operands, 1, "Ltb", + "\\t%0, , "); + else + { + char buf[64]; + uint64_t val = ((uint64_t) 1) + << (GET_MODE_SIZE (mode) * BITS_PER_UNIT - 1); + sprintf (buf, "tst\t%%0, %" PRId64, val); + output_asm_insn (buf, operands); + return "\t%l1"; + } } else return "\t%0, , %l1"; @@ -543,7 +597,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 498358a6354fe3afc3032d5be7526d942d1ec3ac..81ca974fdfd02bcd183357a8af450fe5c772c4ee 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -822,9 +822,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_1.c b/gcc/testsuite/gcc.target/aarch64/long_branch_1.c new file mode 100644 index 0000000000000000000000000000000000000000..46f500d36a2d9ff04f71ae0bcc7c47e3d0b92c1b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/long_branch_1.c @@ -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" } } */ -- 1.9.1