+2016-05-07 Oleg Endo <olegendo@gcc.gnu.org>
+
+ * config/sh/sh-protos.h (sh_cbranch_distance): Declare new function.
+ * config/sh/sh.c (sh_cbranch_distance): Implement it.
+ * config/sh/sh.md (branch_zero): Remove define_attr.
+ (define_delay): Disable delay slot if branch distance is one insn.
+
2016-05-06 Uros Bizjak <ubizjak@gmail.com>
* config/i386/i386.md (LEAMODE): New mode attribute.
extern sh_treg_insns sh_split_treg_set_expr (rtx x, rtx_insn* curr_insn);
+enum
+{
+ /* An effective conditional branch distance of zero bytes is impossible.
+ Hence we can use it to designate an unknown value. */
+ unknown_cbranch_distance = 0u,
+ infinite_cbranch_distance = ~0u
+};
+
+unsigned int
+sh_cbranch_distance (rtx_insn* cbranch_insn,
+ unsigned int max_dist = infinite_cbranch_distance);
+
#endif /* RTX_CODE */
extern void sh_cpu_cpp_builtins (cpp_reader* pfile);
return true;
}
+/* Try to calculate the branch distance of a conditional branch in bytes.
+
+ FIXME: Because of PR 59189 we can't use the CFG here. Instead just
+ walk from this insn into the next (fall-through) basic block and see if
+ we hit the label. */
+unsigned int
+sh_cbranch_distance (rtx_insn* _cbranch_insn, unsigned int max_dist)
+{
+ rtx_jump_insn* cbranch_insn = safe_as_a<rtx_jump_insn*> (_cbranch_insn);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "sh_cbranch_distance insn = \n");
+ print_rtl_single (dump_file, cbranch_insn);
+ }
+
+ unsigned int dist = 0;
+
+ for (rtx_insn* i = next_nonnote_insn (cbranch_insn);
+ i != NULL && dist < max_dist; i = next_nonnote_insn (i))
+ {
+ const unsigned int i_len = get_attr_length (i);
+ dist += i_len;
+
+ if (dump_file)
+ fprintf (dump_file, " insn %d length = %u dist = %u\n",
+ INSN_UID (i), i_len, dist);
+
+ if (rtx_code_label* l = dyn_cast<rtx_code_label*> (i))
+ {
+ if (l == cbranch_insn->jump_target ())
+ {
+ if (dump_file)
+ fprintf (dump_file, " cbranch dist = %u\n", dist);
+ return dist;
+ }
+ break;
+ }
+ }
+
+ if (dump_file)
+ fprintf (dump_file, " cbranch dist = unknown\n");
+
+ return unknown_cbranch_distance;
+}
+
enum rtx_code
prepare_cbranch_operands (rtx *operands, machine_mode mode,
enum rtx_code comparison)
(define_attr "is_sfunc" ""
(if_then_else (eq_attr "type" "sfunc") (const_int 1) (const_int 0)))
-(define_attr "branch_zero" "yes,no"
- (cond [(eq_attr "type" "!cbranch") (const_string "no")
- (ne (symbol_ref "(next_active_insn (insn)\
- == (prev_active_insn\
- (XEXP (SET_SRC (PATTERN (insn)), 1))))\
- && get_attr_length (next_active_insn (insn)) == 2")
- (const_int 0))
- (const_string "yes")]
- (const_string "no")))
-
;; SH4 Double-precision computation with double-precision result -
;; the two halves are ready at different times.
(define_attr "dfp_comp" "yes,no"
(eq_attr "type" "!pstore,prget")) (nil) (nil)])
;; Conditional branches with delay slots are available starting with SH2.
+;; If zero displacement conditional branches are fast, disable the delay
+;; slot if the branch jumps over only one 2-byte insn.
(define_delay
- (and (eq_attr "type" "cbranch") (match_test "TARGET_SH2"))
+ (and (eq_attr "type" "cbranch")
+ (match_test "TARGET_SH2")
+ (not (and (match_test "TARGET_ZDCBRANCH")
+ (match_test "sh_cbranch_distance (insn, 4) == 2"))))
[(eq_attr "cond_delay_slot" "yes") (nil) (nil)])
\f
;; -------------------------------------------------------------------------