Commit 44f77a6d by Stam Markianos-Wright

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.
parent e464fc90
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> 2020-02-03 Julian Brown <julian@codesourcery.com>
Tobias Burnus <tobias@codesourcery.com> Tobias Burnus <tobias@codesourcery.com>
......
...@@ -577,4 +577,6 @@ void arm_parse_option_features (sbitmap, const cpu_arch_option *, ...@@ -577,4 +577,6 @@ void arm_parse_option_features (sbitmap, const cpu_arch_option *,
void arm_initialize_isa (sbitmap, const enum isa_feature *); 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 */ #endif /* ! GCC_ARM_PROTOS_H */
...@@ -33041,6 +33041,40 @@ arm_run_selftests (void) ...@@ -33041,6 +33041,40 @@ arm_run_selftests (void)
} }
} /* Namespace selftest. */ } /* 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 #undef TARGET_RUN_TARGET_SELFTESTS
#define TARGET_RUN_TARGET_SELFTESTS selftest::arm_run_selftests #define TARGET_RUN_TARGET_SELFTESTS selftest::arm_run_selftests
#endif /* CHECKING_P */ #endif /* CHECKING_P */
......
...@@ -7584,9 +7584,15 @@ ...@@ -7584,9 +7584,15 @@
;; And for backward branches we have ;; And for backward branches we have
;; (neg_range - neg_base_offs + pc_offs) = (neg_range - (-2 or -4) + 4). ;; (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' pos_range = 2046, neg_range = -2048 giving (-2040->2048).
;; For a 'b<cond>' pos_range = 254, neg_range = -256 giving (-250 ->256). ;; 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" (define_expand "cbranchsi4"
[(set (pc) (if_then_else [(set (pc) (if_then_else
(match_operator 0 "expandable_comparison_operator" (match_operator 0 "expandable_comparison_operator"
...@@ -7759,23 +7765,50 @@ ...@@ -7759,23 +7765,50 @@
(label_ref (match_operand 0 "" "")) (label_ref (match_operand 0 "" ""))
(pc)))] (pc)))]
"TARGET_32BIT" "TARGET_32BIT"
"* {
if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
{ {
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 "conds" "use")
(set_attr "type" "branch") (set_attr "type" "branch")
(set (attr "length") (set (attr "length")
(if_then_else (if_then_else (match_test "!TARGET_THUMB2")
(and (match_test "TARGET_THUMB2")
(and (ge (minus (match_dup 0) (pc)) (const_int -250)) ;;Target is not Thumb2, therefore is A32. Generate b{cond}.
(le (minus (match_dup 0) (pc)) (const_int 256)))) (const_int 4)
(const_int 2)
(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" (define_insn "*arm_cond_branch_reversed"
...@@ -7785,23 +7818,50 @@ ...@@ -7785,23 +7818,50 @@
(pc) (pc)
(label_ref (match_operand 0 "" ""))))] (label_ref (match_operand 0 "" ""))))]
"TARGET_32BIT" "TARGET_32BIT"
"* {
if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2) if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
{ {
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 "conds" "use")
(set_attr "type" "branch") (set_attr "type" "branch")
(set (attr "length") (set (attr "length")
(if_then_else (if_then_else (match_test "!TARGET_THUMB2")
(and (match_test "TARGET_THUMB2")
(and (ge (minus (match_dup 0) (pc)) (const_int -250)) ;;Target is not Thumb2, therefore is A32. Generate b{cond}.
(le (minus (match_dup 0) (pc)) (const_int 256)))) (const_int 4)
(const_int 2)
(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)))))]
) )
......
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> 2020-02-03 Julian Brown <julian@codesourcery.com>
Tobias Burnus <tobias@codesourcery.com> Tobias Burnus <tobias@codesourcery.com>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment