diff options
author | Stam Markianos-Wright <stam.markianos-wright@arm.com> | 2020-11-30 10:47:54 +0000 |
---|---|---|
committer | Stam Markianos-Wright <stam.markianos-wright@arm.com> | 2020-11-30 10:56:09 +0000 |
commit | 3a936a9ecddef58ad5b6ee11697c3f791b942708 (patch) | |
tree | ffbd0b574b10fc78f8e4ae823a16d162e2000592 /gcc/config | |
parent | c715a3659873b5f6b449493f54a29c26d06dfd1c (diff) | |
download | gcc-3a936a9ecddef58ad5b6ee11697c3f791b942708.zip gcc-3a936a9ecddef58ad5b6ee11697c3f791b942708.tar.gz gcc-3a936a9ecddef58ad5b6ee11697c3f791b942708.tar.bz2 |
Backport of the patch for PR target/91816
This is a patch for an issue where the compiler was generating a
conditional branch in Thumb2, which was too far for b{cond} to handle.
This backport also includes the subsequent fixes to the test in this
patch.
gcc/ChangeLog
PR target/91816
* config/arm/arm-protos.h: New function arm_gen_far_branch prototype.
* config/arm/arm.c (arm_gen_far_branch): New function
arm_gen_far_branch.
* config/arm/arm.md: Update b<cond> for Thumb2 range checks.
gcc/testsuite/ChangeLog
PR target/91816
* gcc.target/arm/pr91816.c: New test.
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/arm/arm-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 33 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 112 |
3 files changed, 121 insertions, 26 deletions
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 9d0acde..87e01e3 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -553,4 +553,6 @@ void arm_parse_option_features (sbitmap, const cpu_arch_option *, void arm_initialize_isa (sbitmap, const enum isa_feature *); +const char * arm_gen_far_branch (rtx *, int, const char * , const char *); + #endif /* ! GCC_ARM_PROTOS_H */ diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index f990ca1..eefe3d9 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -31629,6 +31629,39 @@ arm_constant_alignment (const_tree exp, HOST_WIDE_INT align) return align; } +/* Generate code to enable conditional branches in functions over 1 MiB. + Parameters are: + operands: is the operands list of the asm insn (see arm_cond_branch or + arm_cond_branch_reversed). + pos_label: is an index into the operands array where operands[pos_label] is + the asm label of the final jump destination. + dest: is a string which is used to generate the asm label of the intermediate + destination + branch_format: is a string denoting the intermediate branch format, e.g. + "beq", "bne", etc. */ + +const char * +arm_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 = arm_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%%l0%d\n%s:", pos_label, label_ptr); + operands[pos_label] = dest_label; + output_asm_insn (buffer, operands); + return ""; +} + #if CHECKING_P namespace selftest { diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 6d6b377..81c9665 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -7187,9 +7187,15 @@ ;; And for backward branches we have ;; (neg_range - neg_base_offs + pc_offs) = (neg_range - (-2 or -4) + 4). ;; +;; In 16-bit Thumb these ranges are: ;; For a 'b' pos_range = 2046, neg_range = -2048 giving (-2040->2048). ;; For a 'b<cond>' pos_range = 254, neg_range = -256 giving (-250 ->256). +;; In 32-bit Thumb these ranges are: +;; For a 'b' +/- 16MB is not checked for. +;; For a 'b<cond>' pos_range = 1048574, neg_range = -1048576 giving +;; (-1048568 -> 1048576). + (define_expand "cbranchsi4" [(set (pc) (if_then_else (match_operator 0 "expandable_comparison_operator" @@ -7444,23 +7450,50 @@ (label_ref (match_operand 0 "" "")) (pc)))] "TARGET_32BIT" - "* - if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) { arm_ccfsm_state += 2; - return \"\"; + return ""; } - return \"b%d1\\t%l0\"; - " + switch (get_attr_length (insn)) + { + case 2: /* Thumb2 16-bit b{cond}. */ + case 4: /* Thumb2 32-bit b{cond} or A32 b{cond}. */ + return "b%d1\t%l0"; + break; + + /* Thumb2 b{cond} out of range. Use 16-bit b{cond} and + unconditional branch b. */ + default: return arm_gen_far_branch (operands, 0, "Lbcond", "b%D1\t"); + } + } [(set_attr "conds" "use") (set_attr "type" "branch") (set (attr "length") - (if_then_else - (and (match_test "TARGET_THUMB2") - (and (ge (minus (match_dup 0) (pc)) (const_int -250)) - (le (minus (match_dup 0) (pc)) (const_int 256)))) - (const_int 2) - (const_int 4)))] + (if_then_else (match_test "!TARGET_THUMB2") + + ;;Target is not Thumb2, therefore is A32. Generate b{cond}. + (const_int 4) + + ;; Check if target is within 16-bit Thumb2 b{cond} range. + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -250)) + (le (minus (match_dup 0) (pc)) (const_int 256))) + + ;; Target is Thumb2, within narrow range. + ;; Generate b{cond}. + (const_int 2) + + ;; Check if target is within 32-bit Thumb2 b{cond} range. + (if_then_else (and (ge (minus (match_dup 0) (pc))(const_int -1048568)) + (le (minus (match_dup 0) (pc)) (const_int 1048576))) + + ;; Target is Thumb2, within wide range. + ;; Generate b{cond} + (const_int 4) + ;; Target is Thumb2, out of range. + ;; Generate narrow b{cond} and unconditional branch b. + (const_int 6)))))] ) (define_insn "*arm_cond_branch_reversed" @@ -7470,23 +7503,50 @@ (pc) (label_ref (match_operand 0 "" ""))))] "TARGET_32BIT" - "* - if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) - { - arm_ccfsm_state += 2; - return \"\"; - } - return \"b%D1\\t%l0\"; - " - [(set_attr "conds" "use") + { + if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) + { + arm_ccfsm_state += 2; + return ""; + } + switch (get_attr_length (insn)) + { + case 2: /* Thumb2 16-bit b{cond}. */ + case 4: /* Thumb2 32-bit b{cond} or A32 b{cond}. */ + return "b%D1\t%l0"; + break; + + /* Thumb2 b{cond} out of range. Use 16-bit b{cond} and + unconditional branch b. */ + default: return arm_gen_far_branch (operands, 0, "Lbcond", "b%d1\t"); + } + } +[(set_attr "conds" "use") (set_attr "type" "branch") (set (attr "length") - (if_then_else - (and (match_test "TARGET_THUMB2") - (and (ge (minus (match_dup 0) (pc)) (const_int -250)) - (le (minus (match_dup 0) (pc)) (const_int 256)))) - (const_int 2) - (const_int 4)))] + (if_then_else (match_test "!TARGET_THUMB2") + + ;;Target is not Thumb2, therefore is A32. Generate b{cond}. + (const_int 4) + + ;; Check if target is within 16-bit Thumb2 b{cond} range. + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -250)) + (le (minus (match_dup 0) (pc)) (const_int 256))) + + ;; Target is Thumb2, within narrow range. + ;; Generate b{cond}. + (const_int 2) + + ;; Check if target is within 32-bit Thumb2 b{cond} range. + (if_then_else (and (ge (minus (match_dup 0) (pc))(const_int -1048568)) + (le (minus (match_dup 0) (pc)) (const_int 1048576))) + + ;; Target is Thumb2, within wide range. + ;; Generate b{cond}. + (const_int 4) + ;; Target is Thumb2, out of range. + ;; Generate narrow b{cond} and unconditional branch b. + (const_int 6)))))] ) |