aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStam Markianos-Wright <stam.markianos-wright@arm.com>2020-02-03 10:25:46 +0000
committerStam Markianos-Wright <stam.markianos-wright@arm.com>2020-02-03 10:30:59 +0000
commit44f77a6dea2f312ee1743f3dde465c1b8453ee13 (patch)
tree85bdcc4d04784d2b0074d00a4a8bba04ff0d3af2
parente464fc903506b75bef90374ab520b52df317a00e (diff)
downloadgcc-44f77a6dea2f312ee1743f3dde465c1b8453ee13.zip
gcc-44f77a6dea2f312ee1743f3dde465c1b8453ee13.tar.gz
gcc-44f77a6dea2f312ee1743f3dde465c1b8453ee13.tar.bz2
This patch is 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 was originally reported at binutils: https://sourceware.org/bugzilla/show_bug.cgi?id=24991 And then raised for GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91816 As can be seen here: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489c/Cihfddaf.html the range of a 32-bit Thumb B{cond} is +/-1MB. This is now checked for in arm.md and an unconditional branch is generated if the jump would be greater than 1MB. gcc/ChangeLog 2020-02-03 Stam Markianos-Wright <stam.markianos-wright@arm.com> 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 2020-02-03 Stam Markianos-Wright <stam.markianos-wright@arm.com> PR target/91816 * gcc.target/arm/pr91816.c: New test.
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/arm/arm-protos.h2
-rw-r--r--gcc/config/arm/arm.c34
-rw-r--r--gcc/config/arm/arm.md104
-rw-r--r--gcc/testsuite/ChangeLog5
5 files changed, 131 insertions, 22 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ca88b31..c0ef95f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2020-02-03 Stam Markianos-Wright <stam.markianos-wright@arm.com>
+
+ 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.
+
2020-02-03 Julian Brown <julian@codesourcery.com>
Tobias Burnus <tobias@codesourcery.com>
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 8830627..eaff654 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -577,4 +577,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 b54382d..b5ae7e3 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -33041,6 +33041,40 @@ arm_run_selftests (void)
}
} /* Namespace selftest. */
+
+/* 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 "";
+}
+
#undef TARGET_RUN_TARGET_SELFTESTS
#define TARGET_RUN_TARGET_SELFTESTS selftest::arm_run_selftests
#endif /* CHECKING_P */
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index dd73263..5baf82d 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -7584,9 +7584,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"
@@ -7759,23 +7765,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"
@@ -7785,23 +7818,50 @@
(pc)
(label_ref (match_operand 0 "" ""))))]
"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)))))]
)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 67ac4a7..cc9f3c1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2020-02-03 Stam Markianos-Wright <stam.markianos-wright@arm.com>
+
+ PR target/91816
+ * gcc.target/arm/pr91816.c: New test.
+
2020-02-03 Julian Brown <julian@codesourcery.com>
Tobias Burnus <tobias@codesourcery.com>